From 02245429257c6ffe67452a370d215f85167a1198 Mon Sep 17 00:00:00 2001 From: triton Date: Wed, 5 Sep 2012 22:18:12 +0100 Subject: [PATCH] Fixed the native code parser to deal with namespaces. --- src/Parser/Parser.cpp | 143 ++++++++++++++++++++++++++++++++++++++---- src/Parser/Parser.h | 12 ++-- 2 files changed, 138 insertions(+), 17 deletions(-) diff --git a/src/Parser/Parser.cpp b/src/Parser/Parser.cpp index 989ed46e..71568903 100644 --- a/src/Parser/Parser.cpp +++ b/src/Parser/Parser.cpp @@ -49,7 +49,7 @@ static std::string GetClangResourceDir(const std::string& Dir) static std::string GetClangBuiltinIncludeDir() { - using namespace llvm; + using namespace llvm; SmallString<128> P( GetClangResourceDir(".") ); llvm::sys::path::append(P, "include"); @@ -77,8 +77,7 @@ void Parser::Setup(ParserOptions^ Opts) C->createDiagnostics(ARRAY_SIZE(args), args); CompilerInvocation* Inv = new CompilerInvocation(); - CompilerInvocation::CreateFromArgs(*Inv, - args, args + ARRAY_SIZE(args), C->getDiagnostics()); + CompilerInvocation::CreateFromArgs(*Inv, args, args + ARRAY_SIZE(args), C->getDiagnostics()); C->setInvocation(Inv); TargetOptions& TO = Inv->getTargetOpts(); @@ -91,8 +90,8 @@ void Parser::Setup(ParserOptions^ Opts) C->createFileManager(); C->createSourceManager(C->getFileManager()); - if (Opts->Verbose) - C->getHeaderSearchOpts().Verbose = true; + if (Opts->Verbose) + C->getHeaderSearchOpts().Verbose = true; // Initialize the default platform headers. std::string ResourceDir = GetClangResourceDir("."); @@ -232,8 +231,9 @@ Cxxi::Class^ Parser::WalkRecordCXX(clang::CXXRecordDecl* Record) if (Record->isAnonymousStructOrUnion()) return nullptr; - auto RC = gcnew Cxxi::Class(); - RC->Name = marshalString(GetTagDeclName(Record)); + auto NS = GetNamespace(Record); + auto RC = NS->FindClass( + marshalString(GetTagDeclName(Record)), /* Create */ true); RC->IsPOD = Record->isPOD(); // Iterate through the record ctors. @@ -335,6 +335,116 @@ Cxxi::Field^ Parser::WalkFieldCXX(clang::FieldDecl* FD) //-----------------------------------// +Cxxi::Namespace^ Parser::GetNamespace(const clang::NamedDecl* ND) +{ + using namespace clang; + using namespace clix; + + Cxxi::Module^ M = GetModule(ND->getLocation()); + + // If the declaration is at global scope, just early exit. + const DeclContext *Ctx = ND->getDeclContext(); + if (Ctx->isTranslationUnit()) + return M; + + // Else we need to do a more expensive check to get all the namespaces, + // and then perform a reverse iteration to get the namespaces in order. + typedef SmallVector ContextsTy; + ContextsTy Contexts; + + for(; Ctx != nullptr; Ctx = Ctx->getParent()) + Contexts.push_back(Ctx); + + assert(Contexts.back()->isTranslationUnit()); + Contexts.pop_back(); + + Cxxi::Namespace^ NS = M; + + for (auto I = Contexts.rbegin(), E = Contexts.rend(); I != E; ++I) + { + const DeclContext* Ctx = *I; + + switch(Ctx->getDeclKind()) + { + case Decl::Namespace: + { + const NamespaceDecl* ND = cast(Ctx); + if (ND->isAnonymousNamespace()) + continue; + NS = NS->FindNamespace(marshalString(ND->getName())); + break; + } + case Decl::LinkageSpec: + { + const LinkageSpecDecl* LD = cast(Ctx); + continue; + } + case Decl::CXXRecord: + { + // FIXME: Ignore record namespaces... + // We might be able to translate these to C# nested types. + continue; + } + default: + { + StringRef Kind = Ctx->getDeclKindName(); + printf("Unhandled declaration context kind: %s\n", Kind); + assert(0 && "Unhandled declaration context kind"); + } } + } + + return NS; + +#if 0 + + if (const ClassTemplateSpecializationDecl *Spec + = dyn_cast(*I)) { + const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs(); + std::string TemplateArgsStr + = TemplateSpecializationType::PrintTemplateArgumentList( + TemplateArgs.data(), + TemplateArgs.size(), + P); + OS << Spec->getName() << TemplateArgsStr; + } else if (const NamespaceDecl *ND = dyn_cast(*I)) { + if (ND->isAnonymousNamespace()) + OS << ""; + else + OS << *ND; + } else if (const RecordDecl *RD = dyn_cast(*I)) { + if (!RD->getIdentifier()) + OS << "getKindName() << '>'; + else + OS << *RD; + } else if (const FunctionDecl *FD = dyn_cast(*I)) { + const FunctionProtoType *FT = 0; + if (FD->hasWrittenPrototype()) + FT = dyn_cast(FD->getType()->castAs()); + + OS << *FD << '('; + if (FT) { + unsigned NumParams = FD->getNumParams(); + for (unsigned i = 0; i < NumParams; ++i) { + if (i) + OS << ", "; + OS << FD->getParamDecl(i)->getType().stream(P); + } + + if (FT->isVariadic()) { + if (NumParams > 0) + OS << ", "; + OS << "..."; + } + } + OS << ')'; + } else { + OS << *cast(*I); + } + OS << "::"; + } +#endif +} + static Cxxi::PrimitiveType ConvertBuiltinTypeToCLR(const clang::BuiltinType* Builtin) { using namespace Cxxi; @@ -451,7 +561,13 @@ Cxxi::Type^ Parser::ConvertTypeToCLR(clang::QualType QualType) // Assume that the type has already been defined for now. String Name(GetTagDeclName(RD)); - auto D = Lib->FindClass(marshalString(Name)); + + // We have to try to find the class type. If there is none yet, + // then create it, this is needed to deal properly with forward + // referenced types. + + auto NS = GetNamespace(RD); + auto D = NS->FindClass(marshalString(Name), true /* Create */); auto TT = gcnew Cxxi::TagType(); TT->Declaration = D; @@ -766,8 +882,11 @@ void Parser::WalkDeclaration(clang::Decl* D) auto Class = WalkRecordCXX(RD); HandleComments(RD, Class); - auto M = GetModule(RD->getLocation()); - M->Global->Classes->Add(Class); + auto NS = GetNamespace(RD); + auto RC = NS->FindClass(marshalString(GetTagDeclName(RD)), /* Create */ false); + + if (!RC) + NS->Classes->Add(Class); break; } @@ -781,7 +900,7 @@ void Parser::WalkDeclaration(clang::Decl* D) HandleComments(ED, E); auto M = GetModule(ED->getLocation()); - M->Global->Enums->Add(E); + M->Enums->Add(E); break; } @@ -795,7 +914,7 @@ void Parser::WalkDeclaration(clang::Decl* D) HandleComments(FD, F); auto M = GetModule(FD->getLocation()); - M->Global->Functions->Add(F); + M->Functions->Add(F); break; } diff --git a/src/Parser/Parser.h b/src/Parser/Parser.h index 54b7b241..465566d2 100644 --- a/src/Parser/Parser.h +++ b/src/Parser/Parser.h @@ -32,12 +32,12 @@ public ref struct ParserOptions { - // C/C++ header file name. - System::String^ FileName; + // C/C++ header file name. + System::String^ FileName; - Cxxi::Library^ Library; + Cxxi::Library^ Library; - bool Verbose; + bool Verbose; }; struct Parser @@ -63,9 +63,11 @@ protected: bool IsValidDeclaration(const clang::SourceLocation& Loc); std::string GetDeclMangledName(clang::Decl*, clang::TargetCXXABI); std::string GetTypeBindName(const clang::Type*); + void HandleComments(clang::Decl* D, Cxxi::Declaration^); + Cxxi::Module^ GetModule(clang::SourceLocation Loc); + Cxxi::Namespace^ GetNamespace(const clang::NamedDecl*); Cxxi::Type^ ConvertTypeToCLR(clang::QualType QualType); - void HandleComments(clang::Decl* D, Cxxi::Declaration^); gcroot Lib; llvm::OwningPtr C;