xref: /llvm-project/clang-tools-extra/clang-tidy/google/AvoidThrowingObjCExceptionCheck.cpp (revision 7d2ea6c422d3f5712b7253407005e1a465a76946)
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)17 void 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)28 void 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