17#include "clang/AST/RecursiveASTVisitor.h"
18#include "clang/Basic/Diagnostic.h"
19#include "clang/Frontend/CompilerInvocation.h"
20#include "llvm/ADT/ScopeExit.h"
21#include "llvm/Support/ScopedPrinter.h"
22#include "llvm/Support/raw_ostream.h"
31 ImportThunk =
testPath(
"import_thunk.h");
35 std::string ThunkContents =
"#import \"" + FullHeaderName +
"\"\n";
40 FS.
Files[ImportThunk] = ThunkContents;
50 Argv.push_back(
"-Xclang");
51 Argv.push_back(
"-undef");
56 Argv.push_back(
"-include");
61 Inputs.
CompileCommand.CommandLine.push_back(
"-fno-ms-compatibility");
66 Argv.push_back(FullFilename);
82 llvm::SmallString<128> ModuleCachePath;
83 if (llvm::sys::fs::createUniqueDirectory(
"module-cache", ModuleCachePath)) {
84 llvm::errs() <<
"Failed to create temp directory for module-cache";
87 CI.getHeaderSearchOpts().ModuleCachePath = ModuleCachePath.c_str();
91 if (!ModuleCachePath.empty()) {
92 if (llvm::sys::fs::remove_directories(ModuleCachePath)) {
93 llvm::errs() <<
"Failed to delete temp directory for module-cache";
99std::shared_ptr<const PreambleData>
105 assert(CI &&
"Failed to build compilation invocation.");
108 llvm::scope_exit ModuleCacheDeleter(
111 true, PreambleCallback);
116 llvm::errs() <<
"Use either ClangTidyProvider or FeatureModules\n";
124 TidyModules.
add(std::make_unique<ClangTidyFeatureModule>(
128 Inputs.FeatureModules = &TidyModules;
132 assert(CI &&
"Failed to build compilation invocation.");
135 llvm::scope_exit ModuleCacheDeleter(
144 llvm::errs() <<
"Failed to build code:\n" <<
Code;
151 bool ErrorOk = [&,
this] {
152 llvm::StringLiteral Marker =
"error-ok";
153 if (llvm::StringRef(
Code).contains(Marker) ||
157 if (llvm::StringRef(KV.second).contains(Marker))
163 for (
const auto &D :
AST->getDiagnostics())
164 if (D.Severity >= DiagnosticsEngine::Error) {
166 <<
"TestTU failed to build (suppress with /*error-ok*/): \n"
167 << D <<
"\n\nFor code:\n"
172 return std::move(*
AST);
178 "null",
AST.getASTContext(),
AST.getPreprocessor(),
189 auto Idx = std::make_unique<FileIndex>(
true);
191 AST.getASTContext(),
AST.getPreprocessor(),
192 AST.getPragmaIncludes());
194 return std::move(Idx);
198 const Symbol *Result =
nullptr;
199 for (
const Symbol &S : Slab) {
200 if (QName != (S.Scope + S.Name).str())
203 llvm::errs() <<
"Multiple symbols named " << QName <<
":\n"
204 << *Result <<
"\n---\n"
206 assert(
false &&
"QName is not unique");
211 llvm::errs() <<
"No symbol named " << QName <<
" in "
212 << llvm::to_string(Slab);
213 assert(
false &&
"No symbol with QName");
221 std::vector<Decl *> ScopeToRestore;
225 : Ctx(
AST.getASTContext()), ScopeToRestore(Ctx.getTraversalScope()) {
226 Ctx.setTraversalScope({Ctx.getTranslationUnitDecl()});
232 auto &Ctx =
AST.getASTContext();
233 auto LookupDecl = [&Ctx](
const DeclContext &Scope,
234 llvm::StringRef Name) ->
const NamedDecl & {
235 auto LookupRes = Scope.lookup(DeclarationName(&Ctx.Idents.get(Name)));
236 assert(!LookupRes.empty() &&
"Lookup failed");
237 assert(LookupRes.isSingleResult() &&
"Lookup returned multiple results");
238 return *LookupRes.front();
241 const DeclContext *Scope = Ctx.getTranslationUnitDecl();
244 for (std::tie(Cur, Rest) = QName.split(
"::"); !Rest.empty();
245 std::tie(Cur, Rest) = Rest.split(
"::")) {
246 Scope = &cast<DeclContext>(LookupDecl(*Scope, Cur));
248 return LookupDecl(*Scope, Cur);
252 std::function<
bool(
const NamedDecl &)> Filter) {
254 struct Visitor : RecursiveASTVisitor<Visitor> {
256 llvm::SmallVector<const NamedDecl *, 1> Decls;
257 bool VisitNamedDecl(
const NamedDecl *ND) {
264 Visitor.TraverseDecl(
AST.getASTContext().getTranslationUnitDecl());
265 if (Visitor.Decls.size() != 1) {
266 llvm::errs() << Visitor.Decls.size() <<
" symbols matched.\n";
267 assert(Visitor.Decls.size() == 1);
269 return *Visitor.Decls.front();
274 if (
auto *ID = ND.getIdentifier())
275 if (ID->getName() == Name)
A FeatureModuleSet is a collection of feature modules installed in clangd.
void add(std::unique_ptr< FeatureModule > M)
llvm::StringMap< std::string > Files
bool OverlayRealFileSystemForModules
Stores and provides access to parsed AST.
static std::optional< ParsedAST > build(llvm::StringRef Filename, const ParseInputs &Inputs, std::unique_ptr< clang::CompilerInvocation > CI, llvm::ArrayRef< Diag > CompilerInvocationDiags, std::shared_ptr< const PreambleData > Preamble)
Attempts to run Clang and store the parsed AST.
An efficient structure of storing large set of symbol references in memory.
StoreDiags collects the diagnostics that can later be reported by clangd.
std::vector< Diag > take()
An immutable symbol container that stores a set of symbols.
FIXME: Skip testing on windows temporarily due to the different escaping code mode.
const NamedDecl & findDecl(ParsedAST &AST, llvm::StringRef QName)
std::unique_ptr< CompilerInvocation > buildCompilerInvocation(const ParseInputs &Inputs, clang::DiagnosticConsumer &D, std::vector< std::string > *CC1Args)
Builds compiler invocation that could be used to build AST or preamble.
SlabTuple indexMainDecls(ParsedAST &AST)
Retrieves symbols and refs of local top level decls in AST (i.e.
std::string testPath(PathRef File, llvm::sys::path::Style Style)
std::shared_ptr< const PreambleData > buildPreamble(PathRef FileName, CompilerInvocation CI, const ParseInputs &Inputs, bool StoreInMemory, PreambleParsedCallback PreambleCallback, PreambleBuildStats *Stats)
Build a preamble for the new inputs unless an old one can be reused.
SlabTuple indexHeaderSymbols(llvm::StringRef Version, ASTContext &AST, Preprocessor &PP, const include_cleaner::PragmaIncludes &PI, SymbolOrigin Origin)
Index declarations from AST and macros from PP that are declared in included headers.
const NamedDecl & findUnqualifiedDecl(ParsedAST &AST, llvm::StringRef Name)
void initializeModuleCache(CompilerInvocation &CI)
const Symbol & findSymbol(const SymbolSlab &Slab, llvm::StringRef QName)
void deleteModuleCache(const std::string ModuleCachePath)
std::function< void(CapturedASTCtx ASTCtx, std::shared_ptr< const include_cleaner::PragmaIncludes >)> PreambleParsedCallback
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
static CommandMangler forTests()
Ensure we have enough bits to represent all SymbolTag values.
std::vector< std::string > ExtraArgs
TidyProvider ClangTidyProvider
ParseInputs inputs(MockFS &FS) const
RefSlab headerRefs() const
std::string HeaderFilename
SymbolSlab headerSymbols() const
std::shared_ptr< const PreambleData > preamble(PreambleParsedCallback PreambleCallback=nullptr) const
bool OverlayRealFileSystemForModules
const SymbolIndex * ExternalIndex
llvm::StringMap< std::string > AdditionalFiles
FeatureModuleSet * FeatureModules
std::unique_ptr< SymbolIndex > index() const
Contains options for clang-tidy.