339 lines · c
1//===--- CodeComplete.h ------------------------------------------*- C++-*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// Code completion provides suggestions for what the user might type next.10// After "std::string S; S." we might suggest members of std::string.11// Signature help describes the parameters of a function as you type them.12//13//===----------------------------------------------------------------------===//14 15#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_CODECOMPLETE_H16#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_CODECOMPLETE_H17 18#include "ASTSignals.h"19#include "Compiler.h"20#include "Config.h"21#include "Protocol.h"22#include "Quality.h"23#include "index/Index.h"24#include "index/Symbol.h"25#include "index/SymbolOrigin.h"26#include "support/Markup.h"27#include "support/Path.h"28#include "clang/Sema/CodeCompleteConsumer.h"29#include "clang/Sema/CodeCompleteOptions.h"30#include "llvm/ADT/SmallVector.h"31#include "llvm/ADT/StringRef.h"32#include <functional>33#include <future>34#include <optional>35#include <utility>36 37namespace clang {38class NamedDecl;39namespace clangd {40struct PreambleData;41struct CodeCompletion;42 43struct CodeCompleteOptions {44 /// Returns options that can be passed to clang's completion engine.45 clang::CodeCompleteOptions getClangCompleteOpts() const;46 47 /// When true, completion items will contain expandable code snippets in48 /// completion (e.g. `return ${1:expression}` or `foo(${1:int a}, ${2:int49 /// b})).50 bool EnableSnippets = false;51 52 /// Include results that are not legal completions in the current context.53 /// For example, private members are usually inaccessible.54 bool IncludeIneligibleResults = false;55 56 /// Force sema to load decls from preamble even if an index is provided.57 /// This is helpful for cases the index can't provide symbols, e.g. with58 /// experimental c++20 modules59 bool ForceLoadPreamble = false;60 61 /// Combine overloads into a single completion item where possible.62 /// If none, the implementation may choose an appropriate behavior.63 /// (In practice, ClangdLSPServer enables bundling if the client claims64 /// to supports signature help).65 std::optional<bool> BundleOverloads;66 67 /// Limit the number of results returned (0 means no limit).68 /// If more results are available, we set CompletionList.isIncomplete.69 size_t Limit = 0;70 71 /// Whether to present doc comments as plain-text or markdown.72 MarkupKind DocumentationFormat = MarkupKind::PlainText;73 74 Config::HeaderInsertionPolicy InsertIncludes =75 Config::HeaderInsertionPolicy::IWYU;76 77 /// Whether include insertions for Objective-C code should use #import instead78 /// of #include.79 bool ImportInsertions = false;80 81 /// A visual indicator to prepend to the completion label to indicate whether82 /// completion result would trigger an #include insertion or not.83 struct IncludeInsertionIndicator {84 std::string Insert = "•";85 std::string NoInsert = " ";86 } IncludeIndicator;87 88 /// Expose origins of completion items in the label (for debugging).89 bool ShowOrigins = false;90 91 // Populated internally by clangd, do not set.92 /// If `Index` is set, it is used to augment the code completion93 /// results.94 /// FIXME(ioeric): we might want a better way to pass the index around inside95 /// clangd.96 const SymbolIndex *Index = nullptr;97 98 const ASTSignals *MainFileSignals = nullptr;99 /// Include completions that require small corrections, e.g. change '.' to100 /// '->' on member access etc.101 bool IncludeFixIts = false;102 103 /// Whether to include index symbols that are not defined in the scopes104 /// visible from the code completion point. This applies in contexts without105 /// explicit scope qualifiers.106 ///107 /// Such completions can insert scope qualifiers.108 bool AllScopes = false;109 110 /// The way argument list on calls '()' and generics '<>' are handled.111 Config::ArgumentListsPolicy ArgumentLists =112 Config::ArgumentListsPolicy::FullPlaceholders;113 114 /// Whether to suggest code patterns & snippets or not in completion115 Config::CodePatternsPolicy CodePatterns = Config::CodePatternsPolicy::All;116 117 /// Whether to use the clang parser, or fallback to text-based completion118 /// (using identifiers in the current file and symbol indexes).119 enum CodeCompletionParse {120 /// Block until we can run the parser (e.g. preamble is built).121 /// Return an error if this fails.122 AlwaysParse,123 /// Run the parser if inputs (preamble) are ready.124 /// Otherwise, use text-based completion.125 ParseIfReady,126 /// Always use text-based completion.127 NeverParse,128 } RunParser = ParseIfReady;129 130 /// Callback invoked on all CompletionCandidate after they are scored and131 /// before they are ranked (by -Score). Thus the results are yielded in132 /// arbitrary order.133 ///134 /// This callbacks allows capturing various internal structures used by clangd135 /// during code completion. Eg: Symbol quality and relevance signals.136 std::function<void(const CodeCompletion &, const SymbolQualitySignals &,137 const SymbolRelevanceSignals &, float Score)>138 RecordCCResult;139 140 /// Model to use for ranking code completion candidates.141 enum CodeCompletionRankingModel {142 Heuristics,143 DecisionForest,144 };145 static const CodeCompletionRankingModel DefaultRankingModel;146 CodeCompletionRankingModel RankingModel = DefaultRankingModel;147 148 /// Callback used to score a CompletionCandidate if DecisionForest ranking149 /// model is enabled.150 /// This allows us to inject experimental models and compare them with151 /// baseline model using A/B testing.152 std::function<DecisionForestScores(153 const SymbolQualitySignals &, const SymbolRelevanceSignals &, float Base)>154 DecisionForestScorer = &evaluateDecisionForest;155 /// Weight for combining NameMatch and Prediction of DecisionForest.156 /// CompletionScore is NameMatch * pow(Base, Prediction).157 /// The optimal value of Base largely depends on the semantics of the model158 /// and prediction score (e.g. algorithm used during training, number of159 /// trees, etc.). Usually if the range of Prediction is [-20, 20] then a Base160 /// in [1.2, 1.7] works fine.161 /// Semantics: E.g. For Base = 1.3, if the Prediction score reduces by 2.6162 /// points then completion score reduces by 50% or 1.3^(-2.6).163 float DecisionForestBase = 1.3f;164};165 166// Semi-structured representation of a code-complete suggestion for our C++ API.167// We don't use the LSP structures here (unlike most features) as we want168// to expose more data to allow for more precise testing and evaluation.169struct CodeCompletion {170 // The unqualified name of the symbol or other completion item.171 std::string Name;172 // The name of the symbol for filtering and sorting purposes. Typically the173 // same as `Name`, but may be different e.g. for ObjC methods, `Name` is the174 // first selector fragment but the `FilterText` is the entire selector.175 std::string FilterText;176 // The scope qualifier for the symbol name. e.g. "ns1::ns2::"177 // Empty for non-symbol completions. Not inserted, but may be displayed.178 std::string Scope;179 // Text that must be inserted before the name, and displayed (e.g. base::).180 std::string RequiredQualifier;181 // Details to be displayed following the name. Not inserted.182 std::string Signature;183 // Text to be inserted following the name, in snippet format.184 std::string SnippetSuffix;185 // Type to be displayed for this completion.186 std::string ReturnType;187 // The parsed documentation comment.188 std::optional<markup::Document> Documentation;189 CompletionItemKind Kind = CompletionItemKind::Missing;190 // This completion item may represent several symbols that can be inserted in191 // the same way, such as function overloads. In this case BundleSize > 1, and192 // the following fields are summaries:193 // - Signature is e.g. "(...)" for functions.194 // - SnippetSuffix is similarly e.g. "(${0})".195 // - ReturnType may be empty196 // - Documentation may be from one symbol, or a combination of several197 // Other fields should apply equally to all bundled completions.198 unsigned BundleSize = 1;199 SymbolOrigin Origin = SymbolOrigin::Unknown;200 201 struct IncludeCandidate {202 // The header through which this symbol could be included.203 // Quoted string as expected by an #include directive, e.g. "<memory>".204 // Empty for non-symbol completions, or when not known.205 std::string Header;206 // Present if Header should be inserted to use this item.207 std::optional<TextEdit> Insertion;208 };209 // All possible include headers ranked by preference. By default, the first210 // include is used.211 // If we've bundled together overloads that have different sets of includes,212 // thse includes may not be accurate for all of them.213 llvm::SmallVector<IncludeCandidate, 1> Includes;214 215 /// Holds information about small corrections that needs to be done. Like216 /// converting '->' to '.' on member access.217 std::vector<TextEdit> FixIts;218 219 /// Holds the range of the token we are going to replace with this completion.220 Range CompletionTokenRange;221 222 // Scores are used to rank completion items.223 struct Scores {224 // The score that items are ranked by.225 float Total = 0.f;226 227 // The finalScore with the fuzzy name match score excluded.228 // When filtering client-side, editors should calculate the new fuzzy score,229 // whose scale is 0-1 (with 1 = prefix match, special case 2 = exact match),230 // and recompute finalScore = fuzzyScore * symbolScore.231 float ExcludingName = 0.f;232 233 // Component scores that contributed to the final score:234 235 // Quality describes how important we think this candidate is,236 // independent of the query.237 // e.g. symbols with lots of incoming references have higher quality.238 float Quality = 0.f;239 // Relevance describes how well this candidate matched the query.240 // e.g. symbols from nearby files have higher relevance.241 float Relevance = 0.f;242 };243 Scores Score;244 245 /// Indicates if this item is deprecated.246 bool Deprecated = false;247 248 // Serialize this to an LSP completion item. This is a lossy operation.249 CompletionItem render(const CodeCompleteOptions &) const;250};251raw_ostream &operator<<(raw_ostream &, const CodeCompletion &);252struct CodeCompleteResult {253 std::vector<CodeCompletion> Completions;254 bool HasMore = false;255 CodeCompletionContext::Kind Context = CodeCompletionContext::CCC_Other;256 // The text that is being directly completed.257 // Example: foo.pb^ -> foo.push_back()258 // ~~259 // Typically matches the textEdit.range of Completions, but not guaranteed to.260 std::optional<Range> CompletionRange;261 // Usually the source will be parsed with a real C++ parser.262 // But heuristics may be used instead if e.g. the preamble is not ready.263 bool RanParser = true;264};265raw_ostream &operator<<(raw_ostream &, const CodeCompleteResult &);266 267/// A speculative and asynchronous fuzzy find index request (based on cached268/// request) that can be sent before parsing sema. This would reduce completion269/// latency if the speculation succeeds.270struct SpeculativeFuzzyFind {271 /// A cached request from past code completions.272 /// Set by caller of `codeComplete()`.273 std::optional<FuzzyFindRequest> CachedReq;274 /// The actual request used by `codeComplete()`.275 /// Set by `codeComplete()`. This can be used by callers to update cache.276 std::optional<FuzzyFindRequest> NewReq;277 /// The result is consumed by `codeComplete()` if speculation succeeded.278 std::future<std::pair<bool /*Incomplete*/, SymbolSlab>> Result;279};280 281/// Gets code completions at a specified \p Pos in \p FileName.282///283/// If \p Preamble is nullptr, this runs code completion without compiling the284/// code.285///286/// If \p SpecFuzzyFind is set, a speculative and asynchronous fuzzy find index287/// request (based on cached request) will be run before parsing sema. In case288/// the speculative result is used by code completion (e.g. speculation failed),289/// the speculative result is not consumed, and `SpecFuzzyFind` is only290/// destroyed when the async request finishes.291CodeCompleteResult codeComplete(PathRef FileName, Position Pos,292 const PreambleData *Preamble,293 const ParseInputs &ParseInput,294 CodeCompleteOptions Opts,295 SpeculativeFuzzyFind *SpecFuzzyFind = nullptr);296 297/// Get signature help at a specified \p Pos in \p FileName.298SignatureHelp signatureHelp(PathRef FileName, Position Pos,299 const PreambleData &Preamble,300 const ParseInputs &ParseInput,301 MarkupKind DocumentationFormat);302 303// For index-based completion, we only consider:304// * symbols in namespaces or translation unit scopes (e.g. no class305// members, no locals)306// * enum constants (both scoped and unscoped)307// * primary templates (no specializations)308// For the other cases, we let Clang do the completion because it does not309// need any non-local information and it will be much better at following310// lookup rules. Other symbols still appear in the index for other purposes,311// like workspace/symbols or textDocument/definition, but are not used for code312// completion.313bool isIndexedForCodeCompletion(const NamedDecl &ND, ASTContext &ASTCtx);314 315// Text immediately before the completion point that should be completed.316// This is heuristically derived from the source code, and is used when:317// - semantic analysis fails318// - semantic analysis may be slow, and we speculatively query the index319struct CompletionPrefix {320 // The unqualified partial name.321 // If there is none, begin() == end() == completion position.322 llvm::StringRef Name;323 // The spelled scope qualifier, such as Foo::.324 // If there is none, begin() == end() == Name.begin().325 llvm::StringRef Qualifier;326};327// Heuristically parses before Offset to determine what should be completed.328CompletionPrefix guessCompletionPrefix(llvm::StringRef Content,329 unsigned Offset);330 331// Whether it makes sense to complete at the point based on typed characters.332// For instance, we implicitly trigger at `a->^` but not at `a>^`.333bool allowImplicitCompletion(llvm::StringRef Content, unsigned Offset);334 335} // namespace clangd336} // namespace clang337 338#endif // LLVM_CLANG_TOOLS_EXTRA_CLANGD_CODECOMPLETE_H339