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,39 @@ +//===--- 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 { +namespace objc { + +/// 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 objc +} // 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,90 @@ +//===--- 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 objc { + +namespace { + +FixItHint generateFixItHint(const VarDecl *Decl, bool IsConst) { + char 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, since it is difficult to determine the + // proper fix in this case. Users should create a proper variable name by + // their own. + return FixItHint(); + } + char 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, since it is difficult to determine the proper fix in this + // case. + return FixItHint(); + } + auto NewName = (IsConst ? "k" : "g") + + llvm::StringRef(std::string(1, FC)).upper() + + Decl->getName().substr(1).str(); + return FixItHint::CreateReplacement( + CharSourceRange::getTokenRange(SourceRange(Decl->getLocation())), + llvm::StringRef(NewName)); +} +} // namespace + +void GlobalVariableDeclarationCheck::registerMatchers(MatchFinder *Finder) { + // The relevant Style Guide rule only applies to Objective-C. + if (!getLangOpts().ObjC1 && !getLangOpts().ObjC2) { + return; + } + // 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) { + if (const auto *Decl = Result.Nodes.getNodeAs("global_var")) { + diag(Decl->getLocation(), + "non-const global variable '%0' must have a name which starts with " + "'g[A-Z]'") + << Decl->getName() << generateFixItHint(Decl, false); + } + if (const auto *Decl = Result.Nodes.getNodeAs("global_const")) { + diag(Decl->getLocation(), + "const global variable '%0' must have a name which starts with " + "'k[A-Z]'") + << Decl->getName() << generateFixItHint(Decl, true); + } +} + +} // namespace objc +} // 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" @@ -34,7 +35,7 @@ namespace google { class GoogleModule : public ClangTidyModule { -public: + public: void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override { CheckFactories.registerCheck( "google-build-explicit-make-pair"); @@ -46,6 +47,10 @@ "google-default-arguments"); CheckFactories.registerCheck( "google-explicit-constructor"); + CheckFactories.registerCheck( + "google-global-names-in-headers"); + CheckFactories.registerCheck( + "google-objc-global-variable-declaration"); CheckFactories.registerCheck( "google-runtime-int"); CheckFactories.registerCheck( @@ -61,8 +66,6 @@ CheckFactories .registerCheck( "google-readability-braces-around-statements"); - CheckFactories.registerCheck( - "google-global-names-in-headers"); CheckFactories.registerCheck( "google-readability-function-size"); CheckFactories @@ -89,11 +92,11 @@ static ClangTidyModuleRegistry::Add X("google-module", "Adds Google lint checks."); -} // namespace google +} // namespace google // This anchor is used to force the linker to link in the generated object file // and thus register the GoogleModule. volatile int GoogleModuleAnchorSource = 0; -} // namespace tidy -} // namespace clang +} // namespace tidy +} // namespace clang 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,42 @@ +.. 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. + +The corresponding style guide rule: +http://google.github.io/styleguide/objcguide.html#variable-names + +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* gMyString = @"hello"; + +Another example of constant: + +.. code-block:: objc + static NSString* const myConstString = @"hello"; + +The fix will be: + +.. code-block:: objc + static NSString* const kMyConstString = @"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. 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,41 @@ +// 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: static NSString* const kMyConstString = @"hello"; + +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: static NSString* gMyString = @"hi"; + +NSString* globalString = @"test"; +// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: non-const global variable 'globalString' must have a name which starts with 'g[A-Z]' [google-objc-global-variable-declaration] +// CHECK-FIXES: NSString* gGlobalString = @"test"; + +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: static NSString* a = @"too simple"; + +static NSString* noDef; +// CHECK-MESSAGES: :[[@LINE-1]]:18: warning: non-const global variable 'noDef' must have a name which starts with 'g[A-Z]' [google-objc-global-variable-declaration] +// CHECK-FIXES: static NSString* gNoDef; + +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: static NSString* const _notAlpha = @"NotBeginWithAlpha"; + +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: static NSString* const k_Alpha = @"SecondNotAlpha"; + +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