Skip to content

Commit

Permalink
add check to avoid throwing objc exception according to Google Object…
Browse files Browse the repository at this point in the history
…ive-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
  • Loading branch information
ynzhang0509 committed Nov 16, 2017
1 parent 35019db commit 9994581
Show file tree
Hide file tree
Showing 8 changed files with 166 additions and 0 deletions.
@@ -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
@@ -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
1 change: 1 addition & 0 deletions clang-tools-extra/clang-tidy/google/CMakeLists.txt
Expand Up @@ -2,6 +2,7 @@ set(LLVM_LINK_COMPONENTS support)

add_clang_library(clangTidyGoogleModule
AvoidCStyleCastsCheck.cpp
AvoidThrowingObjCExceptionCheck.cpp
DefaultArgumentsCheck.cpp
ExplicitConstructorCheck.cpp
ExplicitMakePairCheck.cpp
Expand Down
3 changes: 3 additions & 0 deletions clang-tools-extra/clang-tidy/google/GoogleTidyModule.cpp
Expand Up @@ -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"
Expand Down Expand Up @@ -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>(
Expand Down
5 changes: 5 additions & 0 deletions clang-tools-extra/docs/ReleaseNotes.rst
Expand Up @@ -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

Expand Down
@@ -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
1 change: 1 addition & 0 deletions clang-tools-extra/docs/clang-tidy/checks/list.rst
Expand Up @@ -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
Expand Down
@@ -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

0 comments on commit 9994581

Please sign in to comment.