Skip to content

Commit 5dead77

Browse files
fangfang1984fangshen
andauthored
Enhance for function template & CppType FullName support. (#76)
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 <fangshen@tencent.com>
1 parent 1e69cbf commit 5dead77

15 files changed

+355
-115
lines changed

src/CppAst.Tests/TestFunctions.cs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,5 +256,32 @@ public void TestFunctionVariadic()
256256
);
257257
}
258258

259+
260+
261+
[Test]
262+
public void TestFunctionTemplate()
263+
{
264+
ParseAssert(@"
265+
template<class T>
266+
void function0(T t);
267+
",
268+
compilation =>
269+
{
270+
Assert.False(compilation.HasErrors);
271+
272+
Assert.AreEqual(1, compilation.Functions.Count);
273+
274+
{
275+
var cppFunction = compilation.Functions[0];
276+
Assert.AreEqual(1, cppFunction.Parameters.Count);
277+
Assert.AreEqual("void", cppFunction.ReturnType.ToString());
278+
Assert.AreEqual(cppFunction.IsFunctionTemplate, true);
279+
Assert.AreEqual(cppFunction.TemplateParameters.Count, 1);
280+
}
281+
282+
}
283+
);
284+
}
285+
259286
}
260287
}

src/CppAst.Tests/TestNamespaces.cs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,5 +107,48 @@ struct MyStruct;
107107
}
108108
);
109109
}
110+
111+
[Test]
112+
public void TestInlineNamespace()
113+
{
114+
var text = @"
115+
namespace A
116+
{
117+
118+
inline namespace __1
119+
{
120+
// Test using Template
121+
template <typename T>
122+
struct MyStruct;
123+
124+
using MyStructInt = MyStruct<int>;
125+
}
126+
127+
}
128+
129+
";
130+
131+
ParseAssert(text,
132+
compilation =>
133+
{
134+
Assert.False(compilation.HasErrors);
135+
136+
Assert.AreEqual(1, compilation.Namespaces.Count);
137+
138+
var inlineNs = compilation.Namespaces[0].Namespaces[0];
139+
Assert.AreEqual(inlineNs.Name, "__1");
140+
Assert.AreEqual(true, inlineNs.IsInlineNamespace);
141+
142+
var cppStruct = compilation.FindByFullName<CppClass>("A::MyStruct");
143+
Assert.AreEqual(inlineNs.Classes[0], cppStruct);
144+
Assert.AreEqual(cppStruct.FullName, "A::MyStruct<T>");
145+
146+
var cppTypedef = compilation.FindByFullName<CppTypedef>("A::MyStructInt");
147+
var cppStructInt = cppTypedef.ElementType as CppClass;
148+
//So now we can use this full name in exporter convenience.
149+
Assert.AreEqual(cppStructInt.FullName, "A::MyStruct<int>");
150+
}
151+
);
152+
}
110153
}
111154
}

src/CppAst/CppBaseType.cs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,31 @@ public override string ToString()
5151
}
5252

5353
builder.Append(Type.GetDisplayName());
54+
55+
var cls = Type as CppClass;
56+
if(cls != null && cls.TemplateKind != CppTemplateKind.NormalClass)
57+
{
58+
builder.Append("<");
59+
60+
if (cls.TemplateKind == CppTemplateKind.TemplateSpecializedClass)
61+
{
62+
for (var i = 0; i < cls.TemplateSpecializedArguments.Count; i++)
63+
{
64+
if (i > 0) builder.Append(", ");
65+
builder.Append(cls.TemplateSpecializedArguments[i].ToString());
66+
}
67+
}
68+
else if (cls.TemplateKind == CppTemplateKind.TemplateClass)
69+
{
70+
for (var i = 0; i < cls.TemplateParameters.Count; i++)
71+
{
72+
if (i > 0) builder.Append(", ");
73+
builder.Append(cls.TemplateParameters[i].ToString());
74+
}
75+
}
76+
77+
builder.Append(">");
78+
}
5479
return builder.ToString();
5580
}
5681
}

src/CppAst/CppClass.cs

Lines changed: 44 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -41,20 +41,57 @@ public CppClass(string name) : base(CppTypeKind.StructOrClass)
4141
/// <inheritdoc />
4242
public string Name { get; set; }
4343

44-
public string FullName
45-
{
46-
get
44+
public override string FullName
45+
{
46+
get
4747
{
48+
StringBuilder sb = new StringBuilder();
4849
string fullparent = FullParentName;
49-
if(string.IsNullOrEmpty(fullparent))
50+
if (string.IsNullOrEmpty(fullparent))
5051
{
51-
return Name;
52+
sb.Append(Name);
5253
}
5354
else
5455
{
55-
return $"{fullparent}{Name}";
56+
sb.Append($"{fullparent}::{Name}");
57+
}
58+
59+
if (TemplateKind == CppTemplateKind.TemplateClass
60+
|| TemplateKind == CppTemplateKind.PartialTemplateClass)
61+
{
62+
sb.Append('<');
63+
for (int i = 0; i < TemplateParameters.Count; i++)
64+
{
65+
var tp = TemplateParameters[i];
66+
if (i != 0)
67+
{
68+
sb.Append(", ");
69+
}
70+
sb.Append(tp.ToString());
71+
}
72+
sb.Append('>');
5673
}
57-
}
74+
else if (TemplateKind == CppTemplateKind.TemplateSpecializedClass)
75+
{
76+
sb.Append('<');
77+
for (int i = 0; i < TemplateSpecializedArguments.Count; i++)
78+
{
79+
var ta = TemplateSpecializedArguments[i];
80+
if (i != 0)
81+
{
82+
sb.Append(", ");
83+
}
84+
sb.Append(ta.ArgString);
85+
}
86+
sb.Append('>');
87+
}
88+
//else if(TemplateKind == CppTemplateKind.PartialTemplateClass)
89+
//{
90+
// sb.Append('<');
91+
// sb.Append('>');
92+
//}
93+
return sb.ToString();
94+
}
5895
}
5996

