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

Provided by KDAB

Privacy Policy
Update your C++ knowledge – Modern C++11/14/17 Training
Find out more

source code of clang-tools-extra/clang-tidy/google/FunctionNamingCheck.cpp