Index: clang-tidy/google/CMakeLists.txt =================================================================== --- clang-tidy/google/CMakeLists.txt +++ clang-tidy/google/CMakeLists.txt @@ -6,6 +6,7 @@ ExplicitConstructorCheck.cpp ExplicitMakePairCheck.cpp GlobalNamesInHeadersCheck.cpp + GlobalVariableDeclarationCheck.cpp GoogleTidyModule.cpp IntegerTypesCheck.cpp NonConstReferences.cpp Index: clang-tidy/google/GlobalVariableDeclarationCheck.h =================================================================== --- /dev/null +++ clang-tidy/google/GlobalVariableDeclarationCheck.h @@ -0,0 +1,37 @@ +//===--- GlobalVariableDeclarationCheck.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_GLOBAL_VARIABLE_DECLARATION_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_OBJC_GLOBAL_VARIABLE_DECLARATION_H + +#include "../ClangTidy.h" + +namespace clang { +namespace tidy { +namespace google { + +/// The check for Objective-C global variables and constants naming convention. +/// The declaration should follow the patterns of 'k[A-Z].*' (constants) or +/// 'g[A-Z].*' (variables). +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/google-objc-global-variable-declaration.html +class GlobalVariableDeclarationCheck : public ClangTidyCheck { +public: + GlobalVariableDeclarationCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; +}; + +} // namespace google +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_OBJC_GLOBAL_VARIABLE_DECLARATION_H Index: clang-tidy/google/GlobalVariableDeclarationCheck.cpp =================================================================== --- /dev/null +++ clang-tidy/google/GlobalVariableDeclarationCheck.cpp @@ -0,0 +1,85 @@ +//===--- GlobalVariableDeclarationCheck.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 "GlobalVariableDeclarationCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringRef.h" + +#include + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace google { + +namespace { + +FixItHint generateFixItHint(const VarDecl *decl, bool isConst) { + auto fc = decl->getName()[0]; + if (!llvm::isAlpha(fc) || decl->getName().size() == 1) { + // No fix available if first character is not alphabetical character, or it + // is a single-character variable. + return FixItHint(); + } + auto sc = decl->getName()[1]; + if ((fc == 'k' || fc == 'g') && !llvm::isAlpha(sc)) { + // No fix available if the prefix is correct but the second character is not + // alphabetical. + return FixItHint(); + } + auto prefix = + (isConst ? "k" : "g") + llvm::StringRef(std::string(1, fc)).upper(); + return FixItHint::CreateReplacement( + CharSourceRange(SourceRange(decl->getLocation(), + decl->getLocation().getLocWithOffset(1)), + false), + llvm::StringRef(prefix)); +} +} // namespace + +void GlobalVariableDeclarationCheck::registerMatchers(MatchFinder *Finder) { + // need to add two matchers since we need to bind different ids to distinguish + // constants and variables. Since bind() can only be called on node matchers, + // we cannot make it in one matcher. + Finder->addMatcher( + varDecl(hasGlobalStorage(), unless(hasType(isConstQualified())), + unless(matchesName("::g[A-Z]"))) + .bind("global_var"), + this); + Finder->addMatcher(varDecl(hasGlobalStorage(), hasType(isConstQualified()), + unless(matchesName("::k[A-Z]"))) + .bind("global_const"), + this); +} + +void GlobalVariableDeclarationCheck::check( + const MatchFinder::MatchResult &Result) { + const auto *variableDecl = Result.Nodes.getNodeAs("global_var"); + const auto *constantDecl = Result.Nodes.getNodeAs("global_const"); + assert(variableDecl != nullptr || constantDecl != nullptr); + if (variableDecl != nullptr) { + diag(variableDecl->getLocation(), + "non-const global variable '%0' must have a name which starts with " + "'g[A-Z]'") + << variableDecl->getName() << generateFixItHint(variableDecl, false); + } + if (constantDecl != nullptr) { + diag(constantDecl->getLocation(), + "const global variable '%0' must have a name which starts with " + "'k[A-Z]'") + << constantDecl->getName() << generateFixItHint(constantDecl, true); + } +} + +} // namespace google +} // namespace tidy +} // namespace clang Index: clang-tidy/google/GoogleTidyModule.cpp =================================================================== --- clang-tidy/google/GoogleTidyModule.cpp +++ clang-tidy/google/GoogleTidyModule.cpp @@ -19,6 +19,7 @@ #include "ExplicitConstructorCheck.h" #include "ExplicitMakePairCheck.h" #include "GlobalNamesInHeadersCheck.h" +#include "GlobalVariableDeclarationCheck.h" #include "IntegerTypesCheck.h" #include "NonConstReferences.h" #include "OverloadedUnaryAndCheck.h" @@ -36,6 +37,8 @@ class GoogleModule : public ClangTidyModule { public: void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override { + CheckFactories.registerCheck( + "google-objc-global-variable-declaration"); CheckFactories.registerCheck( "google-build-explicit-make-pair"); CheckFactories.registerCheck( Index: docs/ReleaseNotes.rst =================================================================== --- docs/ReleaseNotes.rst +++ docs/ReleaseNotes.rst @@ -57,6 +57,13 @@ Improvements to clang-tidy -------------------------- +- New `google-objc-global-variable-declaration + `_ check + + Add new check for Objective-C code to ensure global + variables follow the naming convention of 'k[A-Z].*' (for constants) + or 'g[A-Z].*' (for variables). + - New module `objc` for Objective-C style checks. - New `objc-forbidden-subclassing Index: docs/clang-tidy/checks/google-objc-global-variable-declaration.rst =================================================================== --- /dev/null +++ docs/clang-tidy/checks/google-objc-global-variable-declaration.rst @@ -0,0 +1,29 @@ +.. title:: clang-tidy - google-objc-global-variable-declaration + +google-objc-global-variable-declaration +================================== + +Finds global variable declarations in Objective-C files that are not follow the pattern +of variable names in Google's Objective-C Style Guide. + +All the global variables should follow the pattern of `g[A-Z].*` (variables) or +`k[A-Z].*` (constants). The check will suggest a variable name that follows the pattern +if it can be inferred from the original name. + +For code: + +.. code-block:: objc + static NSString* myString = @"hello"; + +The fix will be: + +.. code-block:: objc + static NSString* kMyString = @"hello"; + +However for code that prefixed with non-alphabetical characters like: + +.. code-block:: objc + static NSString* __anotherString = @"world"; + +The check will give a warning message but will not be able to suggest a fix. The user +need to fix it on his own. \ No newline at end of file Index: docs/clang-tidy/checks/list.rst =================================================================== --- docs/clang-tidy/checks/list.rst +++ docs/clang-tidy/checks/list.rst @@ -60,6 +60,7 @@ google-default-arguments google-explicit-constructor google-global-names-in-headers + google-objc-global-variable-declaration google-readability-braces-around-statements (redirects to readability-braces-around-statements) google-readability-casting google-readability-function-size (redirects to readability-function-size) Index: test/clang-tidy/google-objc-global-variable-declaration.m =================================================================== --- /dev/null +++ test/clang-tidy/google-objc-global-variable-declaration.m @@ -0,0 +1,33 @@ +// RUN: %check_clang_tidy %s google-objc-global-variable-declaration %t + +@class NSString; +static NSString* const myConstString = @"hello"; +// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: const global variable 'myConstString' must have a name which starts with 'k[A-Z]' [google-objc-global-variable-declaration] +// CHECK-FIXES: kMyConstString + +static NSString* MyString = @"hi"; +// CHECK-MESSAGES: :[[@LINE-1]]:18: warning: non-const global variable 'MyString' must have a name which starts with 'g[A-Z]' [google-objc-global-variable-declaration] +// CHECK-FIXES: gMyString + +static NSString* a = @"too simple"; +// CHECK-MESSAGES: :[[@LINE-1]]:18: warning: non-const global variable 'a' must have a name which starts with 'g[A-Z]' [google-objc-global-variable-declaration] +// CHECK-FIXES-NOT: gA + +static NSString* const _notAlpha = @"NotBeginWithAlpha"; +// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: const global variable '_notAlpha' must have a name which starts with 'k[A-Z]' [google-objc-global-variable-declaration] +// CHECK-FIXES-NOT: k_notAlpha + +static NSString* const k_Alpha = @"SecondNotAlpha"; +// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: const global variable 'k_Alpha' must have a name which starts with 'k[A-Z]' [google-objc-global-variable-declaration] +// CHECK-FIXES-NOT: kK_Alpha + +static NSString* const kGood = @"hello"; +// CHECK-MESSAGES-NOT: :[[@LINE-1]]:24: warning: const global variable 'kGood' must have a name which starts with 'k[A-Z]' [google-objc-global-variable-declaration] +static NSString* gMyIntGood = 0; +// CHECK-MESSAGES-NOT: :[[@LINE-1]]:18: warning: non-const global variable 'gMyIntGood' must have a name which starts with 'g[A-Z]' [google-objc-global-variable-declaration] +@implementation Foo +- (void)f { + int x = 0; +// CHECK-MESSAGES-NOT: :[[@LINE-1]]:9: warning: non-const global variable 'gMyIntGood' must have a name which starts with 'g[A-Z]' [google-objc-global-variable-declaration] +} +@end \ No newline at end of file