diff options
Diffstat (limited to 'tools/clang-import-test/clang-import-test.cpp')
-rw-r--r-- | tools/clang-import-test/clang-import-test.cpp | 183 |
1 files changed, 120 insertions, 63 deletions
diff --git a/tools/clang-import-test/clang-import-test.cpp b/tools/clang-import-test/clang-import-test.cpp index 6b724e9cf5fa..1ea7ee3611df 100644 --- a/tools/clang-import-test/clang-import-test.cpp +++ b/tools/clang-import-test/clang-import-test.cpp @@ -17,6 +17,7 @@ #include "clang/Basic/TargetInfo.h" #include "clang/Basic/TargetOptions.h" #include "clang/CodeGen/ModuleBuilder.h" +#include "clang/Driver/Types.h" #include "clang/Frontend/ASTConsumers.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/MultiplexConsumer.h" @@ -26,6 +27,7 @@ #include "clang/Parse/ParseAST.h" #include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Module.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Error.h" #include "llvm/Support/Host.h" @@ -46,16 +48,27 @@ static llvm::cl::list<std::string> static llvm::cl::opt<bool> Direct("direct", llvm::cl::Optional, - llvm::cl::desc("Use the parsed declarations without indirection")); + llvm::cl::desc("Use the parsed declarations without indirection")); + +static llvm::cl::opt<bool> + UseOrigins("use-origins", llvm::cl::Optional, + llvm::cl::desc("Use DeclContext origin information for more accurate lookups")); static llvm::cl::list<std::string> ClangArgs("Xcc", llvm::cl::ZeroOrMore, llvm::cl::desc("Argument to pass to the CompilerInvocation"), llvm::cl::CommaSeparated); -static llvm::cl::opt<bool> -DumpAST("dump-ast", llvm::cl::init(false), - llvm::cl::desc("Dump combined AST")); +static llvm::cl::opt<std::string> + Input("x", llvm::cl::Optional, + llvm::cl::desc("The language to parse (default: c++)"), + llvm::cl::init("c++")); + +static llvm::cl::opt<bool> DumpAST("dump-ast", llvm::cl::init(false), + llvm::cl::desc("Dump combined AST")); + +static llvm::cl::opt<bool> DumpIR("dump-ir", llvm::cl::init(false), + llvm::cl::desc("Dump IR from final parse")); namespace init_convenience { class TestDiagnosticConsumer : public DiagnosticConsumer { @@ -110,6 +123,7 @@ private: llvm::errs() << LineString << '\n'; llvm::errs().indent(LocColumn); llvm::errs() << '^'; + llvm::errs() << '\n'; } virtual void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, @@ -142,8 +156,7 @@ private: } }; -std::unique_ptr<CompilerInstance> -BuildCompilerInstance(ArrayRef<const char *> ClangArgv) { +std::unique_ptr<CompilerInstance> BuildCompilerInstance() { auto Ins = llvm::make_unique<CompilerInstance>(); auto DC = llvm::make_unique<TestDiagnosticConsumer>(); const bool ShouldOwnClient = true; @@ -151,13 +164,27 @@ BuildCompilerInstance(ArrayRef<const char *> ClangArgv) { auto Inv = llvm::make_unique<CompilerInvocation>(); + std::vector<const char *> ClangArgv(ClangArgs.size()); + std::transform(ClangArgs.begin(), ClangArgs.end(), ClangArgv.begin(), + [](const std::string &s) -> const char * { return s.data(); }); CompilerInvocation::CreateFromArgs(*Inv, ClangArgv.data(), &ClangArgv.data()[ClangArgv.size()], Ins->getDiagnostics()); - Inv->getLangOpts()->CPlusPlus = true; - Inv->getLangOpts()->CPlusPlus11 = true; - Inv->getHeaderSearchOpts().UseLibcxx = true; + { + using namespace driver::types; + ID Id = lookupTypeForTypeSpecifier(Input.c_str()); + assert(Id != TY_INVALID); + if (isCXX(Id)) { + Inv->getLangOpts()->CPlusPlus = true; + Inv->getLangOpts()->CPlusPlus11 = true; + Inv->getHeaderSearchOpts().UseLibcxx = true; + } + if (isObjC(Id)) { + Inv->getLangOpts()->ObjC1 = 1; + Inv->getLangOpts()->ObjC2 = 1; + } + } Inv->getLangOpts()->Bool = true; Inv->getLangOpts()->WChar = true; Inv->getLangOpts()->Blocks = true; @@ -201,32 +228,54 @@ std::unique_ptr<CodeGenerator> BuildCodeGen(CompilerInstance &CI, } // end namespace namespace { - -void AddExternalSource( - CompilerInstance &CI, - llvm::ArrayRef<std::unique_ptr<CompilerInstance>> Imports) { - ExternalASTMerger::ImporterEndpoint Target({CI.getASTContext(), CI.getFileManager()}); - llvm::SmallVector<ExternalASTMerger::ImporterEndpoint, 3> Sources; - for (const std::unique_ptr<CompilerInstance> &CI : Imports) { - Sources.push_back({CI->getASTContext(), CI->getFileManager()}); + +/// A container for a CompilerInstance (possibly with an ExternalASTMerger +/// attached to its ASTContext). +/// +/// Provides an accessor for the DeclContext origins associated with the +/// ExternalASTMerger (or an empty list of origins if no ExternalASTMerger is +/// attached). +/// +/// This is the main unit of parsed source code maintained by clang-import-test. +struct CIAndOrigins { + using OriginMap = clang::ExternalASTMerger::OriginMap; + std::unique_ptr<CompilerInstance> CI; + + ASTContext &getASTContext() { return CI->getASTContext(); } + FileManager &getFileManager() { return CI->getFileManager(); } + const OriginMap &getOriginMap() { + static const OriginMap EmptyOriginMap; + if (ExternalASTSource *Source = CI->getASTContext().getExternalSource()) + return static_cast<ExternalASTMerger *>(Source)->GetOrigins(); + return EmptyOriginMap; + } + DiagnosticConsumer &getDiagnosticClient() { + return CI->getDiagnosticClient(); } + CompilerInstance &getCompilerInstance() { return *CI; } +}; + +void AddExternalSource(CIAndOrigins &CI, + llvm::MutableArrayRef<CIAndOrigins> Imports) { + ExternalASTMerger::ImporterTarget Target( + {CI.getASTContext(), CI.getFileManager()}); + llvm::SmallVector<ExternalASTMerger::ImporterSource, 3> Sources; + for (CIAndOrigins &Import : Imports) + Sources.push_back( + {Import.getASTContext(), Import.getFileManager(), Import.getOriginMap()}); auto ES = llvm::make_unique<ExternalASTMerger>(Target, Sources); CI.getASTContext().setExternalSource(ES.release()); CI.getASTContext().getTranslationUnitDecl()->setHasExternalVisibleStorage(); } -std::unique_ptr<CompilerInstance> BuildIndirect(std::unique_ptr<CompilerInstance> &CI) { - std::vector<const char *> ClangArgv(ClangArgs.size()); - std::transform(ClangArgs.begin(), ClangArgs.end(), ClangArgv.begin(), - [](const std::string &s) -> const char * { return s.data(); }); - std::unique_ptr<CompilerInstance> IndirectCI = - init_convenience::BuildCompilerInstance(ClangArgv); +CIAndOrigins BuildIndirect(CIAndOrigins &CI) { + CIAndOrigins IndirectCI{init_convenience::BuildCompilerInstance()}; auto ST = llvm::make_unique<SelectorTable>(); auto BC = llvm::make_unique<Builtin::Context>(); - std::unique_ptr<ASTContext> AST = - init_convenience::BuildASTContext(*IndirectCI, *ST, *BC); - IndirectCI->setASTContext(AST.release()); - AddExternalSource(*IndirectCI, CI); + std::unique_ptr<ASTContext> AST = init_convenience::BuildASTContext( + IndirectCI.getCompilerInstance(), *ST, *BC); + IndirectCI.getCompilerInstance().setASTContext(AST.release()); + AddExternalSource(IndirectCI, CI); return IndirectCI; } @@ -243,46 +292,53 @@ llvm::Error ParseSource(const std::string &Path, CompilerInstance &CI, return llvm::Error::success(); } -llvm::Expected<std::unique_ptr<CompilerInstance>> -Parse(const std::string &Path, - llvm::ArrayRef<std::unique_ptr<CompilerInstance>> Imports, - bool ShouldDumpAST) { - std::vector<const char *> ClangArgv(ClangArgs.size()); - std::transform(ClangArgs.begin(), ClangArgs.end(), ClangArgv.begin(), - [](const std::string &s) -> const char * { return s.data(); }); - std::unique_ptr<CompilerInstance> CI = - init_convenience::BuildCompilerInstance(ClangArgv); +llvm::Expected<CIAndOrigins> Parse(const std::string &Path, + llvm::MutableArrayRef<CIAndOrigins> Imports, + bool ShouldDumpAST, bool ShouldDumpIR) { + CIAndOrigins CI{init_convenience::BuildCompilerInstance()}; auto ST = llvm::make_unique<SelectorTable>(); auto BC = llvm::make_unique<Builtin::Context>(); std::unique_ptr<ASTContext> AST = - init_convenience::BuildASTContext(*CI, *ST, *BC); - CI->setASTContext(AST.release()); + init_convenience::BuildASTContext(CI.getCompilerInstance(), *ST, *BC); + CI.getCompilerInstance().setASTContext(AST.release()); if (Imports.size()) - AddExternalSource(*CI, Imports); + AddExternalSource(CI, Imports); std::vector<std::unique_ptr<ASTConsumer>> ASTConsumers; auto LLVMCtx = llvm::make_unique<llvm::LLVMContext>(); - ASTConsumers.push_back(init_convenience::BuildCodeGen(*CI, *LLVMCtx)); + ASTConsumers.push_back( + init_convenience::BuildCodeGen(CI.getCompilerInstance(), *LLVMCtx)); + auto &CG = *static_cast<CodeGenerator *>(ASTConsumers.back().get()); if (ShouldDumpAST) ASTConsumers.push_back(CreateASTDumper("", true, false, false)); - CI->getDiagnosticClient().BeginSourceFile(CI->getLangOpts(), - &CI->getPreprocessor()); + CI.getDiagnosticClient().BeginSourceFile( + CI.getCompilerInstance().getLangOpts(), + &CI.getCompilerInstance().getPreprocessor()); MultiplexConsumer Consumers(std::move(ASTConsumers)); - Consumers.Initialize(CI->getASTContext()); + Consumers.Initialize(CI.getASTContext()); - if (llvm::Error PE = ParseSource(Path, *CI, Consumers)) { + if (llvm::Error PE = ParseSource(Path, CI.getCompilerInstance(), Consumers)) return std::move(PE); - } - CI->getDiagnosticClient().EndSourceFile(); - if (CI->getDiagnosticClient().getNumErrors()) { + CI.getDiagnosticClient().EndSourceFile(); + if (ShouldDumpIR) + CG.GetModule()->print(llvm::outs(), nullptr); + if (CI.getDiagnosticClient().getNumErrors()) return llvm::make_error<llvm::StringError>( "Errors occured while parsing the expression.", std::error_code()); - } else { - return std::move(CI); - } + return std::move(CI); +} + +void Forget(CIAndOrigins &CI, llvm::MutableArrayRef<CIAndOrigins> Imports) { + llvm::SmallVector<ExternalASTMerger::ImporterSource, 3> Sources; + for (CIAndOrigins &Import : Imports) + Sources.push_back( + {Import.getASTContext(), Import.getFileManager(), Import.getOriginMap()}); + ExternalASTSource *Source = CI.CI->getASTContext().getExternalSource(); + auto *Merger = static_cast<ExternalASTMerger *>(Source); + Merger->RemoveSources(Sources); } } // end namespace @@ -291,31 +347,32 @@ int main(int argc, const char **argv) { const bool DisableCrashReporting = true; llvm::sys::PrintStackTraceOnErrorSignal(argv[0], DisableCrashReporting); llvm::cl::ParseCommandLineOptions(argc, argv); - std::vector<std::unique_ptr<CompilerInstance>> ImportCIs; + std::vector<CIAndOrigins> ImportCIs; for (auto I : Imports) { - llvm::Expected<std::unique_ptr<CompilerInstance>> ImportCI = - Parse(I, {}, false); + llvm::Expected<CIAndOrigins> ImportCI = Parse(I, {}, false, false); if (auto E = ImportCI.takeError()) { llvm::errs() << llvm::toString(std::move(E)); exit(-1); - } else { - ImportCIs.push_back(std::move(*ImportCI)); } + ImportCIs.push_back(std::move(*ImportCI)); } - std::vector<std::unique_ptr<CompilerInstance>> IndirectCIs; - if (!Direct) { + std::vector<CIAndOrigins> IndirectCIs; + if (!Direct || UseOrigins) { for (auto &ImportCI : ImportCIs) { - std::unique_ptr<CompilerInstance> IndirectCI = BuildIndirect(ImportCI); + CIAndOrigins IndirectCI = BuildIndirect(ImportCI); IndirectCIs.push_back(std::move(IndirectCI)); } } - llvm::Expected<std::unique_ptr<CompilerInstance>> ExpressionCI = - Parse(Expression, Direct ? ImportCIs : IndirectCIs, DumpAST); + if (UseOrigins) + for (auto &ImportCI : ImportCIs) + IndirectCIs.push_back(std::move(ImportCI)); + llvm::Expected<CIAndOrigins> ExpressionCI = + Parse(Expression, (Direct && !UseOrigins) ? ImportCIs : IndirectCIs, + DumpAST, DumpIR); if (auto E = ExpressionCI.takeError()) { llvm::errs() << llvm::toString(std::move(E)); exit(-1); - } else { - return 0; } + Forget(*ExpressionCI, (Direct && !UseOrigins) ? ImportCIs : IndirectCIs); + return 0; } - |