1 | //===--- HeuristicResolver.h - Resolution of dependent names -----*- 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 | #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_HEURISTICRESOLVER_H |
10 | #define |
11 | |
12 | #include "clang/AST/Decl.h" |
13 | #include <vector> |
14 | |
15 | namespace clang { |
16 | |
17 | class ASTContext; |
18 | class CallExpr; |
19 | class CXXBasePath; |
20 | class CXXDependentScopeMemberExpr; |
21 | class DeclarationName; |
22 | class DependentScopeDeclRefExpr; |
23 | class NamedDecl; |
24 | class Type; |
25 | class UnresolvedUsingValueDecl; |
26 | |
27 | namespace clangd { |
28 | |
29 | // This class heuristic resolution of declarations and types in template code. |
30 | // |
31 | // As a compiler, clang only needs to perform certain types of processing on |
32 | // template code (such as resolving dependent names to declarations, or |
33 | // resolving the type of a dependent expression) after instantiation. Indeed, |
34 | // C++ language features such as template specialization mean such resolution |
35 | // cannot be done accurately before instantiation |
36 | // |
37 | // However, template code is written and read in uninstantiated form, and clangd |
38 | // would like to provide editor features like go-to-definition in template code |
39 | // where possible. To this end, clangd attempts to resolve declarations and |
40 | // types in uninstantiated code by using heuristics, understanding that the |
41 | // results may not be fully accurate but that this is better than nothing. |
42 | // |
43 | // At this time, the heuristic used is a simple but effective one: assume that |
44 | // template instantiations are based on the primary template definition and not |
45 | // not a specialization. More advanced heuristics may be added in the future. |
46 | class HeuristicResolver { |
47 | public: |
48 | HeuristicResolver(ASTContext &Ctx) : Ctx(Ctx) {} |
49 | |
50 | // Try to heuristically resolve certain types of expressions, declarations, or |
51 | // types to one or more likely-referenced declarations. |
52 | std::vector<const NamedDecl *> |
53 | resolveMemberExpr(const CXXDependentScopeMemberExpr *ME) const; |
54 | std::vector<const NamedDecl *> |
55 | resolveDeclRefExpr(const DependentScopeDeclRefExpr *RE) const; |
56 | std::vector<const NamedDecl *> |
57 | resolveTypeOfCallExpr(const CallExpr *CE) const; |
58 | std::vector<const NamedDecl *> |
59 | resolveCalleeOfCallExpr(const CallExpr *CE) const; |
60 | std::vector<const NamedDecl *> |
61 | resolveUsingValueDecl(const UnresolvedUsingValueDecl *UUVD) const; |
62 | std::vector<const NamedDecl *> |
63 | resolveDependentNameType(const DependentNameType *DNT) const; |
64 | std::vector<const NamedDecl *> resolveTemplateSpecializationType( |
65 | const DependentTemplateSpecializationType *DTST) const; |
66 | |
67 | // Try to heuristically resolve a dependent nested name specifier |
68 | // to the type it likely denotes. Note that *dependent* name specifiers always |
69 | // denote types, not namespaces. |
70 | const Type * |
71 | resolveNestedNameSpecifierToType(const NestedNameSpecifier *NNS) const; |
72 | |
73 | // Given the type T of a dependent expression that appears of the LHS of a |
74 | // "->", heuristically find a corresponding pointee type in whose scope we |
75 | // could look up the name appearing on the RHS. |
76 | const Type *getPointeeType(const Type *T) const; |
77 | |
78 | private: |
79 | ASTContext &Ctx; |
80 | |
81 | // Given a tag-decl type and a member name, heuristically resolve the |
82 | // name to one or more declarations. |
83 | // The current heuristic is simply to look up the name in the primary |
84 | // template. This is a heuristic because the template could potentially |
85 | // have specializations that declare different members. |
86 | // Multiple declarations could be returned if the name is overloaded |
87 | // (e.g. an overloaded method in the primary template). |
88 | // This heuristic will give the desired answer in many cases, e.g. |
89 | // for a call to vector<T>::size(). |
90 | std::vector<const NamedDecl *> resolveDependentMember( |
91 | const Type *T, DeclarationName Name, |
92 | llvm::function_ref<bool(const NamedDecl *ND)> Filter) const; |
93 | |
94 | // Try to heuristically resolve the type of a possibly-dependent expression |
95 | // `E`. |
96 | const Type *resolveExprToType(const Expr *E) const; |
97 | std::vector<const NamedDecl *> resolveExprToDecls(const Expr *E) const; |
98 | |
99 | // Helper function for HeuristicResolver::resolveDependentMember() |
100 | // which takes a possibly-dependent type `T` and heuristically |
101 | // resolves it to a CXXRecordDecl in which we can try name lookup. |
102 | CXXRecordDecl *resolveTypeToRecordDecl(const Type *T) const; |
103 | |
104 | // This is a reimplementation of CXXRecordDecl::lookupDependentName() |
105 | // so that the implementation can call into other HeuristicResolver helpers. |
106 | // FIXME: Once HeuristicResolver is upstreamed to the clang libraries |
107 | // (https://github.com/clangd/clangd/discussions/1662), |
108 | // CXXRecordDecl::lookupDepenedentName() can be removed, and its call sites |
109 | // can be modified to benefit from the more comprehensive heuristics offered |
110 | // by HeuristicResolver instead. |
111 | std::vector<const NamedDecl *> lookupDependentName( |
112 | CXXRecordDecl *RD, DeclarationName Name, |
113 | llvm::function_ref<bool(const NamedDecl *ND)> Filter) const; |
114 | bool findOrdinaryMemberInDependentClasses(const CXXBaseSpecifier *Specifier, |
115 | CXXBasePath &Path, |
116 | DeclarationName Name) const; |
117 | }; |
118 | |
119 | } // namespace clangd |
120 | } // namespace clang |
121 | |
122 | #endif |
123 | |