Skip to content

Commit

Permalink
Enhance the template handle for CppAst (#75)
Browse files Browse the repository at this point in the history
* 1. divide template Parameters to template parameter and template specialized argument
2. add TemplateKind to CppClass  for handle with TemplateClass & SpecializedTemplateClass
3. use ClangSharp internal Decl for handle ClangSharp.ClassTemplateSpecializationDecl, ClangSharp.NonTypeTemplateParmDecl easy
4. some features add for use CppAst easy in Exporter

* add missed test for Template changes

* Use ClangSharp low level objects api to implement the logic(high level api objects lifetime is wrong in hybrid mode here)

* Fix some problems for code review

1. remove not need internal ParseFromTranslationUnit
2. some name changes for class and params
3. add test code for FindByFullName()
4. move nested types to separate files.

---------

Co-authored-by: fangshen <[email protected]>
  • Loading branch information
fangfang1984 and fangshen authored Mar 17, 2023
1 parent 616dddd commit 6fc9dbd
Show file tree
Hide file tree
Showing 14 changed files with 572 additions and 30 deletions.
30 changes: 30 additions & 0 deletions src/CppAst.Tests/TestNamespaces.cs
Original file line number Diff line number Diff line change
Expand Up @@ -77,5 +77,35 @@ namespace A
}
);
}



[Test]
public void TestNamespaceFindByFullName()
{
var text = @"
namespace A
{
// Test using Template
template <typename T>
struct MyStruct;
using MyStructInt = MyStruct<int>;
}
";

ParseAssert(text,
compilation =>
{
Assert.False(compilation.HasErrors);

Assert.AreEqual(1, compilation.Namespaces.Count);

var cppStruct = compilation.FindByFullName<CppClass>("A::MyStruct");
Assert.AreEqual(compilation.Namespaces[0].Classes[0], cppStruct);
}
);
}
}
}
15 changes: 10 additions & 5 deletions src/CppAst.Tests/TestTypes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System;
using System.Linq;
using NUnit.Framework;
using static CppAst.CppTemplateArgument;

namespace CppAst.Tests
{
Expand Down Expand Up @@ -82,8 +83,9 @@ struct Struct2
var exposed = compilation.Fields[0].Type as CppClass;
Assert.AreEqual("TemplateStruct", exposed.Name);
Assert.AreEqual(2, exposed.TemplateParameters.Count);
Assert.AreEqual(CppPrimitiveKind.Int, (exposed.TemplateParameters[0] as CppPrimitiveType)?.Kind);
Assert.AreEqual("Struct2", (exposed.TemplateParameters[1] as CppClass)?.Name);
Assert.AreEqual(CppTemplateArgumentKind.AsType, exposed.TemplateSpecializedArguments[0]?.ArgKind);
Assert.AreEqual(CppPrimitiveKind.Int, (exposed.TemplateSpecializedArguments[0]?.ArgAsType as CppPrimitiveType).Kind);
Assert.AreEqual("Struct2", (exposed.TemplateSpecializedArguments[1].ArgAsType as CppClass)?.Name);

var specialized = exposed.SpecializedTemplate;
Assert.AreEqual("TemplateStruct", specialized.Name);
Expand All @@ -96,8 +98,9 @@ struct Struct2
var unexposed = compilation.Fields[1].Type as CppClass;
Assert.AreEqual("TemplateStruct", unexposed.Name);
Assert.AreEqual(2, unexposed.TemplateParameters.Count);
Assert.AreEqual(CppPrimitiveKind.Int, (unexposed.TemplateParameters[0] as CppPrimitiveType)?.Kind);
Assert.AreEqual("Struct2", (unexposed.TemplateParameters[1] as CppClass)?.Name);
Assert.AreEqual(CppTemplateArgumentKind.AsType, unexposed.TemplateSpecializedArguments[0]?.ArgKind);
Assert.AreEqual(CppPrimitiveKind.Int, (exposed.TemplateSpecializedArguments[0]?.ArgAsType as CppPrimitiveType).Kind);
Assert.AreEqual("Struct2", (unexposed.TemplateSpecializedArguments[1].ArgAsType as CppClass)?.Name);

Assert.AreNotEqual(exposed.GetHashCode(), specialized.GetHashCode());
Assert.AreEqual(exposed.GetHashCode(), unexposed.GetHashCode());
Expand Down Expand Up @@ -136,7 +139,9 @@ class Derived : public ::BaseTemplate<::Derived>
Assert.AreEqual(baseClassSpecialized, derived.BaseTypes[0].Type);

Assert.AreEqual(1, baseClassSpecialized.TemplateParameters.Count);
Assert.AreEqual(derived, baseClassSpecialized.TemplateParameters[0]);

//Here change to argument as a template deduce instance, not as a Template Parameters~~
Assert.AreEqual(derived, baseClassSpecialized.TemplateSpecializedArguments[0].ArgAsType);
Assert.AreEqual(baseTemplate, baseClassSpecialized.SpecializedTemplate);
}
);
Expand Down
57 changes: 56 additions & 1 deletion src/CppAst/CppClass.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,27 @@ public CppClass(string name) : base(CppTypeKind.StructOrClass)
/// </summary>
public CppClassKind ClassKind { get; set; }

