diff --git a/clang-tools-extra/clang-tidy/bugprone/UnusedReturnValueCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/UnusedReturnValueCheck.cpp index 243fe47c2036b..73373147e96fc 100644 --- a/clang-tools-extra/clang-tidy/bugprone/UnusedReturnValueCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/UnusedReturnValueCheck.cpp @@ -31,9 +31,16 @@ AST_MATCHER_P(FunctionDecl, isInstantiatedFrom, Matcher, Finder, Builder); } -AST_MATCHER_P(CXXMethodDecl, isOperatorOverloading, - llvm::SmallVector, Kinds) { - return llvm::is_contained(Kinds, Node.getOverloadedOperator()); +constexpr std::initializer_list + AssignmentOverloadedOperatorKinds = { + OO_Equal, OO_PlusEqual, OO_MinusEqual, OO_StarEqual, + OO_SlashEqual, OO_PercentEqual, OO_CaretEqual, OO_AmpEqual, + OO_PipeEqual, OO_LessLessEqual, OO_GreaterGreaterEqual, OO_PlusPlus, + OO_MinusMinus}; + +AST_MATCHER(FunctionDecl, isAssignmentOverloadedOperator) { + return llvm::is_contained(AssignmentOverloadedOperatorKinds, + Node.getOverloadedOperator()); } } // namespace @@ -164,22 +171,18 @@ void UnusedReturnValueCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { } void UnusedReturnValueCheck::registerMatchers(MatchFinder *Finder) { - auto MatchedDirectCallExpr = expr( - callExpr( - callee(functionDecl( - // Don't match void overloads of checked functions. - unless(returns(voidType())), - // Don't match copy or move assignment operator. - unless(cxxMethodDecl(isOperatorOverloading( - {OO_Equal, OO_PlusEqual, OO_MinusEqual, OO_StarEqual, - OO_SlashEqual, OO_PercentEqual, OO_CaretEqual, OO_AmpEqual, - OO_PipeEqual, OO_LessLessEqual, OO_GreaterGreaterEqual}))), - anyOf( - isInstantiatedFrom( - matchers::matchesAnyListedName(CheckedFunctions)), - returns(hasCanonicalType(hasDeclaration(namedDecl( - matchers::matchesAnyListedName(CheckedReturnTypes))))))))) - .bind("match")); + auto MatchedDirectCallExpr = + expr(callExpr(callee(functionDecl( + // Don't match copy or move assignment operator. + unless(isAssignmentOverloadedOperator()), + // Don't match void overloads of checked functions. + unless(returns(voidType())), + anyOf(isInstantiatedFrom(matchers::matchesAnyListedName( + CheckedFunctions)), + returns(hasCanonicalType(hasDeclaration( + namedDecl(matchers::matchesAnyListedName( + CheckedReturnTypes))))))))) + .bind("match")); auto CheckCastToVoid = AllowCastToVoid ? castExpr(unless(hasCastKind(CK_ToVoid))) : castExpr(); diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/unused-return-value-avoid-assignment.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/unused-return-value-avoid-assignment.cpp index b4a41004adf89..564c07a724ccd 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/unused-return-value-avoid-assignment.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/unused-return-value-avoid-assignment.cpp @@ -3,23 +3,37 @@ // RUN: {bugprone-unused-return-value.CheckedFunctions: "::*"}}' \ // RUN: -- -struct S { - S(){}; - S(S const &); - S(S &&); - S &operator=(S const &); - S &operator=(S &&); - S &operator+=(S); +struct S1 { + S1(){}; + S1(S1 const &); + S1(S1 &&); + S1 &operator=(S1 const &); + S1 &operator=(S1 &&); + S1 &operator+=(S1); + S1 &operator++(); + S1 &operator++(int); + S1 &operator--(); + S1 &operator--(int); }; -S returnValue(); -S const &returnRef(); +struct S2 { + S2(){}; + S2(S2 const &); + S2(S2 &&); +}; + +S2 &operator-=(S2&, int); +S2 &operator++(S2 &); +S2 &operator++(S2 &, int); + +S1 returnValue(); +S1 const &returnRef(); void bar() { returnValue(); // CHECK-MESSAGES: [[@LINE-1]]:3: warning: the value returned by this function should not be disregarded; neglecting it may lead to errors - S a{}; + S1 a{}; a = returnValue(); a.operator=(returnValue()); @@ -27,4 +41,15 @@ void bar() { a.operator=(returnRef()); a += returnRef(); + + a++; + ++a; + a--; + --a; + + S2 b{}; + + b -= 1; + b++; + ++b; }