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
9#include "ReturnBracedInitListCheck.h"
10#include "clang/AST/ASTContext.h"
11#include "clang/ASTMatchers/ASTMatchFinder.h"
12#include "clang/ASTMatchers/ASTMatchers.h"
13#include "clang/Lex/Lexer.h"
14
15using namespace clang::ast_matchers;
16
17namespace clang::tidy::modernize {
18
19void ReturnBracedInitListCheck::registerMatchers(MatchFinder *Finder) {
20 auto SemanticallyDifferentContainer = allOf(
21 hasDeclaration(
22 // Container(size_type count, const T &value,
23 // const Allocator &alloc = Allocator());
24 InnerMatcher: cxxConstructorDecl(parameterCountIs(N: 3),
25 hasParameter(N: 0, InnerMatcher: hasType(InnerMatcher: qualType(hasCanonicalType(
26 InnerMatcher: isInteger())))))),
27 hasType(InnerMatcher: cxxRecordDecl(hasAnyName("::std::basic_string", "::std::vector",
28 "::std::deque", "::std::forward_list",
29 "::std::list"))));
30
31 auto ConstructExpr =
32 cxxConstructExpr(
33 unless(anyOf(
34 // Skip explicit constructor.
35 hasDeclaration(InnerMatcher: cxxConstructorDecl(isExplicit())),
36 // Skip list initialization and constructors with an initializer
37 // list.
38 isListInitialization(), hasDescendant(initListExpr()),
39 // Skip container `vector(size_type, const T&, ...)`.
40 SemanticallyDifferentContainer)))
41 .bind(ID: "ctor");
42
43 Finder->addMatcher(
44 NodeMatch: returnStmt(hasReturnValue(InnerMatcher: ConstructExpr),
45 forFunction(InnerMatcher: functionDecl(returns(InnerMatcher: unless(anyOf(builtinType(),
46 autoType()))))
47 .bind(ID: "fn"))),
48 Action: this);
49}
50
51void ReturnBracedInitListCheck::check(const MatchFinder::MatchResult &Result) {
52 const auto *MatchedFunctionDecl = Result.Nodes.getNodeAs<FunctionDecl>(ID: "fn");
53 const auto *MatchedConstructExpr =
54 Result.Nodes.getNodeAs<CXXConstructExpr>(ID: "ctor");
55
56 // Don't make replacements in macro.
57 SourceLocation Loc = MatchedConstructExpr->getExprLoc();
58 if (Loc.isMacroID())
59 return;
60
61 // Make sure that the return type matches the constructed type.
62 const QualType ReturnType =
63 MatchedFunctionDecl->getReturnType().getCanonicalType();
64 const QualType ConstructType =
65 MatchedConstructExpr->getType().getCanonicalType();
66 if (ReturnType != ConstructType)
67 return;
68
69 auto Diag = diag(Loc, Description: "avoid repeating the return type from the "
70 "declaration; use a braced initializer list instead");
71
72 const SourceRange CallParensRange =
73 MatchedConstructExpr->getParenOrBraceRange();
74
75 // Make sure there is an explicit constructor call.
76 if (CallParensRange.isInvalid())
77 return;
78
79 // Make sure that the ctor arguments match the declaration.
80 for (unsigned I = 0, NumParams = MatchedConstructExpr->getNumArgs();
81 I < NumParams; ++I) {
82 if (const auto *VD = dyn_cast<VarDecl>(
83 MatchedConstructExpr->getConstructor()->getParamDecl(I))) {
84 if (MatchedConstructExpr->getArg(Arg: I)->getType().getCanonicalType() !=
85 VD->getType().getCanonicalType())
86 return;
87 }
88 }
89
90 // Range for constructor name and opening brace.
91 CharSourceRange CtorCallSourceRange = CharSourceRange::getTokenRange(
92 B: Loc, E: CallParensRange.getBegin().getLocWithOffset(Offset: -1));
93
94 Diag << FixItHint::CreateRemoval(RemoveRange: CtorCallSourceRange)
95 << FixItHint::CreateReplacement(RemoveRange: CallParensRange.getBegin(), Code: "{")
96 << FixItHint::CreateReplacement(RemoveRange: CallParensRange.getEnd(), Code: "}");
97}
98
99} // namespace clang::tidy::modernize
100

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

source code of clang-tools-extra/clang-tidy/modernize/ReturnBracedInitListCheck.cpp