26 #include "clang/Format/Format.h" 27 #include "clang/Frontend/CompilerInstance.h" 28 #include "clang/Frontend/CompilerInvocation.h" 29 #include "clang/Lex/Preprocessor.h" 30 #include "clang/Tooling/CompilationDatabase.h" 31 #include "clang/Tooling/Core/Replacement.h" 32 #include "llvm/ADT/ArrayRef.h" 33 #include "llvm/ADT/Optional.h" 34 #include "llvm/ADT/ScopeExit.h" 35 #include "llvm/ADT/StringRef.h" 36 #include "llvm/Support/Errc.h" 37 #include "llvm/Support/Error.h" 38 #include "llvm/Support/FileSystem.h" 39 #include "llvm/Support/Path.h" 40 #include "llvm/Support/raw_ostream.h" 45 #include <type_traits> 52 struct UpdateIndexCallbacks :
public ParsingCallbacks {
53 UpdateIndexCallbacks(FileIndex *FIndex, DiagnosticsConsumer &
DiagConsumer,
54 bool SemanticHighlighting)
55 : FIndex(FIndex), DiagConsumer(DiagConsumer),
56 SemanticHighlighting(SemanticHighlighting) {}
59 std::shared_ptr<clang::Preprocessor> PP,
60 const CanonicalIncludes &CanonIncludes)
override {
62 FIndex->updatePreamble(Path, Ctx, std::move(PP), CanonIncludes);
65 void onMainAST(
PathRef Path, ParsedAST &
AST)
override {
67 FIndex->updateMain(Path, AST);
68 if (SemanticHighlighting)
72 void onDiagnostics(
PathRef File, std::vector<Diag> Diags)
override {
76 void onFileUpdated(
PathRef File,
const TUStatus &Status)
override {
83 bool SemanticHighlighting;
100 : FSProvider(FSProvider),
101 DynamicIdx(Opts.BuildDynamicSymbolIndex
102 ? new
FileIndex(Opts.HeavyweightDynamicSymbolIndex)
104 GetClangTidyOptions(Opts.GetClangTidyOptions),
105 SuggestMissingIncludes(Opts.SuggestMissingIncludes),
106 TweakFilter(Opts.TweakFilter), WorkspaceRoot(Opts.WorkspaceRoot),
113 CDB, Opts.AsyncThreadsCount, Opts.StorePreamblesInMemory,
114 llvm::make_unique<UpdateIndexCallbacks>(
115 DynamicIdx.get(), DiagConsumer, Opts.SemanticHighlighting),
116 Opts.UpdateDebounce, Opts.RetentionPolicy) {
119 if (this->Index !=
nullptr) {
120 MergedIdx.push_back(llvm::make_unique<MergedIndex>(Idx, this->Index));
121 this->Index = MergedIdx.back().get();
129 BackgroundIdx = llvm::make_unique<BackgroundIndex>(
132 [&CDB](llvm::StringRef File) {
return CDB.getProjectInfo(File); }),
134 AddIndex(BackgroundIdx.get());
137 AddIndex(DynamicIdx.get());
147 if (GetClangTidyOptions)
155 Inputs.
Opts = std::move(Opts);
156 Inputs.
Index = Index;
157 bool NewFile = WorkScheduler.
update(File, Inputs, WantDiags);
159 if (NewFile && BackgroundIdx)
160 BackgroundIdx->boostRelated(File);
173 auto CodeCompleteOpts = Opts;
174 if (!CodeCompleteOpts.Index)
175 CodeCompleteOpts.
Index = Index;
178 auto Task = [Pos,
FS, CodeCompleteOpts,
180 llvm::Expected<InputsAndPreamble> IP) {
182 return CB(IP.takeError());
184 return CB(llvm::make_error<CancelledError>());
186 llvm::Optional<SpeculativeFuzzyFind> SpecFuzzyFind;
190 vlog(
"Build for file {0} is not ready. Enter fallback mode.", File);
192 if (CodeCompleteOpts.Index && CodeCompleteOpts.SpeculativeIndexRequest) {
193 SpecFuzzyFind.emplace();
195 std::lock_guard<std::mutex> Lock(
196 CachedCompletionFuzzyFindRequestMutex);
197 SpecFuzzyFind->CachedReq =
198 CachedCompletionFuzzyFindRequestByFile[
File];
205 File, IP->Command, IP->Preamble, IP->Contents, Pos, FS,
206 CodeCompleteOpts, SpecFuzzyFind ? SpecFuzzyFind.getPointer() :
nullptr);
209 CB(std::move(Result));
211 if (SpecFuzzyFind && SpecFuzzyFind->NewReq.hasValue()) {
212 std::lock_guard<std::mutex> Lock(CachedCompletionFuzzyFindRequestMutex);
213 CachedCompletionFuzzyFindRequestByFile[
File] =
214 SpecFuzzyFind->NewReq.getValue();
224 "CodeComplete", File,
228 Bind(Task, File.str(), std::move(CB)));
235 auto *Index = this->Index;
237 llvm::Expected<InputsAndPreamble> IP) {
239 return CB(IP.takeError());
254 llvm::Expected<tooling::Replacements>
258 return Begin.takeError();
261 return End.takeError();
262 return formatCode(Code, File, {
tooling::Range(*Begin, *End - *Begin)});
265 llvm::Expected<tooling::Replacements>
271 llvm::Expected<std::vector<TextEdit>>
273 StringRef TriggerText) {
276 return CursorPos.takeError();
278 auto Style = format::getStyle(format::DefaultFormatStyle, File,
279 format::DefaultFallbackStyle, Code,
FS.get());
281 return Style.takeError();
283 std::vector<TextEdit>
Result;
284 for (
const tooling::Replacement &R :
291 bool WantFormat,
Callback<std::vector<TextEdit>> CB) {
292 auto Action = [Pos, WantFormat,
this](Path
File, std::string NewName,
294 llvm::Expected<InputsAndAST> InpAST) {
296 return CB(InpAST.takeError());
299 return CB(Changes.takeError());
303 InpAST->Inputs.FS.get());
306 *Changes = std::move(*Formatted);
308 elog(
"Failed to format replacements: {0}", Formatted.takeError());
311 std::vector<TextEdit> Edits;
312 for (
const auto &Rep : *Changes)
314 return CB(std::move(Edits));
318 "Rename", File,
Bind(
Action, File.str(), NewName.str(), std::move(CB)));
321 static llvm::Expected<Tweak::Selection>
325 return Begin.takeError();
328 return End.takeError();
333 Callback<std::vector<TweakRef>> CB) {
334 auto Action = [
this, Sel](decltype(CB) CB, std::string
File,
335 Expected<InputsAndAST> InpAST) {
337 return CB(InpAST.takeError());
340 return CB(Selection.takeError());
341 std::vector<TweakRef> Res;
343 Res.push_back({T->id(), T->title(), T->intent()});
348 WorkScheduler.
runWithAST(
"EnumerateTweaks", File,
354 auto Action = [Sel](decltype(CB) CB, std::string
File, std::string TweakID,
355 Expected<InputsAndAST> InpAST) {
357 return CB(InpAST.takeError());
360 return CB(Selection.takeError());
363 return CB(A.takeError());
364 auto Effect = (*A)->apply(*Selection);
366 return CB(Effect.takeError());
367 if (Effect->ApplyEdit) {
371 InpAST->Inputs.FS.get());
373 *Effect->ApplyEdit, Style))
374 Effect->ApplyEdit = std::move(*Formatted);
376 elog(
"Failed to format replacements: {0}", Formatted.takeError());
378 return CB(std::move(*Effect));
382 Bind(
Action, std::move(CB), File.str(), TweakID.str()));
386 llvm::unique_function<
void(std::string)>
Callback) {
388 llvm::Expected<InputsAndAST> InpAST) {
390 llvm::consumeError(InpAST.takeError());
395 llvm::raw_string_ostream ResultOS(Result);
406 Callback<std::vector<LocatedSymbol>> CB) {
407 auto Action = [Pos,
this](decltype(CB) CB,
408 llvm::Expected<InputsAndAST> InpAST) {
410 return CB(InpAST.takeError());
419 llvm::StringRef SourceExtensions[] = {
".cpp",
".c",
".cc",
".cxx",
420 ".c++",
".m",
".mm"};
421 llvm::StringRef HeaderExtensions[] = {
".h",
".hh",
".hpp",
".hxx",
".inc"};
423 llvm::StringRef PathExt = llvm::sys::path::extension(Path);
427 llvm::find_if(SourceExtensions, [&PathExt](
PathRef SourceExt) {
428 return SourceExt.equals_lower(PathExt);
430 bool IsSource = SourceIter != std::end(SourceExtensions);
433 llvm::find_if(HeaderExtensions, [&PathExt](
PathRef HeaderExt) {
434 return HeaderExt.equals_lower(PathExt);
437 bool IsHeader = HeaderIter != std::end(HeaderExtensions);
440 if (!IsSource && !IsHeader)
445 llvm::ArrayRef<llvm::StringRef> NewExts;
447 NewExts = HeaderExtensions;
449 NewExts = SourceExtensions;
452 llvm::SmallString<128> NewPath = llvm::StringRef(Path);
458 for (llvm::StringRef NewExt : NewExts) {
459 llvm::sys::path::replace_extension(NewPath, NewExt);
460 if (
FS->exists(NewPath))
461 return NewPath.str().str();
466 llvm::sys::path::replace_extension(NewPath, NewExt.upper());
467 if (
FS->exists(NewPath))
468 return NewPath.str().str();
474 llvm::Expected<tooling::Replacements>
475 ClangdServer::formatCode(llvm::StringRef Code,
PathRef File,
476 llvm::ArrayRef<tooling::Range> Ranges) {
480 tooling::Replacements IncludeReplaces =
481 format::sortIncludes(Style, Code, Ranges, File);
482 auto Changed = tooling::applyAllReplacements(Code, IncludeReplaces);
486 return IncludeReplaces.merge(format::reformat(
488 tooling::calculateRangesAfterReplacements(IncludeReplaces, Ranges),
495 llvm::Expected<InputsAndAST> InpAST) {
497 return CB(InpAST.takeError());
505 Callback<llvm::Optional<HoverInfo>> CB) {
506 auto Action = [Pos,
this](decltype(CB) CB, Path
File,
507 llvm::Expected<InputsAndAST> InpAST) {
509 return CB(InpAST.takeError());
511 File, InpAST->Inputs.Contents, InpAST->Inputs.FS.get());
521 Callback<Optional<TypeHierarchyItem>> CB) {
522 std::string FileCopy =
File;
523 auto Action = [FileCopy, Pos, Resolve, Direction,
524 this](decltype(CB) CB, Expected<InputsAndAST> InpAST) {
526 return CB(InpAST.takeError());
536 Callback<llvm::Optional<TypeHierarchyItem>> CB) {
547 llvm::StringRef Query,
int Limit,
548 Callback<std::vector<SymbolInformation>> CB) {
549 std::string QueryCopy = Query;
551 "getWorkspaceSymbols",
553 [QueryCopy, Limit,
this](decltype(CB) CB) {
555 WorkspaceRoot.getValueOr(
"")));
561 Callback<std::vector<DocumentSymbol>> CB) {
563 llvm::Expected<InputsAndAST> InpAST) {
565 return CB(InpAST.takeError());
568 WorkScheduler.
runWithAST(
"documentSymbols", File,
573 Callback<std::vector<Location>> CB) {
575 llvm::Expected<InputsAndAST> InpAST) {
577 return CB(InpAST.takeError());
585 Callback<std::vector<SymbolDetails>> CB) {
587 llvm::Expected<InputsAndAST> InpAST) {
589 return CB(InpAST.takeError());
596 std::vector<std::pair<Path, std::size_t>>
605 BackgroundIdx->blockUntilIdleForTest(TimeoutSeconds));
WantDiagnostics
Determines whether diagnostics should be generated for a file snapshot.
void rename(PathRef File, Position Pos, llvm::StringRef NewName, bool WantFormat, Callback< std::vector< TextEdit >> CB)
Rename all occurrences of the symbol at the Pos in File to NewName.
std::vector< tooling::Replacement > formatIncremental(llvm::StringRef OriginalCode, unsigned OriginalCursor, llvm::StringRef InsertedText, format::FormatStyle Style)
Applies limited formatting around new InsertedText.
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...
llvm::Expected< tooling::Replacements > cleanupAndFormat(StringRef Code, const tooling::Replacements &Replaces, const format::FormatStyle &Style)
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.
void typeHierarchy(PathRef File, Position Pos, int Resolve, TypeHierarchyDirection Direction, Callback< llvm::Optional< TypeHierarchyItem >> CB)
Get information about type hierarchy for a given position.
bool BackgroundIndex
If true, ClangdServer automatically indexes files in the current project on background threads...
llvm::Expected< std::unique_ptr< Tweak > > prepareTweak(StringRef ID, const Tweak::Selection &S)
bool blockUntilIdle(Deadline D) const
Wait until there are no scheduled or running tasks.
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.
void resolveTypeHierarchy(TypeHierarchyItem &Item, int ResolveLevels, TypeHierarchyDirection Direction, const SymbolIndex *Index)
Interface for symbol indexes that can be used for searching or matching symbols among a set of symbol...
static Factory createDiskBackedStorageFactory(std::function< llvm::Optional< ProjectInfo >(PathRef)> GetProjectInfo)
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.
Besides accepting stale preamble, this also allow preamble to be absent (not ready or failed to build...
bool SuggestMissingIncludes
llvm::StringRef PathRef
A typedef to represent a ref to file path.
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.
tidy::ClangTidyOptions ClangTidyOpts
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.
void vlog(const char *Fmt, Ts &&... Vals)
bool update(PathRef File, ParseInputs Inputs, WantDiagnostics WD)
Schedule an update for File.
void elog(const char *Fmt, Ts &&... Vals)
void applyTweak(PathRef File, Range Sel, StringRef ID, Callback< Tweak::Effect > CB)
Apply the code tweak with a specified ID.
MockFSProvider FSProvider
static llvm::Expected< Tweak::Selection > tweakSelection(const Range &Sel, const InputsAndAST &AST)
SignatureHelp signatureHelp(PathRef FileName, const tooling::CompileCommand &Command, const PreambleData *Preamble, llvm::StringRef Contents, Position Pos, llvm::IntrusiveRefCntPtr< llvm::vfs::FileSystem > VFS, const SymbolIndex *Index)
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.
llvm::Optional< HoverInfo > getHover(ParsedAST &AST, Position Pos, format::FormatStyle Style, const SymbolIndex *Index)
Get the hover information when hovering at Pos.
llvm::Expected< tooling::Replacements > renameWithinFile(ParsedAST &AST, llvm::StringRef File, Position Pos, llvm::StringRef NewName, const SymbolIndex *Index)
Renames all occurrences of the symbol at Pos to NewName.
Context clone() const
Clone this context object.
void resolveTypeHierarchy(TypeHierarchyItem Item, int Resolve, TypeHierarchyDirection Direction, Callback< llvm::Optional< TypeHierarchyItem >> CB)
Resolve type hierarchy item in the given direction.
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::Expected< std::vector< TextEdit > > formatOnType(StringRef Code, PathRef File, Position Pos, StringRef TriggerText)
Run formatting after TriggerText was typed at Pos in File with content Code.
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.
enum clang::clangd::CodeCompleteOptions::CodeCompletionParse RunParser
std::chrono::steady_clock::duration UpdateDebounce
Time to wait after a new file version before computing diagnostics.
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.
Input to prepare and apply tweaks.
std::vector< std::pair< Path, std::size_t > > getUsedBytesPerFile() const
Returns estimated memory usage for each of the currently open files.
format::FormatStyle getFormatStyleForFile(llvm::StringRef File, llvm::StringRef Content, llvm::vfs::FileSystem *FS)
Choose the clang-format style we should apply to a certain file.
void enumerateTweaks(PathRef File, Range Sel, Callback< std::vector< TweakRef >> CB)
Enumerate the code tweaks available to the user at a specified point.
CodeCompleteResult codeComplete(PathRef FileName, const tooling::CompileCommand &Command, const PreambleData *Preamble, llvm::StringRef Contents, Position Pos, llvm::IntrusiveRefCntPtr< llvm::vfs::FileSystem > VFS, CodeCompleteOptions Opts, SpeculativeFuzzyFind *SpecFuzzyFind)
void findHover(PathRef File, Position Pos, Callback< llvm::Optional< HoverInfo >> CB)
Get code hover for a given position.
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.
Block until we can run the parser (e.g.
bool StorePreamblesInMemory
Cached preambles are potentially large. If false, store them on disk.
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Deadline timeoutSeconds(llvm::Optional< double > Seconds)
Makes a deadline from a timeout in seconds. None means wait forever.
TextEdit replacementToEdit(llvm::StringRef Code, const tooling::Replacement &R)
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...
CharSourceRange Range
SourceRange for the file name.
llvm::Optional< TypeHierarchyItem > getTypeHierarchy(ParsedAST &AST, Position Pos, int ResolveLevels, TypeHierarchyDirection Direction, const SymbolIndex *Index, PathRef TUPath)
Get type hierarchy information at Pos.
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.
llvm::Optional< llvm::Expected< tooling::AtomicChanges > > Result
std::vector< HighlightingToken > getSemanticHighlightings(ParsedAST &AST)
llvm::StringRef getDocument(PathRef File) const
Get the contents of File, which should have been added.
void symbolInfo(PathRef File, Position Pos, Callback< std::vector< SymbolDetails >> CB)
Get symbol info for given position.
IgnoreDiagnostics DiagConsumer
void locateSymbolAt(PathRef File, Position Pos, Callback< std::vector< LocatedSymbol >> CB)
Find declaration/definition locations of symbol at a specified position.
std::vector< LocatedSymbol > locateSymbolAt(ParsedAST &AST, Position Pos, const SymbolIndex *Index)
Get definition of symbol at a specified Pos.
PrecompiledPreamble Preamble
static ClangTidyOptions getDefaults()
These options are used for all settings that haven't been overridden by the OptionsProvider.
Position end
The range's end position.
llvm::StringRef getContents(PathRef File) const
Returns the current contents of the buffer for File, per last update().
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...
bool SemanticHighlighting
Enable semantic highlighting features.
std::vector< std::unique_ptr< Tweak > > prepareTweaks(const Tweak::Selection &S, llvm::function_ref< bool(const Tweak &)> Filter)
Calls prepare() on all tweaks that satisfy the filter, returning those that can run on the selection...
void run(llvm::StringRef Name, llvm::unique_function< void()> Action)
Schedule an async task with no dependencies.
static cl::opt< std::string > FormatStyle("format-style", cl::desc(R"(
Style for formatting code around applied fixes:
- 'none' (default) turns off formatting
- 'file' (literally 'file', not a placeholder)
uses .clang-format file in the closest parent
directory
- '{ <json> }' specifies options inline, e.g.
-format-style='{BasedOnStyle: llvm, IndentWidth: 8}'
- 'llvm', 'google', 'webkit', 'mozilla'
See clang-format documentation for the up-to-date
information about formatting styles and options.
This option overrides the 'FormatStyle` option in
.clang-tidy file, if any.
)"), cl::init("none"), cl::cat(ClangTidyCategory))
virtual llvm::IntrusiveRefCntPtr< llvm::vfs::FileSystem > getFileSystem() const =0
Called by ClangdServer to obtain a vfs::FileSystem to be used for parsing.