blob: 186a7c82dc1a4ca571f3120b9eb786ad959f2b9d [file] [log] [blame]
Sean Callanan7d982502016-12-22 20:03:14 +00001//===-- import-test.cpp - ASTImporter/ExternalASTSource testbed -----------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "clang/AST/ASTContext.h"
11#include "clang/AST/ASTImporter.h"
Sean Callananb7160ca2017-04-11 19:33:35 +000012#include "clang/AST/DeclObjC.h"
13#include "clang/AST/ExternalASTMerger.h"
Sean Callanan7d982502016-12-22 20:03:14 +000014#include "clang/Basic/Builtins.h"
15#include "clang/Basic/IdentifierTable.h"
16#include "clang/Basic/SourceLocation.h"
17#include "clang/Basic/TargetInfo.h"
18#include "clang/Basic/TargetOptions.h"
19#include "clang/CodeGen/ModuleBuilder.h"
Sean Callanan1eac8792017-07-25 19:54:22 +000020#include "clang/Driver/Types.h"
Lang Hames19e07e12017-06-20 21:06:00 +000021#include "clang/Frontend/ASTConsumers.h"
Sean Callanan7d982502016-12-22 20:03:14 +000022#include "clang/Frontend/CompilerInstance.h"
Lang Hames19e07e12017-06-20 21:06:00 +000023#include "clang/Frontend/MultiplexConsumer.h"
Sean Callanan7d982502016-12-22 20:03:14 +000024#include "clang/Frontend/TextDiagnosticBuffer.h"
25#include "clang/Lex/Lexer.h"
26#include "clang/Lex/Preprocessor.h"
27#include "clang/Parse/ParseAST.h"
28
29#include "llvm/IR/LLVMContext.h"
Sean Callanan2b3a54b2017-08-07 22:27:30 +000030#include "llvm/IR/Module.h"
Sean Callanan7d982502016-12-22 20:03:14 +000031#include "llvm/Support/CommandLine.h"
32#include "llvm/Support/Error.h"
33#include "llvm/Support/Host.h"
34#include "llvm/Support/Signals.h"
35
36#include <memory>
37#include <string>
38
39using namespace clang;
40
41static llvm::cl::opt<std::string> Expression(
42 "expression", llvm::cl::Required,
43 llvm::cl::desc("Path to a file containing the expression to parse"));
44
45static llvm::cl::list<std::string>
46 Imports("import", llvm::cl::ZeroOrMore,
47 llvm::cl::desc("Path to a file containing declarations to import"));
48
Sean Callanan9092d472017-05-13 00:46:33 +000049static llvm::cl::opt<bool>
50 Direct("direct", llvm::cl::Optional,
51 llvm::cl::desc("Use the parsed declarations without indirection"));
52
Sean Callanan7d982502016-12-22 20:03:14 +000053static llvm::cl::list<std::string>
54 ClangArgs("Xcc", llvm::cl::ZeroOrMore,
55 llvm::cl::desc("Argument to pass to the CompilerInvocation"),
56 llvm::cl::CommaSeparated);
57
Sean Callanan1eac8792017-07-25 19:54:22 +000058static llvm::cl::opt<std::string>
59 Input("x", llvm::cl::Optional,
60 llvm::cl::desc("The language to parse (default: c++)"),
61 llvm::cl::init("c++"));
62
Lang Hames19e07e12017-06-20 21:06:00 +000063static llvm::cl::opt<bool>
64DumpAST("dump-ast", llvm::cl::init(false),
65 llvm::cl::desc("Dump combined AST"));
66
Sean Callanan2b3a54b2017-08-07 22:27:30 +000067static llvm::cl::opt<bool>
68DumpIR("dump-ir", llvm::cl::init(false),
69 llvm::cl::desc("Dump IR from final parse"));
70
Sean Callanan7d982502016-12-22 20:03:14 +000071namespace init_convenience {
72class TestDiagnosticConsumer : public DiagnosticConsumer {
73private:
74 std::unique_ptr<TextDiagnosticBuffer> Passthrough;
75 const LangOptions *LangOpts = nullptr;
76
77public:
78 TestDiagnosticConsumer()
79 : Passthrough(llvm::make_unique<TextDiagnosticBuffer>()) {}
80
81 virtual void BeginSourceFile(const LangOptions &LangOpts,
82 const Preprocessor *PP = nullptr) override {
83 this->LangOpts = &LangOpts;
84 return Passthrough->BeginSourceFile(LangOpts, PP);
85 }
86
87 virtual void EndSourceFile() override {
88 this->LangOpts = nullptr;
89 Passthrough->EndSourceFile();
90 }
91
92 virtual bool IncludeInDiagnosticCounts() const override {
93 return Passthrough->IncludeInDiagnosticCounts();
94 }
95
96private:
97 static void PrintSourceForLocation(const SourceLocation &Loc,
98 SourceManager &SM) {
99 const char *LocData = SM.getCharacterData(Loc, /*Invalid=*/nullptr);
100 unsigned LocColumn =
101 SM.getSpellingColumnNumber(Loc, /*Invalid=*/nullptr) - 1;
102 FileID FID = SM.getFileID(Loc);
103 llvm::MemoryBuffer *Buffer = SM.getBuffer(FID, Loc, /*Invalid=*/nullptr);
104
105 assert(LocData >= Buffer->getBufferStart() &&
106 LocData < Buffer->getBufferEnd());
107
108 const char *LineBegin = LocData - LocColumn;
109
110 assert(LineBegin >= Buffer->getBufferStart());
111
112 const char *LineEnd = nullptr;
113
114 for (LineEnd = LineBegin; *LineEnd != '\n' && *LineEnd != '\r' &&
115 LineEnd < Buffer->getBufferEnd();
116 ++LineEnd)
117 ;
118
119 llvm::StringRef LineString(LineBegin, LineEnd - LineBegin);
120
121 llvm::errs() << LineString << '\n';
122 llvm::errs().indent(LocColumn);
123 llvm::errs() << '^';
Sean Callanan1eac8792017-07-25 19:54:22 +0000124 llvm::errs() << '\n';
Sean Callanan7d982502016-12-22 20:03:14 +0000125 }
126
127 virtual void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
128 const Diagnostic &Info) override {
129 if (Info.hasSourceManager() && LangOpts) {
130 SourceManager &SM = Info.getSourceManager();
131
132 if (Info.getLocation().isValid()) {
133 Info.getLocation().print(llvm::errs(), SM);
134 llvm::errs() << ": ";
135 }
136
137 SmallString<16> DiagText;
138 Info.FormatDiagnostic(DiagText);
139 llvm::errs() << DiagText << '\n';
140
141 if (Info.getLocation().isValid()) {
142 PrintSourceForLocation(Info.getLocation(), SM);
143 }
144
145 for (const CharSourceRange &Range : Info.getRanges()) {
146 bool Invalid = true;
147 StringRef Ref = Lexer::getSourceText(Range, SM, *LangOpts, &Invalid);
148 if (!Invalid) {
149 llvm::errs() << Ref << '\n';
150 }
151 }
152 }
153 DiagnosticConsumer::HandleDiagnostic(DiagLevel, Info);
154 }
155};
156
157std::unique_ptr<CompilerInstance>
Sean Callanan1eac8792017-07-25 19:54:22 +0000158BuildCompilerInstance() {
Sean Callanan7d982502016-12-22 20:03:14 +0000159 auto Ins = llvm::make_unique<CompilerInstance>();
160 auto DC = llvm::make_unique<TestDiagnosticConsumer>();
161 const bool ShouldOwnClient = true;
162 Ins->createDiagnostics(DC.release(), ShouldOwnClient);
163
164 auto Inv = llvm::make_unique<CompilerInvocation>();
165
Sean Callanan1eac8792017-07-25 19:54:22 +0000166 std::vector<const char *> ClangArgv(ClangArgs.size());
167 std::transform(ClangArgs.begin(), ClangArgs.end(), ClangArgv.begin(),
168 [](const std::string &s) -> const char * { return s.data(); });
Sean Callanan7d982502016-12-22 20:03:14 +0000169 CompilerInvocation::CreateFromArgs(*Inv, ClangArgv.data(),
170 &ClangArgv.data()[ClangArgv.size()],
171 Ins->getDiagnostics());
172
Sean Callanan1eac8792017-07-25 19:54:22 +0000173 {
174 using namespace driver::types;
175 ID Id = lookupTypeForTypeSpecifier(Input.c_str());
176 assert(Id != TY_INVALID);
177 if (isCXX(Id)) {
178 Inv->getLangOpts()->CPlusPlus = true;
179 Inv->getLangOpts()->CPlusPlus11 = true;
180 Inv->getHeaderSearchOpts().UseLibcxx = true;
181 }
182 if (isObjC(Id)) {
183 Inv->getLangOpts()->ObjC1 = 1;
184 Inv->getLangOpts()->ObjC2 = 1;
185 }
186 }
Sean Callanan7d982502016-12-22 20:03:14 +0000187 Inv->getLangOpts()->Bool = true;
188 Inv->getLangOpts()->WChar = true;
189 Inv->getLangOpts()->Blocks = true;
190 Inv->getLangOpts()->DebuggerSupport = true;
191 Inv->getLangOpts()->SpellChecking = false;
192 Inv->getLangOpts()->ThreadsafeStatics = false;
193 Inv->getLangOpts()->AccessControl = false;
194 Inv->getLangOpts()->DollarIdents = true;
195 Inv->getCodeGenOpts().setDebugInfo(codegenoptions::FullDebugInfo);
196 Inv->getTargetOpts().Triple = llvm::sys::getDefaultTargetTriple();
197
David Blaikieea4395e2017-01-06 19:49:01 +0000198 Ins->setInvocation(std::move(Inv));
Sean Callanan7d982502016-12-22 20:03:14 +0000199
200 TargetInfo *TI = TargetInfo::CreateTargetInfo(
201 Ins->getDiagnostics(), Ins->getInvocation().TargetOpts);
202 Ins->setTarget(TI);
203 Ins->getTarget().adjust(Ins->getLangOpts());
204 Ins->createFileManager();
205 Ins->createSourceManager(Ins->getFileManager());
206 Ins->createPreprocessor(TU_Complete);
207
208 return Ins;
209}
210
211std::unique_ptr<ASTContext>
212BuildASTContext(CompilerInstance &CI, SelectorTable &ST, Builtin::Context &BC) {
213 auto AST = llvm::make_unique<ASTContext>(
214 CI.getLangOpts(), CI.getSourceManager(),
215 CI.getPreprocessor().getIdentifierTable(), ST, BC);
216 AST->InitBuiltinTypes(CI.getTarget());
217 return AST;
218}
219
220std::unique_ptr<CodeGenerator> BuildCodeGen(CompilerInstance &CI,
221 llvm::LLVMContext &LLVMCtx) {
222 StringRef ModuleName("$__module");
223 return std::unique_ptr<CodeGenerator>(CreateLLVMCodeGen(
224 CI.getDiagnostics(), ModuleName, CI.getHeaderSearchOpts(),
225 CI.getPreprocessorOpts(), CI.getCodeGenOpts(), LLVMCtx));
226}
227} // end namespace
228
229namespace {
Sean Callananb7160ca2017-04-11 19:33:35 +0000230
Sean Callanan7d982502016-12-22 20:03:14 +0000231void AddExternalSource(
232 CompilerInstance &CI,
233 llvm::ArrayRef<std::unique_ptr<CompilerInstance>> Imports) {
Sean Callananb7160ca2017-04-11 19:33:35 +0000234 ExternalASTMerger::ImporterEndpoint Target({CI.getASTContext(), CI.getFileManager()});
235 llvm::SmallVector<ExternalASTMerger::ImporterEndpoint, 3> Sources;
236 for (const std::unique_ptr<CompilerInstance> &CI : Imports) {
237 Sources.push_back({CI->getASTContext(), CI->getFileManager()});
238 }
239 auto ES = llvm::make_unique<ExternalASTMerger>(Target, Sources);
240 CI.getASTContext().setExternalSource(ES.release());
241 CI.getASTContext().getTranslationUnitDecl()->setHasExternalVisibleStorage();
Sean Callanan7d982502016-12-22 20:03:14 +0000242}
243
Sean Callanan9092d472017-05-13 00:46:33 +0000244std::unique_ptr<CompilerInstance> BuildIndirect(std::unique_ptr<CompilerInstance> &CI) {
Sean Callanan9092d472017-05-13 00:46:33 +0000245 std::unique_ptr<CompilerInstance> IndirectCI =
Sean Callanan1eac8792017-07-25 19:54:22 +0000246 init_convenience::BuildCompilerInstance();
Sean Callanan9092d472017-05-13 00:46:33 +0000247 auto ST = llvm::make_unique<SelectorTable>();
248 auto BC = llvm::make_unique<Builtin::Context>();
249 std::unique_ptr<ASTContext> AST =
250 init_convenience::BuildASTContext(*IndirectCI, *ST, *BC);
251 IndirectCI->setASTContext(AST.release());
252 AddExternalSource(*IndirectCI, CI);
253 return IndirectCI;
254}
255
Sean Callanan7d982502016-12-22 20:03:14 +0000256llvm::Error ParseSource(const std::string &Path, CompilerInstance &CI,
Lang Hames19e07e12017-06-20 21:06:00 +0000257 ASTConsumer &Consumer) {
Sean Callanan7d982502016-12-22 20:03:14 +0000258 SourceManager &SM = CI.getSourceManager();
259 const FileEntry *FE = CI.getFileManager().getFile(Path);
260 if (!FE) {
261 return llvm::make_error<llvm::StringError>(
262 llvm::Twine("Couldn't open ", Path), std::error_code());
263 }
264 SM.setMainFileID(SM.createFileID(FE, SourceLocation(), SrcMgr::C_User));
Lang Hames19e07e12017-06-20 21:06:00 +0000265 ParseAST(CI.getPreprocessor(), &Consumer, CI.getASTContext());
Sean Callanan7d982502016-12-22 20:03:14 +0000266 return llvm::Error::success();
267}
268
269llvm::Expected<std::unique_ptr<CompilerInstance>>
270Parse(const std::string &Path,
Lang Hames19e07e12017-06-20 21:06:00 +0000271 llvm::ArrayRef<std::unique_ptr<CompilerInstance>> Imports,
Sean Callanan2b3a54b2017-08-07 22:27:30 +0000272 bool ShouldDumpAST, bool ShouldDumpIR) {
Sean Callanan7d982502016-12-22 20:03:14 +0000273 std::unique_ptr<CompilerInstance> CI =
Sean Callanan1eac8792017-07-25 19:54:22 +0000274 init_convenience::BuildCompilerInstance();
Sean Callanan7d982502016-12-22 20:03:14 +0000275 auto ST = llvm::make_unique<SelectorTable>();
276 auto BC = llvm::make_unique<Builtin::Context>();
277 std::unique_ptr<ASTContext> AST =
278 init_convenience::BuildASTContext(*CI, *ST, *BC);
279 CI->setASTContext(AST.release());
Sean Callanan9092d472017-05-13 00:46:33 +0000280 if (Imports.size())
281 AddExternalSource(*CI, Imports);
Sean Callanan7d982502016-12-22 20:03:14 +0000282
Lang Hames19e07e12017-06-20 21:06:00 +0000283 std::vector<std::unique_ptr<ASTConsumer>> ASTConsumers;
284
Sean Callanan7d982502016-12-22 20:03:14 +0000285 auto LLVMCtx = llvm::make_unique<llvm::LLVMContext>();
Lang Hames19e07e12017-06-20 21:06:00 +0000286 ASTConsumers.push_back(init_convenience::BuildCodeGen(*CI, *LLVMCtx));
Sean Callanan2b3a54b2017-08-07 22:27:30 +0000287 auto &CG = *static_cast<CodeGenerator*>(ASTConsumers.back().get());
Lang Hames19e07e12017-06-20 21:06:00 +0000288
289 if (ShouldDumpAST)
290 ASTConsumers.push_back(CreateASTDumper("", true, false, false));
Sean Callanan7d982502016-12-22 20:03:14 +0000291
292 CI->getDiagnosticClient().BeginSourceFile(CI->getLangOpts(),
293 &CI->getPreprocessor());
Lang Hames19e07e12017-06-20 21:06:00 +0000294 MultiplexConsumer Consumers(std::move(ASTConsumers));
295 Consumers.Initialize(CI->getASTContext());
296
297 if (llvm::Error PE = ParseSource(Path, *CI, Consumers)) {
Sean Callanan7d982502016-12-22 20:03:14 +0000298 return std::move(PE);
299 }
300 CI->getDiagnosticClient().EndSourceFile();
Sean Callanan2b3a54b2017-08-07 22:27:30 +0000301 if (ShouldDumpIR)
302 CG.GetModule()->print(llvm::outs(), nullptr);
Sean Callanan7d982502016-12-22 20:03:14 +0000303 if (CI->getDiagnosticClient().getNumErrors()) {
304 return llvm::make_error<llvm::StringError>(
305 "Errors occured while parsing the expression.", std::error_code());
306 } else {
307 return std::move(CI);
308 }
309}
Sean Callananb7160ca2017-04-11 19:33:35 +0000310
Sean Callanan7d982502016-12-22 20:03:14 +0000311} // end namespace
312
313int main(int argc, const char **argv) {
314 const bool DisableCrashReporting = true;
315 llvm::sys::PrintStackTraceOnErrorSignal(argv[0], DisableCrashReporting);
316 llvm::cl::ParseCommandLineOptions(argc, argv);
317 std::vector<std::unique_ptr<CompilerInstance>> ImportCIs;
318 for (auto I : Imports) {
Lang Hames19e07e12017-06-20 21:06:00 +0000319 llvm::Expected<std::unique_ptr<CompilerInstance>> ImportCI =
Sean Callanan2b3a54b2017-08-07 22:27:30 +0000320 Parse(I, {}, false, false);
Sean Callanan7d982502016-12-22 20:03:14 +0000321 if (auto E = ImportCI.takeError()) {
322 llvm::errs() << llvm::toString(std::move(E));
323 exit(-1);
324 } else {
325 ImportCIs.push_back(std::move(*ImportCI));
326 }
327 }
Sean Callanan9092d472017-05-13 00:46:33 +0000328 std::vector<std::unique_ptr<CompilerInstance>> IndirectCIs;
329 if (!Direct) {
330 for (auto &ImportCI : ImportCIs) {
Sean Callanan6d565022017-07-11 00:27:57 +0000331 std::unique_ptr<CompilerInstance> IndirectCI = BuildIndirect(ImportCI);
332 IndirectCIs.push_back(std::move(IndirectCI));
Sean Callanan9092d472017-05-13 00:46:33 +0000333 }
334 }
Sean Callanan7d982502016-12-22 20:03:14 +0000335 llvm::Expected<std::unique_ptr<CompilerInstance>> ExpressionCI =
Sean Callanan2b3a54b2017-08-07 22:27:30 +0000336 Parse(Expression, Direct ? ImportCIs : IndirectCIs, DumpAST, DumpIR);
Sean Callanan7d982502016-12-22 20:03:14 +0000337 if (auto E = ExpressionCI.takeError()) {
338 llvm::errs() << llvm::toString(std::move(E));
339 exit(-1);
340 } else {
341 return 0;
342 }
343}
Sean Callanan9092d472017-05-13 00:46:33 +0000344