blob: 6b724e9cf5faea2f8b9473a2ae1109999a35cad0 [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
185std::unique_ptr<ASTContext>
186BuildASTContext(CompilerInstance &CI, SelectorTable &ST, Builtin::Context &BC) {
187 auto AST = llvm::make_unique<ASTContext>(
188 CI.getLangOpts(), CI.getSourceManager(),
189 CI.getPreprocessor().getIdentifierTable(), ST, BC);
190 AST->InitBuiltinTypes(CI.getTarget());
191 return AST;
192}
193
194std::unique_ptr<CodeGenerator> BuildCodeGen(CompilerInstance &CI,
195 llvm::LLVMContext &LLVMCtx) {
196 StringRef ModuleName("$__module");
197 return std::unique_ptr<CodeGenerator>(CreateLLVMCodeGen(
198 CI.getDiagnostics(), ModuleName, CI.getHeaderSearchOpts(),
199 CI.getPreprocessorOpts(), CI.getCodeGenOpts(), LLVMCtx));
200}
201} // end namespace
202
203namespace {
Sean Callananb7160ca2017-04-11 19:33:35 +0000204
Sean Callanan7d982502016-12-22 20:03:14 +0000205void AddExternalSource(
206 CompilerInstance &CI,
207 llvm::ArrayRef<std::unique_ptr<CompilerInstance>> Imports) {
Sean Callananb7160ca2017-04-11 19:33:35 +0000208 ExternalASTMerger::ImporterEndpoint Target({CI.getASTContext(), CI.getFileManager()});
209 llvm::SmallVector<ExternalASTMerger::ImporterEndpoint, 3> Sources;
210 for (const std::unique_ptr<CompilerInstance> &CI : Imports) {
211 Sources.push_back({CI->getASTContext(), CI->getFileManager()});
212 }
213 auto ES = llvm::make_unique<ExternalASTMerger>(Target, Sources);
214 CI.getASTContext().setExternalSource(ES.release());
215 CI.getASTContext().getTranslationUnitDecl()->setHasExternalVisibleStorage();
Sean Callanan7d982502016-12-22 20:03:14 +0000216}
217
Sean Callanan9092d472017-05-13 00:46:33 +0000218std::unique_ptr<CompilerInstance> BuildIndirect(std::unique_ptr<CompilerInstance> &CI) {
219 std::vector<const char *> ClangArgv(ClangArgs.size());
220 std::transform(ClangArgs.begin(), ClangArgs.end(), ClangArgv.begin(),
221 [](const std::string &s) -> const char * { return s.data(); });
222 std::unique_ptr<CompilerInstance> IndirectCI =
223 init_convenience::BuildCompilerInstance(ClangArgv);
224 auto ST = llvm::make_unique<SelectorTable>();
225 auto BC = llvm::make_unique<Builtin::Context>();
226 std::unique_ptr<ASTContext> AST =
227 init_convenience::BuildASTContext(*IndirectCI, *ST, *BC);
228 IndirectCI->setASTContext(AST.release());
229 AddExternalSource(*IndirectCI, CI);
230 return IndirectCI;
231}
232
Sean Callanan7d982502016-12-22 20:03:14 +0000233llvm::Error ParseSource(const std::string &Path, CompilerInstance &CI,
Lang Hames19e07e12017-06-20 21:06:00 +0000234 ASTConsumer &Consumer) {
Sean Callanan7d982502016-12-22 20:03:14 +0000235 SourceManager &SM = CI.getSourceManager();
236 const FileEntry *FE = CI.getFileManager().getFile(Path);
237 if (!FE) {
238 return llvm::make_error<llvm::StringError>(
239 llvm::Twine("Couldn't open ", Path), std::error_code());
240 }
241 SM.setMainFileID(SM.createFileID(FE, SourceLocation(), SrcMgr::C_User));
Lang Hames19e07e12017-06-20 21:06:00 +0000242 ParseAST(CI.getPreprocessor(), &Consumer, CI.getASTContext());
Sean Callanan7d982502016-12-22 20:03:14 +0000243 return llvm::Error::success();
244}
245
246llvm::Expected<std::unique_ptr<CompilerInstance>>
247Parse(const std::string &Path,
Lang Hames19e07e12017-06-20 21:06:00 +0000248 llvm::ArrayRef<std::unique_ptr<CompilerInstance>> Imports,
249 bool ShouldDumpAST) {
Sean Callanan7d982502016-12-22 20:03:14 +0000250 std::vector<const char *> ClangArgv(ClangArgs.size());
251 std::transform(ClangArgs.begin(), ClangArgs.end(), ClangArgv.begin(),
252 [](const std::string &s) -> const char * { return s.data(); });
253 std::unique_ptr<CompilerInstance> CI =
254 init_convenience::BuildCompilerInstance(ClangArgv);
255 auto ST = llvm::make_unique<SelectorTable>();
256 auto BC = llvm::make_unique<Builtin::Context>();
257 std::unique_ptr<ASTContext> AST =
258 init_convenience::BuildASTContext(*CI, *ST, *BC);
259 CI->setASTContext(AST.release());
Sean Callanan9092d472017-05-13 00:46:33 +0000260 if (Imports.size())
261 AddExternalSource(*CI, Imports);
Sean Callanan7d982502016-12-22 20:03:14 +0000262
Lang Hames19e07e12017-06-20 21:06:00 +0000263 std::vector<std::unique_ptr<ASTConsumer>> ASTConsumers;
264
Sean Callanan7d982502016-12-22 20:03:14 +0000265 auto LLVMCtx = llvm::make_unique<llvm::LLVMContext>();
Lang Hames19e07e12017-06-20 21:06:00 +0000266 ASTConsumers.push_back(init_convenience::BuildCodeGen(*CI, *LLVMCtx));
267
268 if (ShouldDumpAST)
269 ASTConsumers.push_back(CreateASTDumper("", true, false, false));
Sean Callanan7d982502016-12-22 20:03:14 +0000270
271 CI->getDiagnosticClient().BeginSourceFile(CI->getLangOpts(),
272 &CI->getPreprocessor());
Lang Hames19e07e12017-06-20 21:06:00 +0000273 MultiplexConsumer Consumers(std::move(ASTConsumers));
274 Consumers.Initialize(CI->getASTContext());
275
276 if (llvm::Error PE = ParseSource(Path, *CI, Consumers)) {
Sean Callanan7d982502016-12-22 20:03:14 +0000277 return std::move(PE);
278 }
279 CI->getDiagnosticClient().EndSourceFile();
280 if (CI->getDiagnosticClient().getNumErrors()) {
281 return llvm::make_error<llvm::StringError>(
282 "Errors occured while parsing the expression.", std::error_code());
283 } else {
284 return std::move(CI);
285 }
286}
Sean Callananb7160ca2017-04-11 19:33:35 +0000287
Sean Callanan7d982502016-12-22 20:03:14 +0000288} // end namespace
289
290int main(int argc, const char **argv) {
291 const bool DisableCrashReporting = true;
292 llvm::sys::PrintStackTraceOnErrorSignal(argv[0], DisableCrashReporting);
293 llvm::cl::ParseCommandLineOptions(argc, argv);
294 std::vector<std::unique_ptr<CompilerInstance>> ImportCIs;
295 for (auto I : Imports) {
Lang Hames19e07e12017-06-20 21:06:00 +0000296 llvm::Expected<std::unique_ptr<CompilerInstance>> ImportCI =
297 Parse(I, {}, false);
Sean Callanan7d982502016-12-22 20:03:14 +0000298 if (auto E = ImportCI.takeError()) {
299 llvm::errs() << llvm::toString(std::move(E));
300 exit(-1);
301 } else {
302 ImportCIs.push_back(std::move(*ImportCI));
303 }
304 }
Sean Callanan9092d472017-05-13 00:46:33 +0000305 std::vector<std::unique_ptr<CompilerInstance>> IndirectCIs;
306 if (!Direct) {
307 for (auto &ImportCI : ImportCIs) {
Sean Callanan6d565022017-07-11 00:27:57 +0000308 std::unique_ptr<CompilerInstance> IndirectCI = BuildIndirect(ImportCI);
309 IndirectCIs.push_back(std::move(IndirectCI));
Sean Callanan9092d472017-05-13 00:46:33 +0000310 }
311 }
Sean Callanan7d982502016-12-22 20:03:14 +0000312 llvm::Expected<std::unique_ptr<CompilerInstance>> ExpressionCI =
Lang Hames19e07e12017-06-20 21:06:00 +0000313 Parse(Expression, Direct ? ImportCIs : IndirectCIs, DumpAST);
Sean Callanan7d982502016-12-22 20:03:14 +0000314 if (auto E = ExpressionCI.takeError()) {
315 llvm::errs() << llvm::toString(std::move(E));
316 exit(-1);
317 } else {
318 return 0;
319 }
320}
Sean Callanan9092d472017-05-13 00:46:33 +0000321