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