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
|
//===--- 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 "ClangdUnit.h"
#include "Headers.h"
#include "Logger.h"
#include "Path.h"
#include "Protocol.h"
#include "index/Index.h"
#include "index/Symbol.h"
#include "index/SymbolOrigin.h"
#include "clang/Frontend/PrecompiledPreamble.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 <future>
namespace clang {
class NamedDecl;
namespace clangd {
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;
/// Add code patterns to completion results.
/// If EnableSnippets is false, this options is ignored and code patterns will
/// always be omitted.
bool IncludeCodePatterns = true;
/// Add macros to code completion results.
bool IncludeMacros = true;
/// Add comments to code completion results, if available.
bool IncludeComments = true;
/// 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 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;
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;
/// If set to true, this will send an asynchronous speculative index request,
/// based on the index request for the last code completion on the same file
/// and the filter text typed before the cursor, before sema code completion
/// is invoked. This can reduce the code completion latency (by roughly
/// latency of sema code completion) if the speculative request is the same as
/// the one generated for the ongoing code completion from sema. As a sequence
/// of code completions often have the same scopes and proximity paths etc,
/// this should be effective for a number of code completions.
bool SpeculativeIndexRequest = 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;
/// 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;
};
// 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;
std::string 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;
// 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,
const tooling::CompileCommand &Command,
const PreambleData *Preamble,
StringRef Contents, Position Pos,
IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS,
CodeCompleteOptions Opts,
SpeculativeFuzzyFind *SpecFuzzyFind = nullptr);
/// Get signature help at a specified \p Pos in \p FileName.
SignatureHelp signatureHelp(PathRef FileName,
const tooling::CompileCommand &Command,
const PreambleData *Preamble, StringRef Contents,
Position Pos,
IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS,
const SymbolIndex *Index);
// 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);
} // namespace clangd
} // namespace clang
#endif // LLVM_CLANG_TOOLS_EXTRA_CLANGD_CODECOMPLETE_H
|