summaryrefslogtreecommitdiffstats
path: root/clang/lib/ASTMatchers/ASTMatchFinder.cpp
diff options
context:
space:
mode:
authorStephane Moore <mog@google.com>2019-08-12 23:23:35 +0000
committerStephane Moore <mog@google.com>2019-08-12 23:23:35 +0000
commita0a47d8ac113b1e959288698deef847f562921d3 (patch)
tree7389a9dabcd21a82c8143ec15db6fd955a0973a9 /clang/lib/ASTMatchers/ASTMatchFinder.cpp
parente9865b9b31bb2e6bc742dc6fca8f9f9517c3c43e (diff)
downloadbcm5719-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.cpp63
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;
OpenPOWER on IntegriCloud