diff options
author | Stephane Moore <mog@google.com> | 2019-08-12 23:23:35 +0000 |
---|---|---|
committer | Stephane Moore <mog@google.com> | 2019-08-12 23:23:35 +0000 |
commit | a0a47d8ac113b1e959288698deef847f562921d3 (patch) | |
tree | 7389a9dabcd21a82c8143ec15db6fd955a0973a9 /clang/lib/ASTMatchers/ASTMatchFinder.cpp | |
parent | e9865b9b31bb2e6bc742dc6fca8f9f9517c3c43e (diff) | |
download | bcm5719-llvm-a0a47d8ac113b1e959288698deef847f562921d3.tar.gz bcm5719-llvm-a0a47d8ac113b1e959288698deef847f562921d3.zip |
[clang] Update isDerivedFrom to support Objective-C classes 🔍
Summary:
This change updates `isDerivedFrom` to support Objective-C classes by
converting it to a polymorphic matcher.
Notes:
The matching behavior for Objective-C classes is modeled to match the
behavior of `isDerivedFrom` with C++ classes. To that effect,
`isDerivedFrom` matches aliased types of derived Objective-C classes,
including compatibility aliases. To achieve this, the AST visitor has
been updated to map compatibility aliases to their underlying
Objective-C class.
`isSameOrDerivedFrom` also provides similar behaviors for C++ and
Objective-C classes. The behavior that
`cxxRecordDecl(isSameOrDerivedFrom("X"))` does not match
`class Y {}; typedef Y X;` is mirrored for Objective-C in that
`objcInterfaceDecl(isSameOrDerivedFrom("X"))` does not match either
`@interface Y @end typedef Y X;` or
`@interface Y @end @compatibility_alias X Y;`.
Test Notes:
Ran clang unit tests.
Reviewers: aaron.ballman, jordan_rose, rjmccall, klimek, alexfh, gribozavr
Reviewed By: aaron.ballman, gribozavr
Subscribers: cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D60543
llvm-svn: 368632
Diffstat (limited to 'clang/lib/ASTMatchers/ASTMatchFinder.cpp')
-rw-r--r-- | clang/lib/ASTMatchers/ASTMatchFinder.cpp | 63 |
1 files changed, 62 insertions, 1 deletions
diff --git a/clang/lib/ASTMatchers/ASTMatchFinder.cpp b/clang/lib/ASTMatchers/ASTMatchFinder.cpp index 6a4715ebe1b..6eb4a2c4268 100644 --- a/clang/lib/ASTMatchers/ASTMatchFinder.cpp +++ b/clang/lib/ASTMatchers/ASTMatchFinder.cpp @@ -374,6 +374,12 @@ public: return true; } + bool VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *CAD) { + const ObjCInterfaceDecl *InterfaceDecl = CAD->getClassInterface(); + CompatibleAliases[InterfaceDecl].insert(CAD); + return true; + } + bool TraverseDecl(Decl *DeclNode); bool TraverseStmt(Stmt *StmtNode, DataRecursionQueue *Queue = nullptr); bool TraverseType(QualType TypeNode); @@ -433,6 +439,11 @@ public: BoundNodesTreeBuilder *Builder, bool Directly) override; + bool objcClassIsDerivedFrom(const ObjCInterfaceDecl *Declaration, + const Matcher<NamedDecl> &Base, + BoundNodesTreeBuilder *Builder, + bool Directly) override; + // Implements ASTMatchFinder::matchesChildOf. bool matchesChildOf(const ast_type_traits::DynTypedNode &Node, const DynTypedMatcher &Matcher, @@ -763,6 +774,23 @@ private: return false; } + bool + objcClassHasMatchingCompatibilityAlias(const ObjCInterfaceDecl *InterfaceDecl, + const Matcher<NamedDecl> &Matcher, + BoundNodesTreeBuilder *Builder) { + auto Aliases = CompatibleAliases.find(InterfaceDecl); + if (Aliases == CompatibleAliases.end()) + return false; + for (const ObjCCompatibleAliasDecl *Alias : Aliases->second) { + BoundNodesTreeBuilder Result(*Builder); + if (Matcher.matches(*Alias, this, &Result)) { + *Builder = std::move(Result); + return true; + } + } + return false; + } + /// Bucket to record map. /// /// Used to get the appropriate bucket for each matcher. @@ -787,6 +815,11 @@ private: // Maps a canonical type to its TypedefDecls. llvm::DenseMap<const Type*, std::set<const TypedefNameDecl*> > TypeAliases; + // Maps an Objective-C interface to its ObjCCompatibleAliasDecls. + llvm::DenseMap<const ObjCInterfaceDecl *, + llvm::SmallPtrSet<const ObjCCompatibleAliasDecl *, 2>> + CompatibleAliases; + // Maps (matcher, node) -> the match result for memoization. typedef std::map<MatchKey, MemoizedMatchResult> MemoizationMap; MemoizationMap ResultCache; @@ -813,7 +846,7 @@ getAsCXXRecordDeclOrPrimaryTemplate(const Type *TypeNode) { return nullptr; } -// Returns true if the given class is directly or indirectly derived +// Returns true if the given C++ class is directly or indirectly derived // from a base type with the given name. A class is not considered to be // derived from itself. bool MatchASTVisitor::classIsDerivedFrom(const CXXRecordDecl *Declaration, @@ -850,6 +883,34 @@ bool MatchASTVisitor::classIsDerivedFrom(const CXXRecordDecl *Declaration, return false; } +// Returns true if the given Objective-C class is directly or indirectly +// derived from a matching base class. A class is not considered to be derived +// from itself. +bool MatchASTVisitor::objcClassIsDerivedFrom( + const ObjCInterfaceDecl *Declaration, const Matcher<NamedDecl> &Base, + BoundNodesTreeBuilder *Builder, bool Directly) { + // Check if any of the superclasses of the class match. + for (const ObjCInterfaceDecl *ClassDecl = Declaration->getSuperClass(); + ClassDecl != nullptr; ClassDecl = ClassDecl->getSuperClass()) { + // Check if there are any matching compatibility aliases. + if (objcClassHasMatchingCompatibilityAlias(ClassDecl, Base, Builder)) + return true; + + // Check if there are any matching type aliases. + const Type *TypeNode = ClassDecl->getTypeForDecl(); + if (typeHasMatchingAlias(TypeNode, Base, Builder)) + return true; + + if (Base.matches(*ClassDecl, this, Builder)) + return true; + + if (Directly) + return false; + } + + return false; +} + bool MatchASTVisitor::TraverseDecl(Decl *DeclNode) { if (!DeclNode) { return true; |