|  | //===--- ReferenceToConstructedTemporaryCheck.cpp - clang-tidy | 
|  | //--------------===// | 
|  | // | 
|  | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | 
|  | // See https://llvm.org/LICENSE.txt for license information. | 
|  | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "ReferenceToConstructedTemporaryCheck.h" | 
|  | #include "clang/AST/ASTContext.h" | 
|  | #include "clang/ASTMatchers/ASTMatchFinder.h" | 
|  |  | 
|  | using namespace clang::ast_matchers; | 
|  |  | 
|  | namespace clang::tidy::readability { | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | // Predicate structure to check if lifetime of temporary is not extended by | 
|  | // ValueDecl pointed out by ID | 
|  | struct NotExtendedByDeclBoundToPredicate { | 
|  | bool operator()(const internal::BoundNodesMap &Nodes) const { | 
|  | const auto *Other = Nodes.getNodeAs<ValueDecl>(ID); | 
|  | if (!Other) | 
|  | return true; | 
|  |  | 
|  | const auto *Self = Node.get<MaterializeTemporaryExpr>(); | 
|  | if (!Self) | 
|  | return true; | 
|  |  | 
|  | return Self->getExtendingDecl() != Other; | 
|  | } | 
|  |  | 
|  | StringRef ID; | 
|  | ::clang::DynTypedNode Node; | 
|  | }; | 
|  |  | 
|  | AST_MATCHER_P(MaterializeTemporaryExpr, isExtendedByDeclBoundTo, StringRef, | 
|  | ID) { | 
|  | NotExtendedByDeclBoundToPredicate Predicate{ | 
|  | ID, ::clang::DynTypedNode::create(Node)}; | 
|  | return Builder->removeBindings(Predicate); | 
|  | } | 
|  |  | 
|  | } // namespace | 
|  |  | 
|  | bool ReferenceToConstructedTemporaryCheck::isLanguageVersionSupported( | 
|  | const LangOptions &LangOpts) const { | 
|  | return LangOpts.CPlusPlus; | 
|  | } | 
|  |  | 
|  | std::optional<TraversalKind> | 
|  | ReferenceToConstructedTemporaryCheck::getCheckTraversalKind() const { | 
|  | return TK_AsIs; | 
|  | } | 
|  |  | 
|  | void ReferenceToConstructedTemporaryCheck::registerMatchers( | 
|  | MatchFinder *Finder) { | 
|  | Finder->addMatcher( | 
|  | varDecl(unless(isExpansionInSystemHeader()), | 
|  | hasType(qualType(references(qualType().bind("type")))), | 
|  | decl().bind("var"), | 
|  | hasInitializer(expr(hasDescendant( | 
|  | materializeTemporaryExpr( | 
|  | isExtendedByDeclBoundTo("var"), | 
|  | has(expr(anyOf(cxxTemporaryObjectExpr(), initListExpr(), | 
|  | cxxConstructExpr()), | 
|  | hasType(qualType(equalsBoundNode("type")))))) | 
|  | .bind("temporary"))))), | 
|  | this); | 
|  | } | 
|  |  | 
|  | void ReferenceToConstructedTemporaryCheck::check( | 
|  | const MatchFinder::MatchResult &Result) { | 
|  | const auto *MatchedDecl = Result.Nodes.getNodeAs<VarDecl>("var"); | 
|  | const auto *MatchedTemporary = Result.Nodes.getNodeAs<Expr>("temporary"); | 
|  |  | 
|  | diag(MatchedDecl->getLocation(), | 
|  | "reference variable %0 extends the lifetime of a just-constructed " | 
|  | "temporary object %1, consider changing reference to value") | 
|  | << MatchedDecl << MatchedTemporary->getType(); | 
|  | } | 
|  |  | 
|  | } // namespace clang::tidy::readability |