mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-11-23 05:40:09 +00:00
0c1dcd6752
When resolving names inside templates that implement recursive compile-time functions (e.g. waldo<N>::type is defined in terms of waldo<N-1>::type), HeuristicResolver could get into an infinite recursion, specifically one where resolveDependentNameType() can be called recursively with the same DependentNameType*. To guard against this, HeuristicResolver tracks, for each external call into a HeuristicResolver function, the set of DependentNameTypes that it has seen, and bails if it sees the same DependentNameType again. To implement this, a helper class HeuristicResolverImpl is introduced to store state that persists for the duration of an external call into HeuristicResolver (but does not persist between such calls). Fixes https://github.com/clangd/clangd/issues/1951 (cherry picked from commit e6e53ca8470d719882539359ebe3ad8b442a8cb0)
86 lines
3.3 KiB
C++
86 lines
3.3 KiB
C++
//===--- HeuristicResolver.h - Resolution of dependent names -----*- C++-*-===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_HEURISTICRESOLVER_H
|
|
#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_HEURISTICRESOLVER_H
|
|
|
|
#include "clang/AST/Decl.h"
|
|
#include <vector>
|
|
|
|
namespace clang {
|
|
|
|
class ASTContext;
|
|
class CallExpr;
|
|
class CXXBasePath;
|
|
class CXXDependentScopeMemberExpr;
|
|
class DeclarationName;
|
|
class DependentScopeDeclRefExpr;
|
|
class NamedDecl;
|
|
class Type;
|
|
class UnresolvedUsingValueDecl;
|
|
|
|
namespace clangd {
|
|
|
|
// This class heuristic resolution of declarations and types in template code.
|
|
//
|
|
// As a compiler, clang only needs to perform certain types of processing on
|
|
// template code (such as resolving dependent names to declarations, or
|
|
// resolving the type of a dependent expression) after instantiation. Indeed,
|
|
// C++ language features such as template specialization mean such resolution
|
|
// cannot be done accurately before instantiation
|
|
//
|
|
// However, template code is written and read in uninstantiated form, and clangd
|
|
// would like to provide editor features like go-to-definition in template code
|
|
// where possible. To this end, clangd attempts to resolve declarations and
|
|
// types in uninstantiated code by using heuristics, understanding that the
|
|
// results may not be fully accurate but that this is better than nothing.
|
|
//
|
|
// At this time, the heuristic used is a simple but effective one: assume that
|
|
// template instantiations are based on the primary template definition and not
|
|
// not a specialization. More advanced heuristics may be added in the future.
|
|
class HeuristicResolver {
|
|
public:
|
|
HeuristicResolver(ASTContext &Ctx) : Ctx(Ctx) {}
|
|
|
|
// Try to heuristically resolve certain types of expressions, declarations, or
|
|
// types to one or more likely-referenced declarations.
|
|
std::vector<const NamedDecl *>
|
|
resolveMemberExpr(const CXXDependentScopeMemberExpr *ME) const;
|
|
std::vector<const NamedDecl *>
|
|
resolveDeclRefExpr(const DependentScopeDeclRefExpr *RE) const;
|
|
std::vector<const NamedDecl *>
|
|
resolveTypeOfCallExpr(const CallExpr *CE) const;
|
|
std::vector<const NamedDecl *>
|
|
resolveCalleeOfCallExpr(const CallExpr *CE) const;
|
|
std::vector<const NamedDecl *>
|
|
resolveUsingValueDecl(const UnresolvedUsingValueDecl *UUVD) const;
|
|
std::vector<const NamedDecl *>
|
|
resolveDependentNameType(const DependentNameType *DNT) const;
|
|
std::vector<const NamedDecl *> resolveTemplateSpecializationType(
|
|
const DependentTemplateSpecializationType *DTST) const;
|
|
|
|
// Try to heuristically resolve a dependent nested name specifier
|
|
// to the type it likely denotes. Note that *dependent* name specifiers always
|
|
// denote types, not namespaces.
|
|
const Type *
|
|
resolveNestedNameSpecifierToType(const NestedNameSpecifier *NNS) const;
|
|
|
|
// Given the type T of a dependent expression that appears of the LHS of a
|
|
// "->", heuristically find a corresponding pointee type in whose scope we
|
|
// could look up the name appearing on the RHS.
|
|
const Type *getPointeeType(const Type *T) const;
|
|
|
|
private:
|
|
ASTContext &Ctx;
|
|
};
|
|
|
|
} // namespace clangd
|
|
} // namespace clang
|
|
|
|
#endif
|