1 //===--- MissingHashCheck.cpp - clang-tidy --------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "MissingHashCheck.h" 10 #include "clang/AST/ASTContext.h" 11 #include "clang/ASTMatchers/ASTMatchFinder.h" 12 13 using namespace clang::ast_matchers; 14 15 namespace clang { 16 namespace tidy { 17 namespace objc { 18 19 namespace { 20 21 AST_MATCHER_P(ObjCImplementationDecl, hasInterface, 22 ast_matchers::internal::Matcher<ObjCInterfaceDecl>, Base) { 23 const ObjCInterfaceDecl *InterfaceDecl = Node.getClassInterface(); 24 return Base.matches(*InterfaceDecl, Finder, Builder); 25 } 26 27 AST_MATCHER_P(ObjCContainerDecl, hasInstanceMethod, 28 ast_matchers::internal::Matcher<ObjCMethodDecl>, Base) { 29 // Check each instance method against the provided matcher. 30 for (const auto *I : Node.instance_methods()) { 31 if (Base.matches(*I, Finder, Builder)) 32 return true; 33 } 34 return false; 35 } 36 37 } // namespace 38 39 void MissingHashCheck::registerMatchers(MatchFinder *Finder) { 40 Finder->addMatcher( 41 objcMethodDecl( 42 hasName("isEqual:"), isInstanceMethod(), 43 hasDeclContext(objcImplementationDecl( 44 hasInterface(isDirectlyDerivedFrom("NSObject")), 45 unless(hasInstanceMethod(hasName("hash")))) 46 .bind("impl"))), 47 this); 48 } 49 50 void MissingHashCheck::check(const MatchFinder::MatchResult &Result) { 51 const auto *ID = Result.Nodes.getNodeAs<ObjCImplementationDecl>("impl"); 52 diag(ID->getLocation(), "%0 implements -isEqual: without implementing -hash") 53 << ID; 54 } 55 56 } // namespace objc 57 } // namespace tidy 58 } // namespace clang 59