1 //===--- FunctionNamingCheck.cpp - clang-tidy -----------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "FunctionNamingCheck.h"
10 #include "clang/AST/ASTContext.h"
11 #include "clang/ASTMatchers/ASTMatchFinder.h"
12 #include "llvm/Support/Regex.h"
14 using namespace clang::ast_matchers
;
16 namespace clang::tidy::google::objc
{
20 std::string
validFunctionNameRegex(bool RequirePrefix
) {
21 // Allow the following name patterns for all functions:
22 // • ABFoo (prefix + UpperCamelCase)
23 // • ABURL (prefix + capitalized acronym/initialism)
25 // If no prefix is required, additionally allow the following name patterns:
26 // • Foo (UpperCamelCase)
27 // • URL (capitalized acronym/initialism)
29 // The function name following the prefix can contain standard and
30 // non-standard capitalized character sequences including acronyms,
31 // initialisms, and prefixes of symbols (e.g., UIColorFromNSString). For this
32 // reason, the regex only verifies that the function name after the prefix
33 // begins with a capital letter followed by an arbitrary sequence of
34 // alphanumeric characters.
36 // If a prefix is required, the regex checks for a capital letter followed by
37 // another capital letter or number that is part of the prefix and another
38 // capital letter or number that begins the name following the prefix.
39 std::string FunctionNameMatcher
=
40 std::string(RequirePrefix
? "[A-Z][A-Z0-9]+" : "") + "[A-Z][a-zA-Z0-9]*";
41 return std::string("::(") + FunctionNameMatcher
+ ")$";
44 /// For now we will only fix functions of static storage class with names like
45 /// 'functionName' or 'function_name' and convert them to 'FunctionName'. For
46 /// other cases the user must determine an appropriate name on their own.
47 FixItHint
generateFixItHint(const FunctionDecl
*Decl
) {
48 // A fixit can be generated for functions of static storage class but
49 // otherwise the check cannot determine the appropriate function name prefix
51 if (Decl
->getStorageClass() != SC_Static
)
54 StringRef Name
= Decl
->getName();
55 std::string NewName
= Decl
->getName().str();
58 bool AtWordBoundary
= true;
59 while (Index
< NewName
.size()) {
60 char Ch
= NewName
[Index
];
62 // Capitalize the first letter after every word boundary.
64 NewName
[Index
] = toupper(NewName
[Index
]);
65 AtWordBoundary
= false;
68 // Advance the index after every alphanumeric character.
71 // Strip out any characters other than alphanumeric characters.
72 NewName
.erase(Index
, 1);
73 AtWordBoundary
= true;
77 // Generate a fixit hint if the new name is different.
79 return FixItHint::CreateReplacement(
80 CharSourceRange::getTokenRange(SourceRange(Decl
->getLocation())),
81 llvm::StringRef(NewName
));
88 void FunctionNamingCheck::registerMatchers(MatchFinder
*Finder
) {
89 // Enforce Objective-C function naming conventions on all functions except:
90 // • Functions defined in system headers.
91 // • C++ member functions.
92 // • Namespaced functions.
93 // • Implicitly defined functions.
94 // • The main function.
97 unless(anyOf(isExpansionInSystemHeader(), cxxMethodDecl(),
98 hasAncestor(namespaceDecl()), isMain(), isImplicit(),
99 matchesName(validFunctionNameRegex(true)),
100 allOf(isStaticStorageClass(),
101 matchesName(validFunctionNameRegex(false))))))
106 void FunctionNamingCheck::check(const MatchFinder::MatchResult
&Result
) {
107 const auto *MatchedDecl
= Result
.Nodes
.getNodeAs
<FunctionDecl
>("function");
109 bool IsGlobal
= MatchedDecl
->getStorageClass() != SC_Static
;
110 diag(MatchedDecl
->getLocation(),
111 "%select{static function|function in global namespace}1 named %0 must "
112 "%select{be in|have an appropriate prefix followed by}1 Pascal case as "
113 "required by Google Objective-C style guide")
114 << MatchedDecl
<< IsGlobal
<< generateFixItHint(MatchedDecl
);
117 } // namespace clang::tidy::google::objc