diff --git a/src/AST/Namespace.cs b/src/AST/Namespace.cs index 48566673..64c77d1d 100644 --- a/src/AST/Namespace.cs +++ b/src/AST/Namespace.cs @@ -226,9 +226,16 @@ namespace CppSharp.AST return newClass; } - public ClassTemplate FindClassTemplate(string name) + public FunctionTemplate FindFunctionTemplate(IntPtr ptr) { - return null; + return Templates.FirstOrDefault(template => + template.OriginalPtr == ptr) as FunctionTemplate; + } + + public ClassTemplate FindClassTemplate(IntPtr ptr) + { + return Templates.FirstOrDefault(template => + template.OriginalPtr == ptr) as ClassTemplate; } public TypedefDecl FindTypedef(string name, bool createDecl = false) diff --git a/src/AST/Template.cs b/src/AST/Template.cs index 637400a0..588fd049 100644 --- a/src/AST/Template.cs +++ b/src/AST/Template.cs @@ -1,4 +1,6 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; +using System.Linq; namespace CppSharp.AST { @@ -7,8 +9,17 @@ namespace CppSharp.AST public string Name; } + /// + /// The base class of all kinds of template declarations + /// (e.g., class, function, etc.). + /// public abstract class Template : Declaration { + protected Template() + { + Parameters = new List(); + } + protected Template(Declaration decl) { TemplatedDecl = decl; @@ -25,16 +36,27 @@ namespace CppSharp.AST } } + /// + /// Declaration of a class template. + /// public class ClassTemplate : Template { - public ClassTemplate(Declaration decl) - : base(decl) + public List Specializations; + + public Class TemplatedClass { + get { return TemplatedDecl as Class; } } - public Class TemplatedClass + public ClassTemplate() { - get { return TemplatedDecl as Class; } + Specializations = new List(); + } + + public ClassTemplate(Declaration decl) + : base(decl) + { + Specializations = new List(); } public override T Visit(IDeclVisitor visitor) @@ -75,17 +97,87 @@ namespace CppSharp.AST base.OriginalName = value; } } + + public ClassTemplateSpecialization FindSpecialization( + TemplateSpecializationType type) + { + return Specializations.FirstOrDefault( + spec => spec.Arguments.SequenceEqual(type.Arguments)); + } + + public ClassTemplateSpecialization FindSpecialization(IntPtr ptr) + { + return Specializations.FirstOrDefault(spec => spec.OriginalPtr == ptr); + } + + public ClassTemplatePartialSpecialization FindPartialSpecialization( + TemplateSpecializationType type) + { + return FindSpecialization(type) as ClassTemplatePartialSpecialization; + } + + public ClassTemplatePartialSpecialization FindPartialSpecialization(IntPtr ptr) + { + return FindSpecialization(ptr) as ClassTemplatePartialSpecialization; + } } + /// + /// Describes the kind of template specialization that a particular + /// template specialization declaration represents. + /// + public enum TemplateSpecializationKind + { + /// This template specialization was formed from a template-id but has + /// not yet been declared, defined, or instantiated. + Undeclared, + + /// This template specialization was implicitly instantiated from a + /// template. + ImplicitInstantiation, + + /// This template specialization was declared or defined by an explicit + /// specialization or partial specialization. + ExplicitSpecialization, + + /// This template specialization was instantiated from a template due + /// to an explicit instantiation declaration request. + ExplicitInstantiationDeclaration, + + /// This template specialization was instantiated from a template due + /// to an explicit instantiation definition request. + ExplicitInstantiationDefinition + } + + /// + /// Represents a class template specialization, which refers to a class + /// template with a given set of template arguments. + /// public class ClassTemplateSpecialization : Class { public ClassTemplate TemplatedDecl; + + public List Arguments; + + public TemplateSpecializationKind SpecializationKind; + + public ClassTemplateSpecialization() + { + Arguments = new List(); + } } + /// + /// Represents a class template partial specialization, which refers to + /// a class template with a given partial set of template arguments. + /// public class ClassTemplatePartialSpecialization : ClassTemplateSpecialization { } + /// + /// Declaration of a template function. + /// public class FunctionTemplate : Template { public FunctionTemplate(Declaration decl) diff --git a/src/Parser/Parser.cpp b/src/Parser/Parser.cpp index 6180cdd1..439c194d 100644 --- a/src/Parser/Parser.cpp +++ b/src/Parser/Parser.cpp @@ -527,45 +527,12 @@ void Parser::WalkVTable(clang::CXXRecordDecl* RD, CppSharp::AST::Class^ C) } } -CppSharp::AST::Class^ Parser::WalkRecordCXX(clang::CXXRecordDecl* Record) +void Parser::WalkRecordCXX(clang::CXXRecordDecl* Record, + CppSharp::AST::Class^ RC) { using namespace clang; using namespace clix; - if (Record->isInjectedClassName()) - return nullptr; - - auto NS = GetNamespace(Record); - assert(NS && "Expected a valid namespace"); - - bool isCompleteDefinition = Record->isCompleteDefinition(); - - CppSharp::AST::Class^ RC = nullptr; - - auto Name = marshalString(GetTagDeclName(Record)); - auto HasEmptyName = Record->getDeclName().isEmpty(); - - if (HasEmptyName) - { - if (auto AR = NS->FindAnonymous((uint64_t)Record)) - RC = safe_cast(AR); - } - else - { - RC = NS->FindClass(Name, isCompleteDefinition, /*Create=*/false); - } - - if (RC) - return RC; - - RC = NS->FindClass(Name, isCompleteDefinition, /*Create=*/true); - - if (HasEmptyName) - NS->Anonymous[(uint64_t)Record] = RC; - - if (!isCompleteDefinition) - return RC; - auto headStartLoc = GetDeclStartLocation(C.get(), Record); auto headEndLoc = Record->getLocation(); // identifier location auto bodyEndLoc = Record->getLocEnd(); @@ -674,19 +641,141 @@ CppSharp::AST::Class^ Parser::WalkRecordCXX(clang::CXXRecordDecl* Record) // Process the vtables if (hasLayout && Record->isDynamicClass()) WalkVTable(Record, RC); +} + +CppSharp::AST::Class^ Parser::WalkRecordCXX(clang::CXXRecordDecl* Record) +{ + using namespace clang; + using namespace clix; + + if (Record->isInjectedClassName()) + return nullptr; + + auto NS = GetNamespace(Record); + assert(NS && "Expected a valid namespace"); + + bool isCompleteDefinition = Record->isCompleteDefinition(); + + CppSharp::AST::Class^ RC = nullptr; + + auto Name = marshalString(GetTagDeclName(Record)); + auto HasEmptyName = Record->getDeclName().isEmpty(); + + if (HasEmptyName) + { + if (auto AR = NS->FindAnonymous((uint64_t)Record)) + RC = safe_cast(AR); + } + else + { + RC = NS->FindClass(Name, isCompleteDefinition, /*Create=*/false); + } + + if (RC) + return RC; + + RC = NS->FindClass(Name, isCompleteDefinition, /*Create=*/true); + + if (HasEmptyName) + NS->Anonymous[(uint64_t)Record] = RC; + + if (!isCompleteDefinition) + return RC; + + WalkRecordCXX(Record, RC); return RC; } //-----------------------------------// +static CppSharp::AST::TemplateSpecializationKind +WalkTemplateSpecializationKind(clang::TemplateSpecializationKind Kind) +{ + using namespace clang; + switch(Kind) + { + case TSK_Undeclared: + return CppSharp::AST::TemplateSpecializationKind::Undeclared; + case TSK_ImplicitInstantiation: + return CppSharp::AST::TemplateSpecializationKind::ImplicitInstantiation; + case TSK_ExplicitSpecialization: + return CppSharp::AST::TemplateSpecializationKind::ExplicitSpecialization; + case TSK_ExplicitInstantiationDeclaration: + return CppSharp::AST::TemplateSpecializationKind::ExplicitInstantiationDeclaration; + case TSK_ExplicitInstantiationDefinition: + return CppSharp::AST::TemplateSpecializationKind::ExplicitInstantiationDefinition; + } +} + +CppSharp::AST::ClassTemplateSpecialization^ +Parser::WalkClassTemplateSpecialization(clang::ClassTemplateSpecializationDecl* CTS) +{ + auto CT = WalkClassTemplate(CTS->getSpecializedTemplate()); + auto Spec = CT->FindSpecialization(System::IntPtr(CTS)); + if (Spec != nullptr) + return Spec; + + auto TS = gcnew CppSharp::AST::ClassTemplateSpecialization(); + TS->OriginalPtr = System::IntPtr(CTS); + TS->TemplatedDecl = CT; + TS->SpecializationKind = WalkTemplateSpecializationKind(CTS->getSpecializationKind()); + CT->Specializations->Add(TS); + + // TODO: Parse the template argument list + + if (CTS->isCompleteDefinition()) + WalkRecordCXX(CTS, TS); + + return TS; +} + +//-----------------------------------// + +CppSharp::AST::ClassTemplatePartialSpecialization^ +Parser::WalkClassTemplatePartialSpecialization(clang::ClassTemplatePartialSpecializationDecl* CTS) +{ + auto CT = WalkClassTemplate(CTS->getSpecializedTemplate()); + auto Spec = CT->FindPartialSpecialization(System::IntPtr(CTS)); + if (Spec != nullptr) + return Spec; + + auto TS = gcnew CppSharp::AST::ClassTemplatePartialSpecialization(); + TS->OriginalPtr = System::IntPtr(CTS); + TS->TemplatedDecl = CT; + TS->SpecializationKind = WalkTemplateSpecializationKind(CTS->getSpecializationKind()); + CT->Specializations->Add(TS); + + // TODO: Parse the template argument list + + if (CTS->isCompleteDefinition()) + WalkRecordCXX(CTS, TS); + + return TS; +} + +//-----------------------------------// + CppSharp::AST::ClassTemplate^ Parser::WalkClassTemplate(clang::ClassTemplateDecl* TD) { using namespace clang; using namespace clix; - auto Class = WalkRecordCXX(TD->getTemplatedDecl()); - CppSharp::AST::ClassTemplate^ CT = gcnew CppSharp::AST::ClassTemplate(Class); + if (TD->getCanonicalDecl() != TD) + return WalkClassTemplate(TD->getCanonicalDecl()); + + auto NS = GetNamespace(TD); + assert(NS && "Expected a valid namespace"); + + auto CT = NS->FindClassTemplate(System::IntPtr(TD)); + if (CT != nullptr) + return CT; + + CT = gcnew CppSharp::AST::ClassTemplate(); + CT->OriginalPtr = System::IntPtr(TD); + NS->Templates->Add(CT); + + CT->TemplatedDecl = WalkRecordCXX(TD->getTemplatedDecl()); auto TPL = TD->getTemplateParameters(); for(auto it = TPL->begin(); it != TPL->end(); ++it) @@ -709,9 +798,21 @@ CppSharp::AST::FunctionTemplate^ Parser::WalkFunctionTemplate(clang::FunctionTem using namespace clang; using namespace clix; + if (TD->getCanonicalDecl() != TD) + return WalkFunctionTemplate(TD->getCanonicalDecl()); + + auto NS = GetNamespace(TD); + assert(NS && "Expected a valid namespace"); + + auto FT = NS->FindFunctionTemplate(System::IntPtr(TD)); + if (FT != nullptr) + return FT; + auto Function = WalkFunction(TD->getTemplatedDecl(), /*IsDependent=*/true, /*AddToNamespace=*/false); - CppSharp::AST::FunctionTemplate^ FT = gcnew CppSharp::AST::FunctionTemplate(Function); + FT = gcnew CppSharp::AST::FunctionTemplate(Function); + FT->OriginalPtr = System::IntPtr(TD); + NS->Templates->Add(FT); auto TPL = TD->getTemplateParameters(); for(auto it = TPL->begin(); it != TPL->end(); ++it) @@ -951,10 +1052,15 @@ CppSharp::AST::DeclarationContext^ Parser::GetNamespace(clang::Decl* D, continue; } case Decl::ClassTemplateSpecialization: + { + auto CTSpec = cast(Ctx); + DC = WalkClassTemplateSpecialization(CTSpec); + continue; + } case Decl::ClassTemplatePartialSpecialization: { - // FIXME: Ignore ClassTemplateSpecialization namespaces... - // We might be able to translate these to C# nested types. + auto CTPSpec = cast(Ctx); + DC = WalkClassTemplatePartialSpecialization(CTPSpec); continue; } default: @@ -1072,6 +1178,13 @@ static CppSharp::AST::CallingConvention ConvertCallConv(clang::CallingConv CC) return CppSharp::AST::CallingConvention::Default; } +CppSharp::AST::QualifiedType^ Parser::WalkQualifiedType(clang::TypeSourceInfo* TSI) +{ + auto TL = TSI->getTypeLoc(); + auto Ty = WalkType(TSI->getType(), &TL); + return GetQualifiedType(TSI->getType(), Ty); +} + CppSharp::AST::Type^ Parser::WalkType(clang::QualType QualType, clang::TypeLoc* TL, bool DesugarType) { @@ -1982,17 +2095,13 @@ CppSharp::AST::Declaration^ Parser::WalkDeclaration(clang::Decl* D, ClassTemplateDecl* TD = cast(D); auto Template = WalkClassTemplate(TD); - auto NS = GetNamespace(TD); - Template->Namespace = NS; - NS->Templates->Add(Template); - Decl = Template; break; } case Decl::ClassTemplateSpecialization: { auto TS = cast(D); - auto CT = gcnew CppSharp::AST::ClassTemplateSpecialization(); + auto CT = WalkClassTemplateSpecialization(TS); Decl = CT; break; @@ -2000,21 +2109,17 @@ CppSharp::AST::Declaration^ Parser::WalkDeclaration(clang::Decl* D, case Decl::ClassTemplatePartialSpecialization: { auto TS = cast(D); - auto CT = gcnew CppSharp::AST::ClassTemplatePartialSpecialization(); + auto CT = WalkClassTemplatePartialSpecialization(TS); Decl = CT; break; } case Decl::FunctionTemplate: { - FunctionTemplateDecl* TD = cast(D); - auto Template = WalkFunctionTemplate(TD); + auto TD = cast(D); + auto FT = WalkFunctionTemplate(TD); - auto NS = GetNamespace(TD); - Template->Namespace = NS; - NS->Templates->Add(Template); - - Decl = Template; + Decl = FT; break; } case Decl::Enum: diff --git a/src/Parser/Parser.h b/src/Parser/Parser.h index 305cff25..1069b537 100644 --- a/src/Parser/Parser.h +++ b/src/Parser/Parser.h @@ -65,6 +65,11 @@ protected: CppSharp::AST::Function^ WalkFunction(clang::FunctionDecl*, bool IsDependent = false, bool AddToNamespace = true); CppSharp::AST::Class^ WalkRecordCXX(clang::CXXRecordDecl*); + void WalkRecordCXX(clang::CXXRecordDecl*, CppSharp::AST::Class^); + CppSharp::AST::ClassTemplateSpecialization^ + WalkClassTemplateSpecialization(clang::ClassTemplateSpecializationDecl*); + CppSharp::AST::ClassTemplatePartialSpecialization^ + WalkClassTemplatePartialSpecialization(clang::ClassTemplatePartialSpecializationDecl*); CppSharp::AST::Method^ WalkMethodCXX(clang::CXXMethodDecl*); CppSharp::AST::Field^ WalkFieldCXX(clang::FieldDecl*, CppSharp::AST::Class^); CppSharp::AST::ClassTemplate^ Parser::WalkClassTemplate(clang::ClassTemplateDecl*); @@ -74,6 +79,7 @@ protected: CppSharp::AST::RawComment^ WalkRawComment(const clang::RawComment*); CppSharp::AST::Type^ WalkType(clang::QualType, clang::TypeLoc* = 0, bool DesugarType = false); + CppSharp::AST::QualifiedType^ WalkQualifiedType(clang::TypeSourceInfo* TSI); void WalkVTable(clang::CXXRecordDecl*, CppSharp::AST::Class^); CppSharp::AST::VTableLayout^ WalkVTableLayout(const clang::VTableLayout&); CppSharp::AST::VTableComponent WalkVTableComponent(const clang::VTableComponent&);