add check to avoid throwing objc exception according to Google Objective-C guide

Summary:
This is a small check to avoid throwing objc exceptions.
In specific it will detect the usage of @throw statement and throw warning.

Reviewers: hokein, benhamilton

Reviewed By: hokein, benhamilton

Subscribers: cfe-commits, mgorny

Differential Revision: https://reviews.llvm.org/D40058

llvm-svn: 318366
This commit is contained in:
Yan Zhang 2017-11-16 01:28:29 +00:00
parent 35019dbe6b
commit 9994581395
8 changed files with 166 additions and 0 deletions

View File

@ -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<ObjCAtThrowStmt>("throwStmt");
const auto *MatchedExpr =
Result.Nodes.getNodeAs<ObjCMessageExpr>("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

View File

@ -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

View File

@ -2,6 +2,7 @@ set(LLVM_LINK_COMPONENTS support)
add_clang_library(clangTidyGoogleModule
AvoidCStyleCastsCheck.cpp
AvoidThrowingObjCExceptionCheck.cpp
DefaultArgumentsCheck.cpp
ExplicitConstructorCheck.cpp
ExplicitMakePairCheck.cpp

View File

@ -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 @@ class GoogleModule : public ClangTidyModule {
"google-explicit-constructor");
CheckFactories.registerCheck<readability::GlobalNamesInHeadersCheck>(
"google-global-names-in-headers");
CheckFactories.registerCheck<objc::AvoidThrowingObjCExceptionCheck>(
"google-objc-avoid-throwing-exception");
CheckFactories.registerCheck<objc::GlobalVariableDeclarationCheck>(
"google-objc-global-variable-declaration");
CheckFactories.registerCheck<runtime::IntegerTypesCheck>(

View File

@ -57,6 +57,11 @@ The improvements are...
Improvements to clang-tidy
--------------------------
- New `google-avoid-throwing-objc-exception
<http://clang.llvm.org/extra/clang-tidy/checks/google-objc-avoid-throwing-exception.html>`_ check
Add new check to detect throwing exceptions in Objective-C code, which should be avoided.
- New `objc-property-declaration
<http://clang.llvm.org/extra/clang-tidy/checks/objc-property-declaration.html>`_ check

View File

@ -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

View File

@ -60,6 +60,7 @@ Clang-Tidy Checks
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-braces-around-statements>
google-readability-casting

View File

@ -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