brintos

brintos / llvm-project-archived public Read only

0
0
Text · 14.3 KiB · 1cf3b41 Raw
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