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 157