Sam McCall | 489cc58 | 2019-09-03 11:35:50 +0000 | [diff] [blame] | 1 | //===--- FindTarget.h - What does an AST node refer to? ---------*- 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-exception |
| 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | // |
| 9 | // Many clangd features are concerned with references in the AST: |
| 10 | // - xrefs, go-to-definition, explicitly talk about references |
| 11 | // - hover and code actions relate to things you "target" in the editor |
| 12 | // - refactoring actions need to know about entities that are referenced |
| 13 | // to determine whether/how the edit can be applied. |
| 14 | // |
| 15 | // Historically, we have used libIndex (IndexDataConsumer) to tie source |
| 16 | // locations to referenced declarations. This file defines a more decoupled |
| 17 | // approach based around AST nodes (DynTypedNode), and can be combined with |
| 18 | // SelectionTree or other traversals. |
| 19 | // |
| 20 | //===----------------------------------------------------------------------===// |
| 21 | |
Haojian Wu | c00627f | 2019-09-25 12:54:53 +0000 | [diff] [blame] | 22 | #ifndef LLVM_CLANG_TOOLS_EXTRA_UNITTESTS_CLANGD_FINDTARGET_H |
| 23 | #define LLVM_CLANG_TOOLS_EXTRA_UNITTESTS_CLANGD_FINDTARGET_H |
| 24 | |
Sam McCall | 489cc58 | 2019-09-03 11:35:50 +0000 | [diff] [blame] | 25 | #include "clang/AST/ASTTypeTraits.h" |
Ilya Biryukov | f96d2e1 | 2019-09-25 12:40:22 +0000 | [diff] [blame] | 26 | #include "clang/AST/NestedNameSpecifier.h" |
| 27 | #include "clang/AST/Stmt.h" |
Sam McCall | 489cc58 | 2019-09-03 11:35:50 +0000 | [diff] [blame] | 28 | #include "clang/Basic/SourceLocation.h" |
Ilya Biryukov | f96d2e1 | 2019-09-25 12:40:22 +0000 | [diff] [blame] | 29 | #include "llvm/ADT/Optional.h" |
| 30 | #include "llvm/ADT/STLExtras.h" |
Sam McCall | 489cc58 | 2019-09-03 11:35:50 +0000 | [diff] [blame] | 31 | #include "llvm/ADT/SmallPtrSet.h" |
Ilya Biryukov | f96d2e1 | 2019-09-25 12:40:22 +0000 | [diff] [blame] | 32 | #include "llvm/ADT/SmallVector.h" |
| 33 | #include "llvm/Support/raw_ostream.h" |
Sam McCall | 489cc58 | 2019-09-03 11:35:50 +0000 | [diff] [blame] | 34 | |
| 35 | #include <bitset> |
| 36 | |
| 37 | namespace clang { |
| 38 | namespace clangd { |
| 39 | /// Describes the link between an AST node and a Decl it refers to. |
| 40 | enum class DeclRelation : unsigned; |
| 41 | /// A bitfield of DeclRelations. |
| 42 | class DeclRelationSet; |
| 43 | |
| 44 | /// targetDecl() finds the declaration referred to by an AST node. |
| 45 | /// For example a RecordTypeLoc refers to the RecordDecl for the type. |
| 46 | /// |
| 47 | /// In some cases there are multiple results, e.g. a dependent unresolved |
| 48 | /// OverloadExpr may have several candidates. All will be returned: |
| 49 | /// |
| 50 | /// void foo(int); <-- candidate |
| 51 | /// void foo(double); <-- candidate |
| 52 | /// template <typename T> callFoo() { foo(T()); } |
| 53 | /// ^ OverloadExpr |
| 54 | /// |
| 55 | /// In other cases, there may be choices about what "referred to" means. |
| 56 | /// e.g. does naming a typedef refer to the underlying type? |
| 57 | /// The results are marked with a set of DeclRelations, and can be filtered. |
| 58 | /// |
| 59 | /// struct S{}; <-- candidate (underlying) |
| 60 | /// using T = S{}; <-- candidate (alias) |
| 61 | /// T x; |
| 62 | /// ^ TypedefTypeLoc |
| 63 | /// |
| 64 | /// Formally, we walk a graph starting at the provided node, and return the |
| 65 | /// decls that were found. Certain edges in the graph have labels, and for each |
| 66 | /// decl we return the set of labels seen on a path to the decl. |
| 67 | /// For the previous example: |
| 68 | /// |
| 69 | /// TypedefTypeLoc T |
| 70 | /// | |
| 71 | /// TypedefType T |
| 72 | /// / \ |
| 73 | /// [underlying] [alias] |
| 74 | /// / \ |
| 75 | /// RecordDecl S TypeAliasDecl T |
| 76 | /// |
| 77 | /// FIXME: some AST nodes cannot be DynTypedNodes, these cannot be specified. |
| 78 | llvm::SmallVector<const Decl *, 1> |
| 79 | targetDecl(const ast_type_traits::DynTypedNode &, DeclRelationSet Mask); |
| 80 | |
Ilya Biryukov | f96d2e1 | 2019-09-25 12:40:22 +0000 | [diff] [blame] | 81 | /// Information about a reference written in the source code, independent of the |
| 82 | /// actual AST node that this reference lives in. |
| 83 | /// Useful for tools that are source-aware, e.g. refactorings. |
| 84 | struct ReferenceLoc { |
| 85 | /// Contains qualifier written in the code, if any, e.g. 'ns::' for 'ns::foo'. |
| 86 | NestedNameSpecifierLoc Qualifier; |
| 87 | /// Start location of the last name part, i.e. 'foo' in 'ns::foo<int>'. |
| 88 | SourceLocation NameLoc; |
| 89 | // FIXME: add info about template arguments. |
| 90 | /// A list of targets referenced by this name. Normally this has a single |
| 91 | /// element, but multiple is also possible, e.g. in case of using declarations |
| 92 | /// or unresolved overloaded functions. |
| 93 | /// For dependent and unresolved references, Targets can also be empty. |
| 94 | llvm::SmallVector<const NamedDecl *, 1> Targets; |
| 95 | }; |
| 96 | llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, ReferenceLoc R); |
| 97 | |
| 98 | /// Recursively traverse \p S and report all references explicitly written in |
| 99 | /// the code. The main use-case is refactorings that need to process all |
| 100 | /// references in some subrange of the file and apply simple edits, e.g. add |
| 101 | /// qualifiers. |
| 102 | /// FIXME: currently this does not report references to overloaded operators. |
| 103 | /// FIXME: extend to report location information about declaration names too. |
Kadir Cetinkaya | 007e4fe | 2019-09-25 15:44:26 +0000 | [diff] [blame^] | 104 | void findExplicitReferences(const Stmt *S, |
Ilya Biryukov | f96d2e1 | 2019-09-25 12:40:22 +0000 | [diff] [blame] | 105 | llvm::function_ref<void(ReferenceLoc)> Out); |
Kadir Cetinkaya | 007e4fe | 2019-09-25 15:44:26 +0000 | [diff] [blame^] | 106 | void findExplicitReferences(const Decl *D, |
Ilya Biryukov | f96d2e1 | 2019-09-25 12:40:22 +0000 | [diff] [blame] | 107 | llvm::function_ref<void(ReferenceLoc)> Out); |
| 108 | |
Sam McCall | 489cc58 | 2019-09-03 11:35:50 +0000 | [diff] [blame] | 109 | /// Similar to targetDecl(), however instead of applying a filter, all possible |
| 110 | /// decls are returned along with their DeclRelationSets. |
| 111 | /// This is suitable for indexing, where everything is recorded and filtering |
| 112 | /// is applied later. |
| 113 | llvm::SmallVector<std::pair<const Decl *, DeclRelationSet>, 1> |
| 114 | allTargetDecls(const ast_type_traits::DynTypedNode &); |
| 115 | |
| 116 | enum class DeclRelation : unsigned { |
| 117 | // Template options apply when the declaration is an instantiated template. |
| 118 | // e.g. [[vector<int>]] vec; |
| 119 | |
| 120 | /// This is the template instantiation that was referred to. |
| 121 | /// e.g. template<> class vector<int> (the implicit specialization) |
| 122 | TemplateInstantiation, |
| 123 | /// This is the pattern the template specialization was instantiated from. |
| 124 | /// e.g. class vector<T> (the pattern within the primary template) |
| 125 | TemplatePattern, |
| 126 | |
| 127 | // Alias options apply when the declaration is an alias. |
| 128 | // e.g. namespace clang { [[StringRef]] S; } |
| 129 | |
| 130 | /// This declaration is an alias that was referred to. |
| 131 | /// e.g. using llvm::StringRef (the UsingDecl directly referenced). |
| 132 | Alias, |
| 133 | /// This is the underlying declaration for an alias, decltype etc. |
| 134 | /// e.g. class llvm::StringRef (the underlying declaration referenced). |
| 135 | Underlying, |
| 136 | }; |
| 137 | llvm::raw_ostream &operator<<(llvm::raw_ostream &, DeclRelation); |
| 138 | |
| 139 | class DeclRelationSet { |
| 140 | using Set = std::bitset<static_cast<unsigned>(DeclRelation::Underlying) + 1>; |
| 141 | Set S; |
| 142 | DeclRelationSet(Set S) : S(S) {} |
| 143 | |
| 144 | public: |
| 145 | DeclRelationSet() = default; |
| 146 | DeclRelationSet(DeclRelation R) { S.set(static_cast<unsigned>(R)); } |
| 147 | |
| 148 | explicit operator bool() const { return S.any(); } |
| 149 | friend DeclRelationSet operator&(DeclRelationSet L, DeclRelationSet R) { |
| 150 | return L.S & R.S; |
| 151 | } |
| 152 | friend DeclRelationSet operator|(DeclRelationSet L, DeclRelationSet R) { |
| 153 | return L.S | R.S; |
| 154 | } |
| 155 | friend bool operator==(DeclRelationSet L, DeclRelationSet R) { |
| 156 | return L.S == R.S; |
| 157 | } |
| 158 | friend DeclRelationSet operator~(DeclRelationSet R) { return ~R.S; } |
| 159 | DeclRelationSet &operator|=(DeclRelationSet Other) { |
| 160 | S |= Other.S; |
| 161 | return *this; |
| 162 | } |
| 163 | DeclRelationSet &operator&=(DeclRelationSet Other) { |
| 164 | S &= Other.S; |
| 165 | return *this; |
| 166 | } |
| 167 | friend llvm::raw_ostream &operator<<(llvm::raw_ostream &, DeclRelationSet); |
| 168 | }; |
| 169 | // The above operators can't be looked up if both sides are enums. |
| 170 | // over.match.oper.html#3.2 |
| 171 | inline DeclRelationSet operator|(DeclRelation L, DeclRelation R) { |
| 172 | return DeclRelationSet(L) | DeclRelationSet(R); |
| 173 | } |
| 174 | inline DeclRelationSet operator&(DeclRelation L, DeclRelation R) { |
| 175 | return DeclRelationSet(L) & DeclRelationSet(R); |
| 176 | } |
| 177 | inline DeclRelationSet operator~(DeclRelation R) { return ~DeclRelationSet(R); } |
| 178 | llvm::raw_ostream &operator<<(llvm::raw_ostream &, DeclRelationSet); |
| 179 | |
| 180 | } // namespace clangd |
| 181 | } // namespace clang |
Haojian Wu | c00627f | 2019-09-25 12:54:53 +0000 | [diff] [blame] | 182 | |
| 183 | #endif // LLVM_CLANG_TOOLS_EXTRA_UNITTESTS_CLANGD_FINDTARGET_H |