Skip to content

Commit e34a761

Browse files
committedNov 17, 2018
[clang-tidy/checks] Implement a clang-tidy check to verify Google Objective-C function naming conventions 📜
Summary: §1 Description This check finds function names in function declarations in Objective-C files that do not follow the naming pattern described in the Google Objective-C Style Guide. Function names should be in UpperCamelCase and functions that are not of static storage class should have an appropriate prefix as described in the Google Objective-C Style Guide. The function `main` is a notable exception. Function declarations in expansions in system headers are ignored. Example conforming function definitions: ``` static bool IsPositive(int i) { return i > 0; } static bool ABIsPositive(int i) { return i > 0; } bool ABIsNegative(int i) { return i < 0; } ``` A fixit hint is generated for functions of static storage class but otherwise the check does not generate a fixit hint because an appropriate prefix for the function cannot be determined. §2 Test Notes * Verified clang-tidy tests pass successfully. * Used check_clang_tidy.py to verify expected output of processing google-objc-function-naming.m Reviewers: benhamilton, hokein, Wizard, aaron.ballman Reviewed By: benhamilton Subscribers: Eugene.Zelenko, mgorny, xazax.hun, cfe-commits Tags: #clang-tools-extra Differential Revision: https://reviews.llvm.org/D51575 llvm-svn: 347132
1 parent dd61f11 commit e34a761

File tree

8 files changed

+254
-0
lines changed

8 files changed

+254
-0
lines changed
 

