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
|
//===--- FindTarget.h - What does an AST node refer to? ---------*- 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
//
//===----------------------------------------------------------------------===//
//
// Many clangd features are concerned with references in the AST:
// - xrefs, go-to-definition, explicitly talk about references
// - hover and code actions relate to things you "target" in the editor
// - refactoring actions need to know about entities that are referenced
// to determine whether/how the edit can be applied.
//
// Historically, we have used libIndex (IndexDataConsumer) to tie source
// locations to referenced declarations. This file defines a more decoupled
// approach based around AST nodes (DynTypedNode), and can be combined with
// SelectionTree or other traversals.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_TOOLS_EXTRA_UNITTESTS_CLANGD_FINDTARGET_H
#define LLVM_CLANG_TOOLS_EXTRA_UNITTESTS_CLANGD_FINDTARGET_H
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTTypeTraits.h"
#include "clang/AST/NestedNameSpecifier.h"
#include "clang/AST/Stmt.h"
#include "clang/Basic/SourceLocation.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/raw_ostream.h"
#include <bitset>
namespace clang {
namespace clangd {
class HeuristicResolver;
/// Describes the link between an AST node and a Decl it refers to.
enum class DeclRelation : unsigned;
/// A bitfield of DeclRelations.
class DeclRelationSet;
/// targetDecl() finds the declaration referred to by an AST node.
/// For example a RecordTypeLoc refers to the RecordDecl for the type.
///
/// In some cases there are multiple results, e.g. a dependent unresolved
/// OverloadExpr may have several candidates. All will be returned:
///
/// void foo(int); <-- candidate
/// void foo(double); <-- candidate
/// template <typename T> callFoo() { foo(T()); }
/// ^ OverloadExpr
///
/// In other cases, there may be choices about what "referred to" means.
/// e.g. does naming a typedef refer to the underlying type?
/// The results are marked with a set of DeclRelations, and can be filtered.
///
/// struct S{}; <-- candidate (underlying)
/// using T = S{}; <-- candidate (alias)
/// T x;
/// ^ TypedefTypeLoc
///
/// Formally, we walk a graph starting at the provided node, and return the
/// decls that were found. Certain edges in the graph have labels, and for each
/// decl we return the set of labels seen on a path to the decl.
/// For the previous example:
///
/// TypedefTypeLoc T
/// |
/// TypedefType T
/// / \
/// [underlying] [alias]
/// / \
/// RecordDecl S TypeAliasDecl T
///
/// Note that this function only returns NamedDecls. Generally other decls
/// don't have references in this sense, just the node itself.
/// If callers want to support such decls, they should cast the node directly.
///
/// FIXME: some AST nodes cannot be DynTypedNodes, these cannot be specified.
llvm::SmallVector<const NamedDecl *, 1>
targetDecl(const DynTypedNode &, DeclRelationSet Mask,
const HeuristicResolver *Resolver);
/// Similar to targetDecl(), however instead of applying a filter, all possible
/// decls are returned along with their DeclRelationSets.
/// This is suitable for indexing, where everything is recorded and filtering
/// is applied later.
llvm::SmallVector<std::pair<const NamedDecl *, DeclRelationSet>, 1>
allTargetDecls(const DynTypedNode &, const HeuristicResolver *);
enum class DeclRelation : unsigned {
// Template options apply when the declaration is an instantiated template.
// e.g. [[vector<int>]] vec;
/// This is the template instantiation that was referred to.
/// e.g. template<> class vector<int> (the implicit specialization)
TemplateInstantiation,
/// This is the pattern the template specialization was instantiated from.
/// e.g. class vector<T> (the pattern within the primary template)
TemplatePattern,
// Alias options apply when the declaration is an alias.
// e.g. namespace client { [[X]] x; }
/// This declaration is an alias that was referred to.
/// e.g. using ns::X (the UsingDecl directly referenced),
/// using Z = ns::Y (the TypeAliasDecl directly referenced)
Alias,
/// This is the underlying declaration for a renaming-alias, decltype etc.
/// e.g. class ns::Y (the underlying declaration referenced).
///
/// Note that we don't treat `using ns::X` as a first-class declaration like
/// `using Z = ns::Y`. Therefore reference to X that goes through this
/// using-decl is considered a direct reference (without the Underlying bit).
/// Nevertheless, we report `using ns::X` as an Alias, so that some features
/// like go-to-definition can still target it.
Underlying,
};
llvm::raw_ostream &operator<<(llvm::raw_ostream &, DeclRelation);
/// Information about a reference written in the source code, independent of the
/// actual AST node that this reference lives in.
/// Useful for tools that are source-aware, e.g. refactorings.
struct ReferenceLoc {
/// Contains qualifier written in the code, if any, e.g. 'ns::' for 'ns::foo'.
NestedNameSpecifierLoc Qualifier;
/// Start location of the last name part, i.e. 'foo' in 'ns::foo<int>'.
SourceLocation NameLoc;
/// True if the reference is a declaration or definition;
bool IsDecl = false;
// FIXME: add info about template arguments.
/// A list of targets referenced by this name. Normally this has a single
/// element, but multiple is also possible, e.g. in case of using declarations
/// or unresolved overloaded functions.
/// For dependent and unresolved references, Targets can also be empty.
llvm::SmallVector<const NamedDecl *, 1> Targets;
};
llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, ReferenceLoc R);
/// Recursively traverse \p S and report all references explicitly written in
/// the code. The main use-case is refactorings that need to process all
/// references in some subrange of the file and apply simple edits, e.g. add
/// qualifiers.
/// FIXME: currently this does not report references to overloaded operators.
/// FIXME: extend to report location information about declaration names too.
void findExplicitReferences(const Stmt *S,
llvm::function_ref<void(ReferenceLoc)> Out,
const HeuristicResolver *Resolver);
void findExplicitReferences(const Decl *D,
llvm::function_ref<void(ReferenceLoc)> Out,
const HeuristicResolver *Resolver);
void findExplicitReferences(const ASTContext &AST,
llvm::function_ref<void(ReferenceLoc)> Out,
const HeuristicResolver *Resolver);
/// Find declarations explicitly referenced in the source code defined by \p N.
/// For templates, will prefer to return a template instantiation whenever
/// possible. However, can also return a template pattern if the specialization
/// cannot be picked, e.g. in dependent code or when there is no corresponding
/// Decl for a template instantiation, e.g. for templated using decls:
/// template <class T> using Ptr = T*;
/// Ptr<int> x;
/// ^~~ there is no Decl for 'Ptr<int>', so we return the template pattern.
/// \p Mask should not contain TemplatePattern or TemplateInstantiation.
llvm::SmallVector<const NamedDecl *, 1>
explicitReferenceTargets(DynTypedNode N, DeclRelationSet Mask,
const HeuristicResolver *Resolver);
// Boring implementation details of bitfield.
class DeclRelationSet {
using Set = std::bitset<static_cast<unsigned>(DeclRelation::Underlying) + 1>;
Set S;
DeclRelationSet(Set S) : S(S) {}
public:
DeclRelationSet() = default;
DeclRelationSet(DeclRelation R) { S.set(static_cast<unsigned>(R)); }
explicit operator bool() const { return S.any(); }
friend DeclRelationSet operator&(DeclRelationSet L, DeclRelationSet R) {
return L.S & R.S;
}
friend DeclRelationSet operator|(DeclRelationSet L, DeclRelationSet R) {
return L.S | R.S;
}
friend bool operator==(DeclRelationSet L, DeclRelationSet R) {
return L.S == R.S;
}
friend DeclRelationSet operator~(DeclRelationSet R) { return ~R.S; }
DeclRelationSet &operator|=(DeclRelationSet Other) {
S |= Other.S;
return *this;
}
DeclRelationSet &operator&=(DeclRelationSet Other) {
S &= Other.S;
return *this;
}
bool contains(DeclRelationSet Other) const {
return (S & Other.S) == Other.S;
}
friend llvm::raw_ostream &operator<<(llvm::raw_ostream &, DeclRelationSet);
};
// The above operators can't be looked up if both sides are enums.
// over.match.oper.html#3.2
inline DeclRelationSet operator|(DeclRelation L, DeclRelation R) {
return DeclRelationSet(L) | DeclRelationSet(R);
}
inline DeclRelationSet operator&(DeclRelation L, DeclRelation R) {
return DeclRelationSet(L) & DeclRelationSet(R);
}
inline DeclRelationSet operator~(DeclRelation R) { return ~DeclRelationSet(R); }
llvm::raw_ostream &operator<<(llvm::raw_ostream &, DeclRelationSet);
} // namespace clangd
} // namespace clang
#endif // LLVM_CLANG_TOOLS_EXTRA_UNITTESTS_CLANGD_FINDTARGET_H
|