19 #include "clang/Format/Format.h" 20 #include "clang/Frontend/CompilerInstance.h" 21 #include "clang/Frontend/CompilerInvocation.h" 22 #include "clang/Lex/Preprocessor.h" 23 #include "clang/Tooling/CompilationDatabase.h" 24 #include "clang/Tooling/Refactoring/RefactoringResultConsumer.h" 25 #include "clang/Tooling/Refactoring/Rename/RenamingAction.h" 26 #include "llvm/ADT/ArrayRef.h" 27 #include "llvm/ADT/Optional.h" 28 #include "llvm/ADT/ScopeExit.h" 29 #include "llvm/ADT/StringRef.h" 30 #include "llvm/Support/Errc.h" 31 #include "llvm/Support/FileSystem.h" 32 #include "llvm/Support/Path.h" 33 #include "llvm/Support/raw_ostream.h" 41 class RefactoringResultCollector final
42 :
public tooling::RefactoringResultConsumer {
44 void handleError(llvm::Error Err)
override {
45 assert(!
Result.hasValue());
53 using tooling::RefactoringResultConsumer::handle;
55 void handle(tooling::AtomicChanges SourceReplacements)
override {
56 assert(!
Result.hasValue());
57 Result = std::move(SourceReplacements);
60 llvm::Optional<llvm::Expected<tooling::AtomicChanges>>
Result;
64 struct UpdateIndexCallbacks :
public ParsingCallbacks {
65 UpdateIndexCallbacks(FileIndex *FIndex, DiagnosticsConsumer &DiagConsumer)
66 : FIndex(FIndex), DiagConsumer(DiagConsumer) {}
69 std::shared_ptr<clang::Preprocessor> PP)
override {
71 FIndex->updatePreamble(Path, Ctx, std::move(PP));
74 void onMainAST(
PathRef Path, ParsedAST &
AST)
override {
76 FIndex->updateMain(Path, AST);
79 void onDiagnostics(
PathRef File, std::vector<Diag> Diags)
override {
80 DiagConsumer.onDiagnosticsReady(File, std::move(Diags));
83 void onFileUpdated(
PathRef File,
const TUStatus &Status)
override {
84 DiagConsumer.onFileUpdated(File, Status);
89 DiagnosticsConsumer &DiagConsumer;
105 : CDB(CDB), FSProvider(FSProvider),
106 DynamicIdx(Opts.BuildDynamicSymbolIndex
107 ? new
FileIndex(Opts.HeavyweightDynamicSymbolIndex)
109 WorkspaceRoot(Opts.WorkspaceRoot),
110 PCHs(std::make_shared<PCHContainerOperations>()),
116 WorkScheduler(Opts.AsyncThreadsCount, Opts.StorePreamblesInMemory,
117 llvm::make_unique<UpdateIndexCallbacks>(DynamicIdx.get(),
119 Opts.UpdateDebounce, Opts.RetentionPolicy) {
122 if (this->Index !=
nullptr) {
123 MergedIdx.push_back(llvm::make_unique<MergedIndex>(Idx, this->Index));
124 this->Index = MergedIdx.back().get();
132 BackgroundIdx = llvm::make_unique<BackgroundIndex>(
136 AddIndex(BackgroundIdx.get());
139 AddIndex(DynamicIdx.get());
148 WorkScheduler.
update(File,
160 auto CodeCompleteOpts = Opts;
161 if (!CodeCompleteOpts.Index)
162 CodeCompleteOpts.
Index = Index;
165 std::shared_ptr<PCHContainerOperations> PCHs = this->PCHs;
168 auto Task = [PCHs,
Pos, FS, CodeCompleteOpts,
170 llvm::Expected<InputsAndPreamble> IP) {
172 return CB(IP.takeError());
174 return CB(llvm::make_error<CancelledError>());
176 llvm::Optional<SpeculativeFuzzyFind> SpecFuzzyFind;
177 if (CodeCompleteOpts.Index && CodeCompleteOpts.SpeculativeIndexRequest) {
178 SpecFuzzyFind.emplace();
180 std::lock_guard<std::mutex> Lock(CachedCompletionFuzzyFindRequestMutex);
181 SpecFuzzyFind->CachedReq = CachedCompletionFuzzyFindRequestByFile[
File];
188 File, IP->Command, IP->Preamble, IP->Contents, Pos, FS, PCHs,
189 CodeCompleteOpts, SpecFuzzyFind ? SpecFuzzyFind.getPointer() :
nullptr);
192 CB(std::move(Result));
194 if (SpecFuzzyFind && SpecFuzzyFind->NewReq.hasValue()) {
195 std::lock_guard<std::mutex> Lock(CachedCompletionFuzzyFindRequestMutex);
196 CachedCompletionFuzzyFindRequestByFile[
File] =
197 SpecFuzzyFind->NewReq.getValue();
207 Bind(Task, File.str(), std::move(CB)));
213 auto PCHs = this->PCHs;
215 auto *Index = this->Index;
217 llvm::Expected<InputsAndPreamble> IP) {
219 return CB(IP.takeError());
234 llvm::Expected<tooling::Replacements>
238 return Begin.takeError();
241 return End.takeError();
242 return formatCode(Code, File, {
tooling::Range(*Begin, *End - *Begin)});
245 llvm::Expected<tooling::Replacements>
251 llvm::Expected<tooling::Replacements>
257 return CursorPos.takeError();
258 size_t PreviousLBracePos =
259 llvm::StringRef(Code).find_last_of(
'{', *CursorPos);
260 if (PreviousLBracePos == llvm::StringRef::npos)
261 PreviousLBracePos = *CursorPos;
262 size_t Len = *CursorPos - PreviousLBracePos;
264 return formatCode(Code, File, {
tooling::Range(PreviousLBracePos, Len)});
268 Callback<std::vector<tooling::Replacement>> CB) {
271 llvm::Expected<InputsAndAST> InpAST) {
273 return CB(InpAST.takeError());
274 auto &
AST = InpAST->AST;
276 RefactoringResultCollector ResultCollector;
277 const SourceManager &SourceMgr = AST.getASTContext().getSourceManager();
278 SourceLocation SourceLocationBeg =
280 tooling::RefactoringRuleContext
Context(
281 AST.getASTContext().getSourceManager());
282 Context.setASTContext(AST.getASTContext());
283 auto Rename = clang::tooling::RenameOccurrences::initiate(
284 Context, SourceRange(SourceLocationBeg), NewName);
286 return CB(Rename.takeError());
288 Rename->invoke(ResultCollector,
Context);
290 assert(ResultCollector.Result.hasValue());
291 if (!ResultCollector.Result.getValue())
292 return CB(ResultCollector.Result->takeError());
294 std::vector<tooling::Replacement> Replacements;
295 for (
const tooling::AtomicChange &Change : ResultCollector.Result->get()) {
296 tooling::Replacements ChangeReps = Change.getReplacements();
297 for (
const auto &Rep : ChangeReps) {
307 if (Rep.getFilePath() ==
File)
308 Replacements.push_back(Rep);
311 return CB(std::move(Replacements));
315 "Rename", File,
Bind(
Action, File.str(), NewName.str(), std::move(CB)));
319 llvm::unique_function<
void(std::string)>
Callback) {
321 llvm::Expected<InputsAndAST> InpAST) {
323 llvm::consumeError(InpAST.takeError());
328 llvm::raw_string_ostream ResultOS(Result);
339 Callback<std::vector<Location>> CB) {
341 llvm::Expected<InputsAndAST> InpAST) {
343 return CB(InpAST.takeError());
352 llvm::StringRef SourceExtensions[] = {
".cpp",
".c",
".cc",
".cxx",
353 ".c++",
".m",
".mm"};
354 llvm::StringRef HeaderExtensions[] = {
".h",
".hh",
".hpp",
".hxx",
".inc"};
356 llvm::StringRef PathExt = llvm::sys::path::extension(Path);
360 llvm::find_if(SourceExtensions, [&PathExt](
PathRef SourceExt) {
361 return SourceExt.equals_lower(PathExt);
363 bool IsSource = SourceIter != std::end(SourceExtensions);
366 llvm::find_if(HeaderExtensions, [&PathExt](
PathRef HeaderExt) {
367 return HeaderExt.equals_lower(PathExt);
370 bool IsHeader = HeaderIter != std::end(HeaderExtensions);
373 if (!IsSource && !IsHeader)
378 llvm::ArrayRef<llvm::StringRef> NewExts;
380 NewExts = HeaderExtensions;
382 NewExts = SourceExtensions;
385 llvm::SmallString<128> NewPath = llvm::StringRef(Path);
391 for (llvm::StringRef NewExt : NewExts) {
392 llvm::sys::path::replace_extension(NewPath, NewExt);
393 if (FS->exists(NewPath))
394 return NewPath.str().str();
399 llvm::sys::path::replace_extension(NewPath, NewExt.upper());
400 if (FS->exists(NewPath))
401 return NewPath.str().str();
407 llvm::Expected<tooling::Replacements>
408 ClangdServer::formatCode(llvm::StringRef Code,
PathRef File,
409 llvm::ArrayRef<tooling::Range> Ranges) {
412 auto Style = format::getStyle(format::DefaultFormatStyle, File,
413 format::DefaultFallbackStyle, Code, FS.get());
415 return Style.takeError();
417 tooling::Replacements IncludeReplaces =
418 format::sortIncludes(*Style, Code, Ranges, File);
419 auto Changed = tooling::applyAllReplacements(Code, IncludeReplaces);
423 return IncludeReplaces.merge(format::reformat(
425 tooling::calculateRangesAfterReplacements(IncludeReplaces, Ranges),
432 llvm::Expected<InputsAndAST> InpAST) {
434 return CB(InpAST.takeError());
442 Callback<llvm::Optional<Hover>> CB) {
444 llvm::Expected<InputsAndAST> InpAST) {
446 return CB(InpAST.takeError());
453 tooling::CompileCommand ClangdServer::getCompileCommand(
PathRef File) {
458 return std::move(*C);
467 llvm::StringRef Query,
int Limit,
468 Callback<std::vector<SymbolInformation>> CB) {
469 std::string QueryCopy = Query;
471 "getWorkspaceSymbols",
473 [QueryCopy, Limit,
this](decltype(CB) CB) {
475 WorkspaceRoot.getValueOr(
"")));
481 Callback<std::vector<DocumentSymbol>> CB) {
483 llvm::Expected<InputsAndAST> InpAST) {
485 return CB(InpAST.takeError());
488 WorkScheduler.
runWithAST(
"documentSymbols", File,
493 Callback<std::vector<Location>> CB) {
495 llvm::Expected<InputsAndAST> InpAST) {
497 return CB(InpAST.takeError());
505 Callback<std::vector<SymbolDetails>> CB) {
507 llvm::Expected<InputsAndAST> InpAST) {
509 return CB(InpAST.takeError());
516 std::vector<std::pair<Path, std::size_t>>
525 BackgroundIdx->blockUntilIdleForTest(TimeoutSeconds));
SignatureHelp signatureHelp(PathRef FileName, const tooling::CompileCommand &Command, const PreambleData *Preamble, llvm::StringRef Contents, Position Pos, llvm::IntrusiveRefCntPtr< llvm::vfs::FileSystem > VFS, std::shared_ptr< PCHContainerOperations > PCHs, const SymbolIndex *Index)
llvm::Optional< Hover > getHover(ParsedAST &AST, Position Pos)
Get the hover information when hovering at Pos.
void findDefinitions(PathRef File, Position Pos, Callback< std::vector< Location >> CB)
Get definition of symbol at a specified Line and Column in File.
WantDiagnostics
Determines whether diagnostics should be generated for a file snapshot.
std::vector< Location > findDefinitions(ParsedAST &AST, Position Pos, const SymbolIndex *Index)
Get definition of symbol at a specified Pos.
void addDocument(PathRef File, StringRef Contents, WantDiagnostics WD=WantDiagnostics::Auto)
Add a File to the list of tracked C++ files or update the contents if File is already tracked...
CodeCompleteResult codeComplete(PathRef FileName, const tooling::CompileCommand &Command, const PreambleData *Preamble, llvm::StringRef Contents, Position Pos, llvm::IntrusiveRefCntPtr< llvm::vfs::FileSystem > VFS, std::shared_ptr< PCHContainerOperations > PCHs, CodeCompleteOptions Opts, SpeculativeFuzzyFind *SpecFuzzyFind)
llvm::Expected< std::vector< SymbolInformation > > getWorkspaceSymbols(llvm::StringRef Query, int Limit, const SymbolIndex *const Index, llvm::StringRef HintPath)
Searches for the symbols matching Query.
Some operations such as code completion produce a set of candidates.
void codeComplete(PathRef File, Position Pos, const clangd::CodeCompleteOptions &Opts, Callback< CodeCompleteResult > CB)
Run code completion for File at Pos.
Position start
The range's start position.
The preamble may be generated from an older version of the file.
llvm::Expected< tooling::Replacements > formatOnType(StringRef Code, PathRef File, Position Pos)
Run formatting after a character was typed at Pos in File with content Code.
bool BackgroundIndex
If true, ClangdServer automatically indexes files in the current project on background threads...
bool blockUntilIdle(Deadline D) const
Wait until there are no scheduled or running tasks.
void findHover(PathRef File, Position Pos, Callback< llvm::Optional< Hover >> CB)
Get code hover for a given position.
void remove(PathRef File)
Remove File from the list of tracked files and schedule removal of its resources. ...
void dumpAST(ParsedAST &AST, llvm::raw_ostream &OS)
For testing/debugging purposes.
void onFileEvent(const DidChangeWatchedFilesParams &Params)
Called when an event occurs for a watched file in the workspace.
virtual llvm::Optional< tooling::CompileCommand > getCompileCommand(PathRef File, ProjectInfo *=nullptr) const =0
If there are any known-good commands for building this file, returns one.
Interface for symbol indexes that can be used for searching or matching symbols among a set of symbol...
ClangdServer(const GlobalCompilationDatabase &CDB, const FileSystemProvider &FSProvider, DiagnosticsConsumer &DiagConsumer, const Options &Opts)
Creates a new ClangdServer instance.
This manages symbols from files and an in-memory index on all symbols.
static Factory createDiskBackedStorageFactory()
llvm::StringRef PathRef
A typedef to represent a ref to file path.
void update(PathRef File, ParseInputs Inputs, WantDiagnostics WD)
Schedule an update for File.
llvm::unique_function< void(llvm::Expected< T >)> Callback
A Callback<T> is a void function that accepts Expected<T>.
LLVM_NODISCARD bool blockUntilIdleForTest(llvm::Optional< double > TimeoutSeconds=10)
static Options optsForTest()
Documents should not be synced at all.
void findDocumentHighlights(PathRef File, Position Pos, Callback< std::vector< DocumentHighlight >> CB)
Get document highlights for a given position.
unsigned AsyncThreadsCount
To process requests asynchronously, ClangdServer spawns worker threads.
bool isCancelled(const Context &Ctx)
True if the current context is within a cancelable task which was cancelled.
void findReferences(PathRef File, Position Pos, uint32_t Limit, Callback< std::vector< Location >> CB)
Retrieve locations for symbol references.
Provides compilation arguments used for parsing C and C++ files.
std::vector< SymbolDetails > getSymbolInfo(ParsedAST &AST, Position Pos)
Get info about symbols at Pos.
Context clone() const
Clone this context object.
llvm::Expected< size_t > positionToOffset(llvm::StringRef Code, Position P, bool AllowColumnsBeyondLineLength)
Turn a [line, column] pair into an offset in Code.
ForwardBinder< Func, Args... > Bind(Func F, Args &&... As)
Creates an object that stores a callable (F) and first arguments to the callable (As) and allows to c...
llvm::unique_function< void()> Action
std::string Path
A typedef to represent a file path.
static const Context & current()
Returns the context for the current thread, creating it if needed.
std::vector< std::pair< Path, std::size_t > > getUsedBytesPerFile() const
Returns estimated memory usage for each of the currently open files.
void runWithPreamble(llvm::StringRef Name, PathRef File, PreambleConsistency Consistency, Callback< InputsAndPreamble > Action)
Schedule an async read of the preamble.
std::chrono::steady_clock::duration UpdateDebounce
Time to wait after a new file version before computing diagnostics.
llvm::Optional< llvm::Expected< tooling::AtomicChanges > > Result
void dumpAST(PathRef File, llvm::unique_function< void(std::string)> Callback)
Only for testing purposes.
void documentSymbols(StringRef File, Callback< std::vector< DocumentSymbol >> CB)
Retrieve the symbols within the specified file.
std::vector< DocumentHighlight > findDocumentHighlights(ParsedAST &AST, Position Pos)
Returns highlights for all usages of a symbol at Pos.
A context is an immutable container for per-request data that must be propagated through layers that ...
void rename(PathRef File, Position Pos, llvm::StringRef NewName, Callback< std::vector< tooling::Replacement >> CB)
Rename all occurrences of the symbol at the Pos in File to NewName.
size_t BackgroundIndexRebuildPeriodMs
If set to non-zero, the background index rebuilds the symbol index periodically every BuildIndexPerio...
std::vector< std::pair< Path, std::size_t > > getUsedBytesPerFile() const
Returns estimated memory usage for each of the currently open files.
const SymbolIndex * Index
If Index is set, it is used to augment the code completion results.
llvm::Expected< tooling::Replacements > formatRange(StringRef Code, PathRef File, Range Rng)
Run formatting for Rng inside File with content Code.
std::vector< Location > findReferences(ParsedAST &AST, Position Pos, uint32_t Limit, const SymbolIndex *Index)
Returns reference locations of the symbol at a specified Pos.
bool StorePreamblesInMemory
Cached preambles are potentially large. If false, store them on disk.
SourceLocation getBeginningOfIdentifier(ParsedAST &Unit, const Position &Pos, const FileID FID)
Get the beginning SourceLocation at a specified Pos.
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Deadline timeoutSeconds(llvm::Optional< double > Seconds)
Makes a deadline from a timeout in seconds. None means wait forever.
llvm::Expected< std::vector< DocumentSymbol > > getDocumentSymbols(ParsedAST &AST)
Retrieves the symbols contained in the "main file" section of an AST in the same order that they appe...
std::shared_ptr< PCHContainerOperations > PCHs
CharSourceRange Range
SourceRange for the file name.
void removeDocument(PathRef File)
Remove File from list of tracked files, schedule a request to free resources associated with it...
void runWithAST(llvm::StringRef Name, PathRef File, Callback< InputsAndAST > Action)
Schedule an async read of the AST.
void symbolInfo(PathRef File, Position Pos, Callback< std::vector< SymbolDetails >> CB)
Get symbol info for given position.
PrecompiledPreamble Preamble
Position end
The range's end position.
Records an event whose duration is the lifetime of the Span object.
SymbolIndex * StaticIndex
If set, use this index to augment code completion results.
void workspaceSymbols(StringRef Query, int Limit, Callback< std::vector< SymbolInformation >> CB)
Retrieve the top symbols from the workspace matching a query.
llvm::Expected< tooling::Replacements > formatFile(StringRef Code, PathRef File)
Run formatting for the whole File with content Code.
void signatureHelp(PathRef File, Position Pos, Callback< SignatureHelp > CB)
Provide signature help for File at Pos.
The preamble is generated from the current version of the file.
llvm::Optional< Path > switchSourceHeader(PathRef Path)
Helper function that returns a path to the corresponding source file when given a header file and vic...
virtual tooling::CompileCommand getFallbackCommand(PathRef File) const
Makes a guess at how to build a file.
void run(llvm::StringRef Name, llvm::unique_function< void()> Action)
Schedule an async task with no dependencies.
virtual llvm::IntrusiveRefCntPtr< llvm::vfs::FileSystem > getFileSystem() const =0
Called by ClangdServer to obtain a vfs::FileSystem to be used for parsing.