Diff for: ‎clang-tools-extra/clang-tidy/google/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ add_clang_library(clangTidyGoogleModule
66
DefaultArgumentsCheck.cpp
77
ExplicitConstructorCheck.cpp
88
ExplicitMakePairCheck.cpp
9+
FunctionNamingCheck.cpp
910
GlobalNamesInHeadersCheck.cpp
1011
GlobalVariableDeclarationCheck.cpp
1112
GoogleTidyModule.cpp
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
//===--- FunctionNamingCheck.cpp - clang-tidy -----------------------------===//
2+
//
3+
// The LLVM Compiler Infrastructure
4+
//
5+
// This file is distributed under the University of Illinois Open Source
6+
// License. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
10+
#include "FunctionNamingCheck.h"
11+
#include "clang/AST/ASTContext.h"
12+
#include "clang/ASTMatchers/ASTMatchFinder.h"
13+
#include "llvm/Support/Regex.h"
14+
15+
using namespace clang::ast_matchers;
16+
17+
namespace clang {
18+
namespace tidy {
19+
namespace google {
20+
namespace objc {
21+
22+
namespace {
23+
24+
std::string validFunctionNameRegex(bool RequirePrefix) {
25+
// Allow the following name patterns for all functions:
26+
// • ABFoo (prefix + UpperCamelCase)
27+
// • ABURL (prefix + capitalized acronym/initialism)
28+
//
29+
// If no prefix is required, additionally allow the following name patterns:
30+
// • Foo (UpperCamelCase)
31+
// • URL (capitalized acronym/initialism)
32+
//
33+
// The function name following the prefix can contain standard and
34+
// non-standard capitalized character sequences including acronyms,
35+
// initialisms, and prefixes of symbols (e.g., UIColorFromNSString). For this
36+
// reason, the regex only verifies that the function name after the prefix
37+
// begins with a capital letter followed by an arbitrary sequence of
38+
// alphanumeric characters.
39+
//
40+
// If a prefix is required, the regex checks for a capital letter followed by
41+
// another capital letter or number that is part of the prefix and another
42+
// capital letter or number that begins the name following the prefix.
43+
std::string FunctionNameMatcher =
44+
std::string(RequirePrefix ? "[A-Z][A-Z0-9]+" : "") + "[A-Z][a-zA-Z0-9]*";
45+
return std::string("::(") + FunctionNameMatcher + ")$";
46+
}
47+
48+
/// For now we will only fix functions of static storage class with names like
49+
/// 'functionName' or 'function_name' and convert them to 'FunctionName'. For
50+
/// other cases the user must determine an appropriate name on their own.
51+
FixItHint generateFixItHint(const FunctionDecl *Decl) {
52+
// A fixit can be generated for functions of static storage class but
53+
// otherwise the check cannot determine the appropriate function name prefix
54+
// to use.
55+
if (Decl->getStorageClass() != SC_Static)
56+
return FixItHint();
57+
58+
StringRef Name = Decl->getName();
59+
std::string NewName = Decl->getName().str();
60+
61+
size_t Index = 0;
62+
bool AtWordBoundary = true;
63+
while (Index < NewName.size()) {
64+
char ch = NewName[Index];
65+
if (isalnum(ch)) {
66+
// Capitalize the first letter after every word boundary.
67+
if (AtWordBoundary) {
68+
NewName[Index] = toupper(NewName[Index]);
69+
AtWordBoundary = false;
70+
}
71+
72+
// Advance the index after every alphanumeric character.
73+
Index++;
74+
} else {
75+
// Strip out any characters other than alphanumeric characters.
76+
NewName.erase(Index, 1);
77+
AtWordBoundary = true;
78+
}
79+
}
80+
81+
// Generate a fixit hint if the new name is different.
82+
if (NewName != Name)
83+
return FixItHint::CreateReplacement(
84+
CharSourceRange::getTokenRange(SourceRange(Decl->getLocation())),
85+
llvm::StringRef(NewName));
86+
87+
return FixItHint();
88+
}
89+
90+
} // namespace
91+
92+
void FunctionNamingCheck::registerMatchers(MatchFinder *Finder) {
93+
// This check should only be applied to Objective-C sources.
94+
if (!getLangOpts().ObjC)
95+
return;
96+
97+
// Match function declarations that are not in system headers and are not
98+
// main.
99+
Finder->addMatcher(
100+
functionDecl(
101+
unless(isExpansionInSystemHeader()),
102+
unless(anyOf(isMain(), matchesName(validFunctionNameRegex(true)),
103+
allOf(isStaticStorageClass(),
104+
matchesName(validFunctionNameRegex(false))))))
105+
.bind("function"),
106+
this);
107+
}
108+
109+
void FunctionNamingCheck::check(const MatchFinder::MatchResult &Result) {
110+
const auto *MatchedDecl = Result.Nodes.getNodeAs<FunctionDecl>("function");
111+
112+
diag(MatchedDecl->getLocation(),
113+
"function name %0 not using function naming conventions described by "
114+
"Google Objective-C style guide")
115+
<< MatchedDecl << generateFixItHint(MatchedDecl);
116+
}
117+
118+
} // namespace objc
119+
} // namespace google
120+
} // namespace tidy
121+
} // namespace clang
+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
//===--- FunctionNamingCheck.h - clang-tidy ---------------------*- C++ -*-===//
2+
//
3+
// The LLVM Compiler Infrastructure
4+
//
5+
// This file is distributed under the University of Illinois Open Source
6+
// License. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
10+
#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_OBJC_FUNCTION_NAMING_CHECK_H
11+
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_OBJC_FUNCTION_NAMING_CHECK_H
12+
13+
#include "../ClangTidy.h"
14+
#include "llvm/ADT/StringRef.h"
15+
16+
namespace clang {
17+
namespace tidy {
18+
namespace google {
19+
namespace objc {
20+
21+
/// Finds function names that do not conform to the recommendations of the
22+
/// Google Objective-C Style Guide. Function names should be in upper camel case
23+
/// including capitalized acronyms and initialisms. Functions that are not of
24+
/// static storage class must also have an appropriate prefix. The function
25+
/// `main` is an exception. Note that this check does not apply to Objective-C
26+
/// method or property declarations.
27+
///
28+
/// For the user-facing documentation see:
29+
/// http://clang.llvm.org/extra/clang-tidy/checks/google-objc-function-naming.html
30+
class FunctionNamingCheck : public ClangTidyCheck {
31+
public:
32+
FunctionNamingCheck(StringRef Name, ClangTidyContext *Context)
33+
: ClangTidyCheck(Name, Context) {}
34+
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
35+
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
36+
};
37+
38+
} // namespace objc
39+
} // namespace google
40+
} // namespace tidy
41+
} // namespace clang
42+
43+
#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_OBJC_FUNCTION_NAMING_CHECK_H

Diff for: ‎clang-tools-extra/clang-tidy/google/GoogleTidyModule.cpp

+3
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "DefaultArgumentsCheck.h"
1919
#include "ExplicitConstructorCheck.h"
2020
#include "ExplicitMakePairCheck.h"
21+
#include "FunctionNamingCheck.h"
2122
#include "GlobalNamesInHeadersCheck.h"
2223
#include "GlobalVariableDeclarationCheck.h"
2324
#include "IntegerTypesCheck.h"
@@ -50,6 +51,8 @@ class GoogleModule : public ClangTidyModule {
5051
"google-global-names-in-headers");
5152
CheckFactories.registerCheck<objc::AvoidThrowingObjCExceptionCheck>(
5253
"google-objc-avoid-throwing-exception");
54+
CheckFactories.registerCheck<objc::FunctionNamingCheck>(
55+
"google-objc-function-naming");
5356
CheckFactories.registerCheck<objc::GlobalVariableDeclarationCheck>(
5457
"google-objc-global-variable-declaration");
5558
CheckFactories.registerCheck<runtime::IntegerTypesCheck>(

Diff for: ‎clang-tools-extra/docs/ReleaseNotes.rst

+6
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,12 @@ Improvements to clang-tidy
123123
Finds macro usage that is considered problematic because better language
124124
constructs exist for the task.
125125

126+
- New :doc:`google-objc-function-naming
127+
<clang-tidy/checks/google-objc-function-naming>` check.
128+
129+
Checks that function names in function declarations comply with the naming
130+
conventions described in the Google Objective-C Style Guide.
131+
126132
- New :doc:`misc-non-private-member-variables-in-classes
127133
<clang-tidy/checks/misc-non-private-member-variables-in-classes>` check.
128134

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
.. title:: clang-tidy - google-objc-function-naming
2+
3+
google-objc-function-naming
4+
===========================
5+
6+
Finds function declarations in Objective-C files that do not follow the pattern
7+
described in the Google Objective-C Style Guide.
8+
9+
The corresponding style guide rule can be found here:
10+
https://google.github.io/styleguide/objcguide.html#function-names
11+
12+
All function names should be in Pascal case. Functions whose storage class is
13+
not static should have an appropriate prefix.
14+
15+
The following code sample does not follow this pattern:
16+
17+
.. code-block:: objc
18+
19+
static bool is_positive(int i) { return i > 0; }
20+
bool IsNegative(int i) { return i < 0; }
21+
22+
The sample above might be corrected to the following code:
23+
24+
.. code-block:: objc
25+
26+
static bool IsPositive(int i) { return i > 0; }
27+
bool *ABCIsNegative(int i) { return i < 0; }

Diff for: ‎clang-tools-extra/docs/clang-tidy/checks/list.rst

+1
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ Clang-Tidy Checks
124124
google-explicit-constructor
125125
google-global-names-in-headers
126126
google-objc-avoid-throwing-exception
127+
google-objc-function-naming
127128
google-objc-global-variable-declaration
128129
google-readability-braces-around-statements (redirects to readability-braces-around-statements) <google-readability-braces-around-statements>
129130
google-readability-casting
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// RUN: %check_clang_tidy %s google-objc-function-naming %t
2+
3+
typedef _Bool bool;
4+
5+
static bool ispositive(int a) { return a > 0; }
6+
// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: function name 'ispositive' not using function naming conventions described by Google Objective-C style guide
7+
// CHECK-FIXES: static bool Ispositive(int a) { return a > 0; }
8+
9+
static bool is_positive(int a) { return a > 0; }
10+
// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: function name 'is_positive' not using function naming conventions described by Google Objective-C style guide
11+
// CHECK-FIXES: static bool IsPositive(int a) { return a > 0; }
12+
13+
static bool isPositive(int a) { return a > 0; }
14+
// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: function name 'isPositive' not using function naming conventions described by Google Objective-C style guide
15+
// CHECK-FIXES: static bool IsPositive(int a) { return a > 0; }
16+
17+
static bool Is_Positive(int a) { return a > 0; }
18+
// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: function name 'Is_Positive' not using function naming conventions described by Google Objective-C style guide
19+
// CHECK-FIXES: static bool IsPositive(int a) { return a > 0; }
20+
21+
static bool IsPositive(int a) { return a > 0; }
22+
23+
bool ispalindrome(const char *str);
24+
// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: function name 'ispalindrome' not using function naming conventions described by Google Objective-C style guide
25+
26+
static const char *md5(const char *str) { return 0; }
27+
// CHECK-MESSAGES: :[[@LINE-1]]:20: warning: function name 'md5' not using function naming conventions described by Google Objective-C style guide
28+
// CHECK-FIXES: static const char *Md5(const char *str) { return 0; }
29+
30+
static const char *MD5(const char *str) { return 0; }
31+
32+
static const char *URL(void) { return "https://clang.llvm.org/"; }
33+
34+
static const char *DEFURL(void) { return "https://clang.llvm.org/"; }
35+
36+
static const char *DEFFooURL(void) { return "https://clang.llvm.org/"; }
37+
38+
static const char *StringFromNSString(id str) { return ""; }
39+
40+
void ABLog_String(const char *str);
41+
// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: function name 'ABLog_String' not using function naming conventions described by Google Objective-C style guide
42+
43+
void ABLogString(const char *str);
44+
45+
bool IsPrime(int a);
46+
// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: function name 'IsPrime' not using function naming conventions described by Google Objective-C style guide
47+
48+
const char *ABURL(void) { return "https://clang.llvm.org/"; }
49+
50+
const char *ABFooURL(void) { return "https://clang.llvm.org/"; }
51+
52+
int main(int argc, const char **argv) { return 0; }

0 commit comments

Comments
 (0)
Please sign in to comment.