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" 50 struct UpdateIndexCallbacks :
public ParsingCallbacks {
51 UpdateIndexCallbacks(FileIndex *FIndex, DiagnosticsConsumer &
DiagConsumer,
52 bool SemanticHighlighting)
53 : FIndex(FIndex), DiagConsumer(DiagConsumer),
54 SemanticHighlighting(SemanticHighlighting) {}
57 std::shared_ptr<clang::Preprocessor> PP,
58 const CanonicalIncludes &CanonIncludes)
override {
60 FIndex->updatePreamble(Path, Ctx, std::move(PP), CanonIncludes);
63 void onMainAST(
PathRef Path, ParsedAST &
AST)
override {
65 FIndex->updateMain(Path, AST);
66 if (SemanticHighlighting)
70 void onDiagnostics(
PathRef File, std::vector<Diag> Diags)
override {
74 void onFileUpdated(
PathRef File,
const TUStatus &Status)
override {
81 bool SemanticHighlighting;
98 : FSProvider(FSProvider),
99 DynamicIdx(Opts.BuildDynamicSymbolIndex
100 ? new
FileIndex(Opts.HeavyweightDynamicSymbolIndex)
102 GetClangTidyOptions(Opts.GetClangTidyOptions),
103 SuggestMissingIncludes(Opts.SuggestMissingIncludes),
104 TweakFilter(Opts.TweakFilter),
105 WorkspaceRoot(Opts.WorkspaceRoot),
112 CDB, Opts.AsyncThreadsCount, Opts.StorePreamblesInMemory,
113 llvm::make_unique<UpdateIndexCallbacks>(
114 DynamicIdx.get(), DiagConsumer, Opts.SemanticHighlighting),
115 Opts.UpdateDebounce, Opts.RetentionPolicy) {
118 if (this->Index !=
nullptr) {
119 MergedIdx.push_back(llvm::make_unique<MergedIndex>(Idx, this->Index));
120 this->Index = MergedIdx.back().get();
128 BackgroundIdx = llvm::make_unique<BackgroundIndex>(
131 [&CDB](llvm::StringRef File) {
return CDB.getProjectInfo(File); }));
132 AddIndex(BackgroundIdx.get());
135 AddIndex(DynamicIdx.get());
145 if (GetClangTidyOptions)
153 Inputs.
Opts = std::move(Opts);
154 Inputs.
Index = Index;
155 bool NewFile = WorkScheduler.
update(File, Inputs, WantDiags);
157 if (NewFile && BackgroundIdx)
158 BackgroundIdx->boostRelated(File);
171 auto CodeCompleteOpts = Opts;
172 if (!CodeCompleteOpts.Index)
173 CodeCompleteOpts.
Index = Index;
176 auto Task = [Pos,
FS, CodeCompleteOpts,
178 llvm::Expected<InputsAndPreamble> IP) {
180 return CB(IP.takeError());
182 return CB(llvm::make_error<CancelledError>());
184 llvm::Optional<SpeculativeFuzzyFind> SpecFuzzyFind;
188 vlog(
"Build for file {0} is not ready. Enter fallback mode.", File);
190 if (CodeCompleteOpts.Index && CodeCompleteOpts.SpeculativeIndexRequest) {
191 SpecFuzzyFind.emplace();
193 std::lock_guard<std::mutex> Lock(
194 CachedCompletionFuzzyFindRequestMutex);
195 SpecFuzzyFind->CachedReq =
196 CachedCompletionFuzzyFindRequestByFile[
File];
203 File, IP->Command, IP->Preamble, IP->Contents, Pos, FS,
204 CodeCompleteOpts, SpecFuzzyFind ? SpecFuzzyFind.getPointer() :
nullptr);
207 CB(std::move(Result));
209 if (SpecFuzzyFind && SpecFuzzyFind->NewReq.hasValue()) {
210 std::lock_guard<std::mutex> Lock(CachedCompletionFuzzyFindRequestMutex);
211 CachedCompletionFuzzyFindRequestByFile[
File] =
212 SpecFuzzyFind->NewReq.getValue();
222 "CodeComplete", File,
226 Bind(Task, File.str(), std::move(CB)));
233 auto *Index = this->Index;
235 llvm::Expected<InputsAndPreamble> IP) {
237 return CB(IP.takeError());
252 llvm::Expected<tooling::Replacements>
256 return Begin.takeError();
259 return End.takeError();
260 return formatCode(Code, File, {
tooling::Range(*Begin, *End - *Begin)});
263 llvm::Expected<tooling::Replacements>
269 llvm::Expected<std::vector<TextEdit>>
271 StringRef TriggerText) {
274 return CursorPos.takeError();
276 auto Style = format::getStyle(format::DefaultFormatStyle, File,
277 format::DefaultFallbackStyle, Code,
FS.get());
279 return Style.takeError();
281 std::vector<TextEdit>
Result;
282 for (
const tooling::Replacement &R :
289 bool WantFormat,
Callback<std::vector<TextEdit>> CB) {
290 auto Action = [Pos, WantFormat,
this](Path
File, std::string NewName,
292 llvm::Expected<InputsAndAST> InpAST) {
294 return CB(InpAST.takeError());
297 return CB(Changes.takeError());
301 InpAST->Inputs.FS.get());
304 *Changes = std::move(*Formatted);
306 elog(
"Failed to format replacements: {0}", Formatted.takeError());
309 std::vector<TextEdit> Edits;
310 for (
const auto &Rep : *Changes)
312 return CB(std::move(Edits));
316 "Rename", File,
Bind(
Action, File.str(), NewName.str(), std::move(CB)));
319 static llvm::Expected<Tweak::Selection>
323 return Begin.takeError();
326 return End.takeError();
331 Callback<std::vector<TweakRef>> CB) {
332 auto Action = [
this, Sel](decltype(CB) CB, std::string
File,
333 Expected<InputsAndAST> InpAST) {
335 return CB(InpAST.takeError());
338 return CB(Selection.takeError());
339 std::vector<TweakRef> Res;
341 Res.push_back({T->id(), T->title(), T->intent()});
346 WorkScheduler.
runWithAST(
"EnumerateTweaks", File,
352 auto Action = [Sel](decltype(CB) CB, std::string
File, std::string TweakID,
353 Expected<InputsAndAST> InpAST) {
355 return CB(InpAST.takeError());
358 return CB(Selection.takeError());
361 return CB(A.takeError());
362 auto Effect = (*A)->apply(*Selection);
364 return CB(Effect.takeError());
365 if (Effect->ApplyEdit) {
369 InpAST->Inputs.FS.get());
371 *Effect->ApplyEdit, Style))
372 Effect->ApplyEdit = std::move(*Formatted);
374 elog(
"Failed to format replacements: {0}", Formatted.takeError());
376 return CB(std::move(*Effect));
380 Bind(
Action, std::move(CB), File.str(), TweakID.str()));
384 llvm::unique_function<
void(std::string)>
Callback) {
386 llvm::Expected<InputsAndAST> InpAST) {
388 llvm::consumeError(InpAST.takeError());
393 llvm::raw_string_ostream ResultOS(Result);
404 Callback<std::vector<LocatedSymbol>> CB) {
405 auto Action = [Pos,
this](decltype(CB) CB,
406 llvm::Expected<InputsAndAST> InpAST) {
408 return CB(InpAST.takeError());
417 llvm::StringRef SourceExtensions[] = {
".cpp",
".c",
".cc",
".cxx",
418 ".c++",
".m",
".mm"};
419 llvm::StringRef HeaderExtensions[] = {
".h",
".hh",
".hpp",
".hxx",
".inc"};
421 llvm::StringRef PathExt = llvm::sys::path::extension(Path);
425 llvm::find_if(SourceExtensions, [&PathExt](
PathRef SourceExt) {
426 return SourceExt.equals_lower(PathExt);
428 bool IsSource = SourceIter != std::end(SourceExtensions);
431 llvm::find_if(HeaderExtensions, [&PathExt](
PathRef HeaderExt) {
432 return HeaderExt.equals_lower(PathExt);
435 bool IsHeader = HeaderIter != std::end(HeaderExtensions);
438 if (!IsSource && !IsHeader)
443 llvm::ArrayRef<llvm::StringRef> NewExts;
445 NewExts = HeaderExtensions;
447 NewExts = SourceExtensions;
450 llvm::SmallString<128> NewPath = llvm::StringRef(Path);
456 for (llvm::StringRef NewExt : NewExts) {
457 llvm::sys::path::replace_extension(NewPath, NewExt);
458 if (
FS->exists(NewPath))
459 return NewPath.str().str();
464 llvm::sys::path::replace_extension(NewPath, NewExt.upper());
465 if (
FS->exists(NewPath))
466 return NewPath.str().str();
472 llvm::Expected<tooling::Replacements>
473 ClangdServer::formatCode(llvm::StringRef Code,
PathRef File,
474 llvm::ArrayRef<tooling::Range> Ranges) {
478 tooling::Replacements IncludeReplaces =
479 format::sortIncludes(Style, Code, Ranges, File);
480 auto Changed = tooling::applyAllReplacements(Code, IncludeReplaces);
484 return IncludeReplaces.merge(format::reformat(
486 tooling::calculateRangesAfterReplacements(IncludeReplaces, Ranges),
493 llvm::Expected<InputsAndAST> InpAST) {
495 return CB(InpAST.takeError());
503 Callback<llvm::Optional<HoverInfo>> CB) {
504 auto Action = [Pos,
this](decltype(CB) CB, Path
File,
505 llvm::Expected<InputsAndAST> InpAST) {
507 return CB(InpAST.takeError());
509 File, InpAST->Inputs.Contents, InpAST->Inputs.FS.get());
519 Callback<Optional<TypeHierarchyItem>> CB) {
520 std::string FileCopy =
File;
521 auto Action = [FileCopy, Pos, Resolve, Direction,
522 this](decltype(CB) CB, Expected<InputsAndAST> InpAST) {
524 return CB(InpAST.takeError());
534 Callback<llvm::Optional<TypeHierarchyItem>> CB) {
545 llvm::StringRef Query,
int Limit,
546 Callback<std::vector<SymbolInformation>> CB) {
547 std::string QueryCopy = Query;
549 "getWorkspaceSymbols",
551 [QueryCopy, Limit,
this](decltype(CB) CB) {
553 WorkspaceRoot.getValueOr(
"")));
559 Callback<std::vector<DocumentSymbol>> CB) {
561 llvm::Expected<InputsAndAST> InpAST) {
563 return CB(InpAST.takeError());
566 WorkScheduler.
runWithAST(
"documentSymbols", File,
571 Callback<std::vector<Location>> CB) {
573 llvm::Expected<InputsAndAST> InpAST) {
575 return CB(InpAST.takeError());
583 Callback<std::vector<SymbolDetails>> CB) {
585 llvm::Expected<InputsAndAST> InpAST) {
587 return CB(InpAST.takeError());
594 std::vector<std::pair<Path, std::size_t>>
603 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.