diff --git a/clang-tools-extra/clang-tidy/abseil/DurationUnnecessaryConversionCheck.cpp b/clang-tools-extra/clang-tidy/abseil/DurationUnnecessaryConversionCheck.cpp --- a/clang-tools-extra/clang-tidy/abseil/DurationUnnecessaryConversionCheck.cpp +++ b/clang-tools-extra/clang-tidy/abseil/DurationUnnecessaryConversionCheck.cpp @@ -11,6 +11,7 @@ #include "DurationRewriter.h" #include "clang/AST/ASTContext.h" #include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" #include "clang/Tooling/FixIt.h" using namespace clang::ast_matchers; @@ -19,6 +20,11 @@ namespace tidy { namespace abseil { +ast_matchers::internal::Matcher +elidable(ast_matchers::internal::Matcher InnerMatcher) { + return anyOf(cxxConstructExpr(hasArgument(0, InnerMatcher)), InnerMatcher); +} + void DurationUnnecessaryConversionCheck::registerMatchers(MatchFinder *Finder) { for (const auto &Scale : {"Hours", "Minutes", "Seconds", "Milliseconds", "Microseconds", "Nanoseconds"}) { @@ -30,10 +36,10 @@ // Matcher which matches the current scale's factory with a `1` argument, // e.g. `absl::Seconds(1)`. - auto factory_matcher = cxxConstructExpr(hasArgument( - 0, + + auto factory_matcher = elidable( callExpr(callee(functionDecl(hasName(DurationFactory))), - hasArgument(0, ignoringImpCasts(integerLiteral(equals(1))))))); + hasArgument(0, ignoringImpCasts(integerLiteral(equals(1)))))); // Matcher which matches either inverse function and binds its argument, // e.g. `absl::ToDoubleSeconds(dur)`. diff --git a/clang-tools-extra/clang-tidy/abseil/FasterStrsplitDelimiterCheck.cpp b/clang-tools-extra/clang-tidy/abseil/FasterStrsplitDelimiterCheck.cpp --- a/clang-tools-extra/clang-tidy/abseil/FasterStrsplitDelimiterCheck.cpp +++ b/clang-tools-extra/clang-tidy/abseil/FasterStrsplitDelimiterCheck.cpp @@ -9,6 +9,7 @@ #include "FasterStrsplitDelimiterCheck.h" #include "clang/AST/ASTContext.h" #include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" using namespace clang::ast_matchers; @@ -48,7 +49,8 @@ if (Result == R"("'")") return std::string(R"('\'')"); - assert(Result.size() == 3 || (Result.size() == 4 && Result.substr(0, 2) == "\"\\")); + assert(Result.size() == 3 || + (Result.size() == 4 && Result.substr(0, 2) == "\"\\")); // Now replace the " with '. auto Pos = Result.find_first_of('"'); @@ -75,11 +77,16 @@ // Binds to a string_view (either absl or std) that was passed by value and // contructed from string literal. auto StringViewArg = - copyConstructExprWithArg("::absl::string_view", SingleChar); + anyOf(copyConstructExprWithArg("::absl::string_view", SingleChar), + constructExprWithArg("::absl::string_view", SingleChar)); auto ByAnyCharArg = - expr(copyConstructExprWithArg("::absl::ByAnyChar", StringViewArg)) - .bind("ByAnyChar"); + anyOf(expr(copyConstructExprWithArg("::absl::ByAnyChar", StringViewArg)) + .bind("ByAnyChar"), + expr(hasDescendant(cxxConstructExpr( + hasType(recordDecl(hasName("::absl::ByAnyChar"))), + hasArgument(0, ignoringParenCasts(StringViewArg))))) + .bind("ByAnyChar")); // Find uses of absl::StrSplit(..., "x") and absl::StrSplit(..., // absl::ByAnyChar("x")) to transform them into absl::StrSplit(..., 'x'). @@ -110,6 +117,7 @@ llvm::Optional Replacement = makeCharacterLiteral(Literal); if (!Replacement) return; + SourceRange Range = Literal->getSourceRange(); if (const auto *ByAnyChar = Result.Nodes.getNodeAs("ByAnyChar")) diff --git a/clang-tools-extra/clang-tidy/abseil/TimeSubtractionCheck.cpp b/clang-tools-extra/clang-tidy/abseil/TimeSubtractionCheck.cpp --- a/clang-tools-extra/clang-tidy/abseil/TimeSubtractionCheck.cpp +++ b/clang-tools-extra/clang-tidy/abseil/TimeSubtractionCheck.cpp @@ -10,6 +10,7 @@ #include "DurationRewriter.h" #include "clang/AST/ASTContext.h" #include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" #include "clang/Tooling/FixIt.h" using namespace clang::ast_matchers; @@ -29,33 +30,24 @@ static bool isConstructorAssignment(const MatchFinder::MatchResult &Result, const Expr *Node) { - return selectFirst( - "e", match(expr(hasParent(materializeTemporaryExpr(hasParent( - cxxConstructExpr(hasParent(exprWithCleanups( - hasParent(varDecl())))))))) - .bind("e"), - *Node, *Result.Context)) != nullptr; + return selectFirst("e", + match(expr(hasAncestor(varDecl())).bind("e"), + *Node, *Result.Context)) != nullptr; } static bool isArgument(const MatchFinder::MatchResult &Result, const Expr *Node) { return selectFirst( - "e", - match(expr(hasParent( - materializeTemporaryExpr(hasParent(cxxConstructExpr( - hasParent(callExpr()), - unless(hasParent(cxxOperatorCallExpr()))))))) - .bind("e"), - *Node, *Result.Context)) != nullptr; + "e", match(expr(hasAncestor(callExpr()), + unless(hasAncestor(cxxOperatorCallExpr()))) + .bind("e"), + *Node, *Result.Context)) != nullptr; } static bool isReturn(const MatchFinder::MatchResult &Result, const Expr *Node) { return selectFirst( - "e", match(expr(hasParent(materializeTemporaryExpr(hasParent( - cxxConstructExpr(hasParent(exprWithCleanups( - hasParent(returnStmt())))))))) - .bind("e"), - *Node, *Result.Context)) != nullptr; + "e", match(expr(hasAncestor(returnStmt())).bind("e"), *Node, + *Result.Context)) != nullptr; } static bool parensRequired(const MatchFinder::MatchResult &Result, @@ -106,7 +98,6 @@ Finder->addMatcher(OperandMatcher, this); } } - void TimeSubtractionCheck::check(const MatchFinder::MatchResult &Result) { const auto *BinOp = Result.Nodes.getNodeAs("binop"); std::string InverseName = diff --git a/clang-tools-extra/clang-tidy/abseil/UpgradeDurationConversionsCheck.h b/clang-tools-extra/clang-tidy/abseil/UpgradeDurationConversionsCheck.h --- a/clang-tools-extra/clang-tidy/abseil/UpgradeDurationConversionsCheck.h +++ b/clang-tools-extra/clang-tidy/abseil/UpgradeDurationConversionsCheck.h @@ -17,7 +17,8 @@ namespace tidy { namespace abseil { -/// Finds deprecated uses of `absl::Duration` arithmetic operators and factories. +/// Finds deprecated uses of `absl::Duration` arithmetic operators and +/// factories. /// /// For the user-facing documentation see: /// http://clang.llvm.org/extra/clang-tidy/checks/abseil-upgrade-duration-conversions.html diff --git a/clang-tools-extra/clang-tidy/abseil/UpgradeDurationConversionsCheck.cpp b/clang-tools-extra/clang-tidy/abseil/UpgradeDurationConversionsCheck.cpp --- a/clang-tools-extra/clang-tidy/abseil/UpgradeDurationConversionsCheck.cpp +++ b/clang-tools-extra/clang-tidy/abseil/UpgradeDurationConversionsCheck.cpp @@ -10,6 +10,8 @@ #include "DurationRewriter.h" #include "clang/AST/ASTContext.h" #include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" +#include "clang/Basic/Specifiers.h" using namespace clang::ast_matchers; @@ -34,13 +36,15 @@ Finder->addMatcher( cxxOperatorCallExpr( argumentCountIs(2), - hasArgument( - 0, expr(hasType(cxxRecordDecl(hasName("::absl::Duration"))))), + hasArgument(0, + expr(hasType(cxxRecordDecl(hasName("::absl::Duration")))) + .bind("arg0")), hasArgument(1, expr().bind("arg")), callee(functionDecl( hasParent(functionTemplateDecl()), unless(hasTemplateArgument(0, refersToType(builtinType()))), - hasAnyName("operator*=", "operator/=")))), + hasAnyName("operator*=", "operator/=")))) + .bind("operator"), this); // Match expressions like `a.operator*=(b)` and `a.operator/=(b)` where `a` @@ -52,7 +56,8 @@ hasParent(functionTemplateDecl()), unless(hasTemplateArgument(0, refersToType(builtinType()))), hasAnyName("operator*=", "operator/="))), - argumentCountIs(1), hasArgument(0, expr().bind("arg"))), + argumentCountIs(1), hasArgument(0, expr().bind("arg"))) + .bind("operator"), this); // Match expressions like `a * b`, `a / b`, `operator*(a, b)`, and @@ -66,7 +71,8 @@ argumentCountIs(2), hasArgument(0, expr(hasType( cxxRecordDecl(hasName("::absl::Duration"))))), - hasArgument(1, expr().bind("arg"))), + hasArgument(1, expr().bind("arg"))) + .bind("operator"), this); // Match expressions like `a * b` and `operator*(a, b)` where `a` is not of a @@ -77,8 +83,9 @@ unless(hasTemplateArgument(0, refersToType(builtinType()))), hasName("::absl::operator*"))), argumentCountIs(2), hasArgument(0, expr().bind("arg")), - hasArgument(1, expr(hasType(cxxRecordDecl( - hasName("::absl::Duration")))))), + hasArgument(1, expr(hasType( + cxxRecordDecl(hasName("::absl::Duration")))))) + .bind("operator"), this); // For the factory functions, we match only the non-templated overloads that @@ -103,8 +110,9 @@ has(implicitCastExpr(hasCastKind(CK_UserDefinedConversion)))), hasParent(callExpr( callee(functionDecl(DurationFactoryFunction(), - unless(hasParent(functionTemplateDecl())))), - hasArgument(0, expr().bind("arg"))))), + unless(hasParent(functionTemplateDecl())))), + hasArgument(0, expr().bind("arg"))))) + .bind("operator"), this); } @@ -115,9 +123,12 @@ "explicit cast instead"; const auto *ArgExpr = Result.Nodes.getNodeAs("arg"); - SourceLocation Loc = ArgExpr->getBeginLoc(); - if (!match(isInTemplateInstantiation(), *ArgExpr, *Result.Context).empty()) { + const auto *OperatorExpr = Result.Nodes.getNodeAs("operator"); + + SourceLocation Loc = ArgExpr->getBeginLoc(); + if (!match(isInTemplateInstantiation(), *OperatorExpr, *Result.Context) + .empty()) { if (MatchedTemplateLocations.count(Loc.getRawEncoding()) == 0) { // For each location matched in a template instantiation, we check if the // location can also be found in `MatchedTemplateLocations`. If it is not @@ -126,6 +137,7 @@ // probably required so we provide only a warning. diag(Loc, Message); } + return; } diff --git a/clang-tools-extra/test/clang-tidy/abseil-duration-unnecessary-conversion.cpp b/clang-tools-extra/test/clang-tidy/abseil-duration-unnecessary-conversion.cpp --- a/clang-tools-extra/test/clang-tidy/abseil-duration-unnecessary-conversion.cpp +++ b/clang-tools-extra/test/clang-tidy/abseil-duration-unnecessary-conversion.cpp @@ -1,5 +1,4 @@ -// RUN: %check_clang_tidy -std=c++11,c++14 %s abseil-duration-unnecessary-conversion %t -- -- -I %S/Inputs -// FIXME: Fix the checker to work in C++17 mode. +// RUN: %check_clang_tidy -std=c++11,c++14,c++17 %s abseil-duration-unnecessary-conversion %t -- -- -I %S/Inputs #include "absl/time/time.h" diff --git a/clang-tools-extra/test/clang-tidy/abseil-faster-strsplit-delimiter.cpp b/clang-tools-extra/test/clang-tidy/abseil-faster-strsplit-delimiter.cpp --- a/clang-tools-extra/test/clang-tidy/abseil-faster-strsplit-delimiter.cpp +++ b/clang-tools-extra/test/clang-tidy/abseil-faster-strsplit-delimiter.cpp @@ -1,5 +1,4 @@ -// RUN: %check_clang_tidy -std=c++11,c++14 %s abseil-faster-strsplit-delimiter %t -// FIXME: Fix the checker to work in C++17 mode. +// RUN: %check_clang_tidy -std=c++11,c++14,c++17 %s abseil-faster-strsplit-delimiter %t namespace absl { diff --git a/clang-tools-extra/test/clang-tidy/abseil-time-subtraction.cpp b/clang-tools-extra/test/clang-tidy/abseil-time-subtraction.cpp --- a/clang-tools-extra/test/clang-tidy/abseil-time-subtraction.cpp +++ b/clang-tools-extra/test/clang-tidy/abseil-time-subtraction.cpp @@ -1,5 +1,4 @@ -// RUN: %check_clang_tidy -std=c++11,c++14 %s abseil-time-subtraction %t -- -- -I %S/Inputs -// FIXME: Fix the checker to work in C++17 mode. +// RUN: %check_clang_tidy -std=c++11,c++14,c++17 %s abseil-time-subtraction %t -- -- -I %S/Inputs #include "absl/time/time.h" diff --git a/clang-tools-extra/test/clang-tidy/abseil-upgrade-duration-conversions.cpp b/clang-tools-extra/test/clang-tidy/abseil-upgrade-duration-conversions.cpp --- a/clang-tools-extra/test/clang-tidy/abseil-upgrade-duration-conversions.cpp +++ b/clang-tools-extra/test/clang-tidy/abseil-upgrade-duration-conversions.cpp @@ -1,5 +1,4 @@ -// RUN: %check_clang_tidy -std=c++11,c++14 %s abseil-upgrade-duration-conversions %t -- -- -I%S/Inputs -// FIXME: Fix the checker to work in C++17 mode. +// RUN: %check_clang_tidy -std=c++11,c++14,c++17 %s abseil-upgrade-duration-conversions %t -- -- -I%S/Inputs using int64_t = long long;