Skip to content

Commit 6fc9dbd

Browse files
fangfang1984fangshen
andauthored
Enhance the template handle for CppAst (#75)
* 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 <fangshen@tencent.com>
1 parent 616dddd commit 6fc9dbd

14 files changed

+572
-30
lines changed

src/CppAst.Tests/TestNamespaces.cs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,5 +77,35 @@ namespace A
7777
}
7878
);
7979
}
80+
81+
82+
83+
[Test]
84+
public void TestNamespaceFindByFullName()
85+
{
86+
var text = @"
87+
namespace A
88+
{
89+
// Test using Template
90+
template <typename T>
91+
struct MyStruct;
92+
93+
using MyStructInt = MyStruct<int>;
94+
}
95+
96+
";
97+
98+
ParseAssert(text,
99+
compilation =>
100+
{
101+
Assert.False(compilation.HasErrors);
102+
103+
Assert.AreEqual(1, compilation.Namespaces.Count);
104+
105+
var cppStruct = compilation.FindByFullName<CppClass>("A::MyStruct");
106+
Assert.AreEqual(compilation.Namespaces[0].Classes[0], cppStruct);
107+
}
108+
);
109+
}
80110
}
81111
}

src/CppAst.Tests/TestTypes.cs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using System;
66
using System.Linq;
77
using NUnit.Framework;
8+
using static CppAst.CppTemplateArgument;
89

910
namespace CppAst.Tests
1011
{
@@ -82,8 +83,9 @@ struct Struct2
8283
var exposed = compilation.Fields[0].Type as CppClass;
8384
Assert.AreEqual("TemplateStruct", exposed.Name);
8485
Assert.AreEqual(2, exposed.TemplateParameters.Count);
85-
Assert.AreEqual(CppPrimitiveKind.Int, (exposed.TemplateParameters[0] as CppPrimitiveType)?.Kind);
86-
Assert.AreEqual("Struct2", (exposed.TemplateParameters[1] as CppClass)?.Name);
86+
Assert.AreEqual(CppTemplateArgumentKind.AsType, exposed.TemplateSpecializedArguments[0]?.ArgKind);
87+
Assert.AreEqual(CppPrimitiveKind.Int, (exposed.TemplateSpecializedArguments[0]?.ArgAsType as CppPrimitiveType).Kind);
88+
Assert.AreEqual("Struct2", (exposed.TemplateSpecializedArguments[1].ArgAsType as CppClass)?.Name);
8789

8890
var specialized = exposed.SpecializedTemplate;
8991
Assert.AreEqual("TemplateStruct", specialized.Name);
@@ -96,8 +98,9 @@ struct Struct2
9698
var unexposed = compilation.Fields[1].Type as CppClass;
9799
Assert.AreEqual("TemplateStruct", unexposed.Name);
98100
Assert.AreEqual(2, unexposed.TemplateParameters.Count);
99-
Assert.AreEqual(CppPrimitiveKind.Int, (unexposed.TemplateParameters[0] as CppPrimitiveType)?.Kind);
100-
Assert.AreEqual("Struct2", (unexposed.TemplateParameters[1] as CppClass)?.Name);
101+
Assert.AreEqual(CppTemplateArgumentKind.AsType, unexposed.TemplateSpecializedArguments[0]?.ArgKind);
102+
Assert.AreEqual(CppPrimitiveKind.Int, (exposed.TemplateSpecializedArguments[0]?.ArgAsType as CppPrimitiveType).Kind);
103+
Assert.AreEqual("Struct2", (unexposed.TemplateSpecializedArguments[1].ArgAsType as CppClass)?.Name);
101104

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

138141
Assert.AreEqual(1, baseClassSpecialized.TemplateParameters.Count);
139-
Assert.AreEqual(derived, baseClassSpecialized.TemplateParameters[0]);
142+
143+
//Here change to argument as a template deduce instance, not as a Template Parameters~~
144+
Assert.AreEqual(derived, baseClassSpecialized.TemplateSpecializedArguments[0].ArgAsType);
140145
Assert.AreEqual(baseTemplate, baseClassSpecialized.SpecializedTemplate);
141146
}
142147
);

