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
15namespace clang {
16
17class ASTContext;
18class CallExpr;
19class CXXBasePath;
20class CXXDependentScopeMemberExpr;
21class DeclarationName;
22class DependentScopeDeclRefExpr;
23class NamedDecl;
24class Type;
25class UnresolvedUsingValueDecl;
26
27namespace 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.
46class HeuristicResolver {
47public:
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
78private:
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

source code of clang-tools-extra/clangd/HeuristicResolver.h