| //===--- IdentifierLengthCheck.cpp - clang-tidy |
| //-----------------------------===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "IdentifierLengthCheck.h" |
| #include "../utils/OptionsUtils.h" |
| #include "clang/AST/ASTContext.h" |
| #include "clang/ASTMatchers/ASTMatchFinder.h" |
| |
| using namespace clang::ast_matchers; |
| |
| namespace clang { |
| namespace tidy { |
| namespace readability { |
| |
| const unsigned DefaultMinimumVariableNameLength = 3; |
| const unsigned DefaultMinimumLoopCounterNameLength = 2; |
| const unsigned DefaultMinimumExceptionNameLength = 2; |
| const unsigned DefaultMinimumParameterNameLength = 3; |
| const char DefaultIgnoredLoopCounterNames[] = "^[ijk_]$"; |
| const char DefaultIgnoredVariableNames[] = ""; |
| const char DefaultIgnoredExceptionVariableNames[] = "^[e]$"; |
| const char DefaultIgnoredParameterNames[] = "^[n]$"; |
| |
| const char ErrorMessage[] = |
| "%select{variable|exception variable|loop variable|" |
| "parameter}0 name %1 is too short, expected at least %2 characters"; |
| |
| IdentifierLengthCheck::IdentifierLengthCheck(StringRef Name, |
| ClangTidyContext *Context) |
| : ClangTidyCheck(Name, Context), |
| MinimumVariableNameLength(Options.get("MinimumVariableNameLength", |
| DefaultMinimumVariableNameLength)), |
| MinimumLoopCounterNameLength(Options.get( |
| "MinimumLoopCounterNameLength", DefaultMinimumLoopCounterNameLength)), |
| MinimumExceptionNameLength(Options.get( |
| "MinimumExceptionNameLength", DefaultMinimumExceptionNameLength)), |
| MinimumParameterNameLength(Options.get( |
| "MinimumParameterNameLength", DefaultMinimumParameterNameLength)), |
| IgnoredVariableNamesInput( |
| Options.get("IgnoredVariableNames", DefaultIgnoredVariableNames)), |
| IgnoredVariableNames(IgnoredVariableNamesInput), |
| IgnoredLoopCounterNamesInput(Options.get("IgnoredLoopCounterNames", |
| DefaultIgnoredLoopCounterNames)), |
| IgnoredLoopCounterNames(IgnoredLoopCounterNamesInput), |
| IgnoredExceptionVariableNamesInput( |
| Options.get("IgnoredExceptionVariableNames", |
| DefaultIgnoredExceptionVariableNames)), |
| IgnoredExceptionVariableNames(IgnoredExceptionVariableNamesInput), |
| IgnoredParameterNamesInput( |
| Options.get("IgnoredParameterNames", DefaultIgnoredParameterNames)), |
| IgnoredParameterNames(IgnoredParameterNamesInput) {} |
| |
| void IdentifierLengthCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { |
| Options.store(Opts, "MinimumVariableNameLength", MinimumVariableNameLength); |
| Options.store(Opts, "MinimumLoopCounterNameLength", |
| MinimumLoopCounterNameLength); |
| Options.store(Opts, "MinimumExceptionNameLength", MinimumExceptionNameLength); |
| Options.store(Opts, "MinimumParameterNameLength", MinimumParameterNameLength); |
| Options.store(Opts, "IgnoredLoopCounterNames", IgnoredLoopCounterNamesInput); |
| Options.store(Opts, "IgnoredVariableNames", IgnoredVariableNamesInput); |
| Options.store(Opts, "IgnoredExceptionVariableNames", |
| IgnoredExceptionVariableNamesInput); |
| Options.store(Opts, "IgnoredParameterNames", IgnoredParameterNamesInput); |
| } |
| |
| void IdentifierLengthCheck::registerMatchers(MatchFinder *Finder) { |
| if (MinimumLoopCounterNameLength > 1) |
| Finder->addMatcher( |
| forStmt(hasLoopInit(declStmt(forEach(varDecl().bind("loopVar"))))), |
| this); |
| |
| if (MinimumExceptionNameLength > 1) |
| Finder->addMatcher(varDecl(hasParent(cxxCatchStmt())).bind("exceptionVar"), |
| this); |
| |
| if (MinimumParameterNameLength > 1) |
| Finder->addMatcher(parmVarDecl().bind("paramVar"), this); |
| |
| if (MinimumVariableNameLength > 1) |
| Finder->addMatcher( |
| varDecl(unless(anyOf(hasParent(declStmt(hasParent(forStmt()))), |
| hasParent(cxxCatchStmt()), parmVarDecl()))) |
| .bind("standaloneVar"), |
| this); |
| } |
| |
| void IdentifierLengthCheck::check(const MatchFinder::MatchResult &Result) { |
| const auto *StandaloneVar = Result.Nodes.getNodeAs<VarDecl>("standaloneVar"); |
| if (StandaloneVar) { |
| if (!StandaloneVar->getIdentifier()) |
| return; |
| |
| StringRef VarName = StandaloneVar->getName(); |
| |
| if (VarName.size() >= MinimumVariableNameLength || |
| IgnoredVariableNames.match(VarName)) |
| return; |
| |
| diag(StandaloneVar->getLocation(), ErrorMessage) |
| << 0 << StandaloneVar << MinimumVariableNameLength; |
| } |
| |
| auto *ExceptionVarName = Result.Nodes.getNodeAs<VarDecl>("exceptionVar"); |
| if (ExceptionVarName) { |
| if (!ExceptionVarName->getIdentifier()) |
| return; |
| |
| StringRef VarName = ExceptionVarName->getName(); |
| if (VarName.size() >= MinimumExceptionNameLength || |
| IgnoredExceptionVariableNames.match(VarName)) |
| return; |
| |
| diag(ExceptionVarName->getLocation(), ErrorMessage) |
| << 1 << ExceptionVarName << MinimumExceptionNameLength; |
| } |
| |
| const auto *LoopVar = Result.Nodes.getNodeAs<VarDecl>("loopVar"); |
| if (LoopVar) { |
| if (!LoopVar->getIdentifier()) |
| return; |
| |
| StringRef VarName = LoopVar->getName(); |
| |
| if (VarName.size() >= MinimumLoopCounterNameLength || |
| IgnoredLoopCounterNames.match(VarName)) |
| return; |
| |
| diag(LoopVar->getLocation(), ErrorMessage) |
| << 2 << LoopVar << MinimumLoopCounterNameLength; |
| } |
| |
| const auto *ParamVar = Result.Nodes.getNodeAs<VarDecl>("paramVar"); |
| if (ParamVar) { |
| if (!ParamVar->getIdentifier()) |
| return; |
| |
| StringRef VarName = ParamVar->getName(); |
| |
| if (VarName.size() >= MinimumParameterNameLength || |
| IgnoredParameterNames.match(VarName)) |
| return; |
| |
| diag(ParamVar->getLocation(), ErrorMessage) |
| << 3 << ParamVar << MinimumParameterNameLength; |
| } |
| } |
| |
| } // namespace readability |
| } // namespace tidy |
| } // namespace clang |