2016-01-29 23:54:26 +08:00
|
|
|
//===--- ForRangeCopyCheck.cpp - clang-tidy--------------------------------===//
|
|
|
|
//
|
2019-01-19 16:50:56 +08:00
|
|
|
// 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
|
2016-01-29 23:54:26 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "ForRangeCopyCheck.h"
|
2018-08-10 16:25:51 +08:00
|
|
|
#include "../utils/DeclRefExprUtils.h"
|
2016-03-06 05:17:58 +08:00
|
|
|
#include "../utils/FixItHintUtils.h"
|
2018-10-12 21:05:21 +08:00
|
|
|
#include "../utils/Matchers.h"
|
|
|
|
#include "../utils/OptionsUtils.h"
|
2016-01-29 23:54:26 +08:00
|
|
|
#include "../utils/TypeTraits.h"
|
2018-09-12 06:59:46 +08:00
|
|
|
#include "clang/Analysis/Analyses/ExprMutationAnalyzer.h"
|
[clang-tidy] implement utility-function to add 'const' to variables
Summary:
This patch extends the already existing facility to add 'const' to variables
to be more flexible and correct. The previous version did not consider pointers
as value AND pointee. For future automatic introduction for const-correctness
this shortcoming needs to be fixed.
It always allows configuration where the 'const' token is inserted, either on
the left side (if possible) or the right side.
It adds many unit-tests to the utility-function that did not exist before, as
the function was implicitly tested through clang-tidy checks. These
tests were not changed, as the API is still compatible.
Reviewers: aaron.ballman, hokein, alexfh, shuaiwang, lebedev.ri
Reviewed By: aaron.ballman
Subscribers: jdoerfert, mgorny, xazax.hun, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D54395
2020-01-04 03:36:49 +08:00
|
|
|
#include "clang/Basic/Diagnostic.h"
|
2016-01-29 23:54:26 +08:00
|
|
|
|
2016-05-03 02:00:29 +08:00
|
|
|
using namespace clang::ast_matchers;
|
|
|
|
|
2016-01-29 23:54:26 +08:00
|
|
|
namespace clang {
|
|
|
|
namespace tidy {
|
|
|
|
namespace performance {
|
|
|
|
|
|
|
|
ForRangeCopyCheck::ForRangeCopyCheck(StringRef Name, ClangTidyContext *Context)
|
|
|
|
: ClangTidyCheck(Name, Context),
|
2018-10-12 21:05:21 +08:00
|
|
|
WarnOnAllAutoCopies(Options.get("WarnOnAllAutoCopies", 0)),
|
|
|
|
AllowedTypes(
|
|
|
|
utils::options::parseStringList(Options.get("AllowedTypes", ""))) {}
|
2016-01-29 23:54:26 +08:00
|
|
|
|
|
|
|
void ForRangeCopyCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
|
|
|
|
Options.store(Opts, "WarnOnAllAutoCopies", WarnOnAllAutoCopies);
|
2018-10-12 21:05:21 +08:00
|
|
|
Options.store(Opts, "AllowedTypes",
|
|
|
|
utils::options::serializeStringList(AllowedTypes));
|
2016-01-29 23:54:26 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void ForRangeCopyCheck::registerMatchers(MatchFinder *Finder) {
|
|
|
|
// Match loop variables that are not references or pointers or are already
|
|
|
|
// initialized through MaterializeTemporaryExpr which indicates a type
|
|
|
|
// conversion.
|
|
|
|
auto LoopVar = varDecl(
|
2018-10-12 21:05:21 +08:00
|
|
|
hasType(qualType(
|
|
|
|
unless(anyOf(hasCanonicalType(anyOf(referenceType(), pointerType())),
|
|
|
|
hasDeclaration(namedDecl(
|
|
|
|
matchers::matchesAnyListedName(AllowedTypes))))))),
|
2016-01-29 23:54:26 +08:00
|
|
|
unless(hasInitializer(expr(hasDescendant(materializeTemporaryExpr())))));
|
|
|
|
Finder->addMatcher(cxxForRangeStmt(hasLoopVariable(LoopVar.bind("loopVar")))
|
|
|
|
.bind("forRange"),
|
|
|
|
this);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ForRangeCopyCheck::check(const MatchFinder::MatchResult &Result) {
|
|
|
|
const auto *Var = Result.Nodes.getNodeAs<VarDecl>("loopVar");
|
2018-10-12 21:05:21 +08:00
|
|
|
|
2016-01-29 23:54:26 +08:00
|
|
|
// Ignore code in macros since we can't place the fixes correctly.
|
2018-08-10 06:42:26 +08:00
|
|
|
if (Var->getBeginLoc().isMacroID())
|
2016-01-29 23:54:26 +08:00
|
|
|
return;
|
|
|
|
if (handleConstValueCopy(*Var, *Result.Context))
|
|
|
|
return;
|
|
|
|
const auto *ForRange = Result.Nodes.getNodeAs<CXXForRangeStmt>("forRange");
|
|
|
|
handleCopyIsOnlyConstReferenced(*Var, *ForRange, *Result.Context);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ForRangeCopyCheck::handleConstValueCopy(const VarDecl &LoopVar,
|
|
|
|
ASTContext &Context) {
|
|
|
|
if (WarnOnAllAutoCopies) {
|
|
|
|
// For aggressive check just test that loop variable has auto type.
|
|
|
|
if (!isa<AutoType>(LoopVar.getType()))
|
|
|
|
return false;
|
|
|
|
} else if (!LoopVar.getType().isConstQualified()) {
|
|
|
|
return false;
|
|
|
|
}
|
2016-02-15 11:36:23 +08:00
|
|
|
llvm::Optional<bool> Expensive =
|
2016-05-03 10:54:05 +08:00
|
|
|
utils::type_traits::isExpensiveToCopy(LoopVar.getType(), Context);
|
2016-02-15 11:36:23 +08:00
|
|
|
if (!Expensive || !*Expensive)
|
2016-01-29 23:54:26 +08:00
|
|
|
return false;
|
|
|
|
auto Diagnostic =
|
|
|
|
diag(LoopVar.getLocation(),
|
|
|
|
"the loop variable's type is not a reference type; this creates a "
|
|
|
|
"copy in each iteration; consider making this a reference")
|
2016-05-03 10:54:05 +08:00
|
|
|
<< utils::fixit::changeVarDeclToReference(LoopVar, Context);
|
[clang-tidy] implement utility-function to add 'const' to variables
Summary:
This patch extends the already existing facility to add 'const' to variables
to be more flexible and correct. The previous version did not consider pointers
as value AND pointee. For future automatic introduction for const-correctness
this shortcoming needs to be fixed.
It always allows configuration where the 'const' token is inserted, either on
the left side (if possible) or the right side.
It adds many unit-tests to the utility-function that did not exist before, as
the function was implicitly tested through clang-tidy checks. These
tests were not changed, as the API is still compatible.
Reviewers: aaron.ballman, hokein, alexfh, shuaiwang, lebedev.ri
Reviewed By: aaron.ballman
Subscribers: jdoerfert, mgorny, xazax.hun, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D54395
2020-01-04 03:36:49 +08:00
|
|
|
if (!LoopVar.getType().isConstQualified()) {
|
|
|
|
if (llvm::Optional<FixItHint> Fix = utils::fixit::addQualifierToVarDecl(
|
|
|
|
LoopVar, Context, DeclSpec::TQ::TQ_const))
|
|
|
|
Diagnostic << *Fix;
|
|
|
|
}
|
2016-01-29 23:54:26 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ForRangeCopyCheck::handleCopyIsOnlyConstReferenced(
|
|
|
|
const VarDecl &LoopVar, const CXXForRangeStmt &ForRange,
|
|
|
|
ASTContext &Context) {
|
2016-02-15 11:36:23 +08:00
|
|
|
llvm::Optional<bool> Expensive =
|
2016-05-03 10:54:05 +08:00
|
|
|
utils::type_traits::isExpensiveToCopy(LoopVar.getType(), Context);
|
2016-03-06 05:17:58 +08:00
|
|
|
if (LoopVar.getType().isConstQualified() || !Expensive || !*Expensive)
|
2016-01-29 23:54:26 +08:00
|
|
|
return false;
|
2018-08-10 16:25:51 +08:00
|
|
|
// We omit the case where the loop variable is not used in the loop body. E.g.
|
|
|
|
//
|
|
|
|
// for (auto _ : benchmark_state) {
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// Because the fix (changing to `const auto &`) will introduce an unused
|
|
|
|
// compiler warning which can't be suppressed.
|
|
|
|
// Since this case is very rare, it is safe to ignore it.
|
2018-09-12 06:59:46 +08:00
|
|
|
if (!ExprMutationAnalyzer(*ForRange.getBody(), Context).isMutated(&LoopVar) &&
|
2018-08-10 16:25:51 +08:00
|
|
|
!utils::decl_ref_expr::allDeclRefExprs(LoopVar, *ForRange.getBody(),
|
|
|
|
Context)
|
|
|
|
.empty()) {
|
[clang-tidy] implement utility-function to add 'const' to variables
Summary:
This patch extends the already existing facility to add 'const' to variables
to be more flexible and correct. The previous version did not consider pointers
as value AND pointee. For future automatic introduction for const-correctness
this shortcoming needs to be fixed.
It always allows configuration where the 'const' token is inserted, either on
the left side (if possible) or the right side.
It adds many unit-tests to the utility-function that did not exist before, as
the function was implicitly tested through clang-tidy checks. These
tests were not changed, as the API is still compatible.
Reviewers: aaron.ballman, hokein, alexfh, shuaiwang, lebedev.ri
Reviewed By: aaron.ballman
Subscribers: jdoerfert, mgorny, xazax.hun, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D54395
2020-01-04 03:36:49 +08:00
|
|
|
auto Diag = diag(
|
|
|
|
LoopVar.getLocation(),
|
|
|
|
"loop variable is copied but only used as const reference; consider "
|
|
|
|
"making it a const reference");
|
|
|
|
|
|
|
|
if (llvm::Optional<FixItHint> Fix = utils::fixit::addQualifierToVarDecl(
|
|
|
|
LoopVar, Context, DeclSpec::TQ::TQ_const))
|
|
|
|
Diag << *Fix << utils::fixit::changeVarDeclToReference(LoopVar, Context);
|
|
|
|
|
2018-08-10 16:25:51 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
2016-01-29 23:54:26 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace performance
|
|
|
|
} // namespace tidy
|
|
|
|
} // namespace clang
|