1 //===--- AvoidThrowingObjCExceptionCheck.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 "AvoidThrowingObjCExceptionCheck.h" 10 #include "clang/AST/ASTContext.h" 11 #include "clang/ASTMatchers/ASTMatchFinder.h" 12 13 using namespace clang::ast_matchers; 14 15 namespace clang::tidy::google::objc { 16 registerMatchers(MatchFinder * Finder)17void AvoidThrowingObjCExceptionCheck::registerMatchers(MatchFinder *Finder) { 18 19 Finder->addMatcher(objcThrowStmt().bind("throwStmt"), this); 20 Finder->addMatcher( 21 objcMessageExpr(anyOf(hasSelector("raise:format:"), 22 hasSelector("raise:format:arguments:")), 23 hasReceiverType(asString("NSException"))) 24 .bind("raiseException"), 25 this); 26 } 27 check(const MatchFinder::MatchResult & Result)28void AvoidThrowingObjCExceptionCheck::check( 29 const MatchFinder::MatchResult &Result) { 30 const auto *MatchedStmt = 31 Result.Nodes.getNodeAs<ObjCAtThrowStmt>("throwStmt"); 32 const auto *MatchedExpr = 33 Result.Nodes.getNodeAs<ObjCMessageExpr>("raiseException"); 34 auto SourceLoc = MatchedStmt == nullptr ? MatchedExpr->getSelectorStartLoc() 35 : MatchedStmt->getThrowLoc(); 36 37 // Early return on invalid locations. 38 if (SourceLoc.isInvalid()) 39 return; 40 41 // If the match location was in a macro, check if the macro was in a system 42 // header. 43 if (SourceLoc.isMacroID()) { 44 SourceManager &SM = *Result.SourceManager; 45 auto MacroLoc = SM.getImmediateMacroCallerLoc(SourceLoc); 46 47 // Matches in system header macros should be ignored. 48 if (SM.isInSystemHeader(MacroLoc)) 49 return; 50 } 51 52 diag(SourceLoc, 53 "pass in NSError ** instead of throwing exception to indicate " 54 "Objective-C errors"); 55 } 56 57 } // namespace clang::tidy::google::objc 58