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