llvm/clang-tools-extra/clang-tidy/readability/IdentifierLengthCheck.cpp
Florin Iucha d2c5cbc3a8 Add a check for enforcing minimum length for variable names
Add a check for enforcing minimum length for variable names. A default
minimum length of three characters is applied to regular variables
(including function parameters). Loop counters and exception variables
have a minimum of two characters. Additionally, the 'i', 'j' and 'k'
are accepted as legacy values.

All three sizes, as well as the list of accepted legacy loop counter
names are configurable.
2021-08-12 11:31:26 -04:00

157 lines
5.9 KiB
C++

//===--- 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