From 1863e505ce36530596610f80934b86312aad3f63 Mon Sep 17 00:00:00 2001 From: Manuel Klimek Date: Fri, 2 Aug 2013 21:24:09 +0000 Subject: [PATCH] Fix crash when encountering alias templates in isDerivedFrom matches. - pull out function to drill to the CXXRecordDecl from the type, to allow recursive resolution - make the analysis more robust by rather skipping values we don't understand llvm-svn: 187676 --- clang/lib/ASTMatchers/ASTMatchFinder.cpp | 94 ++++++++++++++----------- clang/unittests/ASTMatchers/ASTMatchersTest.cpp | 6 ++ 2 files changed, 57 insertions(+), 43 deletions(-) diff --git a/clang/lib/ASTMatchers/ASTMatchFinder.cpp b/clang/lib/ASTMatchers/ASTMatchFinder.cpp index 5dc67e1..78bd9be 100644 --- a/clang/lib/ASTMatchers/ASTMatchFinder.cpp +++ b/clang/lib/ASTMatchers/ASTMatchFinder.cpp @@ -326,7 +326,7 @@ public: // The following Visit*() and Traverse*() functions "override" // methods in RecursiveASTVisitor. - bool VisitTypedefDecl(TypedefDecl *DeclNode) { + bool VisitTypedefNameDecl(TypedefNameDecl *DeclNode) { // When we see 'typedef A B', we add name 'B' to the set of names // A's canonical type maps to. This is necessary for implementing // isDerivedFrom(x) properly, where x can be the name of the base @@ -589,8 +589,9 @@ private: BoundNodesTreeBuilder *Builder) { const Type *const CanonicalType = ActiveASTContext->getCanonicalType(TypeNode); - const std::set &Aliases = TypeAliases[CanonicalType]; - for (std::set::const_iterator + const std::set &Aliases = + TypeAliases[CanonicalType]; + for (std::set::const_iterator It = Aliases.begin(), End = Aliases.end(); It != End; ++It) { BoundNodesTreeBuilder Result(*Builder); @@ -607,13 +608,55 @@ private: ASTContext *ActiveASTContext; // Maps a canonical type to its TypedefDecls. - llvm::DenseMap > TypeAliases; + llvm::DenseMap > TypeAliases; // Maps (matcher, node) -> the match result for memoization. typedef std::map MemoizationMap; MemoizationMap ResultCache; }; +static CXXRecordDecl *getAsCXXRecordDecl(const Type *TypeNode) { + // Type::getAs<...>() drills through typedefs. + if (TypeNode->getAs() != NULL || + TypeNode->getAs() != NULL || + TypeNode->getAs() != NULL) + // Dependent names and template TypeNode parameters will be matched when + // the template is instantiated. + return NULL; + TemplateSpecializationType const *TemplateType = + TypeNode->getAs(); + if (TemplateType == NULL) { + return TypeNode->getAsCXXRecordDecl(); + } + if (TemplateType->getTemplateName().isDependent()) + // Dependent template specializations will be matched when the + // template is instantiated. + return NULL; + + // For template specialization types which are specializing a template + // declaration which is an explicit or partial specialization of another + // template declaration, getAsCXXRecordDecl() returns the corresponding + // ClassTemplateSpecializationDecl. + // + // For template specialization types which are specializing a template + // declaration which is neither an explicit nor partial specialization of + // another template declaration, getAsCXXRecordDecl() returns NULL and + // we get the CXXRecordDecl of the templated declaration. + CXXRecordDecl *SpecializationDecl = TemplateType->getAsCXXRecordDecl(); + if (SpecializationDecl != NULL) { + return SpecializationDecl; + } + NamedDecl *Templated = + TemplateType->getTemplateName().getAsTemplateDecl()->getTemplatedDecl(); + if (CXXRecordDecl *TemplatedRecord = dyn_cast(Templated)) { + return TemplatedRecord; + } + // Now it can still be that we have an alias template. + TypeAliasDecl *AliasDecl = dyn_cast(Templated); + assert(AliasDecl); + return getAsCXXRecordDecl(AliasDecl->getUnderlyingType().getTypePtr()); +} + // Returns true if the given class is directly or indirectly derived // from a base type with the given name. A class is not considered to be // derived from itself. @@ -624,54 +667,19 @@ bool MatchASTVisitor::classIsDerivedFrom(const CXXRecordDecl *Declaration, return false; typedef CXXRecordDecl::base_class_const_iterator BaseIterator; for (BaseIterator It = Declaration->bases_begin(), - End = Declaration->bases_end(); It != End; ++It) { + End = Declaration->bases_end(); + It != End; ++It) { const Type *TypeNode = It->getType().getTypePtr(); if (typeHasMatchingAlias(TypeNode, Base, Builder)) return true; - // Type::getAs<...>() drills through typedefs. - if (TypeNode->getAs() != NULL || - TypeNode->getAs() != NULL || - TypeNode->getAs() != NULL) - // Dependent names and template TypeNode parameters will be matched when - // the template is instantiated. + CXXRecordDecl *ClassDecl = getAsCXXRecordDecl(TypeNode); + if (ClassDecl == NULL) continue; - CXXRecordDecl *ClassDecl = NULL; - TemplateSpecializationType const *TemplateType = - TypeNode->getAs(); - if (TemplateType != NULL) { - if (TemplateType->getTemplateName().isDependent()) - // Dependent template specializations will be matched when the - // template is instantiated. - continue; - - // For template specialization types which are specializing a template - // declaration which is an explicit or partial specialization of another - // template declaration, getAsCXXRecordDecl() returns the corresponding - // ClassTemplateSpecializationDecl. - // - // For template specialization types which are specializing a template - // declaration which is neither an explicit nor partial specialization of - // another template declaration, getAsCXXRecordDecl() returns NULL and - // we get the CXXRecordDecl of the templated declaration. - CXXRecordDecl *SpecializationDecl = - TemplateType->getAsCXXRecordDecl(); - if (SpecializationDecl != NULL) { - ClassDecl = SpecializationDecl; - } else { - ClassDecl = dyn_cast( - TemplateType->getTemplateName() - .getAsTemplateDecl()->getTemplatedDecl()); - } - } else { - ClassDecl = TypeNode->getAsCXXRecordDecl(); - } - assert(ClassDecl != NULL); if (ClassDecl == Declaration) { // This can happen for recursive template definitions; if the // current declaration did not match, we can safely return false. - assert(TemplateType); return false; } BoundNodesTreeBuilder Result(*Builder); diff --git a/clang/unittests/ASTMatchers/ASTMatchersTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersTest.cpp index fb17a40..4994192 100644 --- a/clang/unittests/ASTMatchers/ASTMatchersTest.cpp +++ b/clang/unittests/ASTMatchers/ASTMatchersTest.cpp @@ -311,6 +311,12 @@ TEST(DeclarationMatcher, ClassIsDerived) { EXPECT_TRUE(matches( "class X {}; class Y : public X {};", recordDecl(isDerivedFrom(recordDecl(hasName("X")).bind("test"))))); + + EXPECT_TRUE(matches( + "template class X {};" + "template using Z = X;" + "template class Y : Z {};", + recordDecl(isDerivedFrom(namedDecl(hasName("X")))))); } TEST(DeclarationMatcher, hasMethod) { -- 2.7.4