6097
/// <inheritdoc />

src/CppAst/CppElement.cs

Lines changed: 39 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -25,35 +25,46 @@ public string FullParentName
2525
{
2626
get
2727
{
28-
string tmpname = "";
29-
var p = Parent;
30-
while (p != null)
31-
{
32-
if (p is CppClass)
33-
{
34-
var cpp = p as CppClass;
35-
tmpname = $"{cpp.Name}::{tmpname}";
36-
p = cpp.Parent;
37-
}
38-
else if (p is CppNamespace)
39-
{
40-
var ns = p as CppNamespace;
41-
tmpname = $"{ns.Name}::{tmpname}";
42-
p = ns.Parent;
43-
}
44-
else if (p is CppCompilation)
45-
{
46-
// root namespace here, just ignore~
47-
p = null;
48-
}
49-
else
50-
{
51-
throw new NotImplementedException("Can not be here, not support type here!");
52-
}
53-
}
28+
string tmpname = "";
29+
var p = Parent;
30+
while (p != null)
31+
{
32+
if (p is CppClass)
33+
{
34+
var cpp = p as CppClass;
35+
tmpname = $"{cpp.Name}::{tmpname}";
36+
p = cpp.Parent;
37+
}
38+
else if (p is CppNamespace)
39+
{
40+
var ns = p as CppNamespace;
5441

55-
return tmpname;
56-
}
42+
//Just ignore inline namespace
43+
if (!ns.IsInlineNamespace)
44+
{
45+
tmpname = $"{ns.Name}::{tmpname}";
46+
}
47+
p = ns.Parent;
48+
}
49+
else if (p is CppCompilation)
50+
{
51+
// root namespace here, just ignore~
52+
p = null;
53+
}
54+
else
55+
{
56+
throw new NotImplementedException("Can not be here, not support type here!");
57+
}
58+
}
59+
60+
//Try to remove not need `::` in string tails.
61+
if (tmpname.EndsWith("::"))
62+
{
63+
tmpname = tmpname.Substring(0, tmpname.Length - 2);
64+
}
65+
66+
return tmpname;
67+
}
5768
}
5869

5970
/// <summary>

src/CppAst/CppEnum.cs

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -30,22 +30,21 @@ public CppEnum(string name) : base(CppTypeKind.Enum)
3030
/// <inheritdoc />
3131
public string Name { get; set; }
3232

33-
public string FullName
34-
{
35-
get
36-
{
37-
string fullparent = FullParentName;
38-
if (string.IsNullOrEmpty(fullparent))
39-
{
40-
return Name;
41-
}
42-
else
43-
{
44-
return $"{fullparent}{Name}";
45-
}
46-
}
47-
}
48-
33+
public override string FullName
34+
{
35+
get
36+
{
37+
string fullparent = FullParentName;
38+
if (string.IsNullOrEmpty(fullparent))
39+
{
40+
return Name;
41+
}
42+
else
43+
{
44+
return $"{fullparent}::{Name}";
45+
}
46+
}
47+
}
4948

5049
/// <summary>
5150
/// Gets or sets a boolean indicating if this enum is scoped.

src/CppAst/CppFunction.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ public int DefaultParamCount
9797

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

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

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

src/CppAst/CppFunctionFlags.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,5 +61,10 @@ public enum CppFunctionFlags
6161
/// This is a variadic function (has `...` parameter)
6262
/// </summary>
6363
Variadic = 1 << 8,
64+
65+
/// <summary>
66+
/// This is a function template (has template params in function)
67+
/// </summary>
68+
FunctionTemplate = 1 << 9,
6469
}
6570
}

src/CppAst/CppGlobalDeclarationContainer.cs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,21 @@ private CppElement SearchForChild(CppElement parent, string child_name)
109109
if (t != null) return t;
110110
}
111111

112+
//Not found, try to find in inline namespace.
113+
if(parent is CppNamespace)
114+
{
115+
var ns = parent as CppNamespace;
116+
foreach(var sn in ns.Namespaces)
117+
{
118+
if (sn.IsInlineNamespace)
119+
{
120+
var findElem = SearchForChild(sn, child_name);
121+
//Find it in inline namespace, just return.
122+
if(findElem != null) return findElem;
123+
}
124+
}
125+
}
126+
112127
return null;
113128
}
114129

@@ -117,7 +132,7 @@ private CppElement SearchForChild(CppElement parent, string child_name)
117132
/// </summary>
118133
/// <param name="name">Name of the element to find</param>
119134
/// <returns>The CppElement found or null if not found</returns>
120-
public CppElement FindByFullName(string name)
135+
public CppElement FindByFullName(string name)
121136
{
122137
var arr = name.Split(new string[] { "::" }, StringSplitOptions.RemoveEmptyEntries);
123138
if(arr.Length == 0) return null;

0 commit comments

Comments
 (0)