blob: db4dc76eded54b10272f9093121dba0270566da7 [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"
Lang Hames19e07e12017-06-20 21:06:00 +000020#include "clang/Frontend/ASTConsumers.h"
Sean Callanan7d982502016-12-22 20:03:14 +000021#include "clang/Frontend/CompilerInstance.h"
Lang Hames19e07e12017-06-20 21:06:00 +000022#include "clang/Frontend/MultiplexConsumer.h"
Sean Callanan7d982502016-12-22 20:03:14 +000023#include "clang/Frontend/TextDiagnosticBuffer.h"
24#include "clang/Lex/Lexer.h"
25#include "clang/Lex/Preprocessor.h"
26#include "clang/Parse/ParseAST.h"
27
28#include "llvm/IR/LLVMContext.h"
29#include "llvm/Support/CommandLine.h"
30#include "llvm/Support/Error.h"
31#include "llvm/Support/Host.h"
32#include "llvm/Support/Signals.h"
33
34#include <memory>
35#include <string>
36
37using namespace clang;
38
39static llvm::cl::opt<std::string> Expression(
40 "expression", llvm::cl::Required,
41 llvm::cl::desc("Path to a file containing the expression to parse"));
42
43static llvm::cl::list<std::string>
44 Imports("import", llvm::cl::ZeroOrMore,
45 llvm::cl::desc("Path to a file containing declarations to import"));
46
Sean Callanan9092d472017-05-13 00:46:33 +000047static llvm::cl::opt<bool>
48 Direct("direct", llvm::cl::Optional,
49 llvm::cl::desc("Use the parsed declarations without indirection"));
50
Sean Callanan7d982502016-12-22 20:03:14 +000051static llvm::cl::list<std::string>
52 ClangArgs("Xcc", llvm::cl::ZeroOrMore,
53 llvm::cl::desc("Argument to pass to the CompilerInvocation"),
54 llvm::cl::CommaSeparated);
55
Lang Hames19e07e12017-06-20 21:06:00 +000056static llvm::cl::opt<bool>
57DumpAST("dump-ast", llvm::cl::init(false),
58 llvm::cl::desc("Dump combined AST"));
59
Sean Callanan7d982502016-12-22 20:03:14 +000060namespace init_convenience {
61class TestDiagnosticConsumer : public DiagnosticConsumer {
62private:
63 std::unique_ptr<TextDiagnosticBuffer> Passthrough;
64 const LangOptions *LangOpts = nullptr;
65
66public:
67 TestDiagnosticConsumer()
68 : Passthrough(llvm::make_unique<TextDiagnosticBuffer>()) {}
69
70 virtual void BeginSourceFile(const LangOptions &LangOpts,
71 const Preprocessor *PP = nullptr) override {
72 this->LangOpts = &LangOpts;
73 return Passthrough->BeginSourceFile(LangOpts, PP);
74 }
75
76 virtual void EndSourceFile() override {
77 this->LangOpts = nullptr;
78 Passthrough->EndSourceFile();
79 }
80
81 virtual bool IncludeInDiagnosticCounts() const override {
82 return Passthrough->IncludeInDiagnosticCounts();
83 }
84
85private:
86 static void PrintSourceForLocation(const SourceLocation &Loc,
87 SourceManager &SM) {
88 const char *LocData = SM.getCharacterData(Loc, /*Invalid=*/nullptr);
89 unsigned LocColumn =
90 SM.getSpellingColumnNumber(Loc, /*Invalid=*/nullptr) - 1;
91 FileID FID = SM.getFileID(Loc);
92 llvm::MemoryBuffer *Buffer = SM.getBuffer(FID, Loc, /*Invalid=*/nullptr);
93
94 assert(LocData >= Buffer->getBufferStart() &&
95 LocData < Buffer->getBufferEnd());
96
97 const char *LineBegin = LocData - LocColumn;
98
99 assert(LineBegin >= Buffer->getBufferStart());
100
101 const char *LineEnd = nullptr;
102
103 for (LineEnd = LineBegin; *LineEnd != '\n' && *LineEnd != '\r' &&
104 LineEnd < Buffer->getBufferEnd();
105 ++LineEnd)
106 ;
107
108 llvm::StringRef LineString(LineBegin, LineEnd - LineBegin);
109
110 llvm::errs() << LineString << '\n';
111 llvm::errs().indent(LocColumn);
112 llvm::errs() << '^';
113 }
114
115 virtual void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
116 const Diagnostic &Info) override {
117 if (Info.hasSourceManager() && LangOpts) {
118 SourceManager &SM = Info.getSourceManager();
119
120 if (Info.getLocation().isValid()) {
121 Info.getLocation().print(llvm::errs(), SM);
122 llvm::errs() << ": ";
123 }
124
125 SmallString<16> DiagText;
126 Info.FormatDiagnostic(DiagText);
127 llvm::errs() << DiagText << '\n';
128
129 if (Info.getLocation().isValid()) {
130 PrintSourceForLocation(Info.getLocation(), SM);
131 }
132
133 for (const CharSourceRange &Range : Info.getRanges()) {
134 bool Invalid = true;
135 StringRef Ref = Lexer::getSourceText(Range, SM, *LangOpts, &Invalid);
136 if (!Invalid) {
137 llvm::errs() << Ref << '\n';
138 }
139 }
140 }
141 DiagnosticConsumer::HandleDiagnostic(DiagLevel, Info);
142 }
143};
144
145std::unique_ptr<CompilerInstance>
146BuildCompilerInstance(ArrayRef<const char *> ClangArgv) {
147 auto Ins = llvm::make_unique<CompilerInstance>();
148 auto DC = llvm::make_unique<TestDiagnosticConsumer>();
149 const bool ShouldOwnClient = true;
150 Ins->createDiagnostics(DC.release(), ShouldOwnClient);
151
152 auto Inv = llvm::make_unique<CompilerInvocation>();
153
154 CompilerInvocation::CreateFromArgs(*Inv, ClangArgv.data(),
155 &ClangArgv.data()[ClangArgv.size()],
156 Ins->getDiagnostics());
157
158 Inv->getLangOpts()->CPlusPlus = true;
159 Inv->getLangOpts()->CPlusPlus11 = true;
160 Inv->getHeaderSearchOpts().UseLibcxx = true;
161 Inv->getLangOpts()->Bool = true;
162 Inv->getLangOpts()->WChar = true;
163 Inv->getLangOpts()->Blocks = true;
164 Inv->getLangOpts()->DebuggerSupport = true;
165 Inv->getLangOpts()->SpellChecking = false;
166 Inv->getLangOpts()->ThreadsafeStatics = false;
167 Inv->getLangOpts()->AccessControl = false;
168 Inv->getLangOpts()->DollarIdents = true;
169 Inv->getCodeGenOpts().setDebugInfo(codegenoptions::FullDebugInfo);
170 Inv->getTargetOpts().Triple = llvm::sys::getDefaultTargetTriple();
171
David Blaikieea4395e2017-01-06 19:49:01 +0000172 Ins->setInvocation(std::move(Inv));
Sean Callanan7d982502016-12-22 20:03:14 +0000173
174 TargetInfo *TI = TargetInfo::CreateTargetInfo(
175 Ins->getDiagnostics(), Ins->getInvocation().TargetOpts);
176 Ins->setTarget(TI);
177 Ins->getTarget().adjust(Ins->getLangOpts());
178 Ins->createFileManager();
179 Ins->createSourceManager(Ins->getFileManager());
180 Ins->createPreprocessor(TU_Complete);
181
182 return Ins;
183}
184
Sean Callanan9092d472017-05-13 00:46:33 +0000185std::unique_ptr<CompilerInstance>
186BuildCompilerInstance(ArrayRef<std::string> ClangArgs) {
187 std::vector<const char *> ClangArgv(ClangArgs.size());
188 std::transform(ClangArgs.begin(), ClangArgs.end(), ClangArgv.begin(),
189 [](const std::string &s) -> const char * { return s.data(); });
190 return init_convenience::BuildCompilerInstance(ClangArgv);
191}
192
Sean Callanan7d982502016-12-22 20:03:14 +0000193std::unique_ptr<ASTContext>
194BuildASTContext(CompilerInstance &CI, SelectorTable &ST, Builtin::Context &BC) {
195 auto AST = llvm::make_unique<ASTContext>(
196 CI.getLangOpts(), CI.getSourceManager(),
197 CI.getPreprocessor().getIdentifierTable(), ST, BC);
198 AST->InitBuiltinTypes(CI.getTarget());
199 return AST;
200}
201
202std::unique_ptr<CodeGenerator> BuildCodeGen(CompilerInstance &CI,
203 llvm::LLVMContext &LLVMCtx) {
204 StringRef ModuleName("$__module");
205 return std::unique_ptr<CodeGenerator>(CreateLLVMCodeGen(
206 CI.getDiagnostics(), ModuleName, CI.getHeaderSearchOpts(),
207 CI.getPreprocessorOpts(), CI.getCodeGenOpts(), LLVMCtx));
208}
209} // end namespace
210
211namespace {
Sean Callananb7160ca2017-04-11 19:33:35 +0000212
Sean Callanan7d982502016-12-22 20:03:14 +0000213void AddExternalSource(
214 CompilerInstance &CI,
215 llvm::ArrayRef<std::unique_ptr<CompilerInstance>> Imports) {
Sean Callananb7160ca2017-04-11 19:33:35 +0000216 ExternalASTMerger::ImporterEndpoint Target({CI.getASTContext(), CI.getFileManager()});
217 llvm::SmallVector<ExternalASTMerger::ImporterEndpoint, 3> Sources;
218 for (const std::unique_ptr<CompilerInstance> &CI : Imports) {
219 Sources.push_back({CI->getASTContext(), CI->getFileManager()});
220 }
221 auto ES = llvm::make_unique<ExternalASTMerger>(Target, Sources);
222 CI.getASTContext().setExternalSource(ES.release());
223 CI.getASTContext().getTranslationUnitDecl()->setHasExternalVisibleStorage();
Sean Callanan7d982502016-12-22 20:03:14 +0000224}
225
Sean Callanan9092d472017-05-13 00:46:33 +0000226std::unique_ptr<CompilerInstance> BuildIndirect(std::unique_ptr<CompilerInstance> &CI) {
227 std::vector<const char *> ClangArgv(ClangArgs.size());
228 std::transform(ClangArgs.begin(), ClangArgs.end(), ClangArgv.begin(),
229 [](const std::string &s) -> const char * { return s.data(); });
230 std::unique_ptr<CompilerInstance> IndirectCI =
231 init_convenience::BuildCompilerInstance(ClangArgv);
232 auto ST = llvm::make_unique<SelectorTable>();
233 auto BC = llvm::make_unique<Builtin::Context>();
234 std::unique_ptr<ASTContext> AST =
235 init_convenience::BuildASTContext(*IndirectCI, *ST, *BC);
236 IndirectCI->setASTContext(AST.release());
237 AddExternalSource(*IndirectCI, CI);
238 return IndirectCI;
239}
240
Sean Callanan7d982502016-12-22 20:03:14 +0000241llvm::Error ParseSource(const std::string &Path, CompilerInstance &CI,
Lang Hames19e07e12017-06-20 21:06:00 +0000242 ASTConsumer &Consumer) {
Sean Callanan7d982502016-12-22 20:03:14 +0000243 SourceManager &SM = CI.getSourceManager();
244 const FileEntry *FE = CI.getFileManager().getFile(Path);
245 if (!FE) {
246 return llvm::make_error<llvm::StringError>(
247 llvm::Twine("Couldn't open ", Path), std::error_code());
248 }
249 SM.setMainFileID(SM.createFileID(FE, SourceLocation(), SrcMgr::C_User));
Lang Hames19e07e12017-06-20 21:06:00 +0000250 ParseAST(CI.getPreprocessor(), &Consumer, CI.getASTContext());
Sean Callanan7d982502016-12-22 20:03:14 +0000251 return llvm::Error::success();
252}
253
254llvm::Expected<std::unique_ptr<CompilerInstance>>
255Parse(const std::string &Path,
Lang Hames19e07e12017-06-20 21:06:00 +0000256 llvm::ArrayRef<std::unique_ptr<CompilerInstance>> Imports,
257 bool ShouldDumpAST) {
Sean Callanan7d982502016-12-22 20:03:14 +0000258 std::vector<const char *> ClangArgv(ClangArgs.size());
259 std::transform(ClangArgs.begin(), ClangArgs.end(), ClangArgv.begin(),
260 [](const std::string &s) -> const char * { return s.data(); });
261 std::unique_ptr<CompilerInstance> CI =
262 init_convenience::BuildCompilerInstance(ClangArgv);
263 auto ST = llvm::make_unique<SelectorTable>();
264 auto BC = llvm::make_unique<Builtin::Context>();
265 std::unique_ptr<ASTContext> AST =
266 init_convenience::BuildASTContext(*CI, *ST, *BC);
267 CI->setASTContext(AST.release());
Sean Callanan9092d472017-05-13 00:46:33 +0000268 if (Imports.size())
269 AddExternalSource(*CI, Imports);
Sean Callanan7d982502016-12-22 20:03:14 +0000270
Lang Hames19e07e12017-06-20 21:06:00 +0000271 std::vector<std::unique_ptr<ASTConsumer>> ASTConsumers;
272
Sean Callanan7d982502016-12-22 20:03:14 +0000273 auto LLVMCtx = llvm::make_unique<llvm::LLVMContext>();
Lang Hames19e07e12017-06-20 21:06:00 +0000274 ASTConsumers.push_back(init_convenience::BuildCodeGen(*CI, *LLVMCtx));
275
276 if (ShouldDumpAST)
277 ASTConsumers.push_back(CreateASTDumper("", true, false, false));
Sean Callanan7d982502016-12-22 20:03:14 +0000278
279 CI->getDiagnosticClient().BeginSourceFile(CI->getLangOpts(),
280 &CI->getPreprocessor());
Lang Hames19e07e12017-06-20 21:06:00 +0000281 MultiplexConsumer Consumers(std::move(ASTConsumers));
282 Consumers.Initialize(CI->getASTContext());
283
284 if (llvm::Error PE = ParseSource(Path, *CI, Consumers)) {
Sean Callanan7d982502016-12-22 20:03:14 +0000285 return std::move(PE);
286 }
287 CI->getDiagnosticClient().EndSourceFile();
288 if (CI->getDiagnosticClient().getNumErrors()) {
289 return llvm::make_error<llvm::StringError>(
290 "Errors occured while parsing the expression.", std::error_code());
291 } else {
292 return std::move(CI);
293 }
294}
Sean Callananb7160ca2017-04-11 19:33:35 +0000295
Sean Callanan7d982502016-12-22 20:03:14 +0000296} // end namespace
297
298int main(int argc, const char **argv) {
299 const bool DisableCrashReporting = true;
300 llvm::sys::PrintStackTraceOnErrorSignal(argv[0], DisableCrashReporting);
301 llvm::cl::ParseCommandLineOptions(argc, argv);
302 std::vector<std::unique_ptr<CompilerInstance>> ImportCIs;
303 for (auto I : Imports) {
Lang Hames19e07e12017-06-20 21:06:00 +0000304 llvm::Expected<std::unique_ptr<CompilerInstance>> ImportCI =
305 Parse(I, {}, false);
Sean Callanan7d982502016-12-22 20:03:14 +0000306 if (auto E = ImportCI.takeError()) {
307 llvm::errs() << llvm::toString(std::move(E));
308 exit(-1);
309 } else {
310 ImportCIs.push_back(std::move(*ImportCI));
311 }
312 }
Sean Callanan9092d472017-05-13 00:46:33 +0000313 std::vector<std::unique_ptr<CompilerInstance>> IndirectCIs;
314 if (!Direct) {
315 for (auto &ImportCI : ImportCIs) {
316 llvm::Expected<std::unique_ptr<CompilerInstance>> IndirectCI =
317 BuildIndirect(ImportCI);
318 if (auto E = IndirectCI.takeError()) {
319 llvm::errs() << llvm::toString(std::move(E));
320 exit(-1);
321 } else {
322 IndirectCIs.push_back(std::move(*IndirectCI));
323 }
324 }
325 }
Sean Callanan7d982502016-12-22 20:03:14 +0000326 llvm::Expected<std::unique_ptr<CompilerInstance>> ExpressionCI =
Lang Hames19e07e12017-06-20 21:06:00 +0000327 Parse(Expression, Direct ? ImportCIs : IndirectCIs, DumpAST);
Sean Callanan7d982502016-12-22 20:03:14 +0000328 if (auto E = ExpressionCI.takeError()) {
329 llvm::errs() << llvm::toString(std::move(E));
330 exit(-1);
331 } else {
332 return 0;
333 }
334}
Sean Callanan9092d472017-05-13 00:46:33 +0000335