clang-tools  6.0.0
ReturnBracedInitListCheck.cpp
Go to the documentation of this file.
1 //===--- ReturnBracedInitListCheck.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 
11 #include "clang/AST/ASTContext.h"
12 #include "clang/ASTMatchers/ASTMatchFinder.h"
13 #include "clang/Lex/Lexer.h"
14 #include "clang/Tooling/FixIt.h"
15 
16 using namespace clang::ast_matchers;
17 
18 namespace clang {
19 namespace tidy {
20 namespace modernize {
21 
22 void ReturnBracedInitListCheck::registerMatchers(MatchFinder *Finder) {
23  // Only register the matchers for C++.
24  if (!getLangOpts().CPlusPlus11)
25  return;
26 
27  // Skip list initialization and constructors with an initializer list.
28  auto ConstructExpr =
29  cxxConstructExpr(
30  unless(anyOf(hasDeclaration(cxxConstructorDecl(isExplicit())),
31  isListInitialization(), hasDescendant(initListExpr()),
32  isInTemplateInstantiation())))
33  .bind("ctor");
34 
35  auto CtorAsArgument = materializeTemporaryExpr(anyOf(
36  has(ConstructExpr), has(cxxFunctionalCastExpr(has(ConstructExpr)))));
37 
38  Finder->addMatcher(
39  functionDecl(isDefinition(), // Declarations don't have return statements.
40  returns(unless(anyOf(builtinType(), autoType()))),
41  hasDescendant(returnStmt(hasReturnValue(
42  has(cxxConstructExpr(has(CtorAsArgument)))))))
43  .bind("fn"),
44  this);
45 }
46 
47 void ReturnBracedInitListCheck::check(const MatchFinder::MatchResult &Result) {
48  const auto *MatchedFunctionDecl = Result.Nodes.getNodeAs<FunctionDecl>("fn");
49  const auto *MatchedConstructExpr =
50  Result.Nodes.getNodeAs<CXXConstructExpr>("ctor");
51 
52  // Don't make replacements in macro.
53  SourceLocation Loc = MatchedConstructExpr->getExprLoc();
54  if (Loc.isMacroID())
55  return;
56 
57  // Make sure that the return type matches the constructed type.
58  const QualType ReturnType =
59  MatchedFunctionDecl->getReturnType().getCanonicalType();
60  const QualType ConstructType =
61  MatchedConstructExpr->getType().getCanonicalType();
62  if (ReturnType != ConstructType)
63  return;
64 
65  auto Diag = diag(Loc, "avoid repeating the return type from the "
66  "declaration; use a braced initializer list instead");
67 
68  const SourceRange CallParensRange =
69  MatchedConstructExpr->getParenOrBraceRange();
70 
71  // Make sure there is an explicit constructor call.
72  if (CallParensRange.isInvalid())
73  return;
74 
75  // Make sure that the ctor arguments match the declaration.
76  for (unsigned I = 0, NumParams = MatchedConstructExpr->getNumArgs();
77  I < NumParams; ++I) {
78  if (const auto *VD = dyn_cast<VarDecl>(
79  MatchedConstructExpr->getConstructor()->getParamDecl(I))) {
80  if (MatchedConstructExpr->getArg(I)->getType().getCanonicalType() !=
81  VD->getType().getCanonicalType())
82  return;
83  }
84  }
85 
86  // Range for constructor name and opening brace.
87  CharSourceRange CtorCallSourceRange = CharSourceRange::getTokenRange(
88  Loc, CallParensRange.getBegin().getLocWithOffset(-1));
89 
90  Diag << FixItHint::CreateRemoval(CtorCallSourceRange)
91  << FixItHint::CreateReplacement(CallParensRange.getBegin(), "{")
92  << FixItHint::CreateReplacement(CallParensRange.getEnd(), "}");
93 }
94 
95 } // namespace modernize
96 } // namespace tidy
97 } // namespace clang
SourceLocation Loc
&#39;#&#39; location in the include directive