1//===--- ReferenceToConstructedTemporaryCheck.cpp - clang-tidy
2//--------------===//
3//
4// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5// See https://llvm.org/LICENSE.txt for license information.
6// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7//
8//===----------------------------------------------------------------------===//
9
10#include "ReferenceToConstructedTemporaryCheck.h"
11#include "clang/AST/ASTContext.h"
12#include "clang/ASTMatchers/ASTMatchFinder.h"
13
14using namespace clang::ast_matchers;
15
16namespace clang::tidy::readability {
17
18namespace {
19
20// Predicate structure to check if lifetime of temporary is not extended by
21// ValueDecl pointed out by ID
22struct NotExtendedByDeclBoundToPredicate {
23 bool operator()(const internal::BoundNodesMap &Nodes) const {
24 const auto *Other = Nodes.getNodeAs<ValueDecl>(ID);
25 if (!Other)
26 return true;
27
28 const auto *Self = Node.get<MaterializeTemporaryExpr>();
29 if (!Self)
30 return true;
31
32 return Self->getExtendingDecl() != Other;
33 }
34
35 StringRef ID;
36 ::clang::DynTypedNode Node;
37};
38
39AST_MATCHER_P(MaterializeTemporaryExpr, isExtendedByDeclBoundTo, StringRef,
40 ID) {
41 NotExtendedByDeclBoundToPredicate Predicate{
42 ID, ::clang::DynTypedNode::create(Node)};
43 return Builder->removeBindings(Predicate);
44}
45
46} // namespace
47
48bool ReferenceToConstructedTemporaryCheck::isLanguageVersionSupported(
49 const LangOptions &LangOpts) const {
50 return LangOpts.CPlusPlus;
51}
52
53std::optional<TraversalKind>
54ReferenceToConstructedTemporaryCheck::getCheckTraversalKind() const {
55 return TK_AsIs;
56}
57
58void ReferenceToConstructedTemporaryCheck::registerMatchers(
59 MatchFinder *Finder) {
60 Finder->addMatcher(
61 NodeMatch: varDecl(unless(isExpansionInSystemHeader()),
62 hasType(InnerMatcher: qualType(references(InnerMatcher: qualType().bind(ID: "type")))),
63 decl().bind(ID: "var"),
64 hasInitializer(InnerMatcher: expr(hasDescendant(
65 materializeTemporaryExpr(
66 isExtendedByDeclBoundTo(ID: "var"),
67 has(expr(anyOf(cxxTemporaryObjectExpr(), initListExpr(),
68 cxxConstructExpr()),
69 hasType(InnerMatcher: qualType(equalsBoundNode(ID: "type"))))))
70 .bind(ID: "temporary"))))),
71 Action: this);
72}
73
74void ReferenceToConstructedTemporaryCheck::check(
75 const MatchFinder::MatchResult &Result) {
76 const auto *MatchedDecl = Result.Nodes.getNodeAs<VarDecl>(ID: "var");
77 const auto *MatchedTemporary = Result.Nodes.getNodeAs<Expr>(ID: "temporary");
78
79 diag(MatchedDecl->getLocation(),
80 "reference variable %0 extends the lifetime of a just-constructed "
81 "temporary object %1, consider changing reference to value")
82 << MatchedDecl << MatchedTemporary->getType();
83}
84
85} // namespace clang::tidy::readability
86

source code of clang-tools-extra/clang-tidy/readability/ReferenceToConstructedTemporaryCheck.cpp