[clang-tools-extra] [clang-tidy] Add check performance-lost-std-move (PR #139525)
https://github.com/segoon updated https://github.com/llvm/llvm-project/pull/139525 >From 3abbce9f817f6d09f9a5b7549a8122c80821eaf8 Mon Sep 17 00:00:00 2001 From: Vasily Kulikov Date: Mon, 12 May 2025 13:05:43 +0300 Subject: [PATCH 1/6] [clang-tidy] Add check performance-lost-std-move --- .../clang-tidy/performance/CMakeLists.txt | 1 + .../performance/LostStdMoveCheck.cpp | 96 .../clang-tidy/performance/LostStdMoveCheck.h | 37 ++ .../performance/PerformanceTidyModule.cpp | 2 + clang-tools-extra/docs/ReleaseNotes.rst | 5 + .../docs/clang-tidy/checks/list.rst | 1 + .../checks/performance/lost-std-move.rst | 14 +++ .../checkers/performance/lost-std-move.cpp| 108 ++ 8 files changed, 264 insertions(+) create mode 100644 clang-tools-extra/clang-tidy/performance/LostStdMoveCheck.cpp create mode 100644 clang-tools-extra/clang-tidy/performance/LostStdMoveCheck.h create mode 100644 clang-tools-extra/docs/clang-tidy/checks/performance/lost-std-move.rst create mode 100644 clang-tools-extra/test/clang-tidy/checkers/performance/lost-std-move.cpp diff --git a/clang-tools-extra/clang-tidy/performance/CMakeLists.txt b/clang-tools-extra/clang-tidy/performance/CMakeLists.txt index 81128ff086021..333abd10a583a 100644 --- a/clang-tools-extra/clang-tidy/performance/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/performance/CMakeLists.txt @@ -12,6 +12,7 @@ add_clang_library(clangTidyPerformanceModule InefficientAlgorithmCheck.cpp InefficientStringConcatenationCheck.cpp InefficientVectorOperationCheck.cpp + LostStdMoveCheck.cpp MoveConstArgCheck.cpp MoveConstructorInitCheck.cpp NoAutomaticMoveCheck.cpp diff --git a/clang-tools-extra/clang-tidy/performance/LostStdMoveCheck.cpp b/clang-tools-extra/clang-tidy/performance/LostStdMoveCheck.cpp new file mode 100644 index 0..26148e1d26de9 --- /dev/null +++ b/clang-tools-extra/clang-tidy/performance/LostStdMoveCheck.cpp @@ -0,0 +1,96 @@ +//===--- LostStdMoveCheck.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 "LostStdMoveCheck.h" +#include "../utils/DeclRefExprUtils.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" + +using namespace clang::ast_matchers; + +namespace clang::tidy::performance { + +using utils::decl_ref_expr::allDeclRefExprs; + +AST_MATCHER(CXXRecordDecl, hasTrivialMoveConstructor) { + return Node.hasDefinition() && Node.hasTrivialMoveConstructor(); +} + +void LostStdMoveCheck::registerMatchers(MatchFinder *Finder) { + auto returnParent = + hasParent(expr(hasParent(cxxConstructExpr(hasParent(returnStmt()); + + Finder->addMatcher( + declRefExpr( + // not "return x;" + unless(returnParent), + + unless(hasType(namedDecl(hasName("::std::string_view", + + // non-trivial type + hasType(hasCanonicalType(hasDeclaration(cxxRecordDecl(, + + // non-trivial X(X&&) + unless(hasType(hasCanonicalType( + hasDeclaration(cxxRecordDecl(hasTrivialMoveConstructor()), + + // Not in a cycle + unless(hasAncestor(forStmt())), unless(hasAncestor(doStmt())), + unless(hasAncestor(whileStmt())), + + // only non-X& + unless(hasDeclaration( + varDecl(hasType(qualType(lValueReferenceType()), + + hasDeclaration( + varDecl(hasAncestor(functionDecl().bind("func"))).bind("decl")), + + hasParent(expr(hasParent(cxxConstructExpr())).bind("use_parent"))) + .bind("use"), + this); +} + +const Expr *LostStdMoveCheck::getLastVarUsage(const VarDecl &Var, + const Decl &Func, + ASTContext &Context) { + auto Exprs = allDeclRefExprs(Var, Func, Context); + + const Expr *LastExpr = nullptr; + for (const auto &Expr : Exprs) { +if (!LastExpr) + LastExpr = Expr; + +if (LastExpr->getBeginLoc() < Expr->getBeginLoc()) + LastExpr = Expr; + } + + return LastExpr; +} + +void LostStdMoveCheck::check(const MatchFinder::MatchResult &Result) { + const auto *MatchedDecl = Result.Nodes.getNodeAs("decl"); + const auto *MatchedFunc = Result.Nodes.getNodeAs("func"); + const auto *MatchedUse = Result.Nodes.getNodeAs("use"); + const auto *MatchedUseCall = Result.Nodes.getNodeAs("use_parent"); + + if (MatchedUseCall) +return; + + const auto *LastUsage = + getLastVarUsage(*MatchedDecl, *MatchedFunc, *Result.Context); + if (LastUsage == nullptr) +return; + + if (LastUsage->getBeginLoc() > MatchedUse->getBeginLoc()) { +// "use" is not the last refere
[clang-tools-extra] [clang-tidy] Add check performance-lost-std-move (PR #139525)
https://github.com/segoon updated https://github.com/llvm/llvm-project/pull/139525 >From 3abbce9f817f6d09f9a5b7549a8122c80821eaf8 Mon Sep 17 00:00:00 2001 From: Vasily Kulikov Date: Mon, 12 May 2025 13:05:43 +0300 Subject: [PATCH 1/2] [clang-tidy] Add check performance-lost-std-move --- .../clang-tidy/performance/CMakeLists.txt | 1 + .../performance/LostStdMoveCheck.cpp | 96 .../clang-tidy/performance/LostStdMoveCheck.h | 37 ++ .../performance/PerformanceTidyModule.cpp | 2 + clang-tools-extra/docs/ReleaseNotes.rst | 5 + .../docs/clang-tidy/checks/list.rst | 1 + .../checks/performance/lost-std-move.rst | 14 +++ .../checkers/performance/lost-std-move.cpp| 108 ++ 8 files changed, 264 insertions(+) create mode 100644 clang-tools-extra/clang-tidy/performance/LostStdMoveCheck.cpp create mode 100644 clang-tools-extra/clang-tidy/performance/LostStdMoveCheck.h create mode 100644 clang-tools-extra/docs/clang-tidy/checks/performance/lost-std-move.rst create mode 100644 clang-tools-extra/test/clang-tidy/checkers/performance/lost-std-move.cpp diff --git a/clang-tools-extra/clang-tidy/performance/CMakeLists.txt b/clang-tools-extra/clang-tidy/performance/CMakeLists.txt index 81128ff086021..333abd10a583a 100644 --- a/clang-tools-extra/clang-tidy/performance/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/performance/CMakeLists.txt @@ -12,6 +12,7 @@ add_clang_library(clangTidyPerformanceModule InefficientAlgorithmCheck.cpp InefficientStringConcatenationCheck.cpp InefficientVectorOperationCheck.cpp + LostStdMoveCheck.cpp MoveConstArgCheck.cpp MoveConstructorInitCheck.cpp NoAutomaticMoveCheck.cpp diff --git a/clang-tools-extra/clang-tidy/performance/LostStdMoveCheck.cpp b/clang-tools-extra/clang-tidy/performance/LostStdMoveCheck.cpp new file mode 100644 index 0..26148e1d26de9 --- /dev/null +++ b/clang-tools-extra/clang-tidy/performance/LostStdMoveCheck.cpp @@ -0,0 +1,96 @@ +//===--- LostStdMoveCheck.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 "LostStdMoveCheck.h" +#include "../utils/DeclRefExprUtils.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" + +using namespace clang::ast_matchers; + +namespace clang::tidy::performance { + +using utils::decl_ref_expr::allDeclRefExprs; + +AST_MATCHER(CXXRecordDecl, hasTrivialMoveConstructor) { + return Node.hasDefinition() && Node.hasTrivialMoveConstructor(); +} + +void LostStdMoveCheck::registerMatchers(MatchFinder *Finder) { + auto returnParent = + hasParent(expr(hasParent(cxxConstructExpr(hasParent(returnStmt()); + + Finder->addMatcher( + declRefExpr( + // not "return x;" + unless(returnParent), + + unless(hasType(namedDecl(hasName("::std::string_view", + + // non-trivial type + hasType(hasCanonicalType(hasDeclaration(cxxRecordDecl(, + + // non-trivial X(X&&) + unless(hasType(hasCanonicalType( + hasDeclaration(cxxRecordDecl(hasTrivialMoveConstructor()), + + // Not in a cycle + unless(hasAncestor(forStmt())), unless(hasAncestor(doStmt())), + unless(hasAncestor(whileStmt())), + + // only non-X& + unless(hasDeclaration( + varDecl(hasType(qualType(lValueReferenceType()), + + hasDeclaration( + varDecl(hasAncestor(functionDecl().bind("func"))).bind("decl")), + + hasParent(expr(hasParent(cxxConstructExpr())).bind("use_parent"))) + .bind("use"), + this); +} + +const Expr *LostStdMoveCheck::getLastVarUsage(const VarDecl &Var, + const Decl &Func, + ASTContext &Context) { + auto Exprs = allDeclRefExprs(Var, Func, Context); + + const Expr *LastExpr = nullptr; + for (const auto &Expr : Exprs) { +if (!LastExpr) + LastExpr = Expr; + +if (LastExpr->getBeginLoc() < Expr->getBeginLoc()) + LastExpr = Expr; + } + + return LastExpr; +} + +void LostStdMoveCheck::check(const MatchFinder::MatchResult &Result) { + const auto *MatchedDecl = Result.Nodes.getNodeAs("decl"); + const auto *MatchedFunc = Result.Nodes.getNodeAs("func"); + const auto *MatchedUse = Result.Nodes.getNodeAs("use"); + const auto *MatchedUseCall = Result.Nodes.getNodeAs("use_parent"); + + if (MatchedUseCall) +return; + + const auto *LastUsage = + getLastVarUsage(*MatchedDecl, *MatchedFunc, *Result.Context); + if (LastUsage == nullptr) +return; + + if (LastUsage->getBeginLoc() > MatchedUse->getBeginLoc()) { +// "use" is not the last refere
[clang-tools-extra] [clang-tidy] Add check performance-lost-std-move (PR #139525)
https://github.com/segoon updated https://github.com/llvm/llvm-project/pull/139525 Rate limit · GitHub body { background-color: #f6f8fa; color: #24292e; font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol; font-size: 14px; line-height: 1.5; margin: 0; } .container { margin: 50px auto; max-width: 600px; text-align: center; padding: 0 24px; } a { color: #0366d6; text-decoration: none; } a:hover { text-decoration: underline; } h1 { line-height: 60px; font-size: 48px; font-weight: 300; margin: 0px; text-shadow: 0 1px 0 #fff; } p { color: rgba(0, 0, 0, 0.5); margin: 20px 0 40px; } ul { list-style: none; margin: 25px 0; padding: 0; } li { display: table-cell; font-weight: bold; width: 1%; } .logo { display: inline-block; margin-top: 35px; } .logo-img-2x { display: none; } @media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and ( min--moz-device-pixel-ratio: 2), only screen and ( -o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) { .logo-img-1x { display: none; } .logo-img-2x { display: inline-block; } } #suggestions { margin-top: 35px; color: #ccc; } #suggestions a { color: #66; font-weight: 200; font-size: 14px; margin: 0 10px; } Whoa there! You have exceeded a secondary rate limit. Please wait a few minutes before you try again; in some cases this may take up to an hour. https://support.github.com/contact";>Contact Support — https://githubstatus.com";>GitHub Status — https://twitter.com/githubstatus";>@githubstatus ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-tidy] Add check performance-lost-std-move (PR #139525)
https://github.com/segoon created https://github.com/llvm/llvm-project/pull/139525 None >From 3abbce9f817f6d09f9a5b7549a8122c80821eaf8 Mon Sep 17 00:00:00 2001 From: Vasily Kulikov Date: Mon, 12 May 2025 13:05:43 +0300 Subject: [PATCH] [clang-tidy] Add check performance-lost-std-move --- .../clang-tidy/performance/CMakeLists.txt | 1 + .../performance/LostStdMoveCheck.cpp | 96 .../clang-tidy/performance/LostStdMoveCheck.h | 37 ++ .../performance/PerformanceTidyModule.cpp | 2 + clang-tools-extra/docs/ReleaseNotes.rst | 5 + .../docs/clang-tidy/checks/list.rst | 1 + .../checks/performance/lost-std-move.rst | 14 +++ .../checkers/performance/lost-std-move.cpp| 108 ++ 8 files changed, 264 insertions(+) create mode 100644 clang-tools-extra/clang-tidy/performance/LostStdMoveCheck.cpp create mode 100644 clang-tools-extra/clang-tidy/performance/LostStdMoveCheck.h create mode 100644 clang-tools-extra/docs/clang-tidy/checks/performance/lost-std-move.rst create mode 100644 clang-tools-extra/test/clang-tidy/checkers/performance/lost-std-move.cpp diff --git a/clang-tools-extra/clang-tidy/performance/CMakeLists.txt b/clang-tools-extra/clang-tidy/performance/CMakeLists.txt index 81128ff086021..333abd10a583a 100644 --- a/clang-tools-extra/clang-tidy/performance/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/performance/CMakeLists.txt @@ -12,6 +12,7 @@ add_clang_library(clangTidyPerformanceModule InefficientAlgorithmCheck.cpp InefficientStringConcatenationCheck.cpp InefficientVectorOperationCheck.cpp + LostStdMoveCheck.cpp MoveConstArgCheck.cpp MoveConstructorInitCheck.cpp NoAutomaticMoveCheck.cpp diff --git a/clang-tools-extra/clang-tidy/performance/LostStdMoveCheck.cpp b/clang-tools-extra/clang-tidy/performance/LostStdMoveCheck.cpp new file mode 100644 index 0..26148e1d26de9 --- /dev/null +++ b/clang-tools-extra/clang-tidy/performance/LostStdMoveCheck.cpp @@ -0,0 +1,96 @@ +//===--- LostStdMoveCheck.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 "LostStdMoveCheck.h" +#include "../utils/DeclRefExprUtils.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" + +using namespace clang::ast_matchers; + +namespace clang::tidy::performance { + +using utils::decl_ref_expr::allDeclRefExprs; + +AST_MATCHER(CXXRecordDecl, hasTrivialMoveConstructor) { + return Node.hasDefinition() && Node.hasTrivialMoveConstructor(); +} + +void LostStdMoveCheck::registerMatchers(MatchFinder *Finder) { + auto returnParent = + hasParent(expr(hasParent(cxxConstructExpr(hasParent(returnStmt()); + + Finder->addMatcher( + declRefExpr( + // not "return x;" + unless(returnParent), + + unless(hasType(namedDecl(hasName("::std::string_view", + + // non-trivial type + hasType(hasCanonicalType(hasDeclaration(cxxRecordDecl(, + + // non-trivial X(X&&) + unless(hasType(hasCanonicalType( + hasDeclaration(cxxRecordDecl(hasTrivialMoveConstructor()), + + // Not in a cycle + unless(hasAncestor(forStmt())), unless(hasAncestor(doStmt())), + unless(hasAncestor(whileStmt())), + + // only non-X& + unless(hasDeclaration( + varDecl(hasType(qualType(lValueReferenceType()), + + hasDeclaration( + varDecl(hasAncestor(functionDecl().bind("func"))).bind("decl")), + + hasParent(expr(hasParent(cxxConstructExpr())).bind("use_parent"))) + .bind("use"), + this); +} + +const Expr *LostStdMoveCheck::getLastVarUsage(const VarDecl &Var, + const Decl &Func, + ASTContext &Context) { + auto Exprs = allDeclRefExprs(Var, Func, Context); + + const Expr *LastExpr = nullptr; + for (const auto &Expr : Exprs) { +if (!LastExpr) + LastExpr = Expr; + +if (LastExpr->getBeginLoc() < Expr->getBeginLoc()) + LastExpr = Expr; + } + + return LastExpr; +} + +void LostStdMoveCheck::check(const MatchFinder::MatchResult &Result) { + const auto *MatchedDecl = Result.Nodes.getNodeAs("decl"); + const auto *MatchedFunc = Result.Nodes.getNodeAs("func"); + const auto *MatchedUse = Result.Nodes.getNodeAs("use"); + const auto *MatchedUseCall = Result.Nodes.getNodeAs("use_parent"); + + if (MatchedUseCall) +return; + + const auto *LastUsage = + getLastVarUsage(*MatchedDecl, *MatchedFunc, *Result.Context); + if (LastUsage == nullptr) +return; + + if (LastUsage->getBeginLoc() > MatchedUse->getBeginLoc()) { +// "use" is not the last refe
[clang-tools-extra] [clang-tidy] Add check performance-lost-std-move (PR #139525)
https://github.com/segoon updated https://github.com/llvm/llvm-project/pull/139525 Rate limit · GitHub body { background-color: #f6f8fa; color: #24292e; font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol; font-size: 14px; line-height: 1.5; margin: 0; } .container { margin: 50px auto; max-width: 600px; text-align: center; padding: 0 24px; } a { color: #0366d6; text-decoration: none; } a:hover { text-decoration: underline; } h1 { line-height: 60px; font-size: 48px; font-weight: 300; margin: 0px; text-shadow: 0 1px 0 #fff; } p { color: rgba(0, 0, 0, 0.5); margin: 20px 0 40px; } ul { list-style: none; margin: 25px 0; padding: 0; } li { display: table-cell; font-weight: bold; width: 1%; } .logo { display: inline-block; margin-top: 35px; } .logo-img-2x { display: none; } @media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and ( min--moz-device-pixel-ratio: 2), only screen and ( -o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) { .logo-img-1x { display: none; } .logo-img-2x { display: inline-block; } } #suggestions { margin-top: 35px; color: #ccc; } #suggestions a { color: #66; font-weight: 200; font-size: 14px; margin: 0 10px; } Whoa there! You have exceeded a secondary rate limit. Please wait a few minutes before you try again; in some cases this may take up to an hour. https://support.github.com/contact";>Contact Support — https://githubstatus.com";>GitHub Status — https://twitter.com/githubstatus";>@githubstatus ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-tidy] Add check performance-lost-std-move (PR #139525)
https://github.com/segoon updated https://github.com/llvm/llvm-project/pull/139525 >From 3abbce9f817f6d09f9a5b7549a8122c80821eaf8 Mon Sep 17 00:00:00 2001 From: Vasily Kulikov Date: Mon, 12 May 2025 13:05:43 +0300 Subject: [PATCH 01/16] [clang-tidy] Add check performance-lost-std-move --- .../clang-tidy/performance/CMakeLists.txt | 1 + .../performance/LostStdMoveCheck.cpp | 96 .../clang-tidy/performance/LostStdMoveCheck.h | 37 ++ .../performance/PerformanceTidyModule.cpp | 2 + clang-tools-extra/docs/ReleaseNotes.rst | 5 + .../docs/clang-tidy/checks/list.rst | 1 + .../checks/performance/lost-std-move.rst | 14 +++ .../checkers/performance/lost-std-move.cpp| 108 ++ 8 files changed, 264 insertions(+) create mode 100644 clang-tools-extra/clang-tidy/performance/LostStdMoveCheck.cpp create mode 100644 clang-tools-extra/clang-tidy/performance/LostStdMoveCheck.h create mode 100644 clang-tools-extra/docs/clang-tidy/checks/performance/lost-std-move.rst create mode 100644 clang-tools-extra/test/clang-tidy/checkers/performance/lost-std-move.cpp diff --git a/clang-tools-extra/clang-tidy/performance/CMakeLists.txt b/clang-tools-extra/clang-tidy/performance/CMakeLists.txt index 81128ff086021..333abd10a583a 100644 --- a/clang-tools-extra/clang-tidy/performance/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/performance/CMakeLists.txt @@ -12,6 +12,7 @@ add_clang_library(clangTidyPerformanceModule InefficientAlgorithmCheck.cpp InefficientStringConcatenationCheck.cpp InefficientVectorOperationCheck.cpp + LostStdMoveCheck.cpp MoveConstArgCheck.cpp MoveConstructorInitCheck.cpp NoAutomaticMoveCheck.cpp diff --git a/clang-tools-extra/clang-tidy/performance/LostStdMoveCheck.cpp b/clang-tools-extra/clang-tidy/performance/LostStdMoveCheck.cpp new file mode 100644 index 0..26148e1d26de9 --- /dev/null +++ b/clang-tools-extra/clang-tidy/performance/LostStdMoveCheck.cpp @@ -0,0 +1,96 @@ +//===--- LostStdMoveCheck.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 "LostStdMoveCheck.h" +#include "../utils/DeclRefExprUtils.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" + +using namespace clang::ast_matchers; + +namespace clang::tidy::performance { + +using utils::decl_ref_expr::allDeclRefExprs; + +AST_MATCHER(CXXRecordDecl, hasTrivialMoveConstructor) { + return Node.hasDefinition() && Node.hasTrivialMoveConstructor(); +} + +void LostStdMoveCheck::registerMatchers(MatchFinder *Finder) { + auto returnParent = + hasParent(expr(hasParent(cxxConstructExpr(hasParent(returnStmt()); + + Finder->addMatcher( + declRefExpr( + // not "return x;" + unless(returnParent), + + unless(hasType(namedDecl(hasName("::std::string_view", + + // non-trivial type + hasType(hasCanonicalType(hasDeclaration(cxxRecordDecl(, + + // non-trivial X(X&&) + unless(hasType(hasCanonicalType( + hasDeclaration(cxxRecordDecl(hasTrivialMoveConstructor()), + + // Not in a cycle + unless(hasAncestor(forStmt())), unless(hasAncestor(doStmt())), + unless(hasAncestor(whileStmt())), + + // only non-X& + unless(hasDeclaration( + varDecl(hasType(qualType(lValueReferenceType()), + + hasDeclaration( + varDecl(hasAncestor(functionDecl().bind("func"))).bind("decl")), + + hasParent(expr(hasParent(cxxConstructExpr())).bind("use_parent"))) + .bind("use"), + this); +} + +const Expr *LostStdMoveCheck::getLastVarUsage(const VarDecl &Var, + const Decl &Func, + ASTContext &Context) { + auto Exprs = allDeclRefExprs(Var, Func, Context); + + const Expr *LastExpr = nullptr; + for (const auto &Expr : Exprs) { +if (!LastExpr) + LastExpr = Expr; + +if (LastExpr->getBeginLoc() < Expr->getBeginLoc()) + LastExpr = Expr; + } + + return LastExpr; +} + +void LostStdMoveCheck::check(const MatchFinder::MatchResult &Result) { + const auto *MatchedDecl = Result.Nodes.getNodeAs("decl"); + const auto *MatchedFunc = Result.Nodes.getNodeAs("func"); + const auto *MatchedUse = Result.Nodes.getNodeAs("use"); + const auto *MatchedUseCall = Result.Nodes.getNodeAs("use_parent"); + + if (MatchedUseCall) +return; + + const auto *LastUsage = + getLastVarUsage(*MatchedDecl, *MatchedFunc, *Result.Context); + if (LastUsage == nullptr) +return; + + if (LastUsage->getBeginLoc() > MatchedUse->getBeginLoc()) { +// "use" is not the last refe
[clang-tools-extra] [clang-tidy] Add check performance-lost-std-move (PR #139525)
@@ -0,0 +1,32 @@ +.. title:: clang-tidy - performance-lost-std-move + +performance-lost-std-move += + +Warns if copy constructor is used instead of std::move() and suggests a fix. +It honours cycles, lambdas, and unspecified call order in compound expressions. + +.. code-block:: c++ + + void f(X); + + void g(X x) { + f(x); // warning: Could be std::move() [performance-lost-std-move] + } + +It finds the last local variable usage, and if it is a copy, emits a warning. +The check is based on pure AST matching and doesn't take into account any data flow information. +Thus, it doesn't catch assign-after-copy cases. +Also it doesn't notice variable references "behind the scenes": + +.. code-block:: c++ + + void f(X); + + void g(X x) { + auto &y = x; + f(x); // emits a warning... + y.f(); // ...but it is still used + } segoon wrote: The problem is that any binding to a reference should skip the check. E.g. ``` void f(X); void g(X&); void func(X x) { g(x); // reference is created, we may not move from x anymore f(x); // no fix } ``` I'm afraid too many cases are skipped due to this problem. https://github.com/llvm/llvm-project/pull/139525 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-tidy] Add check performance-lost-std-move (PR #139525)
https://github.com/segoon updated https://github.com/llvm/llvm-project/pull/139525 >From 3abbce9f817f6d09f9a5b7549a8122c80821eaf8 Mon Sep 17 00:00:00 2001 From: Vasily Kulikov Date: Mon, 12 May 2025 13:05:43 +0300 Subject: [PATCH 01/11] [clang-tidy] Add check performance-lost-std-move --- .../clang-tidy/performance/CMakeLists.txt | 1 + .../performance/LostStdMoveCheck.cpp | 96 .../clang-tidy/performance/LostStdMoveCheck.h | 37 ++ .../performance/PerformanceTidyModule.cpp | 2 + clang-tools-extra/docs/ReleaseNotes.rst | 5 + .../docs/clang-tidy/checks/list.rst | 1 + .../checks/performance/lost-std-move.rst | 14 +++ .../checkers/performance/lost-std-move.cpp| 108 ++ 8 files changed, 264 insertions(+) create mode 100644 clang-tools-extra/clang-tidy/performance/LostStdMoveCheck.cpp create mode 100644 clang-tools-extra/clang-tidy/performance/LostStdMoveCheck.h create mode 100644 clang-tools-extra/docs/clang-tidy/checks/performance/lost-std-move.rst create mode 100644 clang-tools-extra/test/clang-tidy/checkers/performance/lost-std-move.cpp diff --git a/clang-tools-extra/clang-tidy/performance/CMakeLists.txt b/clang-tools-extra/clang-tidy/performance/CMakeLists.txt index 81128ff086021..333abd10a583a 100644 --- a/clang-tools-extra/clang-tidy/performance/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/performance/CMakeLists.txt @@ -12,6 +12,7 @@ add_clang_library(clangTidyPerformanceModule InefficientAlgorithmCheck.cpp InefficientStringConcatenationCheck.cpp InefficientVectorOperationCheck.cpp + LostStdMoveCheck.cpp MoveConstArgCheck.cpp MoveConstructorInitCheck.cpp NoAutomaticMoveCheck.cpp diff --git a/clang-tools-extra/clang-tidy/performance/LostStdMoveCheck.cpp b/clang-tools-extra/clang-tidy/performance/LostStdMoveCheck.cpp new file mode 100644 index 0..26148e1d26de9 --- /dev/null +++ b/clang-tools-extra/clang-tidy/performance/LostStdMoveCheck.cpp @@ -0,0 +1,96 @@ +//===--- LostStdMoveCheck.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 "LostStdMoveCheck.h" +#include "../utils/DeclRefExprUtils.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" + +using namespace clang::ast_matchers; + +namespace clang::tidy::performance { + +using utils::decl_ref_expr::allDeclRefExprs; + +AST_MATCHER(CXXRecordDecl, hasTrivialMoveConstructor) { + return Node.hasDefinition() && Node.hasTrivialMoveConstructor(); +} + +void LostStdMoveCheck::registerMatchers(MatchFinder *Finder) { + auto returnParent = + hasParent(expr(hasParent(cxxConstructExpr(hasParent(returnStmt()); + + Finder->addMatcher( + declRefExpr( + // not "return x;" + unless(returnParent), + + unless(hasType(namedDecl(hasName("::std::string_view", + + // non-trivial type + hasType(hasCanonicalType(hasDeclaration(cxxRecordDecl(, + + // non-trivial X(X&&) + unless(hasType(hasCanonicalType( + hasDeclaration(cxxRecordDecl(hasTrivialMoveConstructor()), + + // Not in a cycle + unless(hasAncestor(forStmt())), unless(hasAncestor(doStmt())), + unless(hasAncestor(whileStmt())), + + // only non-X& + unless(hasDeclaration( + varDecl(hasType(qualType(lValueReferenceType()), + + hasDeclaration( + varDecl(hasAncestor(functionDecl().bind("func"))).bind("decl")), + + hasParent(expr(hasParent(cxxConstructExpr())).bind("use_parent"))) + .bind("use"), + this); +} + +const Expr *LostStdMoveCheck::getLastVarUsage(const VarDecl &Var, + const Decl &Func, + ASTContext &Context) { + auto Exprs = allDeclRefExprs(Var, Func, Context); + + const Expr *LastExpr = nullptr; + for (const auto &Expr : Exprs) { +if (!LastExpr) + LastExpr = Expr; + +if (LastExpr->getBeginLoc() < Expr->getBeginLoc()) + LastExpr = Expr; + } + + return LastExpr; +} + +void LostStdMoveCheck::check(const MatchFinder::MatchResult &Result) { + const auto *MatchedDecl = Result.Nodes.getNodeAs("decl"); + const auto *MatchedFunc = Result.Nodes.getNodeAs("func"); + const auto *MatchedUse = Result.Nodes.getNodeAs("use"); + const auto *MatchedUseCall = Result.Nodes.getNodeAs("use_parent"); + + if (MatchedUseCall) +return; + + const auto *LastUsage = + getLastVarUsage(*MatchedDecl, *MatchedFunc, *Result.Context); + if (LastUsage == nullptr) +return; + + if (LastUsage->getBeginLoc() > MatchedUse->getBeginLoc()) { +// "use" is not the last refe
[clang-tools-extra] [clang-tidy] Add check performance-lost-std-move (PR #139525)
https://github.com/segoon updated https://github.com/llvm/llvm-project/pull/139525 >From 3abbce9f817f6d09f9a5b7549a8122c80821eaf8 Mon Sep 17 00:00:00 2001 From: Vasily Kulikov Date: Mon, 12 May 2025 13:05:43 +0300 Subject: [PATCH 01/14] [clang-tidy] Add check performance-lost-std-move --- .../clang-tidy/performance/CMakeLists.txt | 1 + .../performance/LostStdMoveCheck.cpp | 96 .../clang-tidy/performance/LostStdMoveCheck.h | 37 ++ .../performance/PerformanceTidyModule.cpp | 2 + clang-tools-extra/docs/ReleaseNotes.rst | 5 + .../docs/clang-tidy/checks/list.rst | 1 + .../checks/performance/lost-std-move.rst | 14 +++ .../checkers/performance/lost-std-move.cpp| 108 ++ 8 files changed, 264 insertions(+) create mode 100644 clang-tools-extra/clang-tidy/performance/LostStdMoveCheck.cpp create mode 100644 clang-tools-extra/clang-tidy/performance/LostStdMoveCheck.h create mode 100644 clang-tools-extra/docs/clang-tidy/checks/performance/lost-std-move.rst create mode 100644 clang-tools-extra/test/clang-tidy/checkers/performance/lost-std-move.cpp diff --git a/clang-tools-extra/clang-tidy/performance/CMakeLists.txt b/clang-tools-extra/clang-tidy/performance/CMakeLists.txt index 81128ff086021..333abd10a583a 100644 --- a/clang-tools-extra/clang-tidy/performance/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/performance/CMakeLists.txt @@ -12,6 +12,7 @@ add_clang_library(clangTidyPerformanceModule InefficientAlgorithmCheck.cpp InefficientStringConcatenationCheck.cpp InefficientVectorOperationCheck.cpp + LostStdMoveCheck.cpp MoveConstArgCheck.cpp MoveConstructorInitCheck.cpp NoAutomaticMoveCheck.cpp diff --git a/clang-tools-extra/clang-tidy/performance/LostStdMoveCheck.cpp b/clang-tools-extra/clang-tidy/performance/LostStdMoveCheck.cpp new file mode 100644 index 0..26148e1d26de9 --- /dev/null +++ b/clang-tools-extra/clang-tidy/performance/LostStdMoveCheck.cpp @@ -0,0 +1,96 @@ +//===--- LostStdMoveCheck.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 "LostStdMoveCheck.h" +#include "../utils/DeclRefExprUtils.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" + +using namespace clang::ast_matchers; + +namespace clang::tidy::performance { + +using utils::decl_ref_expr::allDeclRefExprs; + +AST_MATCHER(CXXRecordDecl, hasTrivialMoveConstructor) { + return Node.hasDefinition() && Node.hasTrivialMoveConstructor(); +} + +void LostStdMoveCheck::registerMatchers(MatchFinder *Finder) { + auto returnParent = + hasParent(expr(hasParent(cxxConstructExpr(hasParent(returnStmt()); + + Finder->addMatcher( + declRefExpr( + // not "return x;" + unless(returnParent), + + unless(hasType(namedDecl(hasName("::std::string_view", + + // non-trivial type + hasType(hasCanonicalType(hasDeclaration(cxxRecordDecl(, + + // non-trivial X(X&&) + unless(hasType(hasCanonicalType( + hasDeclaration(cxxRecordDecl(hasTrivialMoveConstructor()), + + // Not in a cycle + unless(hasAncestor(forStmt())), unless(hasAncestor(doStmt())), + unless(hasAncestor(whileStmt())), + + // only non-X& + unless(hasDeclaration( + varDecl(hasType(qualType(lValueReferenceType()), + + hasDeclaration( + varDecl(hasAncestor(functionDecl().bind("func"))).bind("decl")), + + hasParent(expr(hasParent(cxxConstructExpr())).bind("use_parent"))) + .bind("use"), + this); +} + +const Expr *LostStdMoveCheck::getLastVarUsage(const VarDecl &Var, + const Decl &Func, + ASTContext &Context) { + auto Exprs = allDeclRefExprs(Var, Func, Context); + + const Expr *LastExpr = nullptr; + for (const auto &Expr : Exprs) { +if (!LastExpr) + LastExpr = Expr; + +if (LastExpr->getBeginLoc() < Expr->getBeginLoc()) + LastExpr = Expr; + } + + return LastExpr; +} + +void LostStdMoveCheck::check(const MatchFinder::MatchResult &Result) { + const auto *MatchedDecl = Result.Nodes.getNodeAs("decl"); + const auto *MatchedFunc = Result.Nodes.getNodeAs("func"); + const auto *MatchedUse = Result.Nodes.getNodeAs("use"); + const auto *MatchedUseCall = Result.Nodes.getNodeAs("use_parent"); + + if (MatchedUseCall) +return; + + const auto *LastUsage = + getLastVarUsage(*MatchedDecl, *MatchedFunc, *Result.Context); + if (LastUsage == nullptr) +return; + + if (LastUsage->getBeginLoc() > MatchedUse->getBeginLoc()) { +// "use" is not the last refe
[clang-tools-extra] [clang-tidy] Add check performance-lost-std-move (PR #139525)
https://github.com/segoon updated https://github.com/llvm/llvm-project/pull/139525 >From 3abbce9f817f6d09f9a5b7549a8122c80821eaf8 Mon Sep 17 00:00:00 2001 From: Vasily Kulikov Date: Mon, 12 May 2025 13:05:43 +0300 Subject: [PATCH 01/15] [clang-tidy] Add check performance-lost-std-move --- .../clang-tidy/performance/CMakeLists.txt | 1 + .../performance/LostStdMoveCheck.cpp | 96 .../clang-tidy/performance/LostStdMoveCheck.h | 37 ++ .../performance/PerformanceTidyModule.cpp | 2 + clang-tools-extra/docs/ReleaseNotes.rst | 5 + .../docs/clang-tidy/checks/list.rst | 1 + .../checks/performance/lost-std-move.rst | 14 +++ .../checkers/performance/lost-std-move.cpp| 108 ++ 8 files changed, 264 insertions(+) create mode 100644 clang-tools-extra/clang-tidy/performance/LostStdMoveCheck.cpp create mode 100644 clang-tools-extra/clang-tidy/performance/LostStdMoveCheck.h create mode 100644 clang-tools-extra/docs/clang-tidy/checks/performance/lost-std-move.rst create mode 100644 clang-tools-extra/test/clang-tidy/checkers/performance/lost-std-move.cpp diff --git a/clang-tools-extra/clang-tidy/performance/CMakeLists.txt b/clang-tools-extra/clang-tidy/performance/CMakeLists.txt index 81128ff086021..333abd10a583a 100644 --- a/clang-tools-extra/clang-tidy/performance/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/performance/CMakeLists.txt @@ -12,6 +12,7 @@ add_clang_library(clangTidyPerformanceModule InefficientAlgorithmCheck.cpp InefficientStringConcatenationCheck.cpp InefficientVectorOperationCheck.cpp + LostStdMoveCheck.cpp MoveConstArgCheck.cpp MoveConstructorInitCheck.cpp NoAutomaticMoveCheck.cpp diff --git a/clang-tools-extra/clang-tidy/performance/LostStdMoveCheck.cpp b/clang-tools-extra/clang-tidy/performance/LostStdMoveCheck.cpp new file mode 100644 index 0..26148e1d26de9 --- /dev/null +++ b/clang-tools-extra/clang-tidy/performance/LostStdMoveCheck.cpp @@ -0,0 +1,96 @@ +//===--- LostStdMoveCheck.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 "LostStdMoveCheck.h" +#include "../utils/DeclRefExprUtils.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" + +using namespace clang::ast_matchers; + +namespace clang::tidy::performance { + +using utils::decl_ref_expr::allDeclRefExprs; + +AST_MATCHER(CXXRecordDecl, hasTrivialMoveConstructor) { + return Node.hasDefinition() && Node.hasTrivialMoveConstructor(); +} + +void LostStdMoveCheck::registerMatchers(MatchFinder *Finder) { + auto returnParent = + hasParent(expr(hasParent(cxxConstructExpr(hasParent(returnStmt()); + + Finder->addMatcher( + declRefExpr( + // not "return x;" + unless(returnParent), + + unless(hasType(namedDecl(hasName("::std::string_view", + + // non-trivial type + hasType(hasCanonicalType(hasDeclaration(cxxRecordDecl(, + + // non-trivial X(X&&) + unless(hasType(hasCanonicalType( + hasDeclaration(cxxRecordDecl(hasTrivialMoveConstructor()), + + // Not in a cycle + unless(hasAncestor(forStmt())), unless(hasAncestor(doStmt())), + unless(hasAncestor(whileStmt())), + + // only non-X& + unless(hasDeclaration( + varDecl(hasType(qualType(lValueReferenceType()), + + hasDeclaration( + varDecl(hasAncestor(functionDecl().bind("func"))).bind("decl")), + + hasParent(expr(hasParent(cxxConstructExpr())).bind("use_parent"))) + .bind("use"), + this); +} + +const Expr *LostStdMoveCheck::getLastVarUsage(const VarDecl &Var, + const Decl &Func, + ASTContext &Context) { + auto Exprs = allDeclRefExprs(Var, Func, Context); + + const Expr *LastExpr = nullptr; + for (const auto &Expr : Exprs) { +if (!LastExpr) + LastExpr = Expr; + +if (LastExpr->getBeginLoc() < Expr->getBeginLoc()) + LastExpr = Expr; + } + + return LastExpr; +} + +void LostStdMoveCheck::check(const MatchFinder::MatchResult &Result) { + const auto *MatchedDecl = Result.Nodes.getNodeAs("decl"); + const auto *MatchedFunc = Result.Nodes.getNodeAs("func"); + const auto *MatchedUse = Result.Nodes.getNodeAs("use"); + const auto *MatchedUseCall = Result.Nodes.getNodeAs("use_parent"); + + if (MatchedUseCall) +return; + + const auto *LastUsage = + getLastVarUsage(*MatchedDecl, *MatchedFunc, *Result.Context); + if (LastUsage == nullptr) +return; + + if (LastUsage->getBeginLoc() > MatchedUse->getBeginLoc()) { +// "use" is not the last refe
[clang-tools-extra] Feature/labmda uaf (PR #145307)
https://github.com/segoon created https://github.com/llvm/llvm-project/pull/145307 None >From 546567ee93c1c0c0de5e34a1ec4d7c2ccfd081c8 Mon Sep 17 00:00:00 2001 From: Vasily Kulikov Date: Mon, 12 May 2025 20:36:43 +0300 Subject: [PATCH 1/2] clang-tidy: add bugprone-taxi-async-use-after-free --- .../bugprone/BugproneTidyModule.cpp | 3 ++ .../clang-tidy/bugprone/CMakeLists.txt| 1 + .../bugprone/TaxiAsyncUseAfterFreeCheck.cpp | 53 +++ .../bugprone/TaxiAsyncUseAfterFreeCheck.h | 33 clang-tools-extra/docs/ReleaseNotes.rst | 5 ++ .../bugprone/taxi-async-use-after-free.rst| 6 +++ .../docs/clang-tidy/checks/list.rst | 1 + .../bugprone/taxi-async-use-after-free.cpp| 35 8 files changed, 137 insertions(+) create mode 100644 clang-tools-extra/clang-tidy/bugprone/TaxiAsyncUseAfterFreeCheck.cpp create mode 100644 clang-tools-extra/clang-tidy/bugprone/TaxiAsyncUseAfterFreeCheck.h create mode 100644 clang-tools-extra/docs/clang-tidy/checks/bugprone/taxi-async-use-after-free.rst create mode 100644 clang-tools-extra/test/clang-tidy/checkers/bugprone/taxi-async-use-after-free.cpp diff --git a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp index b780a85bdf3fe..e22741e66580f 100644 --- a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp @@ -83,6 +83,7 @@ #include "SwappedArgumentsCheck.h" #include "SwitchMissingDefaultCaseCheck.h" #include "TaggedUnionMemberCountCheck.h" +#include "TaxiAsyncUseAfterFreeCheck.h" #include "TerminatingContinueCheck.h" #include "ThrowKeywordMissingCheck.h" #include "TooSmallLoopVariableCheck.h" @@ -151,6 +152,8 @@ class BugproneModule : public ClangTidyModule { "bugprone-incorrect-enable-if"); CheckFactories.registerCheck( "bugprone-incorrect-enable-shared-from-this"); +CheckFactories.registerCheck( +"bugprone-taxi-async-use-after-free"); CheckFactories.registerCheck( "bugprone-unintended-char-ostream-output"); CheckFactories.registerCheck( diff --git a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt index e310ea9c94543..b39177320b6ce 100644 --- a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt @@ -30,6 +30,7 @@ add_clang_library(clangTidyBugproneModule STATIC InaccurateEraseCheck.cpp IncorrectEnableIfCheck.cpp IncorrectEnableSharedFromThisCheck.cpp + TaxiAsyncUseAfterFreeCheck.cpp UnintendedCharOstreamOutputCheck.cpp ReturnConstRefFromParameterCheck.cpp SuspiciousStringviewDataUsageCheck.cpp diff --git a/clang-tools-extra/clang-tidy/bugprone/TaxiAsyncUseAfterFreeCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/TaxiAsyncUseAfterFreeCheck.cpp new file mode 100644 index 0..6fd51b167ac7a --- /dev/null +++ b/clang-tools-extra/clang-tidy/bugprone/TaxiAsyncUseAfterFreeCheck.cpp @@ -0,0 +1,53 @@ +//===--- TaxiAsyncUseAfterFreeCheck.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 "TaxiAsyncUseAfterFreeCheck.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" + +using namespace clang::ast_matchers; + +namespace clang::tidy::bugprone { + +void TaxiAsyncUseAfterFreeCheck::registerMatchers(MatchFinder* Finder) { + auto hasAsyncName = hasAnyName( + "Async", "AsyncNoSpan", "SharedAsyncNoSpan", "CriticalAsyncNoSpan", + "SharedCriticalAsyncNoSpan", "CriticalAsync", "SharedCriticalAsync"); + + Finder->addMatcher( + lambdaExpr( + hasParent(materializeTemporaryExpr(hasParent(callExpr( + hasParent(cxxMemberCallExpr( + + callee(cxxMethodDecl(hasName("push_back"))), + + on(declRefExpr(hasDeclaration(varDecl().bind("tasks")), + + callee(functionDecl(hasAsyncName))) + .bind("lambda"), + this); +} + +void TaxiAsyncUseAfterFreeCheck::check(const MatchFinder::MatchResult& Result) { + const auto* MatchedLambda = Result.Nodes.getNodeAs("lambda"); + const auto* MatchedTasks = Result.Nodes.getNodeAs("tasks"); + const SourceLocation TasksLocation = MatchedTasks->getLocation(); + + for (const auto& Capture : MatchedLambda->captures()) { +if (!Capture.capturesVariable() || Capture.getCaptureKind() != LCK_ByRef) + continue; + +const ValueDecl* CapturedVarDecl = Capture.getCapturedVar(); +if (CapturedVarDecl->getLocation() >= TasksLocation) { + diag(Capture.getLocation(), "captured here"); + diag(CapturedVarDecl->g
[clang-tools-extra] Feature/labmda uaf (PR #145307)
https://github.com/segoon updated https://github.com/llvm/llvm-project/pull/145307 >From 546567ee93c1c0c0de5e34a1ec4d7c2ccfd081c8 Mon Sep 17 00:00:00 2001 From: Vasily Kulikov Date: Mon, 12 May 2025 20:36:43 +0300 Subject: [PATCH 1/3] clang-tidy: add bugprone-taxi-async-use-after-free --- .../bugprone/BugproneTidyModule.cpp | 3 ++ .../clang-tidy/bugprone/CMakeLists.txt| 1 + .../bugprone/TaxiAsyncUseAfterFreeCheck.cpp | 53 +++ .../bugprone/TaxiAsyncUseAfterFreeCheck.h | 33 clang-tools-extra/docs/ReleaseNotes.rst | 5 ++ .../bugprone/taxi-async-use-after-free.rst| 6 +++ .../docs/clang-tidy/checks/list.rst | 1 + .../bugprone/taxi-async-use-after-free.cpp| 35 8 files changed, 137 insertions(+) create mode 100644 clang-tools-extra/clang-tidy/bugprone/TaxiAsyncUseAfterFreeCheck.cpp create mode 100644 clang-tools-extra/clang-tidy/bugprone/TaxiAsyncUseAfterFreeCheck.h create mode 100644 clang-tools-extra/docs/clang-tidy/checks/bugprone/taxi-async-use-after-free.rst create mode 100644 clang-tools-extra/test/clang-tidy/checkers/bugprone/taxi-async-use-after-free.cpp diff --git a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp index b780a85bdf3fe..e22741e66580f 100644 --- a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp @@ -83,6 +83,7 @@ #include "SwappedArgumentsCheck.h" #include "SwitchMissingDefaultCaseCheck.h" #include "TaggedUnionMemberCountCheck.h" +#include "TaxiAsyncUseAfterFreeCheck.h" #include "TerminatingContinueCheck.h" #include "ThrowKeywordMissingCheck.h" #include "TooSmallLoopVariableCheck.h" @@ -151,6 +152,8 @@ class BugproneModule : public ClangTidyModule { "bugprone-incorrect-enable-if"); CheckFactories.registerCheck( "bugprone-incorrect-enable-shared-from-this"); +CheckFactories.registerCheck( +"bugprone-taxi-async-use-after-free"); CheckFactories.registerCheck( "bugprone-unintended-char-ostream-output"); CheckFactories.registerCheck( diff --git a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt index e310ea9c94543..b39177320b6ce 100644 --- a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt @@ -30,6 +30,7 @@ add_clang_library(clangTidyBugproneModule STATIC InaccurateEraseCheck.cpp IncorrectEnableIfCheck.cpp IncorrectEnableSharedFromThisCheck.cpp + TaxiAsyncUseAfterFreeCheck.cpp UnintendedCharOstreamOutputCheck.cpp ReturnConstRefFromParameterCheck.cpp SuspiciousStringviewDataUsageCheck.cpp diff --git a/clang-tools-extra/clang-tidy/bugprone/TaxiAsyncUseAfterFreeCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/TaxiAsyncUseAfterFreeCheck.cpp new file mode 100644 index 0..6fd51b167ac7a --- /dev/null +++ b/clang-tools-extra/clang-tidy/bugprone/TaxiAsyncUseAfterFreeCheck.cpp @@ -0,0 +1,53 @@ +//===--- TaxiAsyncUseAfterFreeCheck.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 "TaxiAsyncUseAfterFreeCheck.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" + +using namespace clang::ast_matchers; + +namespace clang::tidy::bugprone { + +void TaxiAsyncUseAfterFreeCheck::registerMatchers(MatchFinder* Finder) { + auto hasAsyncName = hasAnyName( + "Async", "AsyncNoSpan", "SharedAsyncNoSpan", "CriticalAsyncNoSpan", + "SharedCriticalAsyncNoSpan", "CriticalAsync", "SharedCriticalAsync"); + + Finder->addMatcher( + lambdaExpr( + hasParent(materializeTemporaryExpr(hasParent(callExpr( + hasParent(cxxMemberCallExpr( + + callee(cxxMethodDecl(hasName("push_back"))), + + on(declRefExpr(hasDeclaration(varDecl().bind("tasks")), + + callee(functionDecl(hasAsyncName))) + .bind("lambda"), + this); +} + +void TaxiAsyncUseAfterFreeCheck::check(const MatchFinder::MatchResult& Result) { + const auto* MatchedLambda = Result.Nodes.getNodeAs("lambda"); + const auto* MatchedTasks = Result.Nodes.getNodeAs("tasks"); + const SourceLocation TasksLocation = MatchedTasks->getLocation(); + + for (const auto& Capture : MatchedLambda->captures()) { +if (!Capture.capturesVariable() || Capture.getCaptureKind() != LCK_ByRef) + continue; + +const ValueDecl* CapturedVarDecl = Capture.getCapturedVar(); +if (CapturedVarDecl->getLocation() >= TasksLocation) { + diag(Capture.getLocation(), "captured here"); + diag(CapturedVarDecl->getLoca
[clang-tools-extra] Feature/labmda uaf (PR #145307)
segoon wrote: Sorry, this PR was not indended to be merged as is =( sorry for the noise https://github.com/llvm/llvm-project/pull/145307 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] Feature/labmda uaf (PR #145307)
https://github.com/segoon closed https://github.com/llvm/llvm-project/pull/145307 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits