85 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9#include "ReferenceToConstructedTemporaryCheck.h"10#include "clang/AST/ASTContext.h"11#include "clang/ASTMatchers/ASTMatchFinder.h"12 13using namespace clang::ast_matchers;14 15namespace clang::tidy::readability {16 17namespace {18 19// Predicate structure to check if lifetime of temporary is not extended by20// ValueDecl pointed out by ID21struct 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 const NotExtendedByDeclBoundToPredicate Predicate{41 ID, ::clang::DynTypedNode::create(Node)};42 return Builder->removeBindings(Predicate);43}44 45} // namespace46 47bool ReferenceToConstructedTemporaryCheck::isLanguageVersionSupported(48 const LangOptions &LangOpts) const {49 return LangOpts.CPlusPlus;50}51 52std::optional<TraversalKind>53ReferenceToConstructedTemporaryCheck::getCheckTraversalKind() const {54 return TK_AsIs;55}56 57void ReferenceToConstructedTemporaryCheck::registerMatchers(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 73void ReferenceToConstructedTemporaryCheck::check(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::readability85