clang-tools 22.0.0git
FunctionNamingCheck.cpp
Go to the documentation of this file.
1//===----------------------------------------------------------------------===//
2//
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
6//
7//===----------------------------------------------------------------------===//
8
10#include "clang/ASTMatchers/ASTMatchFinder.h"
11#include "llvm/Support/Regex.h"
12
13using namespace clang::ast_matchers;
14
16
17static std::string validFunctionNameRegex(bool RequirePrefix) {
18 // Allow the following name patterns for all functions:
19 // • ABFoo (prefix + UpperCamelCase)
20 // • ABURL (prefix + capitalized acronym/initialism)
21 //
22 // If no prefix is required, additionally allow the following name patterns:
23 // • Foo (UpperCamelCase)
24 // • URL (capitalized acronym/initialism)
25 //
26 // The function name following the prefix can contain standard and
27 // non-standard capitalized character sequences including acronyms,
28 // initialisms, and prefixes of symbols (e.g., UIColorFromNSString). For this
29 // reason, the regex only verifies that the function name after the prefix
30 // begins with a capital letter followed by an arbitrary sequence of
31 // alphanumeric characters.
32 //
33 // If a prefix is required, the regex checks for a capital letter followed by
34 // another capital letter or number that is part of the prefix and another
35 // capital letter or number that begins the name following the prefix.
36 const std::string FunctionNameMatcher =
37 std::string(RequirePrefix ? "[A-Z][A-Z0-9]+" : "") + "[A-Z][a-zA-Z0-9]*";
38 return std::string("::(") + FunctionNameMatcher + ")$";
39}
40
41/// For now we will only fix functions of static storage class with names like
42/// 'functionName' or 'function_name' and convert them to 'FunctionName'. For
43/// other cases the user must determine an appropriate name on their own.
44static FixItHint generateFixItHint(const FunctionDecl *Decl) {
45 // A fixit can be generated for functions of static storage class but
46 // otherwise the check cannot determine the appropriate function name prefix
47 // to use.
48 if (Decl->getStorageClass() != SC_Static)
49 return {};
50
51 const StringRef Name = Decl->getName();
52 std::string NewName = Decl->getName().str();
53
54 size_t Index = 0;
55 bool AtWordBoundary = true;
56 while (Index < NewName.size()) {
57 const char Ch = NewName[Index];
58 if (isalnum(Ch)) {
59 // Capitalize the first letter after every word boundary.
60 if (AtWordBoundary) {
61 NewName[Index] = toupper(NewName[Index]);
62 AtWordBoundary = false;
63 }
64
65 // Advance the index after every alphanumeric character.
66 Index++;
67 } else {
68 // Strip out any characters other than alphanumeric characters.
69 NewName.erase(Index, 1);
70 AtWordBoundary = true;
71 }
72 }
73
74 // Generate a fixit hint if the new name is different.
75 if (NewName != Name)
76 return FixItHint::CreateReplacement(
77 CharSourceRange::getTokenRange(SourceRange(Decl->getLocation())),
78 llvm::StringRef(NewName));
79
80 return {};
81}
82
83void FunctionNamingCheck::registerMatchers(MatchFinder *Finder) {
84 // Enforce Objective-C function naming conventions on all functions except:
85 // • Functions defined in system headers.
86 // • C++ member functions.
87 // • Namespaced functions.
88 // • Implicitly defined functions.
89 // • The main function.
90 Finder->addMatcher(
91 functionDecl(
92 unless(anyOf(isExpansionInSystemHeader(), cxxMethodDecl(),
93 hasAncestor(namespaceDecl()), isMain(), isImplicit(),
94 matchesName(validFunctionNameRegex(true)),
95 allOf(isStaticStorageClass(),
96 matchesName(validFunctionNameRegex(false))))))
97 .bind("function"),
98 this);
99}
100
101void FunctionNamingCheck::check(const MatchFinder::MatchResult &Result) {
102 const auto *MatchedDecl = Result.Nodes.getNodeAs<FunctionDecl>("function");
103
104 const bool IsGlobal = MatchedDecl->getStorageClass() != SC_Static;
105 diag(MatchedDecl->getLocation(),
106 "%select{static function|function in global namespace}1 named %0 must "
107 "%select{be in|have an appropriate prefix followed by}1 Pascal case as "
108 "required by Google Objective-C style guide")
109 << MatchedDecl << IsGlobal << generateFixItHint(MatchedDecl);
110}
111
112} // namespace clang::tidy::google::objc
void registerMatchers(ast_matchers::MatchFinder *Finder) override
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
static FixItHint generateFixItHint(const FunctionDecl *Decl)
For now we will only fix functions of static storage class with names like 'functionName' or 'functio...
static std::string validFunctionNameRegex(bool RequirePrefix)