clang-tools 24.0.0git
GlobalVariableDeclarationCheck.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 "../utils/Matchers.h"
11#include "clang/ASTMatchers/ASTMatchFinder.h"
12#include "llvm/ADT/StringExtras.h"
13#include "llvm/ADT/StringRef.h"
14
15#include <string>
16
17using namespace clang::ast_matchers;
18using namespace clang::tidy::matchers;
19
21
22static FixItHint generateFixItHint(const VarDecl *Decl, bool IsConst) {
23 if (IsConst && (Decl->getStorageClass() != SC_Static)) {
24 // No fix available if it is not a static constant, since it is difficult
25 // to determine the proper fix in this case.
26 return {};
27 }
28
29 const char FC = Decl->getName()[0];
30 if (!llvm::isAlpha(FC) || Decl->getName().size() == 1) {
31 // No fix available if first character is not alphabetical character, or it
32 // is a single-character variable, since it is difficult to determine the
33 // proper fix in this case. Users should create a proper variable name by
34 // their own.
35 return {};
36 }
37 const char SC = Decl->getName()[1];
38 if ((FC == 'k' || FC == 'g') && !llvm::isAlpha(SC)) {
39 // No fix available if the prefix is correct but the second character is
40 // not alphabetical, since it is difficult to determine the proper fix in
41 // this case.
42 return {};
43 }
44
45 const auto NewName = (IsConst ? "k" : "g") +
46 StringRef(std::string(1, FC)).upper() +
47 Decl->getName().substr(1).str();
48
49 return FixItHint::CreateReplacement(
50 CharSourceRange::getTokenRange(SourceRange(Decl->getLocation())),
51 StringRef(NewName));
52}
53
55 // need to add two matchers since we need to bind different ids to distinguish
56 // constants and variables. Since bind() can only be called on node matchers,
57 // we cannot make it in one matcher.
58 //
59 // Note that hasGlobalStorage() matches static variables declared locally
60 // inside a function or method, so we need to exclude those with
61 // isLocalVarDecl().
62 Finder->addMatcher(
63 varDecl(hasGlobalStorage(), unless(hasType(isConstQualified())),
64 unless(isLocalVarDecl()), unless(matchesName("::g[A-Z]")))
65 .bind("global_var"),
66 this);
67 Finder->addMatcher(varDecl(hasGlobalStorage(), hasType(isConstQualified()),
68 unless(isLocalVarDecl()),
69 unless(matchesName("::(k[A-Z])|([A-Z][A-Z0-9])")))
70 .bind("global_const"),
71 this);
72}
73
75 const MatchFinder::MatchResult &Result) {
76 if (const auto *Decl = Result.Nodes.getNodeAs<VarDecl>("global_var")) {
77 if (Decl->isStaticDataMember())
78 return;
79 diag(Decl->getLocation(),
80 "non-const global variable '%0' must have a name which starts with "
81 "'g[A-Z]'")
82 << Decl->getName() << generateFixItHint(Decl, false);
83 }
84 if (const auto *Decl = Result.Nodes.getNodeAs<VarDecl>("global_const")) {
85 if (Decl->isStaticDataMember())
86 return;
87 diag(Decl->getLocation(),
88 "const global variable '%0' must have a name which starts with "
89 "an appropriate prefix")
90 << Decl->getName() << generateFixItHint(Decl, true);
91 }
92}
93
94} // namespace clang::tidy::google::objc
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
void registerMatchers(ast_matchers::MatchFinder *Finder) override
static FixItHint generateFixItHint(const FunctionDecl *Decl)
For now we will only fix functions of static storage class with names like 'functionName' or 'functio...