clang-tools 22.0.0git
ReferenceToConstructedTemporaryCheck.cpp
Go to the documentation of this file.
1//===----------------------------------------------------------------------===//
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
13using namespace clang::ast_matchers;
14
16
17namespace {
18
19// Predicate structure to check if lifetime of temporary is not extended by
20// ValueDecl pointed out by ID
21struct NotExtendedByDeclBoundToPredicate {
22 bool operator()(const internal::BoundNodesMap &Nodes) const {
23 const auto *Other = Nodes.getNodeAs<ValueDecl>(ID);
24 if (!Other)
25 return true;
26
27 const auto *Self = Node.get<MaterializeTemporaryExpr>();
28 if (!Self)
29 return true;
30
31 return Self->getExtendingDecl() != Other;
32 }
33
34 StringRef ID;
35 ::clang::DynTypedNode Node;
36};
37
38AST_MATCHER_P(MaterializeTemporaryExpr, isExtendedByDeclBoundTo, StringRef,
39 ID) {
40 NotExtendedByDeclBoundToPredicate Predicate{
41 ID, ::clang::DynTypedNode::create(Node)};
42 return Builder->removeBindings(Predicate);
43}
44
45} // namespace
46
48 const LangOptions &LangOpts) const {
49 return LangOpts.CPlusPlus;
50}
51
52std::optional<TraversalKind>
56
58 MatchFinder *Finder) {
59 Finder->addMatcher(
60 varDecl(unless(isExpansionInSystemHeader()),
61 hasType(qualType(references(qualType().bind("type")))),
62 decl().bind("var"),
63 hasInitializer(expr(hasDescendant(
64 materializeTemporaryExpr(
65 isExtendedByDeclBoundTo("var"),
66 has(expr(anyOf(cxxTemporaryObjectExpr(), initListExpr(),
67 cxxConstructExpr()),
68 hasType(qualType(equalsBoundNode("type"))))))
69 .bind("temporary"))))),
70 this);
71}
72
74 const MatchFinder::MatchResult &Result) {
75 const auto *MatchedDecl = Result.Nodes.getNodeAs<VarDecl>("var");
76 const auto *MatchedTemporary = Result.Nodes.getNodeAs<Expr>("temporary");
77
78 diag(MatchedDecl->getLocation(),
79 "reference variable %0 extends the lifetime of a just-constructed "
80 "temporary object %1, consider changing reference to value")
81 << MatchedDecl << MatchedTemporary->getType();
82}
83
84} // namespace clang::tidy::readability
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
AST_MATCHER_P(Stmt, isStatementIdenticalToBoundNode, std::string, ID)