blob: 286cb05219c75e1b0fb453fe01733e367ba2c978 [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"
30#include "llvm/Support/CommandLine.h"
31#include "llvm/Support/Error.h"
32#include "llvm/Support/Host.h"
33#include "llvm/Support/Signals.h"
34
35#include <memory>
36#include <string>
37
38using namespace clang;
39
40static llvm::cl::opt<std::string> Expression(
41 "expression", llvm::cl::Required,
42 llvm::cl::desc("Path to a file containing the expression to parse"));
43
44static llvm::cl::list<std::string>
45 Imports("import", llvm::cl::ZeroOrMore,
46 llvm::cl::desc("Path to a file containing declarations to import"));
47
Sean Callanan9092d472017-05-13 00:46:33 +000048static llvm::cl::opt<bool>
49 Direct("direct", llvm::cl::Optional,
50 llvm::cl::desc("Use the parsed declarations without indirection"));
51
Sean Callanan7d982502016-12-22 20:03:14 +000052static llvm::cl::list<std::string>
53 ClangArgs("Xcc", llvm::cl::ZeroOrMore,
54 llvm::cl::desc("Argument to pass to the CompilerInvocation"),
55 llvm::cl::CommaSeparated);
56
Sean Callanan1eac8792017-07-25 19:54:22 +000057static llvm::cl::opt<std::string>
58 Input("x", llvm::cl::Optional,
59 llvm::cl::desc("The language to parse (default: c++)"),
60 llvm::cl::init("c++"));
61
Lang Hames19e07e12017-06-20 21:06:00 +000062static llvm::cl::opt<bool>
63DumpAST("dump-ast", llvm::cl::init(false),
64 llvm::cl::desc("Dump combined AST"));
65
Sean Callanan7d982502016-12-22 20:03:14 +000066namespace init_convenience {
67class TestDiagnosticConsumer : public DiagnosticConsumer {
68private:
69 std::unique_ptr<TextDiagnosticBuffer> Passthrough;
70 const LangOptions *LangOpts = nullptr;
71
72public:
73 TestDiagnosticConsumer()
74 : Passthrough(llvm::make_unique<TextDiagnosticBuffer>()) {}
75
76 virtual void BeginSourceFile(const LangOptions &LangOpts,
77 const Preprocessor *PP = nullptr) override {
78 this->LangOpts = &LangOpts;
79 return Passthrough->BeginSourceFile(LangOpts, PP);
80 }
81
82 virtual void EndSourceFile() override {
83 this->LangOpts = nullptr;
84 Passthrough->EndSourceFile();
85 }
86
87 virtual bool IncludeInDiagnosticCounts() const override {
88 return Passthrough->IncludeInDiagnosticCounts();
89 }
90
91private:
92 static void PrintSourceForLocation(const SourceLocation &Loc,
93 SourceManager &SM) {
94 const char *LocData = SM.getCharacterData(Loc, /*Invalid=*/nullptr);
95 unsigned LocColumn =
96 SM.getSpellingColumnNumber(Loc, /*Invalid=*/nullptr) - 1;
97 FileID FID = SM.getFileID(Loc);
98 llvm::MemoryBuffer *Buffer = SM.getBuffer(FID, Loc, /*Invalid=*/nullptr);
99
100 assert(LocData >= Buffer->getBufferStart() &&
101 LocData < Buffer->getBufferEnd());
102
103 const char *LineBegin = LocData - LocColumn;
104
105 assert(LineBegin >= Buffer->getBufferStart());
106
107 const char *LineEnd = nullptr;
108
109 for (LineEnd = LineBegin; *LineEnd != '\n' && *LineEnd != '\r' &&
110 LineEnd < Buffer->getBufferEnd();
111 ++LineEnd)
112 ;
113
114 llvm::StringRef LineString(LineBegin, LineEnd - LineBegin);
115
116 llvm::errs() << LineString << '\n';
117 llvm::errs().indent(LocColumn);
118 llvm::errs() << '^';
Sean Callanan1eac8792017-07-25 19:54:22 +0000119 llvm::errs() << '\n';
Sean Callanan7d982502016-12-22 20:03:14 +0000120 }
121
122 virtual void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
123 const Diagnostic &Info) override {
124 if (Info.hasSourceManager() && LangOpts) {
125 SourceManager &SM = Info.getSourceManager();
126
127 if (Info.getLocation().isValid()) {
128 Info.getLocation().print(llvm::errs(), SM);
129 llvm::errs() << ": ";
130 }
131
132 SmallString<16> DiagText;
133 Info.FormatDiagnostic(DiagText);
134 llvm::errs() << DiagText << '\n';
135
136 if (Info.getLocation().isValid()) {
137 PrintSourceForLocation(Info.getLocation(), SM);
138 }
139
140 for (const CharSourceRange &Range : Info.getRanges()) {
141 bool Invalid = true;
142 StringRef Ref = Lexer::getSourceText(Range, SM, *LangOpts, &Invalid);
143 if (!Invalid) {
144 llvm::errs() << Ref << '\n';
145 }
146 }
147 }
148 DiagnosticConsumer::HandleDiagnostic(DiagLevel, Info);
149 }
150};
151
152std::unique_ptr<CompilerInstance>
Sean Callanan1eac8792017-07-25 19:54:22 +0000153BuildCompilerInstance() {
Sean Callanan7d982502016-12-22 20:03:14 +0000154 auto Ins = llvm::make_unique<CompilerInstance>();
155 auto DC = llvm::make_unique<TestDiagnosticConsumer>();
156 const bool ShouldOwnClient = true;
157 Ins->createDiagnostics(DC.release(), ShouldOwnClient);
158
159 auto Inv = llvm::make_unique<CompilerInvocation>();
160
Sean Callanan1eac8792017-07-25 19:54:22 +0000161 std::vector<const char *> ClangArgv(ClangArgs.size());
162 std::transform(ClangArgs.begin(), ClangArgs.end(), ClangArgv.begin(),
163 [](const std::string &s) -> const char * { return s.data(); });
Sean Callanan7d982502016-12-22 20:03:14 +0000164 CompilerInvocation::CreateFromArgs(*Inv, ClangArgv.data(),
165 &ClangArgv.data()[ClangArgv.size()],
166 Ins->getDiagnostics());
167
Sean Callanan1eac8792017-07-25 19:54:22 +0000168 {
169 using namespace driver::types;
170 ID Id = lookupTypeForTypeSpecifier(Input.c_str());
171 assert(Id != TY_INVALID);
172 if (isCXX(Id)) {
173 Inv->getLangOpts()->CPlusPlus = true;
174 Inv->getLangOpts()->CPlusPlus11 = true;
175 Inv->getHeaderSearchOpts().UseLibcxx = true;
176 }
177 if (isObjC(Id)) {
178 Inv->getLangOpts()->ObjC1 = 1;
179 Inv->getLangOpts()->ObjC2 = 1;
180 }
181 }
Sean Callanan7d982502016-12-22 20:03:14 +0000182 Inv->getLangOpts()->Bool = true;
183 Inv->getLangOpts()->WChar = true;
184 Inv->getLangOpts()->Blocks = true;
185 Inv->getLangOpts()->DebuggerSupport = true;
186 Inv->getLangOpts()->SpellChecking = false;
187 Inv->getLangOpts()->ThreadsafeStatics = false;
188 Inv->getLangOpts()->AccessControl = false;
189 Inv->getLangOpts()->DollarIdents = true;
190 Inv->getCodeGenOpts().setDebugInfo(codegenoptions::FullDebugInfo);
191 Inv->getTargetOpts().Triple = llvm::sys::getDefaultTargetTriple();
192
David Blaikieea4395e2017-01-06 19:49:01 +0000193 Ins->setInvocation(std::move(Inv));
Sean Callanan7d982502016-12-22 20:03:14 +0000194
195 TargetInfo *TI = TargetInfo::CreateTargetInfo(
196 Ins->getDiagnostics(), Ins->getInvocation().TargetOpts);
197 Ins->setTarget(TI);
198 Ins->getTarget().adjust(Ins->getLangOpts());
199 Ins->createFileManager();
200 Ins->createSourceManager(Ins->getFileManager());
201 Ins->createPreprocessor(TU_Complete);
202
203 return Ins;
204}
205
206std::unique_ptr<ASTContext>
207BuildASTContext(CompilerInstance &CI, SelectorTable &ST, Builtin::Context &BC) {
208 auto AST = llvm::make_unique<ASTContext>(
209 CI.getLangOpts(), CI.getSourceManager(),
210 CI.getPreprocessor().getIdentifierTable(), ST, BC);
211 AST->InitBuiltinTypes(CI.getTarget());
212 return AST;
213}
214
215std::unique_ptr<CodeGenerator> BuildCodeGen(CompilerInstance &CI,
216 llvm::LLVMContext &LLVMCtx) {
217 StringRef ModuleName("$__module");
218 return std::unique_ptr<CodeGenerator>(CreateLLVMCodeGen(
219 CI.getDiagnostics(), ModuleName, CI.getHeaderSearchOpts(),
220 CI.getPreprocessorOpts(), CI.getCodeGenOpts(), LLVMCtx));
221}
222} // end namespace
223
224namespace {
Sean Callananb7160ca2017-04-11 19:33:35 +0000225
Sean Callanan7d982502016-12-22 20:03:14 +0000226void AddExternalSource(
227 CompilerInstance &CI,
228 llvm::ArrayRef<std::unique_ptr<CompilerInstance>> Imports) {
Sean Callananb7160ca2017-04-11 19:33:35 +0000229 ExternalASTMerger::ImporterEndpoint Target({CI.getASTContext(), CI.getFileManager()});
230 llvm::SmallVector<ExternalASTMerger::ImporterEndpoint, 3> Sources;
231 for (const std::unique_ptr<CompilerInstance> &CI : Imports) {
232 Sources.push_back({CI->getASTContext(), CI->getFileManager()});
233 }
234 auto ES = llvm::make_unique<ExternalASTMerger>(Target, Sources);
235 CI.getASTContext().setExternalSource(ES.release());
236 CI.getASTContext().getTranslationUnitDecl()->setHasExternalVisibleStorage();
Sean Callanan7d982502016-12-22 20:03:14 +0000237}
238
Sean Callanan9092d472017-05-13 00:46:33 +0000239std::unique_ptr<CompilerInstance> BuildIndirect(std::unique_ptr<CompilerInstance> &CI) {
Sean Callanan9092d472017-05-13 00:46:33 +0000240 std::unique_ptr<CompilerInstance> IndirectCI =
Sean Callanan1eac8792017-07-25 19:54:22 +0000241 init_convenience::BuildCompilerInstance();
Sean Callanan9092d472017-05-13 00:46:33 +0000242 auto ST = llvm::make_unique<SelectorTable>();
243 auto BC = llvm::make_unique<Builtin::Context>();
244 std::unique_ptr<ASTContext> AST =
245 init_convenience::BuildASTContext(*IndirectCI, *ST, *BC);
246 IndirectCI->setASTContext(AST.release());
247 AddExternalSource(*IndirectCI, CI);
248 return IndirectCI;
249}
250
Sean Callanan7d982502016-12-22 20:03:14 +0000251llvm::Error ParseSource(const std::string &Path, CompilerInstance &CI,
Lang Hames19e07e12017-06-20 21:06:00 +0000252 ASTConsumer &Consumer) {
Sean Callanan7d982502016-12-22 20:03:14 +0000253 SourceManager &SM = CI.getSourceManager();
254 const FileEntry *FE = CI.getFileManager().getFile(Path);
255 if (!FE) {
256 return llvm::make_error<llvm::StringError>(
257 llvm::Twine("Couldn't open ", Path), std::error_code());
258 }
259 SM.setMainFileID(SM.createFileID(FE, SourceLocation(), SrcMgr::C_User));
Lang Hames19e07e12017-06-20 21:06:00 +0000260 ParseAST(CI.getPreprocessor(), &Consumer, CI.getASTContext());
Sean Callanan7d982502016-12-22 20:03:14 +0000261 return llvm::Error::success();
262}
263
264llvm::Expected<std::unique_ptr<CompilerInstance>>
265Parse(const std::string &Path,
Lang Hames19e07e12017-06-20 21:06:00 +0000266 llvm::ArrayRef<std::unique_ptr<CompilerInstance>> Imports,
267 bool ShouldDumpAST) {
Sean Callanan7d982502016-12-22 20:03:14 +0000268 std::unique_ptr<CompilerInstance> CI =
Sean Callanan1eac8792017-07-25 19:54:22 +0000269 init_convenience::BuildCompilerInstance();
Sean Callanan7d982502016-12-22 20:03:14 +0000270 auto ST = llvm::make_unique<SelectorTable>();
271 auto BC = llvm::make_unique<Builtin::Context>();
272 std::unique_ptr<ASTContext> AST =
273 init_convenience::BuildASTContext(*CI, *ST, *BC);
274 CI->setASTContext(AST.release());
Sean Callanan9092d472017-05-13 00:46:33 +0000275 if (Imports.size())
276 AddExternalSource(*CI, Imports);
Sean Callanan7d982502016-12-22 20:03:14 +0000277
Lang Hames19e07e12017-06-20 21:06:00 +0000278 std::vector<std::unique_ptr<ASTConsumer>> ASTConsumers;
279
Sean Callanan7d982502016-12-22 20:03:14 +0000280 auto LLVMCtx = llvm::make_unique<llvm::LLVMContext>();
Lang Hames19e07e12017-06-20 21:06:00 +0000281 ASTConsumers.push_back(init_convenience::BuildCodeGen(*CI, *LLVMCtx));
282
283 if (ShouldDumpAST)
284 ASTConsumers.push_back(CreateASTDumper("", true, false, false));
Sean Callanan7d982502016-12-22 20:03:14 +0000285
286 CI->getDiagnosticClient().BeginSourceFile(CI->getLangOpts(),
287 &CI->getPreprocessor());
Lang Hames19e07e12017-06-20 21:06:00 +0000288 MultiplexConsumer Consumers(std::move(ASTConsumers));
289 Consumers.Initialize(CI->getASTContext());
290
291 if (llvm::Error PE = ParseSource(Path, *CI, Consumers)) {
Sean Callanan7d982502016-12-22 20:03:14 +0000292 return std::move(PE);
293 }
294 CI->getDiagnosticClient().EndSourceFile();
295 if (CI->getDiagnosticClient().getNumErrors()) {
296 return llvm::make_error<llvm::StringError>(
297 "Errors occured while parsing the expression.", std::error_code());
298 } else {
299 return std::move(CI);
300 }
301}
Sean Callananb7160ca2017-04-11 19:33:35 +0000302
Sean Callanan7d982502016-12-22 20:03:14 +0000303} // end namespace
304
305int main(int argc, const char **argv) {
306 const bool DisableCrashReporting = true;
307 llvm::sys::PrintStackTraceOnErrorSignal(argv[0], DisableCrashReporting);
308 llvm::cl::ParseCommandLineOptions(argc, argv);
309 std::vector<std::unique_ptr<CompilerInstance>> ImportCIs;
310 for (auto I : Imports) {
Lang Hames19e07e12017-06-20 21:06:00 +0000311 llvm::Expected<std::unique_ptr<CompilerInstance>> ImportCI =
312 Parse(I, {}, false);
Sean Callanan7d982502016-12-22 20:03:14 +0000313 if (auto E = ImportCI.takeError()) {
314 llvm::errs() << llvm::toString(std::move(E));
315 exit(-1);
316 } else {
317 ImportCIs.push_back(std::move(*ImportCI));
318 }
319 }
Sean Callanan9092d472017-05-13 00:46:33 +0000320 std::vector<std::unique_ptr<CompilerInstance>> IndirectCIs;
321 if (!Direct) {
322 for (auto &ImportCI : ImportCIs) {
Sean Callanan6d565022017-07-11 00:27:57 +0000323 std::unique_ptr<CompilerInstance> IndirectCI = BuildIndirect(ImportCI);
324 IndirectCIs.push_back(std::move(IndirectCI));
Sean Callanan9092d472017-05-13 00:46:33 +0000325 }
326 }
Sean Callanan7d982502016-12-22 20:03:14 +0000327 llvm::Expected<std::unique_ptr<CompilerInstance>> ExpressionCI =
Lang Hames19e07e12017-06-20 21:06:00 +0000328 Parse(Expression, Direct ? ImportCIs : IndirectCIs, DumpAST);
Sean Callanan7d982502016-12-22 20:03:14 +0000329 if (auto E = ExpressionCI.takeError()) {
330 llvm::errs() << llvm::toString(std::move(E));
331 exit(-1);
332 } else {
333 return 0;
334 }
335}
Sean Callanan9092d472017-05-13 00:46:33 +0000336