13 #include "clang/Frontend/CompilerInvocation.h" 14 #include "clang/Tooling/ArgumentsAdjusters.h" 15 #include "clang/Tooling/CompilationDatabase.h" 16 #include "llvm/ADT/None.h" 17 #include "llvm/ADT/Optional.h" 18 #include "llvm/ADT/STLExtras.h" 19 #include "llvm/ADT/SmallString.h" 20 #include "llvm/Support/FileSystem.h" 21 #include "llvm/Support/FileUtilities.h" 22 #include "llvm/Support/Path.h" 23 #include "llvm/Support/Program.h" 36 for (
auto Path = llvm::sys::path::parent_path(FileName);
38 Path = llvm::sys::path::parent_path(
Path))
44 tooling::CompileCommand
46 std::vector<std::string> Argv = {
"clang"};
50 auto FileExtension = llvm::sys::path::extension(File);
51 if (FileExtension.empty() || FileExtension ==
".h")
52 Argv.push_back(
"-xobjective-c++-header");
54 tooling::CompileCommand Cmd(llvm::sys::path::parent_path(File),
55 llvm::sys::path::filename(File), std::move(Argv),
57 Cmd.Heuristic =
"clangd fallback";
63 llvm::Optional<Path> CompileCommandsDir)
64 : CompileCommandsDir(std::move(CompileCommandsDir)) {}
69 llvm::Optional<tooling::CompileCommand>
73 Req.ShouldBroadcast =
true;
75 auto Res = lookupCDB(Req);
77 log(
"Failed to find compilation database for {0}", File);
81 auto Candidates = Res->CDB->getCompileCommands(File);
82 if (!Candidates.empty())
83 return std::move(Candidates.front());
95 #if defined(_WIN32) || defined(__APPLE__) 103 #if defined(_WIN32) || defined(__APPLE__) 104 return A.equals_lower(B);
110 DirectoryBasedGlobalCompilationDatabase::CachedCDB &
111 DirectoryBasedGlobalCompilationDatabase::getCDBInDirLocked(
PathRef Dir)
const {
115 auto R = CompilationDatabases.try_emplace(
Key);
117 CachedCDB &
Entry = R.first->second;
118 std::string
Error =
"";
119 Entry.CDB = tooling::CompilationDatabase::loadFromDirectory(Dir, Error);
122 return R.first->second;
125 llvm::Optional<DirectoryBasedGlobalCompilationDatabase::CDBLookupResult>
126 DirectoryBasedGlobalCompilationDatabase::lookupCDB(
127 CDBLookupRequest Request)
const {
128 assert(llvm::sys::path::is_absolute(Request.FileName) &&
129 "path must be absolute");
131 bool ShouldBroadcast =
false;
132 CDBLookupResult Result;
135 std::lock_guard<std::mutex> Lock(Mutex);
136 CachedCDB *
Entry =
nullptr;
137 if (CompileCommandsDir) {
138 Entry = &getCDBInDirLocked(*CompileCommandsDir);
143 actOnAllParentDirectories(
removeDots(Request.FileName),
145 Entry = &getCDBInDirLocked(Path);
146 return Entry->CDB != nullptr;
150 if (!Entry || !Entry->CDB)
154 if (Request.ShouldBroadcast && !Entry->SentBroadcast) {
155 Entry->SentBroadcast =
true;
156 ShouldBroadcast =
true;
159 Result.CDB = Entry->CDB.get();
160 Result.PI.SourceRoot = Entry->Path;
166 broadcastCDB(Result);
170 void DirectoryBasedGlobalCompilationDatabase::broadcastCDB(
171 CDBLookupResult Result)
const {
172 assert(Result.CDB &&
"Trying to broadcast an invalid CDB!");
174 std::vector<std::string> AllFiles = Result.CDB->getAllFiles();
177 if (CompileCommandsDir) {
178 assert(*CompileCommandsDir == Result.PI.SourceRoot &&
179 "Trying to broadcast a CDB outside of CompileCommandsDir!");
184 llvm::StringMap<bool> DirectoryHasCDB;
186 std::lock_guard<std::mutex> Lock(Mutex);
188 for (llvm::StringRef
File : AllFiles) {
190 auto It = DirectoryHasCDB.try_emplace(Path);
195 CachedCDB &
Entry = getCDBInDirLocked(Path);
196 It.first->second = Entry.CDB !=
nullptr;
197 return pathEqual(Path, Result.PI.SourceRoot);
202 std::vector<std::string> GovernedFiles;
203 for (llvm::StringRef
File : AllFiles) {
207 if (DirectoryHasCDB.lookup(Path)) {
208 if (
pathEqual(Path, Result.PI.SourceRoot))
221 llvm::Optional<ProjectInfo>
223 CDBLookupRequest Req;
225 Req.ShouldBroadcast =
false;
226 auto Res = lookupCDB(Req);
233 std::vector<std::string> FallbackFlags,
234 tooling::ArgumentsAdjuster Adjuster)
235 : Base(Base), ArgsAdjuster(std::move(Adjuster)),
236 FallbackFlags(std::move(FallbackFlags)) {
238 BaseChanged = Base->
watch([
this](
const std::vector<std::string>
Changes) {
243 llvm::Optional<tooling::CompileCommand>
245 llvm::Optional<tooling::CompileCommand> Cmd;
247 std::lock_guard<std::mutex> Lock(Mutex);
249 if (It != Commands.end())
257 Cmd->CommandLine = ArgsAdjuster(Cmd->CommandLine, Cmd->Filename);
264 std::lock_guard<std::mutex> Lock(Mutex);
265 Cmd.CommandLine.insert(Cmd.CommandLine.end(), FallbackFlags.begin(),
266 FallbackFlags.end());
268 Cmd.CommandLine = ArgsAdjuster(Cmd.CommandLine, Cmd.Filename);
273 PathRef File, llvm::Optional<tooling::CompileCommand> Cmd) {
279 std::unique_lock<std::mutex> Lock(Mutex);
281 Commands[CanonPath] = std::move(*Cmd);
283 Commands.erase(CanonPath);
290 std::lock_guard<std::mutex> Lock(Mutex);
292 if (It != Commands.end())
virtual llvm::Optional< tooling::CompileCommand > getCompileCommand(PathRef File) const =0
If there are any known-good commands for building this file, returns one.
llvm::StringRef PathRef
A typedef to represent a ref to file path.
Values in a Context are indexed by typed keys.
~DirectoryBasedGlobalCompilationDatabase() override
Documents should not be synced at all.
OverlayCDB(const GlobalCompilationDatabase *Base, std::vector< std::string > FallbackFlags={}, tooling::ArgumentsAdjuster Adjuster=nullptr)
llvm::Optional< ProjectInfo > getProjectInfo(PathRef File) const override
Returns the path to first directory containing a compilation database in File's parents.
Provides compilation arguments used for parsing C and C++ files.
llvm::Optional< tooling::CompileCommand > getCompileCommand(PathRef File) const override
If there are any known-good commands for building this file, returns one.
static bool pathEqual(PathRef A, PathRef B)
llvm::Optional< ProjectInfo > getProjectInfo(PathRef File) const override
Finds the closest project to File.
void broadcast(const T &V)
llvm::unique_function< void()> Action
void log(const char *Fmt, Ts &&... Vals)
std::string Path
A typedef to represent a file path.
DirectoryBasedGlobalCompilationDatabase(llvm::Optional< Path > CompileCommandsDir)
tooling::CompileCommand getFallbackCommand(PathRef File) const override
Makes a guess at how to build a file.
void setCompileCommand(PathRef File, llvm::Optional< tooling::CompileCommand > CompilationCommand)
Sets or clears the compilation command for a particular file.
CommandChanged::Subscription watch(CommandChanged::Listener L) const
The callback is notified when files may have new compile commands.
static std::string maybeCaseFoldPath(PathRef Path)
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
std::unique_ptr< GlobalCompilationDatabase > Base
Path removeDots(PathRef File)
Returns a version of File that doesn't contain dots and dot dots.
CommandChanged OnCommandChanged
llvm::Optional< tooling::CompileCommand > getCompileCommand(PathRef File) const override
Scans File's parents looking for compilation databases.
virtual llvm::Optional< ProjectInfo > getProjectInfo(PathRef File) const
Finds the closest project to File.
virtual tooling::CompileCommand getFallbackCommand(PathRef File) const
Makes a guess at how to build a file.