public CppTemplateKind TemplateKind { get; set; }

/// <inheritdoc />
public string Name { get; set; }

public string FullName
{
get
{
string fullparent = FullParentName;
if(string.IsNullOrEmpty(fullparent))
{
return Name;
}
else
{
return $"{fullparent}{Name}";
}
}
}

/// <inheritdoc />
public CppVisibility Visibility { get; set; }

Expand Down Expand Up @@ -83,12 +101,20 @@ public CppClass(string name) : base(CppTypeKind.StructOrClass)
/// <inheritdoc />
public List<CppType> TemplateParameters { get; }

public List<CppTemplateArgument> TemplateSpecializedArguments { get; } = new List<CppTemplateArgument>();

/// <summary>
/// Gets the specialized class template of this instance.
/// </summary>
public CppClass SpecializedTemplate { get; set; }

private bool Equals(CppClass other)

public bool IsEmbeded => Parent is CppClass;

public bool IsAbstract { get; set; }


private bool Equals(CppClass other)
{
return base.Equals(other) && Equals(Parent, other.Parent) && Name.Equals(other.Name);
}
Expand Down Expand Up @@ -118,6 +144,10 @@ public override int GetHashCode()
foreach (var templateParameter in TemplateParameters)
{
hashCode = (hashCode * 397) ^ templateParameter.GetHashCode();
}
foreach (var templateArgument in TemplateSpecializedArguments)
{
hashCode = (hashCode * 397) ^ templateArgument.GetHashCode();
}
return hashCode;
}
Expand Down Expand Up @@ -164,6 +194,31 @@ public override string ToString()
}
}

//Add template arguments here
if(TemplateKind != CppTemplateKind.NormalClass)
{
builder.Append("<");

if(TemplateKind == CppTemplateKind.TemplateSpecializedClass)
{
for(var i = 0; i < TemplateSpecializedArguments.Count; i++)
{
if(i > 0) builder.Append(", ");
builder.Append(TemplateSpecializedArguments[i].ToString());
}
}
else if(TemplateKind == CppTemplateKind.TemplateClass)
{
for (var i = 0; i < TemplateParameters.Count; i++)
{
if (i > 0) builder.Append(", ");
builder.Append(TemplateParameters[i].ToString());
}
}

builder.Append(">");
}

builder.Append(" { ... }");
return builder.ToString();
}
Expand Down
37 changes: 37 additions & 0 deletions src/CppAst/CppElement.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
// Licensed under the BSD-Clause 2 license.
// See license.txt file in the project root for full license information.

using System;