src/CppAst/CppClass.cs

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,27 @@ public CppClass(string name) : base(CppTypeKind.StructOrClass)
3636
/// </summary>
3737
public CppClassKind ClassKind { get; set; }
3838

39+
public CppTemplateKind TemplateKind { get; set; }
40+
3941
/// <inheritdoc />
4042
public string Name { get; set; }
4143

44+
public string FullName
45+
{
46+
get
47+
{
48+
string fullparent = FullParentName;
49+
if(string.IsNullOrEmpty(fullparent))
50+
{
51+
return Name;
52+
}
53+
else
54+
{
55+
return $"{fullparent}{Name}";
56+
}
57+
}
58+
}
59+
4260
/// <inheritdoc />
4361
public CppVisibility Visibility { get; set; }
4462

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

104+
public List<CppTemplateArgument> TemplateSpecializedArguments { get; } = new List<CppTemplateArgument>();
105+
86106
/// <summary>
87107
/// Gets the specialized class template of this instance.
88108
/// </summary>
89109
public CppClass SpecializedTemplate { get; set; }
90110

91-
private bool Equals(CppClass other)
111+
112+
public bool IsEmbeded => Parent is CppClass;
113+
114+
public bool IsAbstract { get; set; }
115+
116+
117+
private bool Equals(CppClass other)
92118
{
93119
return base.Equals(other) && Equals(Parent, other.Parent) && Name.Equals(other.Name);
94120
}
@@ -118,6 +144,10 @@ public override int GetHashCode()
118144
foreach (var templateParameter in TemplateParameters)
119145
{
120146
hashCode = (hashCode * 397) ^ templateParameter.GetHashCode();
147+
}
148+
foreach (var templateArgument in TemplateSpecializedArguments)
149+
{
150+
hashCode = (hashCode * 397) ^ templateArgument.GetHashCode();
121151
}
122152
return hashCode;
123153
}
@@ -164,6 +194,31 @@ public override string ToString()
164194
}
165195
}
166196

197+
//Add template arguments here
198+
if(TemplateKind != CppTemplateKind.NormalClass)
199+
{
200+
builder.Append("<");
201+
202+
if(TemplateKind == CppTemplateKind.TemplateSpecializedClass)
203+
{
204+
for(var i = 0; i < TemplateSpecializedArguments.Count; i++)
205+
{
206+
if(i > 0) builder.Append(", ");
207+
builder.Append(TemplateSpecializedArguments[i].ToString());
208+
}
209+
}
210+
else if(TemplateKind == CppTemplateKind.TemplateClass)
211+
{
212+
for (var i = 0; i < TemplateParameters.Count; i++)
213+
{
214+
if (i > 0) builder.Append(", ");
215+
builder.Append(TemplateParameters[i].ToString());
216+
}
217+
}
218+
219+
builder.Append(">");
220+
}
221+
167222
builder.Append(" { ... }");
168223
return builder.ToString();
169224
}

src/CppAst/CppElement.cs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
// Licensed under the BSD-Clause 2 license.
33
// See license.txt file in the project root for full license information.
44

5+
using System;
6+
57
namespace CppAst
68
{
79
/// <summary>
@@ -19,6 +21,41 @@ public abstract class CppElement : ICppElement
1921
/// </summary>
2022
public ICppContainer Parent { get; internal set; }
2123

24+
public string FullParentName
25+
{
26+
get
27+
{
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+
}
54+
55+
return tmpname;
56+
}
57+
}
58+
2259
/// <summary>
2360
/// Gets the source file of this element.
2461
/// </summary>

src/CppAst/CppEnum.cs

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

33-
/// <summary>
34-
/// Gets or sets a boolean indicating if this enum is scoped.
35-
/// </summary>
36-
public bool IsScoped { get; set; }
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+
49+
50+
/// <summary>
51+
/// Gets or sets a boolean indicating if this enum is scoped.
52+
/// </summary>
53+
public bool IsScoped { get; set; }
3754

3855

3956
/// <summary>

src/CppAst/CppFunction.cs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Licensed under the BSD-Clause 2 license.
33
// See license.txt file in the project root for full license information.
44

5+
using System;
56
using System.Collections.Generic;
67
using System.Text;
78

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

