1 //===--- IdentifierLengthCheck.cpp - clang-tidy
2 //-----------------------------===//
3 //
4 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5 // See https://llvm.org/LICENSE.txt for license information.
6 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //
8 //===----------------------------------------------------------------------===//
9
10 #include "IdentifierLengthCheck.h"
11 #include "../utils/OptionsUtils.h"
12 #include "clang/AST/ASTContext.h"
13 #include "clang/ASTMatchers/ASTMatchFinder.h"
14
15 using namespace clang::ast_matchers;
16
17 namespace clang {
18 namespace tidy {
19 namespace readability {
20
21 const unsigned DefaultMinimumVariableNameLength = 3;
22 const unsigned DefaultMinimumLoopCounterNameLength = 2;
23 const unsigned DefaultMinimumExceptionNameLength = 2;
24 const unsigned DefaultMinimumParameterNameLength = 3;
25 const char DefaultIgnoredLoopCounterNames[] = "^[ijk_]$";
26 const char DefaultIgnoredVariableNames[] = "";
27 const char DefaultIgnoredExceptionVariableNames[] = "^[e]$";
28 const char DefaultIgnoredParameterNames[] = "^[n]$";
29
30 const char ErrorMessage[] =
31 "%select{variable|exception variable|loop variable|"
32 "parameter}0 name %1 is too short, expected at least %2 characters";
33
IdentifierLengthCheck(StringRef Name,ClangTidyContext * Context)34 IdentifierLengthCheck::IdentifierLengthCheck(StringRef Name,
35 ClangTidyContext *Context)
36 : ClangTidyCheck(Name, Context),
37 MinimumVariableNameLength(Options.get("MinimumVariableNameLength",
38 DefaultMinimumVariableNameLength)),
39 MinimumLoopCounterNameLength(Options.get(
40 "MinimumLoopCounterNameLength", DefaultMinimumLoopCounterNameLength)),
41 MinimumExceptionNameLength(Options.get(
42 "MinimumExceptionNameLength", DefaultMinimumExceptionNameLength)),
43 MinimumParameterNameLength(Options.get(
44 "MinimumParameterNameLength", DefaultMinimumParameterNameLength)),
45 IgnoredVariableNamesInput(
46 Options.get("IgnoredVariableNames", DefaultIgnoredVariableNames)),
47 IgnoredVariableNames(IgnoredVariableNamesInput),
48 IgnoredLoopCounterNamesInput(Options.get("IgnoredLoopCounterNames",
49 DefaultIgnoredLoopCounterNames)),
50 IgnoredLoopCounterNames(IgnoredLoopCounterNamesInput),
51 IgnoredExceptionVariableNamesInput(
52 Options.get("IgnoredExceptionVariableNames",
53 DefaultIgnoredExceptionVariableNames)),
54 IgnoredExceptionVariableNames(IgnoredExceptionVariableNamesInput),
55 IgnoredParameterNamesInput(
56 Options.get("IgnoredParameterNames", DefaultIgnoredParameterNames)),
57 IgnoredParameterNames(IgnoredParameterNamesInput) {}
58
storeOptions(ClangTidyOptions::OptionMap & Opts)59 void IdentifierLengthCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
60 Options.store(Opts, "MinimumVariableNameLength", MinimumVariableNameLength);
61 Options.store(Opts, "MinimumLoopCounterNameLength",
62 MinimumLoopCounterNameLength);
63 Options.store(Opts, "MinimumExceptionNameLength", MinimumExceptionNameLength);
64 Options.store(Opts, "MinimumParameterNameLength", MinimumParameterNameLength);
65 Options.store(Opts, "IgnoredLoopCounterNames", IgnoredLoopCounterNamesInput);
66 Options.store(Opts, "IgnoredVariableNames", IgnoredVariableNamesInput);
67 Options.store(Opts, "IgnoredExceptionVariableNames",
68 IgnoredExceptionVariableNamesInput);
69 Options.store(Opts, "IgnoredParameterNames", IgnoredParameterNamesInput);
70 }
71
registerMatchers(MatchFinder * Finder)72 void IdentifierLengthCheck::registerMatchers(MatchFinder *Finder) {
73 if (MinimumLoopCounterNameLength > 1)
74 Finder->addMatcher(
75 forStmt(hasLoopInit(declStmt(forEach(varDecl().bind("loopVar"))))),
76 this);
77
78 if (MinimumExceptionNameLength > 1)
79 Finder->addMatcher(varDecl(hasParent(cxxCatchStmt())).bind("exceptionVar"),
80 this);
81
82 if (MinimumParameterNameLength > 1)
83 Finder->addMatcher(parmVarDecl().bind("paramVar"), this);
84
85 if (MinimumVariableNameLength > 1)
86 Finder->addMatcher(
87 varDecl(unless(anyOf(hasParent(declStmt(hasParent(forStmt()))),
88 hasParent(cxxCatchStmt()), parmVarDecl())))
89 .bind("standaloneVar"),
90 this);
91 }
92
check(const MatchFinder::MatchResult & Result)93 void IdentifierLengthCheck::check(const MatchFinder::MatchResult &Result) {
94 const auto *StandaloneVar = Result.Nodes.getNodeAs<VarDecl>("standaloneVar");
95 if (StandaloneVar) {
96 if (!StandaloneVar->getIdentifier())
97 return;
98
99 StringRef VarName = StandaloneVar->getName();
100
101 if (VarName.size() >= MinimumVariableNameLength ||
102 IgnoredVariableNames.match(VarName))
103 return;
104
105 diag(StandaloneVar->getLocation(), ErrorMessage)
106 << 0 << StandaloneVar << MinimumVariableNameLength;
107 }
108
109 auto *ExceptionVarName = Result.Nodes.getNodeAs<VarDecl>("exceptionVar");
110 if (ExceptionVarName) {
111 if (!ExceptionVarName->getIdentifier())
112 return;
113
114 StringRef VarName = ExceptionVarName->getName();
115 if (VarName.size() >= MinimumExceptionNameLength ||
116 IgnoredExceptionVariableNames.match(VarName))
117 return;
118
119 diag(ExceptionVarName->getLocation(), ErrorMessage)
120 << 1 << ExceptionVarName << MinimumExceptionNameLength;
121 }
122
123 const auto *LoopVar = Result.Nodes.getNodeAs<VarDecl>("loopVar");
124 if (LoopVar) {
125 if (!LoopVar->getIdentifier())
126 return;
127
128 StringRef VarName = LoopVar->getName();
129
130 if (VarName.size() >= MinimumLoopCounterNameLength ||
131 IgnoredLoopCounterNames.match(VarName))
132 return;
133
134 diag(LoopVar->getLocation(), ErrorMessage)
135 << 2 << LoopVar << MinimumLoopCounterNameLength;
136 }
137
138 const auto *ParamVar = Result.Nodes.getNodeAs<VarDecl>("paramVar");
139 if (ParamVar) {
140 if (!ParamVar->getIdentifier())
141 return;
142
143 StringRef VarName = ParamVar->getName();
144
145 if (VarName.size() >= MinimumParameterNameLength ||
146 IgnoredParameterNames.match(VarName))
147 return;
148
149 diag(ParamVar->getLocation(), ErrorMessage)
150 << 3 << ParamVar << MinimumParameterNameLength;
151 }
152 }
153
154 } // namespace readability
155 } // namespace tidy
156 } // namespace clang
157