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