diff --git a/clang-tidy/misc/AssignOperatorSignatureCheck.cpp b/clang-tidy/misc/AssignOperatorSignatureCheck.cpp index ad62c56..5b71e0e 100644 --- a/clang-tidy/misc/AssignOperatorSignatureCheck.cpp +++ b/clang-tidy/misc/AssignOperatorSignatureCheck.cpp @@ -19,31 +19,37 @@ namespace misc { void AssignOperatorSignatureCheck::registerMatchers( ast_matchers::MatchFinder *Finder) { - const auto HasGoodReturnType = methodDecl(returns(lValueReferenceType(pointee( - unless(isConstQualified()), hasDeclaration(equalsBoundNode("class")))))); + // Only register the matchers for C++; the functionality currently does not + // provide any benefit to other languages, despite being benign. + if (getLangOpts().CPlusPlus) { + const auto HasGoodReturnType = methodDecl(returns(lValueReferenceType( + pointee(unless(isConstQualified()), + hasDeclaration(equalsBoundNode("class")))))); - const auto IsSelf = qualType( - anyOf(hasDeclaration(equalsBoundNode("class")), - referenceType(pointee(hasDeclaration(equalsBoundNode("class")))))); - const auto IsSelfAssign = - methodDecl(unless(anyOf(isDeleted(), isPrivate(), isImplicit())), - hasName("operator="), ofClass(recordDecl().bind("class")), - hasParameter(0, parmVarDecl(hasType(IsSelf)))).bind("method"); + const auto IsSelf = qualType(anyOf( + hasDeclaration(equalsBoundNode("class")), + referenceType(pointee(hasDeclaration(equalsBoundNode("class")))))); + const auto IsSelfAssign = + methodDecl(unless(anyOf(isDeleted(), isPrivate(), isImplicit())), + hasName("operator="), ofClass(recordDecl().bind("class")), + hasParameter(0, parmVarDecl(hasType(IsSelf)))) + .bind("method"); - Finder->addMatcher( - methodDecl(IsSelfAssign, unless(HasGoodReturnType)).bind("ReturnType"), - this); + Finder->addMatcher( + methodDecl(IsSelfAssign, unless(HasGoodReturnType)).bind("ReturnType"), + this); - const auto BadSelf = referenceType( - anyOf(lValueReferenceType(pointee(unless(isConstQualified()))), - rValueReferenceType(pointee(isConstQualified())))); + const auto BadSelf = referenceType( + anyOf(lValueReferenceType(pointee(unless(isConstQualified()))), + rValueReferenceType(pointee(isConstQualified())))); - Finder->addMatcher( - methodDecl(IsSelfAssign, hasParameter(0, parmVarDecl(hasType(BadSelf)))) - .bind("ArgumentType"), - this); + Finder->addMatcher( + methodDecl(IsSelfAssign, hasParameter(0, parmVarDecl(hasType(BadSelf)))) + .bind("ArgumentType"), + this); - Finder->addMatcher(methodDecl(IsSelfAssign, isConst()).bind("Const"), this); + Finder->addMatcher(methodDecl(IsSelfAssign, isConst()).bind("Const"), this); + } } diff --git a/clang-tidy/misc/InaccurateEraseCheck.cpp b/clang-tidy/misc/InaccurateEraseCheck.cpp index c172cd7..835c948 100644 --- a/clang-tidy/misc/InaccurateEraseCheck.cpp +++ b/clang-tidy/misc/InaccurateEraseCheck.cpp @@ -19,21 +19,27 @@ namespace tidy { namespace misc { void InaccurateEraseCheck::registerMatchers(MatchFinder *Finder) { - const auto CheckForEndCall = hasArgument( - 1, - anyOf(constructExpr(has(memberCallExpr(callee(methodDecl(hasName("end")))) - .bind("InaccEndCall"))), - anything())); + // Only register the matchers for C++; the functionality currently does not + // provide any benefit to other languages, despite being benign. + if (getLangOpts().CPlusPlus) { + const auto CheckForEndCall = hasArgument( + 1, anyOf(constructExpr( + has(memberCallExpr(callee(methodDecl(hasName("end")))) + .bind("InaccEndCall"))), + anything())); - Finder->addMatcher( - memberCallExpr( - on(hasType(namedDecl(matchesName("^::std::")))), - callee(methodDecl(hasName("erase"))), argumentCountIs(1), - hasArgument(0, has(callExpr(callee(functionDecl(matchesName( - "^::std::(remove(_if)?|unique)$"))), - CheckForEndCall).bind("InaccAlgCall"))), - unless(isInTemplateInstantiation())).bind("InaccErase"), - this); + Finder->addMatcher( + memberCallExpr( + on(hasType(namedDecl(matchesName("^::std::")))), + callee(methodDecl(hasName("erase"))), argumentCountIs(1), + hasArgument(0, has(callExpr(callee(functionDecl(matchesName( + "^::std::(remove(_if)?|unique)$"))), + CheckForEndCall) + .bind("InaccAlgCall"))), + unless(isInTemplateInstantiation())) + .bind("InaccErase"), + this); + } } void InaccurateEraseCheck::check(const MatchFinder::MatchResult &Result) { diff --git a/clang-tidy/misc/InefficientAlgorithmCheck.cpp b/clang-tidy/misc/InefficientAlgorithmCheck.cpp index 3ca6c81..17ef560 100644 --- a/clang-tidy/misc/InefficientAlgorithmCheck.cpp +++ b/clang-tidy/misc/InefficientAlgorithmCheck.cpp @@ -28,30 +28,35 @@ static bool areTypesCompatible(QualType Left, QualType Right) { } void InefficientAlgorithmCheck::registerMatchers(MatchFinder *Finder) { - const std::string Algorithms = - "^::std::(find|count|equal_range|lower_bound|upper_bound)$"; - const auto ContainerMatcher = classTemplateSpecializationDecl( - matchesName("^::std::(unordered_)?(multi)?(set|map)$")); - const auto Matcher = - callExpr( - callee(functionDecl(matchesName(Algorithms))), - hasArgument( - 0, constructExpr(has(memberCallExpr( - callee(methodDecl(hasName("begin"))), - on(declRefExpr( - hasDeclaration(decl().bind("IneffContObj")), - anyOf(hasType(ContainerMatcher.bind("IneffCont")), - hasType(pointsTo( - ContainerMatcher.bind("IneffContPtr"))))) - .bind("IneffContExpr")))))), - hasArgument(1, constructExpr(has(memberCallExpr( - callee(methodDecl(hasName("end"))), - on(declRefExpr(hasDeclaration( - equalsBoundNode("IneffContObj")))))))), - hasArgument(2, expr().bind("AlgParam")), - unless(isInTemplateInstantiation())).bind("IneffAlg"); + // Only register the matchers for C++; the functionality currently does not + // provide any benefit to other languages, despite being benign. + if (getLangOpts().CPlusPlus) { + const std::string Algorithms = + "^::std::(find|count|equal_range|lower_bound|upper_bound)$"; + const auto ContainerMatcher = classTemplateSpecializationDecl( + matchesName("^::std::(unordered_)?(multi)?(set|map)$")); + const auto Matcher = + callExpr( + callee(functionDecl(matchesName(Algorithms))), + hasArgument( + 0, constructExpr(has(memberCallExpr( + callee(methodDecl(hasName("begin"))), + on(declRefExpr( + hasDeclaration(decl().bind("IneffContObj")), + anyOf(hasType(ContainerMatcher.bind("IneffCont")), + hasType(pointsTo(ContainerMatcher.bind( + "IneffContPtr"))))) + .bind("IneffContExpr")))))), + hasArgument(1, constructExpr(has(memberCallExpr( + callee(methodDecl(hasName("end"))), + on(declRefExpr(hasDeclaration( + equalsBoundNode("IneffContObj")))))))), + hasArgument(2, expr().bind("AlgParam")), + unless(isInTemplateInstantiation())) + .bind("IneffAlg"); - Finder->addMatcher(Matcher, this); + Finder->addMatcher(Matcher, this); + } } void InefficientAlgorithmCheck::check(const MatchFinder::MatchResult &Result) { diff --git a/clang-tidy/misc/MoveConstructorInitCheck.cpp b/clang-tidy/misc/MoveConstructorInitCheck.cpp index b1ec6da..5b2c789 100644 --- a/clang-tidy/misc/MoveConstructorInitCheck.cpp +++ b/clang-tidy/misc/MoveConstructorInitCheck.cpp @@ -17,15 +17,19 @@ namespace clang { namespace tidy { void MoveConstructorInitCheck::registerMatchers(MatchFinder *Finder) { - Finder->addMatcher( - constructorDecl(unless(isImplicit()), allOf( - isMoveConstructor(), - hasAnyConstructorInitializer( - ctorInitializer(withInitializer(constructExpr(hasDeclaration( - constructorDecl(isCopyConstructor()).bind("ctor") - )))).bind("init") - ) - )), this); + // Only register the matchers for C++11; the functionality currently does not + // provide any benefit to other languages, despite being benign. + if (getLangOpts().CPlusPlus11) { + Finder->addMatcher( + constructorDecl(unless(isImplicit()), allOf( + isMoveConstructor(), + hasAnyConstructorInitializer( + ctorInitializer(withInitializer(constructExpr(hasDeclaration( + constructorDecl(isCopyConstructor()).bind("ctor") + )))).bind("init") + ) + )), this); + } } void MoveConstructorInitCheck::check(const MatchFinder::MatchResult &Result) { diff --git a/clang-tidy/misc/NoexceptMoveConstructorCheck.cpp b/clang-tidy/misc/NoexceptMoveConstructorCheck.cpp index 7bc7835..155baf8 100644 --- a/clang-tidy/misc/NoexceptMoveConstructorCheck.cpp +++ b/clang-tidy/misc/NoexceptMoveConstructorCheck.cpp @@ -17,11 +17,15 @@ namespace clang { namespace tidy { void NoexceptMoveConstructorCheck::registerMatchers(MatchFinder *Finder) { - Finder->addMatcher( - methodDecl(anyOf(constructorDecl(), hasOverloadedOperatorName("=")), - unless(isImplicit()), unless(isDeleted())) - .bind("decl"), - this); + // Only register the matchers for C++11; the functionality currently does not + // provide any benefit to other languages, despite being benign. + if (getLangOpts().CPlusPlus11) { + Finder->addMatcher( + methodDecl(anyOf(constructorDecl(), hasOverloadedOperatorName("=")), + unless(isImplicit()), unless(isDeleted())) + .bind("decl"), + this); + } } void NoexceptMoveConstructorCheck::check( diff --git a/clang-tidy/misc/StaticAssertCheck.cpp b/clang-tidy/misc/StaticAssertCheck.cpp index 1b6b897..e5aa86e 100644 --- a/clang-tidy/misc/StaticAssertCheck.cpp +++ b/clang-tidy/misc/StaticAssertCheck.cpp @@ -27,34 +27,47 @@ StaticAssertCheck::StaticAssertCheck(StringRef Name, ClangTidyContext *Context) : ClangTidyCheck(Name, Context) {} void StaticAssertCheck::registerMatchers(MatchFinder *Finder) { - auto IsAlwaysFalse = expr(ignoringParenImpCasts( - expr(anyOf(boolLiteral(equals(false)), integerLiteral(equals(0)), - nullPtrLiteralExpr(), gnuNullExpr())).bind("isAlwaysFalse"))); - auto IsAlwaysFalseWithCast = ignoringParenImpCasts(anyOf(IsAlwaysFalse, - cStyleCastExpr(has(IsAlwaysFalse)).bind("castExpr"))); - auto AssertExprRoot = anyOf( - binaryOperator( - anyOf(hasOperatorName("&&"), hasOperatorName("==")), - hasEitherOperand(ignoringImpCasts(stringLiteral().bind("assertMSG"))), - anyOf(binaryOperator(hasEitherOperand(IsAlwaysFalseWithCast)), - anything())).bind("assertExprRoot"), - IsAlwaysFalse); - auto NonConstexprFunctionCall = - callExpr(hasDeclaration(functionDecl(unless(isConstexpr())))); - auto AssertCondition = expr(anyOf( - expr(ignoringParenCasts(anyOf( - AssertExprRoot, - unaryOperator(hasUnaryOperand(ignoringParenCasts(AssertExprRoot)))))), - anything()), unless(findAll(NonConstexprFunctionCall))).bind("condition"); - auto Condition = anyOf(ignoringParenImpCasts(callExpr( - hasDeclaration(functionDecl(hasName("__builtin_expect"))), - hasArgument(0, AssertCondition))), AssertCondition); + // FIXME: I don't see why this checker couldn't also be interesting for + // _Static_assert in C11, or static_assert if has been included, + // but it is currently only enabled for C++11. Investigate. + if (getLangOpts().CPlusPlus11) { + auto IsAlwaysFalse = expr(ignoringParenImpCasts( + expr(anyOf(boolLiteral(equals(false)), integerLiteral(equals(0)), + nullPtrLiteralExpr(), gnuNullExpr())) + .bind("isAlwaysFalse"))); + auto IsAlwaysFalseWithCast = ignoringParenImpCasts(anyOf( + IsAlwaysFalse, cStyleCastExpr(has(IsAlwaysFalse)).bind("castExpr"))); + auto AssertExprRoot = + anyOf(binaryOperator( + anyOf(hasOperatorName("&&"), hasOperatorName("==")), + hasEitherOperand( + ignoringImpCasts(stringLiteral().bind("assertMSG"))), + anyOf(binaryOperator(hasEitherOperand(IsAlwaysFalseWithCast)), + anything())) + .bind("assertExprRoot"), + IsAlwaysFalse); + auto NonConstexprFunctionCall = + callExpr(hasDeclaration(functionDecl(unless(isConstexpr())))); + auto AssertCondition = + expr(anyOf(expr(ignoringParenCasts( + anyOf(AssertExprRoot, + unaryOperator(hasUnaryOperand( + ignoringParenCasts(AssertExprRoot)))))), + anything()), + unless(findAll(NonConstexprFunctionCall))) + .bind("condition"); + auto Condition = + anyOf(ignoringParenImpCasts(callExpr( + hasDeclaration(functionDecl(hasName("__builtin_expect"))), + hasArgument(0, AssertCondition))), + AssertCondition); - Finder->addMatcher( - stmt(anyOf(conditionalOperator(hasCondition(Condition)), - ifStmt(hasCondition(Condition))), - unless(isInTemplateInstantiation())).bind("condStmt"), - this); + Finder->addMatcher(stmt(anyOf(conditionalOperator(hasCondition(Condition)), + ifStmt(hasCondition(Condition))), + unless(isInTemplateInstantiation())) + .bind("condStmt"), + this); + } } void StaticAssertCheck::check(const MatchFinder::MatchResult &Result) { @@ -70,8 +83,7 @@ void StaticAssertCheck::check(const MatchFinder::MatchResult &Result) { const auto *CastExpr = Result.Nodes.getNodeAs("castExpr"); SourceLocation AssertExpansionLoc = CondStmt->getLocStart(); - if (!Opts.CPlusPlus11 || !AssertExpansionLoc.isValid() || - !AssertExpansionLoc.isMacroID()) + if (!AssertExpansionLoc.isValid() || !AssertExpansionLoc.isMacroID()) return; StringRef MacroName = diff --git a/clang-tidy/misc/UndelegatedConstructor.cpp b/clang-tidy/misc/UndelegatedConstructor.cpp index 0390c23..5f56a4c 100644 --- a/clang-tidy/misc/UndelegatedConstructor.cpp +++ b/clang-tidy/misc/UndelegatedConstructor.cpp @@ -55,15 +55,20 @@ void UndelegatedConstructorCheck::registerMatchers(MatchFinder *Finder) { // depending on the type's destructor and the number of arguments on the // constructor call, this is handled by ignoringTemporaryExpr. Ignore template // instantiations to reduce the number of duplicated warnings. - Finder->addMatcher( - compoundStmt( - hasParent(constructorDecl(ofClass(recordDecl().bind("parent")))), - forEach(ignoringTemporaryExpr( - constructExpr(hasDeclaration(constructorDecl(ofClass( - recordDecl(baseOfBoundNode("parent")))))) - .bind("construct"))), - unless(isInTemplateInstantiation())), - this); + // + // Only register the matchers for C++11; the functionality currently does not + // provide any benefit to other languages, despite being benign. + if (getLangOpts().CPlusPlus11) { + Finder->addMatcher( + compoundStmt( + hasParent(constructorDecl(ofClass(recordDecl().bind("parent")))), + forEach(ignoringTemporaryExpr( + constructExpr(hasDeclaration(constructorDecl(ofClass( + recordDecl(baseOfBoundNode("parent")))))) + .bind("construct"))), + unless(isInTemplateInstantiation())), + this); + } } void UndelegatedConstructorCheck::check(const MatchFinder::MatchResult &Result) { diff --git a/clang-tidy/misc/UniqueptrResetReleaseCheck.cpp b/clang-tidy/misc/UniqueptrResetReleaseCheck.cpp index 436cd10..e42e3a6 100644 --- a/clang-tidy/misc/UniqueptrResetReleaseCheck.cpp +++ b/clang-tidy/misc/UniqueptrResetReleaseCheck.cpp @@ -18,21 +18,25 @@ namespace tidy { namespace misc { void UniqueptrResetReleaseCheck::registerMatchers(MatchFinder *Finder) { - Finder->addMatcher( - memberCallExpr( - on(expr().bind("left")), callee(memberExpr().bind("reset_member")), - callee(methodDecl(hasName("reset"), - ofClass(recordDecl(hasName("::std::unique_ptr"), - decl().bind("left_class"))))), - has(memberCallExpr( - on(expr().bind("right")), - callee(memberExpr().bind("release_member")), - callee(methodDecl( - hasName("release"), - ofClass(recordDecl(hasName("::std::unique_ptr"), - decl().bind("right_class")))))))) - .bind("reset_call"), - this); + // Only register the matchers for C++11; the functionality currently does not + // provide any benefit to other languages, despite being benign. + if (getLangOpts().CPlusPlus11) { + Finder->addMatcher( + memberCallExpr( + on(expr().bind("left")), callee(memberExpr().bind("reset_member")), + callee(methodDecl(hasName("reset"), + ofClass(recordDecl(hasName("::std::unique_ptr"), + decl().bind("left_class"))))), + has(memberCallExpr( + on(expr().bind("right")), + callee(memberExpr().bind("release_member")), + callee(methodDecl( + hasName("release"), + ofClass(recordDecl(hasName("::std::unique_ptr"), + decl().bind("right_class")))))))) + .bind("reset_call"), + this); + } } namespace { diff --git a/clang-tidy/misc/UnusedAliasDeclsCheck.cpp b/clang-tidy/misc/UnusedAliasDeclsCheck.cpp index 80e4861..707a220 100644 --- a/clang-tidy/misc/UnusedAliasDeclsCheck.cpp +++ b/clang-tidy/misc/UnusedAliasDeclsCheck.cpp @@ -22,11 +22,15 @@ const ast_matchers::internal::VariadicDynCastAllOfMatcher< Decl, NamespaceAliasDecl> namespaceAliasDecl; void UnusedAliasDeclsCheck::registerMatchers(MatchFinder *Finder) { - // We cannot do anything about headers (yet), as the alias declarations - // used in one header could be used by some other translation unit. - Finder->addMatcher(namespaceAliasDecl(isExpansionInMainFile()).bind("alias"), - this); - Finder->addMatcher(nestedNameSpecifier().bind("nns"), this); + // Only register the matchers for C++11; the functionality currently does not + // provide any benefit to other languages, despite being benign. + if (getLangOpts().CPlusPlus11) { + // We cannot do anything about headers (yet), as the alias declarations + // used in one header could be used by some other translation unit. + Finder->addMatcher( + namespaceAliasDecl(isExpansionInMainFile()).bind("alias"), this); + Finder->addMatcher(nestedNameSpecifier().bind("nns"), this); + } } void UnusedAliasDeclsCheck::check(const MatchFinder::MatchResult &Result) { diff --git a/clang-tidy/misc/UnusedRAIICheck.cpp b/clang-tidy/misc/UnusedRAIICheck.cpp index 4ca89a3..ffd114d 100644 --- a/clang-tidy/misc/UnusedRAIICheck.cpp +++ b/clang-tidy/misc/UnusedRAIICheck.cpp @@ -25,17 +25,22 @@ namespace tidy { namespace misc { void UnusedRAIICheck::registerMatchers(MatchFinder *Finder) { - // Look for temporaries that are constructed in-place and immediately - // destroyed. Look for temporaries created by a functional cast but not for - // those returned from a call. - auto BindTemp = bindTemporaryExpr(unless(has(callExpr()))).bind("temp"); - Finder->addMatcher( - exprWithCleanups(unless(isInTemplateInstantiation()), - hasParent(compoundStmt().bind("compound")), - hasType(recordDecl(hasNonTrivialDestructor())), - anyOf(has(BindTemp), has(functionalCastExpr( - has(BindTemp))))).bind("expr"), - this); + // Only register the matchers for C++; the functionality currently does not + // provide any benefit to other languages, despite being benign. + if (getLangOpts().CPlusPlus) { + // Look for temporaries that are constructed in-place and immediately + // destroyed. Look for temporaries created by a functional cast but not for + // those returned from a call. + auto BindTemp = bindTemporaryExpr(unless(has(callExpr()))).bind("temp"); + Finder->addMatcher( + exprWithCleanups( + unless(isInTemplateInstantiation()), + hasParent(compoundStmt().bind("compound")), + hasType(recordDecl(hasNonTrivialDestructor())), + anyOf(has(BindTemp), has(functionalCastExpr(has(BindTemp))))) + .bind("expr"), + this); + } } void UnusedRAIICheck::check(const MatchFinder::MatchResult &Result) { diff --git a/clang-tidy/misc/UseOverrideCheck.cpp b/clang-tidy/misc/UseOverrideCheck.cpp index ec71d1b..1c9b9ab 100644 --- a/clang-tidy/misc/UseOverrideCheck.cpp +++ b/clang-tidy/misc/UseOverrideCheck.cpp @@ -19,7 +19,9 @@ namespace tidy { namespace misc { void UseOverrideCheck::registerMatchers(MatchFinder *Finder) { - Finder->addMatcher(methodDecl(isOverride()).bind("method"), this); + // Only register the matcher for C++11. + if (getLangOpts().CPlusPlus11) + Finder->addMatcher(methodDecl(isOverride()).bind("method"), this); } // Re-lex the tokens to get precise locations to insert 'override' and remove @@ -58,9 +60,6 @@ static StringRef GetText(const Token &Tok, const SourceManager &Sources) { } void UseOverrideCheck::check(const MatchFinder::MatchResult &Result) { - if (!Result.Context->getLangOpts().CPlusPlus11) - return; - const FunctionDecl *Method = Result.Nodes.getStmtAs("method"); const SourceManager &Sources = *Result.SourceManager; diff --git a/test/clang-tidy/misc-undelegated-constructor-cxx98.cpp b/test/clang-tidy/misc-undelegated-constructor-cxx98.cpp new file mode 100644 index 0000000..e614f22 --- /dev/null +++ b/test/clang-tidy/misc-undelegated-constructor-cxx98.cpp @@ -0,0 +1,23 @@ +// RUN: clang-tidy %s -checks=-*,misc-undelegated-constructor -- -std=c++98 | count 0 + +// Note: this test expects no diagnostics, but FileCheck cannot handle that, +// hence the use of | count 0. + +struct Ctor; +Ctor foo(); + +struct Ctor { + Ctor(); + Ctor(int); + Ctor(int, int); + Ctor(Ctor *i) { + Ctor(); + Ctor(0); + Ctor(1, 2); + foo(); + } +}; + +Ctor::Ctor() { + Ctor(1); +}