Index: clang-tools-extra/trunk/clang-tidy/google/AvoidThrowingObjCExceptionCheck.h =================================================================== --- clang-tools-extra/trunk/clang-tidy/google/AvoidThrowingObjCExceptionCheck.h +++ clang-tools-extra/trunk/clang-tidy/google/AvoidThrowingObjCExceptionCheck.h @@ -0,0 +1,39 @@ +//===--- AvoidThrowingObjCExceptionCheck.h - clang-tidy----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_OBJC_AVOID_THROWING_EXCEPTION_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_OBJC_AVOID_THROWING_EXCEPTION_H + +#include "../ClangTidy.h" + +namespace clang { +namespace tidy { +namespace google { +namespace objc { + +/// The check is to find usage of @throw invocation in Objective-C code. +/// We should avoid using @throw for Objective-C exceptions according to +/// the Google Objective-C Style Guide. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/google-objc-avoid-throwing-exception.html +class AvoidThrowingObjCExceptionCheck : public ClangTidyCheck { + public: + AvoidThrowingObjCExceptionCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; +}; + +} // namespace objc +} // namespace google +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_OBJC_AVOID_THROWING_EXCEPTION_H Index: clang-tools-extra/trunk/clang-tidy/google/AvoidThrowingObjCExceptionCheck.cpp =================================================================== --- clang-tools-extra/trunk/clang-tidy/google/AvoidThrowingObjCExceptionCheck.cpp +++ clang-tools-extra/trunk/clang-tidy/google/AvoidThrowingObjCExceptionCheck.cpp @@ -0,0 +1,47 @@ +//===--- AvoidThrowingObjCExceptionCheck.cpp - clang-tidy------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "AvoidThrowingObjCExceptionCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace google { +namespace objc { + +void AvoidThrowingObjCExceptionCheck::registerMatchers(MatchFinder *Finder) { + Finder->addMatcher(objcThrowStmt().bind("throwStmt"), this); + Finder->addMatcher( + objcMessageExpr(anyOf(hasSelector("raise:format:"), + hasSelector("raise:format:arguments:")), + hasReceiverType(asString("NSException"))) + .bind("raiseException"), + this); +} + +void AvoidThrowingObjCExceptionCheck::check( + const MatchFinder::MatchResult &Result) { + const auto *MatchedStmt = + Result.Nodes.getNodeAs("throwStmt"); + const auto *MatchedExpr = + Result.Nodes.getNodeAs("raiseException"); + auto SourceLoc = MatchedStmt == nullptr ? MatchedExpr->getSelectorStartLoc() + : MatchedStmt->getThrowLoc(); + diag(SourceLoc, + "pass in NSError ** instead of throwing exception to indicate " + "Objective-C errors"); +} + +} // namespace objc +} // namespace google +} // namespace tidy +} // namespace clang Index: clang-tools-extra/trunk/clang-tidy/google/CMakeLists.txt =================================================================== --- clang-tools-extra/trunk/clang-tidy/google/CMakeLists.txt +++ clang-tools-extra/trunk/clang-tidy/google/CMakeLists.txt @@ -2,6 +2,7 @@ add_clang_library(clangTidyGoogleModule AvoidCStyleCastsCheck.cpp + AvoidThrowingObjCExceptionCheck.cpp DefaultArgumentsCheck.cpp ExplicitConstructorCheck.cpp ExplicitMakePairCheck.cpp Index: clang-tools-extra/trunk/clang-tidy/google/GoogleTidyModule.cpp =================================================================== --- clang-tools-extra/trunk/clang-tidy/google/GoogleTidyModule.cpp +++ clang-tools-extra/trunk/clang-tidy/google/GoogleTidyModule.cpp @@ -15,6 +15,7 @@ #include "../readability/NamespaceCommentCheck.h" #include "../readability/RedundantSmartptrGetCheck.h" #include "AvoidCStyleCastsCheck.h" +#include "AvoidThrowingObjCExceptionCheck.h" #include "DefaultArgumentsCheck.h" #include "ExplicitConstructorCheck.h" #include "ExplicitMakePairCheck.h" @@ -49,6 +50,8 @@ "google-explicit-constructor"); CheckFactories.registerCheck( "google-global-names-in-headers"); + CheckFactories.registerCheck( + "google-objc-avoid-throwing-exception"); CheckFactories.registerCheck( "google-objc-global-variable-declaration"); CheckFactories.registerCheck( Index: clang-tools-extra/trunk/docs/ReleaseNotes.rst =================================================================== --- clang-tools-extra/trunk/docs/ReleaseNotes.rst +++ clang-tools-extra/trunk/docs/ReleaseNotes.rst @@ -57,6 +57,11 @@ Improvements to clang-tidy -------------------------- +- New `google-avoid-throwing-objc-exception + `_ check + + Add new check to detect throwing exceptions in Objective-C code, which should be avoided. + - New `objc-property-declaration `_ check Index: clang-tools-extra/trunk/docs/clang-tidy/checks/google-objc-avoid-throwing-exception.rst =================================================================== --- clang-tools-extra/trunk/docs/clang-tidy/checks/google-objc-avoid-throwing-exception.rst +++ clang-tools-extra/trunk/docs/clang-tidy/checks/google-objc-avoid-throwing-exception.rst @@ -0,0 +1,38 @@ +.. title:: clang-tidy - google-objc-avoid-throwing-exception + +google-objc-avoid-throwing-exception +==================================== + +This check finds finds uses of throwing exceptions usages in Objective-C files. +For the same reason as the Google C++ style guide, we prefer not throwing +exceptions from Objective-C code. + +The corresponding C++ style guide rule: +https://google.github.io/styleguide/cppguide.html#Exceptions + +Instead, prefer passing in ``NSError **`` and return ``BOOL`` to indicate success or failure. + +A counterexample: + +.. code-block:: objc + + - (void)readFile { + if ([self isError]) { + @throw [NSException exceptionWithName:...]; + } + } + +Instead, returning an error via ``NSError **`` is preferred: + +.. code-block:: objc + + - (BOOL)readFileWithError:(NSError **)error { + if ([self isError]) { + *error = [NSError errorWithDomain:...]; + return NO; + } + return YES; + } + +The corresponding style guide rule: +http://google.github.io/styleguide/objcguide.html#avoid-throwing-exceptions Index: clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst =================================================================== --- clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst +++ clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst @@ -60,6 +60,7 @@ google-default-arguments google-explicit-constructor google-global-names-in-headers + google-objc-avoid-throwing-exception google-objc-global-variable-declaration google-readability-braces-around-statements (redirects to readability-braces-around-statements) google-readability-casting Index: clang-tools-extra/trunk/test/clang-tidy/google-objc-avoid-throwing-exception.m =================================================================== --- clang-tools-extra/trunk/test/clang-tidy/google-objc-avoid-throwing-exception.m +++ clang-tools-extra/trunk/test/clang-tidy/google-objc-avoid-throwing-exception.m @@ -0,0 +1,32 @@ +// RUN: %check_clang_tidy %s google-objc-avoid-throwing-exception %t +@class NSString; + +@interface NSException + ++ (void)raise:(NSString *)name format:(NSString *)format; ++ (void)raise:(NSString *)name format:(NSString *)format arguments:(NSString *)args; // using NSString type since va_list cannot be recognized here + +@end + +@interface NotException + ++ (void)raise:(NSString *)name format:(NSString *)format; + +@end + +@implementation Foo +- (void)f { + NSString *foo = @"foo"; + @throw foo; + // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: pass in NSError ** instead of throwing exception to indicate Objective-C errors [google-objc-avoid-throwing-exception] +} + +- (void)f2 { + [NSException raise:@"TestException" format:@"Test"]; + // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: pass in NSError ** instead of throwing exception to indicate Objective-C errors [google-objc-avoid-throwing-exception] + [NSException raise:@"TestException" format:@"Test %@" arguments:@"bar"]; + // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: pass in NSError ** instead of throwing exception to indicate Objective-C errors [google-objc-avoid-throwing-exception] + [NotException raise:@"NotException" format:@"Test"]; +} +@end +