187d0aedaSPiotr Zegar //===--- ReferenceToConstructedTemporaryCheck.cpp - clang-tidy
287d0aedaSPiotr Zegar //--------------===//
387d0aedaSPiotr Zegar //
487d0aedaSPiotr Zegar // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
587d0aedaSPiotr Zegar // See https://llvm.org/LICENSE.txt for license information.
687d0aedaSPiotr Zegar // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
787d0aedaSPiotr Zegar //
887d0aedaSPiotr Zegar //===----------------------------------------------------------------------===//
987d0aedaSPiotr Zegar
1087d0aedaSPiotr Zegar #include "ReferenceToConstructedTemporaryCheck.h"
1187d0aedaSPiotr Zegar #include "clang/AST/ASTContext.h"
1287d0aedaSPiotr Zegar #include "clang/ASTMatchers/ASTMatchFinder.h"
1387d0aedaSPiotr Zegar
1487d0aedaSPiotr Zegar using namespace clang::ast_matchers;
1587d0aedaSPiotr Zegar
1687d0aedaSPiotr Zegar namespace clang::tidy::readability {
1787d0aedaSPiotr Zegar
1887d0aedaSPiotr Zegar namespace {
1987d0aedaSPiotr Zegar
2087d0aedaSPiotr Zegar // Predicate structure to check if lifetime of temporary is not extended by
2187d0aedaSPiotr Zegar // ValueDecl pointed out by ID
2287d0aedaSPiotr Zegar struct NotExtendedByDeclBoundToPredicate {
operator ()clang::tidy::readability::__anone31db9cb0111::NotExtendedByDeclBoundToPredicate23*11a411a4SPiotr Zegar bool operator()(const internal::BoundNodesMap &Nodes) const {
2487d0aedaSPiotr Zegar const auto *Other = Nodes.getNodeAs<ValueDecl>(ID);
2587d0aedaSPiotr Zegar if (!Other)
2687d0aedaSPiotr Zegar return true;
2787d0aedaSPiotr Zegar
2887d0aedaSPiotr Zegar const auto *Self = Node.get<MaterializeTemporaryExpr>();
2987d0aedaSPiotr Zegar if (!Self)
3087d0aedaSPiotr Zegar return true;
3187d0aedaSPiotr Zegar
3287d0aedaSPiotr Zegar return Self->getExtendingDecl() != Other;
3387d0aedaSPiotr Zegar }
3487d0aedaSPiotr Zegar
3587d0aedaSPiotr Zegar StringRef ID;
3687d0aedaSPiotr Zegar ::clang::DynTypedNode Node;
3787d0aedaSPiotr Zegar };
3887d0aedaSPiotr Zegar
AST_MATCHER_P(MaterializeTemporaryExpr,isExtendedByDeclBoundTo,StringRef,ID)3987d0aedaSPiotr Zegar AST_MATCHER_P(MaterializeTemporaryExpr, isExtendedByDeclBoundTo, StringRef,
4087d0aedaSPiotr Zegar ID) {
4187d0aedaSPiotr Zegar NotExtendedByDeclBoundToPredicate Predicate{
4287d0aedaSPiotr Zegar ID, ::clang::DynTypedNode::create(Node)};
4387d0aedaSPiotr Zegar return Builder->removeBindings(Predicate);
4487d0aedaSPiotr Zegar }
4587d0aedaSPiotr Zegar
4687d0aedaSPiotr Zegar } // namespace
4787d0aedaSPiotr Zegar
isLanguageVersionSupported(const LangOptions & LangOpts) const4887d0aedaSPiotr Zegar bool ReferenceToConstructedTemporaryCheck::isLanguageVersionSupported(
4987d0aedaSPiotr Zegar const LangOptions &LangOpts) const {
5087d0aedaSPiotr Zegar return LangOpts.CPlusPlus;
5187d0aedaSPiotr Zegar }
5287d0aedaSPiotr Zegar
5387d0aedaSPiotr Zegar std::optional<TraversalKind>
getCheckTraversalKind() const5487d0aedaSPiotr Zegar ReferenceToConstructedTemporaryCheck::getCheckTraversalKind() const {
5587d0aedaSPiotr Zegar return TK_AsIs;
5687d0aedaSPiotr Zegar }
5787d0aedaSPiotr Zegar
registerMatchers(MatchFinder * Finder)5887d0aedaSPiotr Zegar void ReferenceToConstructedTemporaryCheck::registerMatchers(
5987d0aedaSPiotr Zegar MatchFinder *Finder) {
6087d0aedaSPiotr Zegar Finder->addMatcher(
6187d0aedaSPiotr Zegar varDecl(unless(isExpansionInSystemHeader()),
6287d0aedaSPiotr Zegar hasType(qualType(references(qualType().bind("type")))),
6387d0aedaSPiotr Zegar decl().bind("var"),
6487d0aedaSPiotr Zegar hasInitializer(expr(hasDescendant(
6587d0aedaSPiotr Zegar materializeTemporaryExpr(
6687d0aedaSPiotr Zegar isExtendedByDeclBoundTo("var"),
6787d0aedaSPiotr Zegar has(expr(anyOf(cxxTemporaryObjectExpr(), initListExpr(),
6887d0aedaSPiotr Zegar cxxConstructExpr()),
6987d0aedaSPiotr Zegar hasType(qualType(equalsBoundNode("type"))))))
7087d0aedaSPiotr Zegar .bind("temporary"))))),
7187d0aedaSPiotr Zegar this);
7287d0aedaSPiotr Zegar }
7387d0aedaSPiotr Zegar
check(const MatchFinder::MatchResult & Result)7487d0aedaSPiotr Zegar void ReferenceToConstructedTemporaryCheck::check(
7587d0aedaSPiotr Zegar const MatchFinder::MatchResult &Result) {
7687d0aedaSPiotr Zegar const auto *MatchedDecl = Result.Nodes.getNodeAs<VarDecl>("var");
7787d0aedaSPiotr Zegar const auto *MatchedTemporary = Result.Nodes.getNodeAs<Expr>("temporary");
7887d0aedaSPiotr Zegar
7987d0aedaSPiotr Zegar diag(MatchedDecl->getLocation(),
8087d0aedaSPiotr Zegar "reference variable %0 extends the lifetime of a just-constructed "
8187d0aedaSPiotr Zegar "temporary object %1, consider changing reference to value")
8287d0aedaSPiotr Zegar << MatchedDecl << MatchedTemporary->getType();
8387d0aedaSPiotr Zegar }
8487d0aedaSPiotr Zegar
8587d0aedaSPiotr Zegar } // namespace clang::tidy::readability
86