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 CXXDependentScopeMemberExpr;
20 class DeclarationName;
21 class DependentScopeDeclRefExpr;
22 class NamedDecl;
23 class Type;
24 class UnresolvedUsingValueDecl;
25 
26 namespace clangd {
27 
28 // This class heuristic resolution of declarations and types in template code.
29 //
30 // As a compiler, clang only needs to perform certain types of processing on
31 // template code (such as resolving dependent names to declarations, or
32 // resolving the type of a dependent expression) after instantiation. Indeed,
33 // C++ language features such as template specialization mean such resolution
34 // cannot be done accurately before instantiation
35 //
36 // However, template code is written and read in uninstantiated form, and clangd
37 // would like to provide editor features like go-to-definition in template code
38 // where possible. To this end, clangd attempts to resolve declarations and
39 // types in uninstantiated code by using heuristics, understanding that the
40 // results may not be fully accurate but that this is better than nothing.
41 //
42 // At this time, the heuristic used is a simple but effective one: assume that
43 // template instantiations are based on the primary template definition and not
44 // not a specialization. More advanced heuristics may be added in the future.
45 class HeuristicResolver {
46 public:
HeuristicResolver(ASTContext & Ctx)47   HeuristicResolver(ASTContext &Ctx) : Ctx(Ctx) {}
48 
49   // Try to heuristically resolve certain types of expressions, declarations, or
50   // types to one or more likely-referenced declarations.
51   std::vector<const NamedDecl *>
52   resolveMemberExpr(const CXXDependentScopeMemberExpr *ME) const;
53   std::vector<const NamedDecl *>
54   resolveDeclRefExpr(const DependentScopeDeclRefExpr *RE) const;
55   std::vector<const NamedDecl *>
56   resolveTypeOfCallExpr(const CallExpr *CE) const;
57   std::vector<const NamedDecl *>
58   resolveCalleeOfCallExpr(const CallExpr *CE) const;
59   std::vector<const NamedDecl *>
60   resolveUsingValueDecl(const UnresolvedUsingValueDecl *UUVD) const;
61   std::vector<const NamedDecl *>
62   resolveDependentNameType(const DependentNameType *DNT) const;
63   std::vector<const NamedDecl *> resolveTemplateSpecializationType(
64       const DependentTemplateSpecializationType *DTST) const;
65 
66   // Try to heuristically resolve a dependent nested name specifier
67   // to the type it likely denotes. Note that *dependent* name specifiers always
68   // denote types, not namespaces.
69   const Type *
70   resolveNestedNameSpecifierToType(const NestedNameSpecifier *NNS) const;
71 
72   // Given the type T of a dependent expression that appears of the LHS of a
73   // "->", heuristically find a corresponding pointee type in whose scope we
74   // could look up the name appearing on the RHS.
75   const Type *getPointeeType(const Type *T) const;
76 
77 private:
78   ASTContext &Ctx;
79 
80   // Given a tag-decl type and a member name, heuristically resolve the
81   // name to one or more declarations.
82   // The current heuristic is simply to look up the name in the primary
83   // template. This is a heuristic because the template could potentially
84   // have specializations that declare different members.
85   // Multiple declarations could be returned if the name is overloaded
86   // (e.g. an overloaded method in the primary template).
87   // This heuristic will give the desired answer in many cases, e.g.
88   // for a call to vector<T>::size().
89   std::vector<const NamedDecl *> resolveDependentMember(
90       const Type *T, DeclarationName Name,
91       llvm::function_ref<bool(const NamedDecl *ND)> Filter) const;
92 
93   // Try to heuristically resolve the type of a possibly-dependent expression
94   // `E`.
95   const Type *resolveExprToType(const Expr *E) const;
96   std::vector<const NamedDecl *> resolveExprToDecls(const Expr *E) const;
97 };
98 
99 } // namespace clangd
100 } // namespace clang
101 
102 #endif
103