69+
public int DefaultParamCount
70+
{
71+
get
72+
{
73+
int default_count = 0;
74+
foreach (var param in Parameters)
75+
{
76+
if(param.InitExpression != null)
77+
{
78+
default_count++;
79+
}
80+
}
81+
return default_count;
82+
}
83+
}
84+
6885
/// <summary>
6986
/// Gets or sets the flags of this function.
7087
/// </summary>
7188
public CppFunctionFlags Flags { get; set; }
7289

90+
public bool IsCxxClassMethod => ((int)Flags & (int)CppFunctionFlags.Method) != 0;
91+
92+
public bool IsPureVirtual => ((int)Flags & (int)CppFunctionFlags.Pure) != 0;
93+
94+
public bool IsVirtual => ((int)Flags & (int)CppFunctionFlags.Virtual) != 0;
95+
96+
public bool IsStatic => StorageQualifier == CppStorageQualifier.Static;
97+
98+
public bool IsConst => ((int)Flags & (int)CppFunctionFlags.Const) != 0;
99+
100+
73101
/// <inheritdoc />
74102
public List<CppType> TemplateParameters { get; }
75103

src/CppAst/CppGlobalDeclarationContainer.cs

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using System;
66
using System.Collections;
77
using System.Collections.Generic;
8+
using System.Linq;
89
using System.Runtime.CompilerServices;
910

1011
namespace CppAst
@@ -77,6 +78,77 @@ public CppElement FindByName(string name)
7778
return FindByName(this, name);
7879
}
7980

81+
private CppElement SearchForChild(CppElement parent, string child_name)
82+
{
83+
ICppDeclarationContainer container = null;
84+
if(parent is CppNamespace)
85+
{
86+
var ns = parent as CppNamespace;
87+
var n = ns.Namespaces.FirstOrDefault(x => x.Name == child_name);
88+
if (n != null) return n;
89+
90+
container = ns;
91+
}
92+
else if(parent is CppClass)
93+
{
94+
container = parent as ICppDeclarationContainer;
95+
}
96+
97+
if(container != null)
98+
{
99+
var c = container.Classes.FirstOrDefault(x => x.Name == child_name);
100+
if (c != null) return c;
101+
102+
var e = container.Enums.FirstOrDefault(x => x.Name == child_name);
103+
if (e != null) return e;
104+
105+
var f = container.Functions.FirstOrDefault(x => x.Name == child_name);
106+
if (f != null) return f;
107+
108+
var t = container.Typedefs.FirstOrDefault(x => x.Name == child_name);
109+
if (t != null) return t;
110+
}
111+
112+
return null;
113+
}
114+
115+
/// <summary>
116+
/// Find a <see cref="CppElement"/> by full name(such as gbf::math::Vector3).
117+
/// </summary>
118+
/// <param name="name">Name of the element to find</param>
119+
/// <returns>The CppElement found or null if not found</returns>
120+
public CppElement FindByFullName(string name)
121+
{
122+
var arr = name.Split(new string[] { "::" }, StringSplitOptions.RemoveEmptyEntries);
123+
if(arr.Length == 0) return null;
124+
125+
CppElement elem = null;
126+
for(int i = 0; i < arr.Length; i++)
127+
{
128+
if (i == 0)
129+
{
130+
elem = FindByName(arr[0]);
131+
}
132+
else
133+
{
134+
elem = SearchForChild(elem, arr[i]);
135+
}
136+
137+
if (elem == null) return null;
138+
}
139+
return elem;
140+
}
141+
142+
/// <summary>
143+
/// Find a <see cref="CppElement"/> by full name(such as gbf::math::Vector3).
144+
/// </summary>
145+
/// <param name="name">Name of the element to find</param>
146+
/// <returns>The CppElement found or null if not found</returns>
147+
public TCppElement FindByFullName<TCppElement>(string name) where TCppElement : CppElement
148+
{
149+
return (TCppElement)FindByFullName(name);
150+
}
151+
80152
/// <summary>
81153
/// Find a <see cref="CppElement"/> by name declared within the specified container.
82154
/// </summary>

0 commit comments

Comments
 (0)