HeuristicResolver.h (5442B)
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 LLVM_CLANG_TOOLS_EXTRA_CLANGD_HEURISTICRESOLVER_H 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