15 #include "clang/AST/RecursiveASTVisitor.h"
16 #include "clang/Basic/Diagnostic.h"
17 #include "clang/Frontend/CompilerInvocation.h"
18 #include "llvm/ADT/ScopeExit.h"
19 #include "llvm/Support/ScopedPrinter.h"
20 #include "llvm/Support/raw_ostream.h"
29 ImportThunk =
testPath(
"import_thunk.h");
33 std::string ThunkContents =
"#import \"" + FullHeaderName +
"\"\n";
36 FS.Files[FullFilename] =
Code;
38 FS.Files[ImportThunk] = ThunkContents;
42 auto &Argv =
Inputs.CompileCommand.CommandLine;
45 Argv = {
"clang",
"-Xclang",
"-undef"};
49 Argv.push_back(
"-include");
54 Inputs.CompileCommand.CommandLine.push_back(
"-fno-ms-compatibility");
59 Argv.push_back(FullFilename);
62 Mangler.adjust(
Inputs.CompileCommand.CommandLine, FullFilename);
63 Inputs.CompileCommand.Filename = FullFilename;
67 FS.OverlayRealFileSystemForModules =
true;
77 llvm::SmallString<128> ModuleCachePath;
78 if (llvm::sys::fs::createUniqueDirectory(
"module-cache", ModuleCachePath)) {
79 llvm::errs() <<
"Failed to create temp directory for module-cache";
82 CI.getHeaderSearchOpts().ModuleCachePath = ModuleCachePath.c_str();
86 if (!ModuleCachePath.empty()) {
87 if (llvm::sys::fs::remove_directories(ModuleCachePath)) {
88 llvm::errs() <<
"Failed to delete temp directory for module-cache";
94 std::shared_ptr<const PreambleData>
100 assert(
CI &&
"Failed to build compilation invocation.");
103 auto ModuleCacheDeleter = llvm::make_scope_exit(
106 true, PreambleCallback);
115 assert(
CI &&
"Failed to build compilation invocation.");
118 auto ModuleCacheDeleter = llvm::make_scope_exit(
126 if (!AST.hasValue()) {
127 llvm::errs() <<
"Failed to build code:\n" <<
Code;
130 assert(AST->getDiagnostics() &&
131 "TestTU should always build an AST with a fresh Preamble");
136 bool ErrorOk = [&,
this] {
137 llvm::StringLiteral Marker =
"error-ok";
142 if (llvm::StringRef(KV.second).contains(Marker))
148 for (
const auto &
D : *AST->getDiagnostics())
151 <<
"TestTU failed to build (suppress with /*error-ok*/): \n"
152 <<
D <<
"\n\nFor code:\n"
157 return std::move(*AST);
163 AST.getPreprocessor(),
164 AST.getCanonicalIncludes()));
174 auto Idx = std::make_unique<FileIndex>();
176 AST.getASTContext(), AST.getPreprocessor(),
177 AST.getCanonicalIncludes());
179 return std::move(Idx);
183 const Symbol *Result =
nullptr;
184 for (
const Symbol &S : Slab) {
185 if (QName != (S.Scope + S.Name).str())
188 llvm::errs() <<
"Multiple symbols named " << QName <<
":\n"
189 << *Result <<
"\n---\n"
191 assert(
false &&
"QName is not unique");
196 llvm::errs() <<
"No symbol named " << QName <<
" in "
197 << llvm::to_string(Slab);
198 assert(
false &&
"No symbol with QName");
206 std::vector<Decl *> ScopeToRestore;
210 : Ctx(AST.getASTContext()), ScopeToRestore(Ctx.getTraversalScope()) {
211 Ctx.setTraversalScope({Ctx.getTranslationUnitDecl()});
218 auto LookupDecl = [&
Ctx](
const DeclContext &Scope,
219 llvm::StringRef
Name) ->
const NamedDecl & {
220 auto LookupRes = Scope.lookup(DeclarationName(&
Ctx.Idents.
get(
Name)));
221 assert(!LookupRes.empty() &&
"Lookup failed");
222 assert(LookupRes.isSingleResult() &&
"Lookup returned multiple results");
223 return *LookupRes.front();
226 const DeclContext *Scope =
Ctx.getTranslationUnitDecl();
229 for (std::tie(Cur, Rest) = QName.split(
"::"); !Rest.empty();
230 std::tie(Cur, Rest) = Rest.split(
"::")) {
231 Scope = &cast<DeclContext>(LookupDecl(*Scope, Cur));
233 return LookupDecl(*Scope, Cur);
237 std::function<
bool(
const NamedDecl &)> Filter) {
241 llvm::SmallVector<const NamedDecl *, 1> Decls;
242 bool VisitNamedDecl(
const NamedDecl *ND) {
249 Visitor.TraverseDecl(AST.
getASTContext().getTranslationUnitDecl());
250 if (Visitor.Decls.size() != 1) {
251 llvm::errs() << Visitor.Decls.size() <<
" symbols matched.\n";
252 assert(Visitor.Decls.size() == 1);
254 return *Visitor.Decls.front();
259 if (
auto *
ID = ND.getIdentifier())