clang-tools 19.0.0git
ReferenceToConstructedTemporaryCheck.cpp
Go to the documentation of this file.
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
11#include "clang/AST/ASTContext.h"
12#include "clang/ASTMatchers/ASTMatchFinder.h"
13
14using namespace clang::ast_matchers;
15
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
49 const LangOptions &LangOpts) const {
50 return LangOpts.CPlusPlus;
51}
52
53std::optional<TraversalKind>
55 return TK_AsIs;
56}
57
59 MatchFinder *Finder) {
60 Finder->addMatcher(
61 varDecl(unless(isExpansionInSystemHeader()),
62 hasType(qualType(references(qualType().bind("type")))),
63 decl().bind("var"),
64 hasInitializer(expr(hasDescendant(
65 materializeTemporaryExpr(
66 isExtendedByDeclBoundTo("var"),
67 has(expr(anyOf(cxxTemporaryObjectExpr(), initListExpr(),
68 cxxConstructExpr()),
69 hasType(qualType(equalsBoundNode("type"))))))
70 .bind("temporary"))))),
71 this);
72}
73
75 const MatchFinder::MatchResult &Result) {
76 const auto *MatchedDecl = Result.Nodes.getNodeAs<VarDecl>("var");
77 const auto *MatchedTemporary = Result.Nodes.getNodeAs<Expr>("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
CodeCompletionBuilder Builder
::clang::DynTypedNode Node
DiagnosticBuilder diag(SourceLocation Loc, StringRef Description, DiagnosticIDs::Level Level=DiagnosticIDs::Warning)
Add a diagnostic with the check's name.
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
ClangTidyChecks that register ASTMatchers should do the actual work in here.
void registerMatchers(ast_matchers::MatchFinder *Finder) override
Override this to register AST matchers with Finder.
bool isLanguageVersionSupported(const LangOptions &LangOpts) const override
Override this to disable registering matchers and PP callbacks if an invalid language version is bein...
AST_MATCHER_P(CXXMethodDecl, hasCanonicalDecl, ast_matchers::internal::Matcher< CXXMethodDecl >, InnerMatcher)