|
| 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 | + |
| 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 | + |
| 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 | + |
| 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 | + |
| 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 |
0 commit comments