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

19
src/CppParser/Parser.h

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

24
tests/Common/Common.h

@ -1433,3 +1433,27 @@ enum ItemsDifferByCase @@ -1433,3 +1433,27 @@ enum ItemsDifferByCase
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