325 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			325 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C++
		
	
	
	
//===--- 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
 |