diff --git a/clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp index c10c3652a153a..c5b6b541096ca 100644 --- a/clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp @@ -10,13 +10,13 @@ #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" -#include "clang/AST/ExprConcepts.h" #include "clang/ASTMatchers/ASTMatchers.h" #include "clang/Analysis/CFG.h" #include "clang/Lex/Lexer.h" #include "llvm/ADT/STLExtras.h" #include "../utils/ExprSequence.h" +#include "../utils/Matchers.h" #include using namespace clang::ast_matchers; @@ -24,24 +24,9 @@ using namespace clang::tidy::utils; namespace clang::tidy::bugprone { -namespace { +using matchers::hasUnevaluatedContext; -AST_MATCHER(Expr, hasUnevaluatedContext) { - if (isa(Node) || isa(Node)) - return true; - if (const auto *UnaryExpr = dyn_cast(&Node)) { - switch (UnaryExpr->getKind()) { - case UETT_SizeOf: - case UETT_AlignOf: - return true; - default: - return false; - } - } - if (const auto *TypeIDExpr = dyn_cast(&Node)) - return !TypeIDExpr->isPotentiallyEvaluated(); - return false; -} +namespace { /// Contains information about a use-after-move. struct UseAfterMove { @@ -86,7 +71,6 @@ class UseAfterMoveFinder { } // namespace - // Matches nodes that are // - Part of a decltype argument or class template argument (we check this by // seeing if they are children of a TypeLoc), or diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/RvalueReferenceParamNotMovedCheck.cpp b/clang-tools-extra/clang-tidy/cppcoreguidelines/RvalueReferenceParamNotMovedCheck.cpp index eb67df05411a0..da49d5610e229 100644 --- a/clang-tools-extra/clang-tidy/cppcoreguidelines/RvalueReferenceParamNotMovedCheck.cpp +++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/RvalueReferenceParamNotMovedCheck.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "RvalueReferenceParamNotMovedCheck.h" +#include "../utils/Matchers.h" #include "clang/AST/ASTContext.h" #include "clang/ASTMatchers/ASTMatchFinder.h" @@ -14,6 +15,8 @@ using namespace clang::ast_matchers; namespace clang::tidy::cppcoreguidelines { +using matchers::hasUnevaluatedContext; + namespace { AST_MATCHER_P(LambdaExpr, valueCapturesVar, DeclarationMatcher, VarMatcher) { return std::find_if(Node.capture_begin(), Node.capture_end(), @@ -39,16 +42,18 @@ void RvalueReferenceParamNotMovedCheck::registerMatchers(MatchFinder *Finder) { StatementMatcher MoveCallMatcher = callExpr( + argumentCountIs(1), anyOf(callee(functionDecl(hasName("::std::move"))), callee(unresolvedLookupExpr(hasAnyDeclaration( namedDecl(hasUnderlyingDecl(hasName("::std::move"))))))), - argumentCountIs(1), hasArgument( 0, argumentOf( AllowPartialMove, declRefExpr(to(equalsBoundNode("param"))).bind("ref"))), unless(hasAncestor( - lambdaExpr(valueCapturesVar(equalsBoundNode("param")))))) + lambdaExpr(valueCapturesVar(equalsBoundNode("param"))))), + unless(anyOf(hasAncestor(typeLoc()), + hasAncestor(expr(hasUnevaluatedContext()))))) .bind("move-call"); Finder->addMatcher( diff --git a/clang-tools-extra/clang-tidy/utils/Matchers.h b/clang-tools-extra/clang-tidy/utils/Matchers.h index b3b2c8c636174..1e085f59b69ed 100644 --- a/clang-tools-extra/clang-tidy/utils/Matchers.h +++ b/clang-tools-extra/clang-tidy/utils/Matchers.h @@ -10,6 +10,7 @@ #define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_UTILS_MATCHERS_H #include "TypeTraits.h" +#include "clang/AST/ExprConcepts.h" #include "clang/ASTMatchers/ASTMatchers.h" #include @@ -48,6 +49,23 @@ AST_MATCHER_FUNCTION(ast_matchers::TypeMatcher, isPointerToConst) { return pointerType(pointee(qualType(isConstQualified()))); } +AST_MATCHER(Expr, hasUnevaluatedContext) { + if (isa(Node) || isa(Node)) + return true; + if (const auto *UnaryExpr = dyn_cast(&Node)) { + switch (UnaryExpr->getKind()) { + case UETT_SizeOf: + case UETT_AlignOf: + return true; + default: + return false; + } + } + if (const auto *TypeIDExpr = dyn_cast(&Node)) + return !TypeIDExpr->isPotentiallyEvaluated(); + return false; +} + // A matcher implementation that matches a list of type name regular expressions // against a NamedDecl. If a regular expression contains the substring "::" // matching will occur against the qualified name, otherwise only the typename. diff --git a/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/rvalue-reference-param-not-moved.cpp b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/rvalue-reference-param-not-moved.cpp index 9ee26e851bfc2..2ac2d17e0097d 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/rvalue-reference-param-not-moved.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/rvalue-reference-param-not-moved.cpp @@ -156,6 +156,13 @@ void moves_parameter_extra_parens(Obj&& o) { Obj moved = std::move((o)); } +void does_not_move_in_evaluated(Obj&& o) { + // CHECK-MESSAGES: :[[@LINE-1]]:39: warning: rvalue reference parameter 'o' is never moved from inside the function body [cppcoreguidelines-rvalue-reference-param-not-moved] + using result_t = decltype(std::move(o)); + unsigned size = sizeof(std::move(o)); + Obj moved = o; +} + template struct mypair { T1 first;