diff --git a/src/CppAst.Tests/TestMisc.cs b/src/CppAst.Tests/TestMisc.cs new file mode 100644 index 0000000..08fe826 --- /dev/null +++ b/src/CppAst.Tests/TestMisc.cs @@ -0,0 +1,41 @@ +using System; +using NUnit.Framework; + +namespace CppAst.Tests +{ + public class TestMisc : InlineTestBase + { + [Test] + public void TestMiscFeatures() + { + ParseAssert(@" + +class Foo +{ +public: + Foo(int x) : x_{x} {} +private: + int x_{0}; +}; + +class Bar : public Foo +{ +public: + using Foo::Foo; +}; +", + compilation => + { + Assert.False(compilation.HasErrors); + Assert.AreEqual(2, compilation.Classes.Count); + Assert.AreEqual(1, compilation.Classes[0].Constructors.Count); + // Bar will get 3 constructors + Assert.AreEqual(3, compilation.Classes[1].Constructors.Count); + Assert.AreEqual(CppVisibility.Public, compilation.Classes[1].Constructors[0].Visibility); + Assert.AreEqual(CppVisibility.Public, compilation.Classes[1].Constructors[1].Visibility); + Assert.AreEqual(CppVisibility.Public, compilation.Classes[1].Constructors[2].Visibility); + } + ); + } + } +} \ No newline at end of file diff --git a/src/CppAst/CppModelBuilder.cs b/src/CppAst/CppModelBuilder.cs index a1fd00b..f20c044 100644 --- a/src/CppAst/CppModelBuilder.cs +++ b/src/CppAst/CppModelBuilder.cs @@ -297,11 +297,44 @@ private CppClass VisitClassDecl(CXCursor cursor, void* data) return cppStruct; } + private CppFunction VisitUsing(CXCursor cursor, CXCursor parent, void* data) + { + var contextContainer = GetOrCreateDeclarationContainer(cursor.SemanticParent, data); + var container = contextContainer.DeclarationContainer; + + if (container == null) + { + WarningUnhandled(cursor, parent); + return null; + } + + cursor.VisitChildren((childCursor, funcCursor, clientData) => + { + // Please note that this is not the complete using implementation, + // it only works with constructors + if (childCursor.Kind == CXCursorKind.CXCursor_OverloadedDeclRef) + { + // We simply copy the overloaded functions into the current class + for (uint i=0;i< childCursor.NumOverloadedDecls; i++) + { + VisitFunctionDecl(cursor, childCursor.GetOverloadedDecl(i), parent, clientData); + } + return CXChildVisitResult.CXChildVisit_Break; + } + return CXChildVisitResult.CXChildVisit_Continue; + }, new CXClientData((IntPtr)data)); + + return null; + } + private CXChildVisitResult VisitMember(CXCursor cursor, CXCursor parent, void* data) { CppElement element = null; switch (cursor.Kind) { + case CXCursorKind.CXCursor_UsingDeclaration: + element = VisitUsing(cursor, parent, data); + break; case CXCursorKind.CXCursor_FieldDecl: case CXCursorKind.CXCursor_VarDecl: { @@ -390,7 +423,7 @@ private CXChildVisitResult VisitMember(CXCursor cursor, CXCursor parent, void* d case CXCursorKind.CXCursor_FunctionDecl: case CXCursorKind.CXCursor_Constructor: case CXCursorKind.CXCursor_CXXMethod: - element = VisitFunctionDecl(cursor, parent, data); + element = VisitFunctionDecl(cursor, cursor, parent, data); break; case CXCursorKind.CXCursor_UsingDirective: @@ -1227,43 +1260,47 @@ private static CppStorageQualifier GetStorageQualifier(CXCursor cursor) return CppStorageQualifier.None; } - private CppFunction VisitFunctionDecl(CXCursor cursor, CXCursor parent, void* data) +private CppFunction VisitFunctionDecl(CXCursor destinationCursor, CXCursor cursor, CXCursor parent, void* data) { + var destinationContextContainer = GetOrCreateDeclarationContainer(destinationCursor.SemanticParent, data); + var destinationContainer = destinationContextContainer.DeclarationContainer; var contextContainer = GetOrCreateDeclarationContainer(cursor.SemanticParent, data); var container = contextContainer.DeclarationContainer; - if (container == null) + if (destinationContainer == null || container == null) { WarningUnhandled(cursor, parent); return null; } - var functionName = GetCursorSpelling(cursor); + // This (not using 'cursor', but 'destinationCursor') is only used when we pulling in constructors from Foo, into Bar + // We are renaming effectively the pulled in 'Foo' constructor into 'Bar' + var functionName = GetCursorSpelling(destinationCursor); //We need ignore the function define out in the class definition here(Otherwise it will has two same functions here~)! - var semKind = cursor.SemanticParent.Kind; + var semKind = destinationCursor.SemanticParent.Kind; if ((semKind == CXCursorKind.CXCursor_StructDecl || semKind == CXCursorKind.CXCursor_ClassDecl) - && cursor.LexicalParent != cursor.SemanticParent) + && destinationCursor.LexicalParent != destinationCursor.SemanticParent) { return null; } var cppFunction = new CppFunction(functionName) { - Visibility = contextContainer.CurrentVisibility, + Visibility = destinationContextContainer.CurrentVisibility, StorageQualifier = GetStorageQualifier(cursor), LinkageKind = GetLinkage(cursor.Linkage), }; if (cursor.Kind == CXCursorKind.CXCursor_Constructor) { - var cppClass = (CppClass)container; + var cppClass = (CppClass)destinationContainer; cppFunction.IsConstructor = true; cppClass.Constructors.Add(cppFunction); } else { - container.Functions.Add(cppFunction); + destinationContainer.Functions.Add(cppFunction); } if (cursor.kind == CXCursorKind.CXCursor_FunctionTemplate)