namespace CppAst
{
/// <summary>
Expand All @@ -19,6 +21,41 @@ public abstract class CppElement : ICppElement
/// </summary>
public ICppContainer Parent { get; internal set; }

public string FullParentName
{
get
{
string tmpname = "";
var p = Parent;
while (p != null)
{
if (p is CppClass)
{
var cpp = p as CppClass;
tmpname = $"{cpp.Name}::{tmpname}";
p = cpp.Parent;
}
else if (p is CppNamespace)
{
var ns = p as CppNamespace;
tmpname = $"{ns.Name}::{tmpname}";
p = ns.Parent;
}
else if (p is CppCompilation)
{
// root namespace here, just ignore~
p = null;
}
else
{
throw new NotImplementedException("Can not be here, not support type here!");
}
}

return tmpname;
}
}

/// <summary>
/// Gets the source file of this element.
/// </summary>
Expand Down
25 changes: 21 additions & 4 deletions src/CppAst/CppEnum.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,27 @@ public CppEnum(string name) : base(CppTypeKind.Enum)
/// <inheritdoc />
public string Name { get; set; }

/// <summary>
/// Gets or sets a boolean indicating if this enum is scoped.
/// </summary>
public bool IsScoped { get; set; }
public string FullName
{
get
{
string fullparent = FullParentName;
if (string.IsNullOrEmpty(fullparent))
{
return Name;
}
else
{
return $"{fullparent}{Name}";
}
}
}


/// <summary>
/// Gets or sets a boolean indicating if this enum is scoped.
/// </summary>
public bool IsScoped { get; set; }


/// <summary>
Expand Down
28 changes: 28 additions & 0 deletions src/CppAst/CppFunction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Licensed under the BSD-Clause 2 license.
// See license.txt file in the project root for full license information.

using System;
using System.Collections.Generic;
using System.Text;

Expand Down Expand Up @@ -65,11 +66,38 @@ public CppFunction(string name)
/// </summary>
public CppContainerList<CppParameter> Parameters { get; }

public int DefaultParamCount
{
get
{
int default_count = 0;
foreach (var param in Parameters)
{
if(param.InitExpression != null)
{
default_count++;
}
}
return default_count;
}
}

/// <summary>
/// Gets or sets the flags of this function.
/// </summary>
public CppFunctionFlags Flags { get; set; }

public bool IsCxxClassMethod => ((int)Flags & (int)CppFunctionFlags.Method) != 0;

public bool IsPureVirtual => ((int)Flags & (int)CppFunctionFlags.Pure) != 0;

public bool IsVirtual => ((int)Flags & (int)CppFunctionFlags.Virtual) != 0;

public bool IsStatic => StorageQualifier == CppStorageQualifier.Static;

public bool IsConst => ((int)Flags & (int)CppFunctionFlags.Const) != 0;


/// <inheritdoc />
public List<CppType> TemplateParameters { get; }

Expand Down
72 changes: 72 additions & 0 deletions src/CppAst/CppGlobalDeclarationContainer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;

namespace CppAst
Expand Down Expand Up @@ -77,6 +78,77 @@ public CppElement FindByName(string name)
return FindByName(this, name);
}

private CppElement SearchForChild(CppElement parent, string child_name)
{
ICppDeclarationContainer container = null;
if(parent is CppNamespace)
{
var ns = parent as CppNamespace;
var n = ns.Namespaces.FirstOrDefault(x => x.Name == child_name);
if (n != null) return n;

container = ns;
}
else if(parent is CppClass)
{
container = parent as ICppDeclarationContainer;
}

if(container != null)
{
var c = container.Classes.FirstOrDefault(x => x.Name == child_name);
if (c != null) return c;

var e = container.Enums.FirstOrDefault(x => x.Name == child_name);
if (e != null) return e;

var f = container.Functions.FirstOrDefault(x => x.Name == child_name);
if (f != null) return f;

var t = container.Typedefs.FirstOrDefault(x => x.Name == child_name);
if (t != null) return t;
}

return null;
}

/// <summary>
/// Find a <see cref="CppElement"/> by full name(such as gbf::math::Vector3).
/// </summary>
/// <param name="name">Name of the element to find</param>
/// <returns>The CppElement found or null if not found</returns>
public CppElement FindByFullName(string name)
{
var arr = name.Split(new string[] { "::" }, StringSplitOptions.RemoveEmptyEntries);
if(arr.Length == 0) return null;

CppElement elem = null;
for(int i = 0; i < arr.Length; i++)
{
if (i == 0)
{
elem = FindByName(arr[0]);
}
else
{
elem = SearchForChild(elem, arr[i]);
}

if (elem == null) return null;
}
return elem;
}

/// <summary>
/// Find a <see cref="CppElement"/> by full name(such as gbf::math::Vector3).
/// </summary>
/// <param name="name">Name of the element to find</param>
/// <returns>The CppElement found or null if not found</returns>
public TCppElement FindByFullName<TCppElement>(string name) where TCppElement : CppElement
{
return (TCppElement)FindByFullName(name);
}

/// <summary>
/// Find a <see cref="CppElement"/> by name declared within the specified container.
/// </summary>
Expand Down
Loading

0 comments on commit 6fc9dbd

Please sign in to comment.