blob: ed37b32e202ce006b201ca657e485526a9989477 [file] [log] [blame]
Alexander Kornienkob959f4c2015-12-30 10:24:40 +00001//===--- UnnecessaryCopyInitialization.cpp - clang-tidy--------------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "UnnecessaryCopyInitialization.h"
11
Felix Bergeradfdc142016-03-05 21:17:58 +000012#include "../utils/DeclRefExprUtils.h"
13#include "../utils/FixItHintUtils.h"
Alexander Kornienkob959f4c2015-12-30 10:24:40 +000014#include "../utils/Matchers.h"
15
16namespace clang {
17namespace tidy {
18namespace performance {
19
20using namespace ::clang::ast_matchers;
21
Alexander Kornienkob959f4c2015-12-30 10:24:40 +000022void UnnecessaryCopyInitialization::registerMatchers(
23 ast_matchers::MatchFinder *Finder) {
24 auto ConstReference = referenceType(pointee(qualType(isConstQualified())));
25 auto ConstOrConstReference =
26 allOf(anyOf(ConstReference, isConstQualified()),
Felix Bergeradfdc142016-03-05 21:17:58 +000027 unless(allOf(pointerType(), unless(pointerType(pointee(
28 qualType(isConstQualified())))))));
Alexander Kornienkob959f4c2015-12-30 10:24:40 +000029 // Match method call expressions where the this argument is a const
30 // type or const reference. This returned const reference is highly likely to
31 // outlive the local const reference of the variable being declared.
32 // The assumption is that the const reference being returned either points
33 // to a global static variable or to a member of the called object.
34 auto ConstRefReturningMethodCallOfConstParam = cxxMemberCallExpr(
35 callee(cxxMethodDecl(returns(ConstReference))),
36 on(declRefExpr(to(varDecl(hasType(qualType(ConstOrConstReference)))))));
37 auto ConstRefReturningFunctionCall =
38 callExpr(callee(functionDecl(returns(ConstReference))),
39 unless(callee(cxxMethodDecl())));
40 Finder->addMatcher(
Felix Bergeradfdc142016-03-05 21:17:58 +000041 compoundStmt(
42 forEachDescendant(
43 varDecl(
44 hasLocalStorage(), hasType(matchers::isExpensiveToCopy()),
45 hasInitializer(cxxConstructExpr(
46 hasDeclaration(cxxConstructorDecl(isCopyConstructor())),
47 hasArgument(
48 0, anyOf(ConstRefReturningFunctionCall,
Alexander Kornienkob959f4c2015-12-30 10:24:40 +000049 ConstRefReturningMethodCallOfConstParam)))))
Felix Bergeradfdc142016-03-05 21:17:58 +000050 .bind("varDecl"))).bind("blockStmt"),
Alexander Kornienkob959f4c2015-12-30 10:24:40 +000051 this);
52}
53
54void UnnecessaryCopyInitialization::check(
55 const ast_matchers::MatchFinder::MatchResult &Result) {
56 const auto *Var = Result.Nodes.getNodeAs<VarDecl>("varDecl");
Felix Bergeradfdc142016-03-05 21:17:58 +000057 const auto *BlockStmt = Result.Nodes.getNodeAs<Stmt>("blockStmt");
58 bool IsConstQualified = Var->getType().isConstQualified();
59 if (!IsConstQualified &&
60 !decl_ref_expr_utils::isOnlyUsedAsConst(*Var, *BlockStmt,
61 *Result.Context))
62 return;
63 DiagnosticBuilder Diagnostic =
64 diag(Var->getLocation(),
65 IsConstQualified ? "the const qualified variable '%0' is "
66 "copy-constructed from a const reference; "
67 "consider making it a const reference"
68 : "the variable '%0' is copy-constructed from a "
69 "const reference but is only used as const "
70 "reference; consider making it a const reference")
71 << Var->getName();
72 // Do not propose fixes in macros since we cannot place them correctly.
73 if (Var->getLocStart().isMacroID())
74 return;
75 Diagnostic << utils::create_fix_it::changeVarDeclToReference(*Var,
76 *Result.Context);
77 if (!IsConstQualified)
78 Diagnostic << utils::create_fix_it::changeVarDeclToConst(*Var);
Alexander Kornienkob959f4c2015-12-30 10:24:40 +000079}
80
81} // namespace performance
82} // namespace tidy
83} // namespace clang