Browse Source

Split Parser::ParseHeader into helper methods.

Use clang::SemaConsumer interface callback to walk over the parsed AST.

This deals with a nasty bug that occurs when processing late-parsed template declarations.

The clang::Parser object life is tied to clang::ParseAST function, so we need to process the AST in the callback.

Fixes https://github.com/mono/CppSharp/issues/1123 and (hopefully) https://github.com/mono/CppSharp/issues/1124.
pull/1126/head
Joao Matos 7 years ago committed by João Matos
parent
commit
ef0b054301
  1. 133
      src/CppParser/Parser.cpp
  2. 19
      src/CppParser/Parser.h
  3. 24
      tests/Common/Common.h

133
src/CppParser/Parser.cpp

@ -44,8 +44,7 @@
#include <clang/Driver/ToolChain.h> #include <clang/Driver/ToolChain.h>
#include <clang/Driver/Util.h> #include <clang/Driver/Util.h>
#include <clang/Index/USRGeneration.h> #include <clang/Index/USRGeneration.h>
#include <CodeGen/CodeGenModule.h>
#include <CodeGen/CodeGenTypes.h>
#include <CodeGen/TargetInfo.h> #include <CodeGen/TargetInfo.h>
#include <CodeGen/CGCall.h> #include <CodeGen/CGCall.h>
#include <CodeGen/CGCXXABI.h> #include <CodeGen/CGCXXABI.h>
@ -3278,9 +3277,8 @@ bool Parser::IsValidDeclaration(const clang::SourceLocation& Loc)
//-----------------------------------// //-----------------------------------//
void Parser::WalkAST() void Parser::WalkAST(clang::TranslationUnitDecl* TU)
{ {
auto TU = c->getASTContext().getTranslationUnitDecl();
for (auto D : TU->decls()) for (auto D : TU->decls())
{ {
if (D->getBeginLoc().isValid() && if (D->getBeginLoc().isValid() &&
@ -4049,35 +4047,32 @@ void Parser::HandleDiagnostics(ParserResult* res)
} }
} }
ParserResult* Parser::ParseHeader(const std::vector<std::string>& SourceFiles) void Parser::SetupLLVMCodegen()
{ {
assert(opts->ASTContext && "Expected a valid ASTContext"); // Initialize enough Clang codegen machinery so we can get at ABI details.
LLVMModule.reset(new llvm::Module("", LLVMCtx));
auto res = new ParserResult();
if (SourceFiles.empty())
{
res->kind = ParserResultKind::FileNotFound;
return res;
}
Setup(); LLVMModule->setTargetTriple(c->getTarget().getTriple().getTriple());
LLVMModule->setDataLayout(c->getTarget().getDataLayout());
std::unique_ptr<clang::SemaConsumer> SC(new clang::SemaConsumer()); CGM.reset(new clang::CodeGen::CodeGenModule(c->getASTContext(),
c->setASTConsumer(std::move(SC)); c->getHeaderSearchOpts(), c->getPreprocessorOpts(),
c->getCodeGenOpts(), *LLVMModule, c->getDiagnostics()));
c->createSema(clang::TU_Complete, 0); CGT.reset(new clang::CodeGen::CodeGenTypes(*CGM.get()));
auto DiagClient = new DiagnosticConsumer(); codeGenTypes = CGT.get();
c->getDiagnostics().setClient(DiagClient); }
bool Parser::SetupSourceFiles(const std::vector<std::string>& SourceFiles,
std::vector<const clang::FileEntry*>& FileEntries)
{
// Check that the file is reachable. // Check that the file is reachable.
const clang::DirectoryLookup *Dir; const clang::DirectoryLookup *Dir;
llvm::SmallVector< llvm::SmallVector<
std::pair<const clang::FileEntry *, const clang::DirectoryEntry *>, std::pair<const clang::FileEntry *, const clang::DirectoryEntry *>,
0> Includers; 0> Includers;
std::vector<const clang::FileEntry*> FileEntries;
for (const auto& SourceFile : SourceFiles) for (const auto& SourceFile : SourceFiles)
{ {
auto FileEntry = c->getPreprocessor().getHeaderSearchInfo().LookupFile(SourceFile, auto FileEntry = c->getPreprocessor().getHeaderSearchInfo().LookupFile(SourceFile,
@ -4085,71 +4080,97 @@ ParserResult* Parser::ParseHeader(const std::vector<std::string>& SourceFiles)
nullptr, Dir, Includers, nullptr, nullptr, nullptr, nullptr, nullptr); nullptr, Dir, Includers, nullptr, nullptr, nullptr, nullptr, nullptr);
if (!FileEntry) if (!FileEntry)
{ return false;
res->kind = ParserResultKind::FileNotFound;
return res;
}
FileEntries.push_back(FileEntry); FileEntries.push_back(FileEntry);
} }
// Create a virtual file that includes the header. This gets rid of some // Create a virtual file that includes the header. This gets rid of some
// Clang warnings about parsing an header file as the main file. // Clang warnings about parsing an header file as the main file.
std::string str; std::string source;
for (const auto& SourceFile : SourceFiles) for (const auto& SourceFile : SourceFiles)
{ {
str += "#include \"" + SourceFile + "\"" + "\n"; source += "#include \"" + SourceFile + "\"" + "\n";
} }
str += "\0"; source += "\0";
auto buffer = llvm::MemoryBuffer::getMemBuffer(str); auto buffer = llvm::MemoryBuffer::getMemBufferCopy(source);
auto& SM = c->getSourceManager(); auto& SM = c->getSourceManager();
SM.setMainFileID(SM.createFileID(std::move(buffer))); SM.setMainFileID(SM.createFileID(std::move(buffer)));
clang::DiagnosticConsumer* client = c->getDiagnostics().getClient(); return true;
client->BeginSourceFile(c->getLangOpts(), &c->getPreprocessor()); }
ParseAST(c->getSema()); class SemaConsumer : public clang::SemaConsumer {
CppSharp::CppParser::Parser& Parser;
std::vector<const clang::FileEntry*>& FileEntries;
public:
SemaConsumer(CppSharp::CppParser::Parser& parser,
std::vector<const clang::FileEntry*>& entries)
: Parser(parser), FileEntries(entries) {}
virtual void HandleTranslationUnit(clang::ASTContext& Ctx) override;
};
client->EndSourceFile(); void SemaConsumer::HandleTranslationUnit(clang::ASTContext& Ctx)
{
auto FileEntry = FileEntries[0];
auto FileName = FileEntry->getName();
auto Unit = Parser.opts->ASTContext->FindOrCreateModule(FileName);
HandleDiagnostics(res); auto TU = Ctx.getTranslationUnitDecl();
Parser.HandleDeclaration(TU, Unit);
if(client->getNumErrors() != 0) if (Unit->originalPtr == nullptr)
Unit->originalPtr = (void*)FileEntry;
Parser.WalkAST(TU);
}
ParserResult* Parser::ParseHeader(const std::vector<std::string>& SourceFiles)
{
assert(opts->ASTContext && "Expected a valid ASTContext");
auto res = new ParserResult();
if (SourceFiles.empty())
{ {
res->kind = ParserResultKind::Error; res->kind = ParserResultKind::FileNotFound;
return res; return res;
} }
auto& AST = c->getASTContext(); Setup();
SetupLLVMCodegen();
auto FileEntry = FileEntries[0]; std::vector<const clang::FileEntry*> FileEntries;
auto FileName = FileEntry->getName(); if (!SetupSourceFiles(SourceFiles, FileEntries))
auto Unit = opts->ASTContext->FindOrCreateModule(FileName); {
res->kind = ParserResultKind::FileNotFound;
return res;
}
auto TU = AST.getTranslationUnitDecl(); std::unique_ptr<SemaConsumer> SC(new SemaConsumer(*this, FileEntries));
HandleDeclaration(TU, Unit); c->setASTConsumer(std::move(SC));
if (Unit->originalPtr == nullptr) c->createSema(clang::TU_Complete, 0);
Unit->originalPtr = (void*)FileEntry;
// Initialize enough Clang codegen machinery so we can get at ABI details. auto DiagClient = new DiagnosticConsumer();
llvm::LLVMContext Ctx; c->getDiagnostics().setClient(DiagClient);
std::unique_ptr<llvm::Module> M(new llvm::Module("", Ctx));
M->setTargetTriple(c->getTarget().getTriple().getTriple()); clang::DiagnosticConsumer* client = c->getDiagnostics().getClient();
M->setDataLayout(c->getTarget().getDataLayout()); client->BeginSourceFile(c->getLangOpts(), &c->getPreprocessor());
std::unique_ptr<clang::CodeGen::CodeGenModule> CGM( ParseAST(c->getSema());
new clang::CodeGen::CodeGenModule(c->getASTContext(), c->getHeaderSearchOpts(),
c->getPreprocessorOpts(), c->getCodeGenOpts(), *M, c->getDiagnostics()));
std::unique_ptr<clang::CodeGen::CodeGenTypes> CGT( client->EndSourceFile();
new clang::CodeGen::CodeGenTypes(*CGM.get()));
codeGenTypes = CGT.get(); HandleDiagnostics(res);
WalkAST(); if(client->getNumErrors() != 0)
{
res->kind = ParserResultKind::Error;
return res;
}
res->targetInfo = GetTargetInfo(); res->targetInfo = GetTargetInfo();

19
src/CppParser/Parser.h

@ -18,6 +18,9 @@
#include <clang/Frontend/CompilerInstance.h> #include <clang/Frontend/CompilerInstance.h>
#include <clang/Sema/Scope.h> #include <clang/Sema/Scope.h>
#include <CodeGen/CodeGenModule.h>
#include <CodeGen/CodeGenTypes.h>
#include "CXXABI.h" #include "CXXABI.h"
#include "CppParser.h" #include "CppParser.h"
@ -53,11 +56,19 @@ public:
ParserResult* ParseHeader(const std::vector<std::string>& SourceFiles); ParserResult* ParseHeader(const std::vector<std::string>& SourceFiles);
ParserResult* ParseLibrary(const std::string& File); ParserResult* ParseLibrary(const std::string& File);
void WalkAST(clang::TranslationUnitDecl* TU);
void HandleDeclaration(const clang::Decl* D, Declaration* Decl);
CppParserOptions* opts;
private: private:
void SetupLLVMCodegen();
bool SetupSourceFiles(const std::vector<std::string>& SourceFiles,
std::vector<const clang::FileEntry*>& FileEntries);
bool IsSupported(const clang::NamedDecl* ND); bool IsSupported(const clang::NamedDecl* ND);
bool IsSupported(const clang::CXXMethodDecl* MD); bool IsSupported(const clang::CXXMethodDecl* MD);
// AST traversers // AST traversers
void WalkAST();
Declaration* WalkDeclaration(const clang::Decl* D); Declaration* WalkDeclaration(const clang::Decl* D);
Declaration* WalkDeclarationDef(clang::Decl* D); Declaration* WalkDeclarationDef(clang::Decl* D);
Enumeration* WalkEnum(const clang::EnumDecl* ED); Enumeration* WalkEnum(const clang::EnumDecl* ED);
@ -137,7 +148,6 @@ private:
DeclarationContext* GetNamespace(const clang::Decl* D, const clang::DeclContext* Ctx); DeclarationContext* GetNamespace(const clang::Decl* D, const clang::DeclContext* Ctx);
DeclarationContext* GetNamespace(const clang::Decl* D); DeclarationContext* GetNamespace(const clang::Decl* D);
void HandleDeclaration(const clang::Decl* D, Declaration* Decl);
void HandleOriginalText(const clang::Decl* D, Declaration* Decl); void HandleOriginalText(const clang::Decl* D, Declaration* Decl);
void HandleComments(const clang::Decl* D, Declaration* Decl); void HandleComments(const clang::Decl* D, Declaration* Decl);
void HandleDiagnostics(ParserResult* res); void HandleDiagnostics(ParserResult* res);
@ -154,9 +164,12 @@ private:
ParserTargetInfo* GetTargetInfo(); ParserTargetInfo* GetTargetInfo();
int index; int index;
CppParserOptions* opts;
std::unique_ptr<clang::CompilerInstance> c; std::unique_ptr<clang::CompilerInstance> c;
clang::TargetCXXABI::Kind targetABI; clang::TargetCXXABI::Kind targetABI;
llvm::LLVMContext LLVMCtx;
std::unique_ptr<llvm::Module> LLVMModule;
std::unique_ptr<clang::CodeGen::CodeGenModule> CGM;
std::unique_ptr<clang::CodeGen::CodeGenTypes> CGT;
clang::CodeGen::CodeGenTypes* codeGenTypes; clang::CodeGen::CodeGenTypes* codeGenTypes;
std::unordered_map<const clang::TemplateTypeParmDecl*, TypeTemplateParameter*> walkedTypeTemplateParameters; std::unordered_map<const clang::TemplateTypeParmDecl*, TypeTemplateParameter*> walkedTypeTemplateParameters;
std::unordered_map<const clang::TemplateTemplateParmDecl*, TemplateTemplateParameter*> walkedTemplateTemplateParameters; std::unordered_map<const clang::TemplateTemplateParmDecl*, TemplateTemplateParameter*> walkedTemplateTemplateParameters;

24
tests/Common/Common.h

@ -1433,3 +1433,27 @@ enum ItemsDifferByCase
Case_a, Case_a,
Case_A Case_A
}; };
template <typename T> struct MyListBase
{
protected:
~MyListBase() {}
};
template <typename T>
class MyList : public MyListBase<T>
{
public:
inline MyList() { }
};
template <> struct MyListBase<int>
{
};
class MyIntList : public MyList<int>
{
inline MyIntList(MyList<int> &&l) { }
};
void MyFunc(MyList<void *> *list);

Loading…
Cancel
Save