Skip to content

Commit

Permalink
Enhance for function template & CppType FullName support. (#76)
Browse files Browse the repository at this point in the history
1. add support for function template
2. add inline namespace support
3. change FullName as a CppType property, and deduce the CppClass full name with specialized template right, you can just use CppClass full name in a generated c++ codes now.
4. FindByFullName() now can search auto ignore inline namespace now(such as clang std::__1::vector, now you can just use std::vector to search)
5. fix crash when the CppClass has a  specialized template with PartialSpecializedTemplateDecl
6. fix crash when typedef with a AliasTemplateDecl for Underlying type.

Co-authored-by: fangshen <[email protected]>
  • Loading branch information
fangfang1984 and fangshen authored Apr 22, 2023
1 parent 1e69cbf commit 5dead77
Show file tree
Hide file tree
Showing 15 changed files with 355 additions and 115 deletions.
27 changes: 27 additions & 0 deletions src/CppAst.Tests/TestFunctions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -256,5 +256,32 @@ public void TestFunctionVariadic()
);
}



[Test]
public void TestFunctionTemplate()
{
ParseAssert(@"
template<class T>
void function0(T t);
",
compilation =>
{
Assert.False(compilation.HasErrors);

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

{
var cppFunction = compilation.Functions[0];
Assert.AreEqual(1, cppFunction.Parameters.Count);
Assert.AreEqual("void", cppFunction.ReturnType.ToString());
Assert.AreEqual(cppFunction.IsFunctionTemplate, true);
Assert.AreEqual(cppFunction.TemplateParameters.Count, 1);
}

}
);
}

}
}
43 changes: 43 additions & 0 deletions src/CppAst.Tests/TestNamespaces.cs
Original file line number Diff line number Diff line change
Expand Up @@ -107,5 +107,48 @@ struct MyStruct;
}
);
}

[Test]
public void TestInlineNamespace()
{
var text = @"
namespace A
{
inline namespace __1
{
// 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 inlineNs = compilation.Namespaces[0].Namespaces[0];
Assert.AreEqual(inlineNs.Name, "__1");
Assert.AreEqual(true, inlineNs.IsInlineNamespace);

var cppStruct = compilation.FindByFullName<CppClass>("A::MyStruct");
Assert.AreEqual(inlineNs.Classes[0], cppStruct);
Assert.AreEqual(cppStruct.FullName, "A::MyStruct<T>");

var cppTypedef = compilation.FindByFullName<CppTypedef>("A::MyStructInt");
var cppStructInt = cppTypedef.ElementType as CppClass;
//So now we can use this full name in exporter convenience.
Assert.AreEqual(cppStructInt.FullName, "A::MyStruct<int>");
}
);
}
}
}
25 changes: 25 additions & 0 deletions src/CppAst/CppBaseType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,31 @@ public override string ToString()
}

builder.Append(Type.GetDisplayName());

var cls = Type as CppClass;
if(cls != null && cls.TemplateKind != CppTemplateKind.NormalClass)
{
builder.Append("<");

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

builder.Append(">");
}
return builder.ToString();
}
}
Expand Down
51 changes: 44 additions & 7 deletions src/CppAst/CppClass.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,20 +41,57 @@ public CppClass(string name) : base(CppTypeKind.StructOrClass)
/// <inheritdoc />
public string Name { get; set; }

public string FullName
{
get
public override string FullName
{
get
{
StringBuilder sb = new StringBuilder();
string fullparent = FullParentName;
if(string.IsNullOrEmpty(fullparent))
if (string.IsNullOrEmpty(fullparent))
{
return Name;
sb.Append(Name);
}
else
{
return $"{fullparent}{Name}";
sb.Append($"{fullparent}::{Name}");
}

if (TemplateKind == CppTemplateKind.TemplateClass
|| TemplateKind == CppTemplateKind.PartialTemplateClass)
{
sb.Append('<');
for (int i = 0; i < TemplateParameters.Count; i++)
{
var tp = TemplateParameters[i];
if (i != 0)
{
sb.Append(", ");
}
sb.Append(tp.ToString());
}
sb.Append('>');
}
}
else if (TemplateKind == CppTemplateKind.TemplateSpecializedClass)
{
sb.Append('<');
for (int i = 0; i < TemplateSpecializedArguments.Count; i++)
{
var ta = TemplateSpecializedArguments[i];
if (i != 0)
{
sb.Append(", ");
}
sb.Append(ta.ArgString);
}
sb.Append('>');
}
//else if(TemplateKind == CppTemplateKind.PartialTemplateClass)
//{
// sb.Append('<');
// sb.Append('>');
//}
return sb.ToString();
}
}

/// <inheritdoc />
Expand Down
67 changes: 39 additions & 28 deletions src/CppAst/CppElement.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,35 +25,46 @@ 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!");
}
}
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;

return tmpname;
}
//Just ignore inline namespace
if (!ns.IsInlineNamespace)
{
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!");
}
}

//Try to remove not need `::` in string tails.
if (tmpname.EndsWith("::"))
{
tmpname = tmpname.Substring(0, tmpname.Length - 2);
}

return tmpname;
}
}

/// <summary>
Expand Down
31 changes: 15 additions & 16 deletions src/CppAst/CppEnum.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,22 +30,21 @@ public CppEnum(string name) : base(CppTypeKind.Enum)
/// <inheritdoc />
public string Name { get; set; }

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

public override 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.
Expand Down
1 change: 1 addition & 0 deletions src/CppAst/CppFunction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ public int DefaultParamCount

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

public bool IsFunctionTemplate => ((int)Flags & (int)CppFunctionFlags.FunctionTemplate) != 0;

/// <inheritdoc />
public List<CppType> TemplateParameters { get; }
Expand Down
5 changes: 5 additions & 0 deletions src/CppAst/CppFunctionFlags.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,5 +61,10 @@ public enum CppFunctionFlags
/// This is a variadic function (has `...` parameter)
/// </summary>
Variadic = 1 << 8,

/// <summary>
/// This is a function template (has template params in function)
/// </summary>
FunctionTemplate = 1 << 9,
}
}
17 changes: 16 additions & 1 deletion src/CppAst/CppGlobalDeclarationContainer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,21 @@ private CppElement SearchForChild(CppElement parent, string child_name)
if (t != null) return t;
}

//Not found, try to find in inline namespace.
if(parent is CppNamespace)
{
var ns = parent as CppNamespace;
foreach(var sn in ns.Namespaces)
{
if (sn.IsInlineNamespace)
{
var findElem = SearchForChild(sn, child_name);
//Find it in inline namespace, just return.
if(findElem != null) return findElem;
}
}
}

return null;
}

Expand All @@ -117,7 +132,7 @@ private CppElement SearchForChild(CppElement parent, string child_name)
/// </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)
public CppElement FindByFullName(string name)
{
var arr = name.Split(new string[] { "::" }, StringSplitOptions.RemoveEmptyEntries);
if(arr.Length == 0) return null;
Expand Down
Loading

0 comments on commit 5dead77

Please sign in to comment.