llvm-project/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
Alexander Kornienko b959f4c338 [clang-tidy] Add UnnecessaryCopyInitialization check to new "performance" module in ClangTidy
Summary:
The patch adds a new ClangTidy check that detects when expensive-to-copy types are unnecessarily copy initialized from a const reference that has the same or are larger scope than the copy.

It currently only detects this when the copied variable is const qualified. But this will be extended to non const variables if they are only used in a const fashion.

Reviewers: alexfh

Subscribers: cfe-commits

Patch by Felix Berger!

Differential Revision: http://reviews.llvm.org/D15623

llvm-svn: 256632
2015-12-30 10:24:40 +00:00

74 lines
3.0 KiB
C++

//===--- UnnecessaryCopyInitialization.cpp - clang-tidy--------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "UnnecessaryCopyInitialization.h"
#include "../utils/LexerUtils.h"
#include "../utils/Matchers.h"
namespace clang {
namespace tidy {
namespace performance {
using namespace ::clang::ast_matchers;
namespace {
AST_MATCHER(VarDecl, isLocalVarDecl) { return Node.isLocalVarDecl(); }
AST_MATCHER(QualType, isPointerType) { return Node->isPointerType(); }
} // namespace
void UnnecessaryCopyInitialization::registerMatchers(
ast_matchers::MatchFinder *Finder) {
auto ConstReference = referenceType(pointee(qualType(isConstQualified())));
auto ConstOrConstReference =
allOf(anyOf(ConstReference, isConstQualified()),
unless(allOf(isPointerType(), unless(pointerType(pointee(qualType(
isConstQualified())))))));
// Match method call expressions where the this argument is a const
// type or const reference. This returned const reference is highly likely to
// outlive the local const reference of the variable being declared.
// The assumption is that the const reference being returned either points
// to a global static variable or to a member of the called object.
auto ConstRefReturningMethodCallOfConstParam = cxxMemberCallExpr(
callee(cxxMethodDecl(returns(ConstReference))),
on(declRefExpr(to(varDecl(hasType(qualType(ConstOrConstReference)))))));
auto ConstRefReturningFunctionCall =
callExpr(callee(functionDecl(returns(ConstReference))),
unless(callee(cxxMethodDecl())));
Finder->addMatcher(
varDecl(
isLocalVarDecl(), hasType(isConstQualified()),
hasType(matchers::isExpensiveToCopy()),
hasInitializer(cxxConstructExpr(
hasDeclaration(cxxConstructorDecl(isCopyConstructor())),
hasArgument(0, anyOf(ConstRefReturningFunctionCall,
ConstRefReturningMethodCallOfConstParam)))))
.bind("varDecl"),
this);
}
void UnnecessaryCopyInitialization::check(
const ast_matchers::MatchFinder::MatchResult &Result) {
const auto *Var = Result.Nodes.getNodeAs<VarDecl>("varDecl");
SourceLocation AmpLocation = Var->getLocation();
auto Token = lexer_utils::getPreviousNonCommentToken(*Result.Context,
Var->getLocation());
if (!Token.is(tok::unknown)) {
AmpLocation = Token.getLocation().getLocWithOffset(Token.getLength());
}
diag(Var->getLocation(),
"the const qualified variable '%0' is copy-constructed from a "
"const reference; consider making it a const reference")
<< Var->getName() << FixItHint::CreateInsertion(AmpLocation, "&");
}
} // namespace performance
} // namespace tidy
} // namespace clang