24 #include "llvm/ADT/DenseMap.h" 25 #include "llvm/ADT/STLExtras.h" 26 #include "llvm/ADT/SetVector.h" 27 #include "llvm/ADT/SmallVector.h" 28 #include "llvm/ADT/iterator_range.h" 29 #include "llvm/Support/Casting.h" 35 using namespace clang;
39 void CXXBasePaths::ComputeDeclsFound() {
40 assert(NumDeclsFound == 0 && !DeclsFound &&
41 "Already computed the set of declarations");
45 Decls.insert(Path->Decls.front());
47 NumDeclsFound = Decls.size();
48 DeclsFound = llvm::make_unique<NamedDecl *[]>(NumDeclsFound);
49 std::copy(Decls.begin(), Decls.end(), DeclsFound.get());
53 if (NumDeclsFound == 0)
66 IsVirtBaseAndNumberNonVirtBases Subobjects = ClassSubobjects[BaseType];
67 return Subobjects.NumberOfNonVirtBases + (Subobjects.IsVirtBase ? 1 : 0) > 1;
73 ClassSubobjects.clear();
74 VisitedDependentRecords.clear();
76 DetectedVirtual =
nullptr;
82 std::swap(Origin, Other.Origin);
83 Paths.swap(Other.Paths);
84 ClassSubobjects.swap(Other.ClassSubobjects);
85 VisitedDependentRecords.swap(Other.VisitedDependentRecords);
86 std::swap(FindAmbiguities, Other.FindAmbiguities);
87 std::swap(RecordPaths, Other.RecordPaths);
88 std::swap(DetectVirtual, Other.DetectVirtual);
89 std::swap(DetectedVirtual, Other.DetectedVirtual);
95 return isDerivedFrom(Base, Paths);
103 Paths.
setOrigin(const_cast<CXXRecordDecl*>(
this));
106 return lookupInBases(
108 return FindBaseClass(Specifier, Path, BaseDecl);
123 Paths.
setOrigin(const_cast<CXXRecordDecl*>(
this));
126 return lookupInBases(
128 return FindVirtualBaseClass(Specifier, Path, BaseDecl);
142 assert(isDependentContext());
145 if (CurContext->
Equals(
this))
152 bool AllowShortCircuit)
const {
156 bool AllMatches =
true;
158 for (
const auto &I : Record->
bases()) {
161 if (AllowShortCircuit)
return false;
171 if (AllowShortCircuit)
return false;
176 Queue.push_back(Base);
177 if (!BaseMatches(Base)) {
178 if (AllowShortCircuit)
return false;
186 Record = Queue.pop_back_val();
192 bool CXXBasePaths::lookupInBases(
ASTContext &Context,
195 bool LookupInDependent) {
196 bool FoundPath =
false;
200 bool IsFirstStep = ScratchPath.empty();
202 for (
const auto &BaseSpec : Record->
bases()) {
218 IsVirtBaseAndNumberNonVirtBases &Subobjects = ClassSubobjects[BaseType];
219 bool VisitBase =
true;
220 bool SetVirtual =
false;
221 if (BaseSpec.isVirtual()) {
222 VisitBase = !Subobjects.IsVirtBase;
223 Subobjects.IsVirtBase =
true;
231 ++Subobjects.NumberOfNonVirtBases;
236 Element.
Base = &BaseSpec;
237 Element.
Class = Record;
238 if (BaseSpec.isVirtual())
242 ScratchPath.push_back(Element);
260 ScratchPath.
Access = BaseSpec.getAccessSpecifier();
263 BaseSpec.getAccessSpecifier());
267 bool FoundPathThroughBase =
false;
269 if (BaseMatches(&BaseSpec, ScratchPath)) {
271 FoundPath = FoundPathThroughBase =
true;
274 Paths.push_back(ScratchPath);
280 }
else if (VisitBase) {
282 if (LookupInDependent) {
283 BaseRecord =
nullptr;
287 if (
auto *RT = BaseSpec.getType()->getAs<
RecordType>())
288 BaseRecord = cast<CXXRecordDecl>(RT->getDecl());
293 BaseRecord = TD->getTemplatedDecl();
297 VisitedDependentRecords.count(BaseRecord)) {
298 BaseRecord =
nullptr;
300 VisitedDependentRecords.insert(BaseRecord);
304 BaseRecord = cast<CXXRecordDecl>(
305 BaseSpec.getType()->castAs<
RecordType>()->getDecl());
308 lookupInBases(Context, BaseRecord, BaseMatches, LookupInDependent)) {
317 FoundPath = FoundPathThroughBase =
true;
326 ScratchPath.pop_back();
330 if (SetVirtual && !FoundPathThroughBase) {
331 DetectedVirtual =
nullptr;
336 ScratchPath.
Access = AccessToHere;
343 bool LookupInDependent)
const {
345 if (!Paths.lookupInBases(getASTContext(),
this, BaseMatches,
364 Paths.Paths.remove_if([&Paths](
const CXXBasePath &Path) {
366 if (!PE.Base->isVirtual())
371 VBase = cast<CXXRecordDecl>(Record->getDecl());
382 HidingP.back().Base->getType()->getAs<
RecordType>())
383 HidingClass = cast<CXXRecordDecl>(Record->getDecl());
401 "User data for FindBaseClass is not canonical!");
403 ->getCanonicalDecl() == BaseRecord;
410 "User data for FindBaseClass is not canonical!");
413 ->getCanonicalDecl() == BaseRecord;
425 if (Path.
Decls.
front()->isInIdentifierNamespace(IDNS_Tag))
439 if (Path.
Decls.
front()->isInIdentifierNamespace(IDNS))
466 const auto *TD = dyn_cast_or_null<ClassTemplateDecl>(TN.getAsTemplateDecl());
483 if (Path.
Decls.
front()->isInIdentifierNamespace(IDNS_OMPReduction))
501 if (isa<TypedefNameDecl>(Path.
Decls.
front()) ||
502 Path.
Decls.
front()->isInIdentifierNamespace(IDNS_Tag))
512 std::vector<const NamedDecl *> Results;
515 if (!DirectResult.
empty()) {
516 for (
const NamedDecl *ND : DirectResult) {
518 Results.push_back(ND);
528 Specifier, Path, Name);
534 Results.push_back(ND);
542 = Overrides[OverriddenSubobject];
543 if (std::find(SubobjectOverrides.begin(), SubobjectOverrides.end(),
544 Overriding) == SubobjectOverrides.end())
545 SubobjectOverrides.push_back(Overriding);
551 MEnd = I->second.end();
561 I->second.push_back(Overriding);
567 class FinalOverriderCollector {
570 llvm::DenseMap<const CXXRecordDecl *, unsigned> SubobjectCount;
573 llvm::DenseMap<const CXXRecordDecl *, CXXFinalOverriderMap *> VirtualOverriders;
578 ~FinalOverriderCollector();
587 void FinalOverriderCollector::Collect(
const CXXRecordDecl *RD,
591 unsigned SubobjectNumber = 0;
598 const CXXRecordDecl *BaseDecl = cast<CXXRecordDecl>(RT->getDecl());
602 if (Overriders.empty() && !
Base.isVirtual()) {
605 Collect(BaseDecl,
false, InVirtualSubobject, Overriders);
616 if (
Base.isVirtual()) {
618 BaseOverriders = MyVirtualOverriders;
619 if (!MyVirtualOverriders) {
625 BaseOverriders = MyVirtualOverriders;
627 Collect(BaseDecl,
true, BaseDecl, *MyVirtualOverriders);
630 Collect(BaseDecl,
false, InVirtualSubobject, ComputedBaseOverriders);
634 for (CXXFinalOverriderMap::iterator OM = BaseOverriders->begin(),
635 OMEnd = BaseOverriders->end();
639 Overriders[CanonOM].add(OM->second);
644 for (
auto *M : RD->
methods()) {
650 using OverriddenMethodsRange =
651 llvm::iterator_range<CXXMethodDecl::method_iterator>;
654 if (OverriddenMethods.begin() == OverriddenMethods.end()) {
661 Overriders[CanonM].add(SubobjectNumber,
663 InVirtualSubobject));
674 while (!Stack.empty()) {
687 Overriders[CanonOM].replaceAll(
689 InVirtualSubobject));
692 if (OverriddenMethods.begin() == OverriddenMethods.end())
697 Stack.push_back(OverriddenMethods);
703 Overriders[CanonM].add(SubobjectNumber,
705 InVirtualSubobject));
709 FinalOverriderCollector::~FinalOverriderCollector() {
710 for (llvm::DenseMap<const CXXRecordDecl *, CXXFinalOverriderMap *>::iterator
711 VO = VirtualOverriders.begin(), VOEnd = VirtualOverriders.end();
719 FinalOverriderCollector Collector;
720 Collector.Collect(
this,
false,
nullptr, FinalOverriders);
725 for (
auto &OM : FinalOverriders) {
726 for (
auto &SO : OM.second) {
728 if (Overriding.size() < 2)
732 if (!M.InVirtualSubobject)
742 OP.Method->getParent()->isVirtuallyDerivedFrom(
743 M.InVirtualSubobject))
749 std::remove_if(Overriding.begin(), Overriding.end(), IsHidden),
763 for (
const auto &I : RD->
bases()) {
764 assert(!I.getType()->isDependentType() &&
765 "Cannot get indirect primary bases for class with dependent bases.");
768 cast<CXXRecordDecl>(I.getType()->castAs<
RecordType>()->getDecl());
772 if (BaseDecl->getNumVBases())
785 for (
const auto &I : bases()) {
786 assert(!I.getType()->isDependentType() &&
787 "Cannot get indirect primary bases for class with dependent bases.");
790 cast<CXXRecordDecl>(I.getType()->castAs<
RecordType>()->getDecl());
794 if (BaseDecl->getNumVBases())
Defines the clang::ASTContext interface.
static const Decl * getCanonicalDecl(const Decl *D)
void setOrigin(CXXRecordDecl *Rec)
bool isPrimaryBaseVirtual() const
isPrimaryBaseVirtual - Get whether the primary base for this record is virtual or not...
A (possibly-)qualified type.
const ASTRecordLayout & getASTRecordLayout(const RecordDecl *D) const
Get or compute information about the layout of the specified record (struct/union/class) D...
llvm::iterator_range< decl_iterator > decl_range
C Language Family Type Representation.
bool isVirtual() const
Determines whether the base class is a virtual base class (or not).
Defines the C++ template declaration subclasses.
void swap(CXXBasePaths &Other)
Swap this data structure's contents with another CXXBasePaths object.
CanQual< T > getUnqualifiedType() const
Retrieve the unqualified form of this type.
bool isDerivedFrom(const CXXRecordDecl *Base) const
Determine whether this class is derived from the class Base.
SmallVectorImpl< UniqueVirtualMethod >::const_iterator overriding_const_iterator
AccessSpecifier
A C++ access specifier (public, private, protected), plus the special value "none" which means differ...
const NestedNameSpecifier * Specifier
Represents a path from a specific derived class (which is not represented as part of the path) to a p...
std::list< CXXBasePath >::iterator paths_iterator
DeclContext::lookup_result Decls
The set of declarations found inside this base class subobject.
const T * getAs() const
Member-template getAs<specific type>'.
static bool FindOrdinaryMemberInDependentClasses(const CXXBaseSpecifier *Specifier, CXXBasePath &Path, DeclarationName Name)
Base-class lookup callback that determines whether there exists a member with the given name...
void clear()
Clear the base-paths results.
static bool FindOMPReductionMember(const CXXBaseSpecifier *Specifier, CXXBasePath &Path, DeclarationName Name)
Base-class lookup callback that determines whether there exists an OpenMP declare reduction member wi...
bool hasDefinition() const
std::vector< const NamedDecl * > lookupDependentName(const DeclarationName &Name, llvm::function_ref< bool(const NamedDecl *ND)> Filter)
Performs an imprecise lookup of a dependent name in this class.
bool isRecordingPaths() const
Whether we are recording paths.
Represents a struct/union/class.
bool isFindingAmbiguities() const
Whether we are finding multiple paths to detect ambiguities.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
The results of name lookup within a DeclContext.
TemplateDecl * getAsTemplateDecl() const
Retrieve the underlying template declaration that this template name refers to, if known...
RecordDecl * getDefinition() const
Returns the RecordDecl that actually defines this struct/union/class.
TemplateName getTemplateName() const
Retrieve the name of the template that we are specializing.
CXXMethodDecl * getCanonicalDecl() override
Retrieves the "canonical" declaration of the given declaration.
bool Equals(const DeclContext *DC) const
Determine whether this declaration context is equivalent to the declaration context DC...
void add(unsigned OverriddenSubobject, UniqueVirtualMethod Overriding)
NamedDecl ** decl_iterator
The set of methods that override a given virtual method in each subobject where it occurs...
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified...
DeclContextLookupResult slice(size_t N) const
CXXRecordDecl * getCanonicalDecl() override
Retrieves the "canonical" declaration of the given declaration.
static bool findOrdinaryMember(RecordDecl *BaseRecord, CXXBasePath &Path, DeclarationName Name)
lookup_result lookup(DeclarationName Name) const
lookup - Find the declarations (if any) with the given Name in this context.
ASTRecordLayout - This class contains layout information for one RecordDecl, which is a struct/union/...
int SubobjectNumber
Identifies which base class subobject (of type Base->getType()) this base path element refers to...
const T * castAs() const
Member-template castAs<specific type>.
void getFinalOverriders(CXXFinalOverriderMap &FinaOverriders) const
Retrieve the final overriders for each virtual member function in the class hierarchy where this clas...
overridden_method_range overridden_methods() const
bool isFileContext() const
static bool FindNestedNameSpecifierMember(const CXXBaseSpecifier *Specifier, CXXBasePath &Path, DeclarationName Name)
Base-class lookup callback that determines whether there exists a member with the given name that can...
const CXXRecordDecl * getPrimaryBase() const
getPrimaryBase - Get the primary base for this record.
Represents a C++ template name within the type system.
bool isPolymorphic() const
Whether this class is polymorphic (C++ [class.virtual]), which means that the class contains or inher...
DeclContext * getParent()
getParent - Returns the containing DeclContext.
static bool FindOrdinaryMember(const CXXBaseSpecifier *Specifier, CXXBasePath &Path, DeclarationName Name)
Base-class lookup callback that determines whether there exists a member with the given name...
Uniquely identifies a virtual method within a class hierarchy by the method itself and a class subobj...
bool isDependentContext() const
Determines whether this context is dependent on a template parameter.
void getIndirectPrimaryBases(CXXIndirectPrimaryBaseSet &Bases) const
Get the indirect primary bases for this class.
bool isProvablyNotDerivedFrom(const CXXRecordDecl *Base) const
Determine whether this class is provably not derived from the type Base.
llvm::function_ref< bool(const CXXBaseSpecifier *Specifier, CXXBasePath &Path)> BaseMatchesCallback
Function type used by lookupInBases() to determine whether a specific base class subobject matches th...
RecordDecl * getDecl() const
const CXXBaseSpecifier * Base
The base specifier that states the link from a derived class to a base class, which will be followed ...
Members, declared with object declarations within tag definitions.
A set of all the primary bases for a class.
static bool FindBaseClass(const CXXBaseSpecifier *Specifier, CXXBasePath &Path, const CXXRecordDecl *BaseRecord)
Base-class lookup callback that determines whether the given base class specifier refers to a specifi...
Represents a static or instance method of a struct/union/class.
llvm::function_ref< bool(const CXXRecordDecl *BaseDefinition)> ForallBasesCallback
Function type used by forallBases() as a callback.
bool isDetectingVirtual() const
Whether we are detecting virtual bases.
bool forallBases(ForallBasesCallback BaseMatches, bool AllowShortCircuit=true) const
Determines if the given callback holds for all the direct or indirect base classes of this type...
Represents an element in a path from a derived class to a base class.
bool isVirtuallyDerivedFrom(const CXXRecordDecl *Base) const
Determine whether this class is virtually derived from the class Base.
bool isCurrentInstantiation(const DeclContext *CurContext) const
Determine whether this dependent class is a current instantiation, when viewed from within the given ...
Dataflow Directional Tag Classes.
DeclContext - This is used only as base class of specific decl types that can act as declaration cont...
static void AddIndirectPrimaryBases(const CXXRecordDecl *RD, ASTContext &Context, CXXIndirectPrimaryBaseSet &Bases)
MapType::iterator iterator
The name of a declaration.
A mapping from each virtual member function to its set of final overriders.
bool isAmbiguous(CanQualType BaseType)
Determine whether the path from the most-derived type to the given base type is ambiguous (i...
Tags, declared with 'struct foo;' and referenced with 'struct foo'.
static AccessSpecifier MergeAccess(AccessSpecifier PathAccess, AccessSpecifier DeclAccess)
Calculates the access of a decl that is reached along a path.
bool lookupInBases(BaseMatchesCallback BaseMatches, CXXBasePaths &Paths, bool LookupInDependent=false) const
Look for entities within the base classes of this C++ class, transitively searching all base class su...
A helper class that allows the use of isa/cast/dyncast to detect TagType objects of structs/unions/cl...
MapType::const_iterator const_iterator
static bool FindTagMember(const CXXBaseSpecifier *Specifier, CXXBasePath &Path, DeclarationName Name)
Base-class lookup callback that determines whether there exists a tag with the given name...
Represents a base class of a C++ class.
CanQualType getCanonicalType(QualType T) const
Return the canonical (structural) type corresponding to the specified potentially non-canonical type ...
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate.h) and friends (in DeclFriend.h).
Represents a C++ struct/union/class.
AccessSpecifier Access
The access along this inheritance path.
bool isDependentType() const
Whether this type is a dependent type, meaning that its definition somehow depends on a template para...
Represents a type template specialization; the template must be a class template, a type alias templa...
BasePaths - Represents the set of paths from a derived class to one of its (direct or indirect) bases...
void replaceAll(UniqueVirtualMethod Overriding)
This represents a decl that may have a name.
const CXXRecordDecl * Class
The record decl of the class that the base is a base of.
static bool FindVirtualBaseClass(const CXXBaseSpecifier *Specifier, CXXBasePath &Path, const CXXRecordDecl *BaseRecord)
Base-class lookup callback that determines whether the given base class specifier refers to a specifi...
method_range methods() const
QualType getType() const
Retrieves the type of the base class.