summaryrefslogtreecommitdiffstats
path: root/clang-tools-extra/clang-tidy
diff options
context:
space:
mode:
authorEric Fiselier <eric@efcs.ca>2018-12-07 20:03:03 +0000
committerEric Fiselier <eric@efcs.ca>2018-12-07 20:03:03 +0000
commit2bbbd8be24731d485b56a5e8495b2d873eb63d4b (patch)
tree3de27468ecd601e4341b0a4de5d74be5acf0d46b /clang-tools-extra/clang-tidy
parentf7254a698b79a326dffcb8a562205139f2b33d2e (diff)
downloadbcm5719-llvm-2bbbd8be24731d485b56a5e8495b2d873eb63d4b.tar.gz
bcm5719-llvm-2bbbd8be24731d485b56a5e8495b2d873eb63d4b.zip
[clang-tidy]: Abseil: new check 'abseil-upgrade-duration-conversions'
Patch by Alex Strelnikov. Reviewed as D53830 Introduce a new check to upgrade user code based on upcoming API breaking changes to absl::Duration. The check finds calls to arithmetic operators and factory functions for absl::Duration that rely on an implicit user defined conversion to int64_t. These cases will no longer compile after proposed changes are released. Suggested fixes explicitly cast the argument int64_t. llvm-svn: 348633
Diffstat (limited to 'clang-tools-extra/clang-tidy')
-rw-r--r--clang-tools-extra/clang-tidy/abseil/AbseilTidyModule.cpp3
-rw-r--r--clang-tools-extra/clang-tidy/abseil/CMakeLists.txt1
-rw-r--r--clang-tools-extra/clang-tidy/abseil/UpgradeDurationConversionsCheck.cpp158
-rw-r--r--clang-tools-extra/clang-tidy/abseil/UpgradeDurationConversionsCheck.h40
4 files changed, 202 insertions, 0 deletions
diff --git a/clang-tools-extra/clang-tidy/abseil/AbseilTidyModule.cpp b/clang-tools-extra/clang-tidy/abseil/AbseilTidyModule.cpp
index a559ac5f8fe..23fc2cf2770 100644
--- a/clang-tools-extra/clang-tidy/abseil/AbseilTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/abseil/AbseilTidyModule.cpp
@@ -20,6 +20,7 @@
#include "RedundantStrcatCallsCheck.h"
#include "StringFindStartswithCheck.h"
#include "StrCatAppendCheck.h"
+#include "UpgradeDurationConversionsCheck.h"
namespace clang {
namespace tidy {
@@ -47,6 +48,8 @@ public:
"abseil-str-cat-append");
CheckFactories.registerCheck<StringFindStartswithCheck>(
"abseil-string-find-startswith");
+ CheckFactories.registerCheck<UpgradeDurationConversionsCheck>(
+ "abseil-upgrade-duration-conversions");
}
};
diff --git a/clang-tools-extra/clang-tidy/abseil/CMakeLists.txt b/clang-tools-extra/clang-tidy/abseil/CMakeLists.txt
index 1139f2e1797..34640318a22 100644
--- a/clang-tools-extra/clang-tidy/abseil/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/abseil/CMakeLists.txt
@@ -13,6 +13,7 @@ add_clang_library(clangTidyAbseilModule
RedundantStrcatCallsCheck.cpp
StrCatAppendCheck.cpp
StringFindStartswithCheck.cpp
+ UpgradeDurationConversionsCheck.cpp
LINK_LIBS
clangAST
diff --git a/clang-tools-extra/clang-tidy/abseil/UpgradeDurationConversionsCheck.cpp b/clang-tools-extra/clang-tidy/abseil/UpgradeDurationConversionsCheck.cpp
new file mode 100644
index 00000000000..bdf32bccc37
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/abseil/UpgradeDurationConversionsCheck.cpp
@@ -0,0 +1,158 @@
+//===--- UpgradeDurationConversionsCheck.cpp - clang-tidy -----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "UpgradeDurationConversionsCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace abseil {
+
+void UpgradeDurationConversionsCheck::registerMatchers(MatchFinder *Finder) {
+ if (!getLangOpts().CPlusPlus)
+ return;
+
+ // For the arithmetic calls, we match only the uses of the templated operators
+ // where the template parameter is not a built-in type. This means the
+ // instantiation makes use of an available user defined conversion to
+ // `int64_t`.
+ //
+ // The implementation of these templates will be updated to fail SFINAE for
+ // non-integral types. We match them to suggest an explicit cast.
+
+ // Match expressions like `a *= b` and `a /= b` where `a` has type
+ // `absl::Duration` and `b` is not of a built-in type.
+ Finder->addMatcher(
+ cxxOperatorCallExpr(
+ argumentCountIs(2),
+ hasArgument(
+ 0, expr(hasType(cxxRecordDecl(hasName("::absl::Duration"))))),
+ hasArgument(1, expr().bind("arg")),
+ callee(functionDecl(
+ hasParent(functionTemplateDecl()),
+ unless(hasTemplateArgument(0, refersToType(builtinType()))),
+ hasAnyName("operator*=", "operator/=")))),
+ this);
+
+ // Match expressions like `a.operator*=(b)` and `a.operator/=(b)` where `a`
+ // has type `absl::Duration` and `b` is not of a built-in type.
+ Finder->addMatcher(
+ cxxMemberCallExpr(
+ callee(cxxMethodDecl(
+ ofClass(cxxRecordDecl(hasName("::absl::Duration"))),
+ hasParent(functionTemplateDecl()),
+ unless(hasTemplateArgument(0, refersToType(builtinType()))),
+ hasAnyName("operator*=", "operator/="))),
+ argumentCountIs(1), hasArgument(0, expr().bind("arg"))),
+ this);
+
+ // Match expressions like `a * b`, `a / b`, `operator*(a, b)`, and
+ // `operator/(a, b)` where `a` has type `absl::Duration` and `b` is not of a
+ // built-in type.
+ Finder->addMatcher(
+ callExpr(callee(functionDecl(
+ hasParent(functionTemplateDecl()),
+ unless(hasTemplateArgument(0, refersToType(builtinType()))),
+ hasAnyName("::absl::operator*", "::absl::operator/"))),
+ argumentCountIs(2),
+ hasArgument(0, expr(hasType(
+ cxxRecordDecl(hasName("::absl::Duration"))))),
+ hasArgument(1, expr().bind("arg"))),
+ this);
+
+ // Match expressions like `a * b` and `operator*(a, b)` where `a` is not of a
+ // built-in type and `b` has type `absl::Duration`.
+ Finder->addMatcher(
+ callExpr(callee(functionDecl(
+ hasParent(functionTemplateDecl()),
+ unless(hasTemplateArgument(0, refersToType(builtinType()))),
+ hasName("::absl::operator*"))),
+ argumentCountIs(2), hasArgument(0, expr().bind("arg")),
+ hasArgument(1, expr(hasType(cxxRecordDecl(
+ hasName("::absl::Duration")))))),
+ this);
+
+ // For the factory functions, we match only the non-templated overloads that
+ // take an `int64_t` parameter. Within these calls, we care about implicit
+ // casts through a user defined conversion to `int64_t`.
+ //
+ // The factory functions will be updated to be templated and SFINAE on whether
+ // the template parameter is an integral type. This complements the already
+ // existing templated overloads that only accept floating point types.
+
+ // Match calls like:
+ // `absl::Nanoseconds(x)`
+ // `absl::Microseconds(x)`
+ // `absl::Milliseconds(x)`
+ // `absl::Seconds(x)`
+ // `absl::Minutes(x)`
+ // `absl::Hours(x)`
+ // where `x` is not of a built-in type.
+ Finder->addMatcher(
+ implicitCastExpr(
+ anyOf(hasCastKind(CK_UserDefinedConversion),
+ has(implicitCastExpr(hasCastKind(CK_UserDefinedConversion)))),
+ hasParent(callExpr(
+ callee(functionDecl(
+ hasAnyName("::absl::Nanoseconds", "::absl::Microseconds",
+ "::absl::Milliseconds", "::absl::Seconds",
+ "::absl::Minutes", "::absl::Hours"),
+ unless(hasParent(functionTemplateDecl())))),
+ hasArgument(0, expr().bind("arg"))))),
+ this);
+}
+
+void UpgradeDurationConversionsCheck::check(
+ const MatchFinder::MatchResult &Result) {
+ const llvm::StringRef Message =
+ "implicit conversion to 'int64_t' is deprecated in this context; use an "
+ "explicit cast instead";
+
+ const auto *ArgExpr = Result.Nodes.getNodeAs<Expr>("arg");
+ SourceLocation Loc = ArgExpr->getBeginLoc();
+
+ if (!match(isInTemplateInstantiation(), *ArgExpr, *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
+ // found, that means the expression did not create a match without the
+ // instantiation and depends on template parameters. A manual fix is
+ // probably required so we provide only a warning.
+ diag(Loc, Message);
+ }
+ return;
+ }
+
+ // We gather source locations from template matches not in template
+ // instantiations for future matches.
+ internal::Matcher<Stmt> IsInsideTemplate =
+ hasAncestor(decl(anyOf(classTemplateDecl(), functionTemplateDecl())));
+ if (!match(IsInsideTemplate, *ArgExpr, *Result.Context).empty())
+ MatchedTemplateLocations.insert(Loc.getRawEncoding());
+
+ DiagnosticBuilder Diag = diag(Loc, Message);
+ CharSourceRange SourceRange = Lexer::makeFileCharRange(
+ CharSourceRange::getTokenRange(ArgExpr->getSourceRange()),
+ *Result.SourceManager, Result.Context->getLangOpts());
+ if (SourceRange.isInvalid())
+ // An invalid source range likely means we are inside a macro body. A manual
+ // fix is likely needed so we do not create a fix-it hint.
+ return;
+
+ Diag << FixItHint::CreateInsertion(SourceRange.getBegin(),
+ "static_cast<int64_t>(")
+ << FixItHint::CreateInsertion(SourceRange.getEnd(), ")");
+}
+
+} // namespace abseil
+} // namespace tidy
+} // namespace clang
diff --git a/clang-tools-extra/clang-tidy/abseil/UpgradeDurationConversionsCheck.h b/clang-tools-extra/clang-tidy/abseil/UpgradeDurationConversionsCheck.h
new file mode 100644
index 00000000000..63712e2caef
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/abseil/UpgradeDurationConversionsCheck.h
@@ -0,0 +1,40 @@
+//===--- UpgradeDurationConversionsCheck.h - clang-tidy ---------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ABSEIL_UPGRADEDURATIONCONVERSIONSCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ABSEIL_UPGRADEDURATIONCONVERSIONSCHECK_H
+
+#include "../ClangTidy.h"
+
+#include <unordered_set>
+
+namespace clang {
+namespace tidy {
+namespace abseil {
+
+/// 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
+class UpgradeDurationConversionsCheck : public ClangTidyCheck {
+public:
+ UpgradeDurationConversionsCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+ std::unordered_set<unsigned> MatchedTemplateLocations;
+};
+
+} // namespace abseil
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ABSEIL_UPGRADEDURATIONCONVERSIONSCHECK_H
OpenPOWER on IntegriCloud