brintos

brintos / llvm-project-archived public Read only

0
0
Text · 10.4 KiB · 62c47dd Raw
266 lines · c
1//===--- Symbol.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#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_INDEX_SYMBOL_H10#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_INDEX_SYMBOL_H11 12#include "index/SymbolID.h"13#include "index/SymbolLocation.h"14#include "index/SymbolOrigin.h"15#include "clang/Index/IndexSymbol.h"16#include "llvm/ADT/BitmaskEnum.h"17#include "llvm/ADT/StringRef.h"18#include "llvm/Support/StringSaver.h"19 20namespace clang {21namespace clangd {22 23LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();24 25/// The class presents a C++ symbol, e.g. class, function.26///27/// WARNING: Symbols do not own much of their underlying data - typically28/// strings are owned by a SymbolSlab. They should be treated as non-owning29/// references. Copies are shallow.30///31/// When adding new unowned data fields to Symbol, remember to update:32///   - SymbolSlab::Builder in Index.cpp, to copy them to the slab's storage.33///   - mergeSymbol in Merge.cpp, to properly combine two Symbols.34///35/// A fully documented symbol can be split as:36/// size_type std::map<k, t>::count(const K& key) const37/// | Return  |     Scope     |Name|    Signature     |38/// We split up these components to allow display flexibility later.39struct Symbol {40  /// The ID of the symbol.41  SymbolID ID;42  /// The symbol information, like symbol kind.43  index::SymbolInfo SymInfo = index::SymbolInfo();44  /// The unqualified name of the symbol, e.g. "bar" (for ns::bar).45  llvm::StringRef Name;46  /// The containing namespace. e.g. "" (global), "ns::" (top-level namespace).47  llvm::StringRef Scope;48  /// The location of the symbol's definition, if one was found.49  /// This just covers the symbol name (e.g. without class/function body).50  SymbolLocation Definition;51  /// The location of the preferred declaration of the symbol.52  /// This just covers the symbol name.53  /// This may be the same as Definition.54  ///55  /// A C++ symbol may have multiple declarations, and we pick one to prefer.56  ///   * For classes, the canonical declaration should be the definition.57  ///   * For non-inline functions, the canonical declaration typically appears58  ///     in the ".h" file corresponding to the definition.59  SymbolLocation CanonicalDeclaration;60  /// The number of translation units that reference this symbol from their main61  /// file. This number is only meaningful if aggregated in an index.62  unsigned References = 0;63  /// Where this symbol came from. Usually an index provides a constant value.64  SymbolOrigin Origin = SymbolOrigin::Unknown;65  /// A brief description of the symbol that can be appended in the completion66  /// candidate list. For example, "(X x, Y y) const" is a function signature.67  /// Only set when the symbol is indexed for completion.68  llvm::StringRef Signature;69  /// Argument list in human-readable format, will be displayed to help70  /// disambiguate between different specializations of a template. Empty for71  /// non-specializations. Example: "<int, bool, 3>"72  llvm::StringRef TemplateSpecializationArgs;73  /// What to insert when completing this symbol, after the symbol name.74  /// This is in LSP snippet syntax (e.g. "({$0})" for a no-args function).75  /// (When snippets are disabled, the symbol name alone is used).76  /// Only set when the symbol is indexed for completion.77  llvm::StringRef CompletionSnippetSuffix;78  /// Documentation including comment for the symbol declaration.79  llvm::StringRef Documentation;80  /// Type when this symbol is used in an expression. (Short display form).81  /// e.g. return type of a function, or type of a variable.82  /// Only set when the symbol is indexed for completion.83  llvm::StringRef ReturnType;84 85  /// Raw representation of the OpaqueType of the symbol, used for scoring86  /// purposes.87  /// Only set when the symbol is indexed for completion.88  llvm::StringRef Type;89 90  enum IncludeDirective : uint8_t {91    Invalid = 0,92    /// `#include "header.h"`93    Include = 1,94    /// `#import "header.h"`95    Import = 2,96 97    LLVM_MARK_AS_BITMASK_ENUM(Import)98  };99 100  struct IncludeHeaderWithReferences {101    IncludeHeaderWithReferences() = default;102 103    IncludeHeaderWithReferences(llvm::StringRef IncludeHeader,104                                uint32_t References,105                                IncludeDirective SupportedDirectives)106        : IncludeHeader(IncludeHeader), References(References),107          SupportedDirectives(SupportedDirectives) {}108 109    /// This can be either a URI of the header to be #include'd110    /// for this symbol, or a literal header quoted with <> or "" that is111    /// suitable to be included directly. When it is a URI, the exact #include112    /// path needs to be calculated according to the URI scheme.113    ///114    /// Note that the include header is a canonical include for the symbol and115    /// can be different from FileURI in the CanonicalDeclaration.116    llvm::StringRef IncludeHeader = "";117    /// The number of translation units that reference this symbol and include118    /// this header. This number is only meaningful if aggregated in an index.119    uint32_t References : 30;120    /// Bitfield of supported directives (IncludeDirective) that can be used121    /// when including this header.122    uint32_t SupportedDirectives : 2;123 124    IncludeDirective supportedDirectives() const {125      return static_cast<IncludeDirective>(SupportedDirectives);126    }127  };128  /// One Symbol can potentially be included via different headers.129  ///   - If we haven't seen a definition, this covers all declarations.130  ///   - If we have seen a definition, this covers declarations visible from131  ///   any definition.132  /// Only set when the symbol is indexed for completion.133  llvm::SmallVector<IncludeHeaderWithReferences, 1> IncludeHeaders;134 135  enum SymbolFlag : uint8_t {136    None = 0,137    /// Whether or not this symbol is meant to be used for the code completion.138    /// See also isIndexedForCodeCompletion().139    /// Note that we don't store completion information (signature, snippet,140    /// type, includes) if the symbol is not indexed for code completion.141    IndexedForCodeCompletion = 1 << 0,142    /// Indicates if the symbol is deprecated.143    Deprecated = 1 << 1,144    /// Symbol is an implementation detail.145    ImplementationDetail = 1 << 2,146    /// Symbol is visible to other files (not e.g. a static helper function).147    VisibleOutsideFile = 1 << 3,148    /// Symbol has an attached documentation comment.149    HasDocComment = 1 << 4150  };151  SymbolFlag Flags = SymbolFlag::None;152 153  /// FIXME: also add deprecation message and fixit?154};155 156inline Symbol::SymbolFlag operator|(Symbol::SymbolFlag A,157                                    Symbol::SymbolFlag B) {158  return static_cast<Symbol::SymbolFlag>(static_cast<uint8_t>(A) |159                                         static_cast<uint8_t>(B));160}161inline Symbol::SymbolFlag &operator|=(Symbol::SymbolFlag &A,162                                      Symbol::SymbolFlag B) {163  return A = A | B;164}165 166llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Symbol &S);167llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, Symbol::SymbolFlag);168 169/// Invokes Callback with each StringRef& contained in the Symbol.170/// Useful for deduplicating backing strings.171template <typename Callback> void visitStrings(Symbol &S, const Callback &CB) {172  CB(S.Name);173  CB(S.Scope);174  CB(S.TemplateSpecializationArgs);175  CB(S.Signature);176  CB(S.CompletionSnippetSuffix);177  CB(S.Documentation);178  CB(S.ReturnType);179  CB(S.Type);180  auto RawCharPointerCB = [&CB](const char *&P) {181    llvm::StringRef S(P);182    CB(S);183    assert(!S.data()[S.size()] && "Visited StringRef must be null-terminated");184    P = S.data();185  };186  RawCharPointerCB(S.CanonicalDeclaration.FileURI);187  RawCharPointerCB(S.Definition.FileURI);188 189  for (auto &Include : S.IncludeHeaders)190    CB(Include.IncludeHeader);191}192 193/// Computes query-independent quality score for a Symbol.194/// This currently falls in the range [1, ln(#indexed documents)].195/// FIXME: this should probably be split into symbol -> signals196///        and signals -> score, so it can be reused for Sema completions.197float quality(const Symbol &S);198 199/// An immutable symbol container that stores a set of symbols.200/// The container will maintain the lifetime of the symbols.201class SymbolSlab {202public:203  using const_iterator = std::vector<Symbol>::const_iterator;204  using iterator = const_iterator;205  using value_type = Symbol;206 207  SymbolSlab() = default;208 209  const_iterator begin() const { return Symbols.begin(); }210  const_iterator end() const { return Symbols.end(); }211  const_iterator find(const SymbolID &SymID) const;212 213  using size_type = size_t;214  size_type size() const { return Symbols.size(); }215  bool empty() const { return Symbols.empty(); }216  // Estimates the total memory usage.217  size_t bytes() const {218    return sizeof(*this) + Arena.getTotalMemory() +219           Symbols.capacity() * sizeof(Symbol);220  }221 222  /// SymbolSlab::Builder is a mutable container that can 'freeze' to223  /// SymbolSlab. The frozen SymbolSlab will use less memory.224  class Builder {225  public:226    Builder() : UniqueStrings(Arena) {}227 228    /// Adds a symbol, overwriting any existing one with the same ID.229    /// This is a deep copy: underlying strings will be owned by the slab.230    void insert(const Symbol &S);231 232    /// Removes the symbol with an ID, if it exists.233    void erase(const SymbolID &ID) { Symbols.erase(ID); }234 235    /// Returns the symbol with an ID, if it exists. Valid until insert/remove.236    const Symbol *find(const SymbolID &ID) {237      auto I = Symbols.find(ID);238      return I == Symbols.end() ? nullptr : &I->second;239    }240 241    /// Consumes the builder to finalize the slab.242    SymbolSlab build() &&;243 244  private:245    llvm::BumpPtrAllocator Arena;246    /// Intern table for strings. Contents are on the arena.247    llvm::UniqueStringSaver UniqueStrings;248    /// Values are indices into Symbols vector.249    llvm::DenseMap<SymbolID, Symbol> Symbols;250  };251 252private:253  SymbolSlab(llvm::BumpPtrAllocator Arena, std::vector<Symbol> Symbols)254      : Arena(std::move(Arena)), Symbols(std::move(Symbols)) {}255 256  llvm::BumpPtrAllocator Arena; // Owns Symbol data that the Symbols do not.257  std::vector<Symbol> Symbols;  // Sorted by SymbolID to allow lookup.258};259 260llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const SymbolSlab &Slab);261 262} // namespace clangd263} // namespace clang264 265#endif // LLVM_CLANG_TOOLS_EXTRA_CLANGD_INDEX_SYMBOL_H266