[clang-tools-extra] r348633 - [clang-tidy]: Abseil: new check 'abseil-upgrade-duration-conversions'

Eric Fiselier via cfe-commits cfe-commits at lists.llvm.org
Fri Dec 7 12:03:03 PST 2018


Author: ericwf
Date: Fri Dec  7 12:03:03 2018
New Revision: 348633

URL: http://llvm.org/viewvc/llvm-project?rev=348633&view=rev
Log:
[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.

Added:
    clang-tools-extra/trunk/clang-tidy/abseil/UpgradeDurationConversionsCheck.cpp
    clang-tools-extra/trunk/clang-tidy/abseil/UpgradeDurationConversionsCheck.h
    clang-tools-extra/trunk/docs/clang-tidy/checks/abseil-upgrade-duration-conversions.rst
    clang-tools-extra/trunk/test/clang-tidy/abseil-upgrade-duration-conversions.cpp
Modified:
    clang-tools-extra/trunk/clang-tidy/abseil/AbseilTidyModule.cpp
    clang-tools-extra/trunk/clang-tidy/abseil/CMakeLists.txt
    clang-tools-extra/trunk/docs/ReleaseNotes.rst
    clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst

Modified: clang-tools-extra/trunk/clang-tidy/abseil/AbseilTidyModule.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/abseil/AbseilTidyModule.cpp?rev=348633&r1=348632&r2=348633&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/abseil/AbseilTidyModule.cpp (original)
+++ clang-tools-extra/trunk/clang-tidy/abseil/AbseilTidyModule.cpp Fri Dec  7 12:03:03 2018
@@ -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");
   }
 };
 

Modified: clang-tools-extra/trunk/clang-tidy/abseil/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/abseil/CMakeLists.txt?rev=348633&r1=348632&r2=348633&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/abseil/CMakeLists.txt (original)
+++ clang-tools-extra/trunk/clang-tidy/abseil/CMakeLists.txt Fri Dec  7 12:03:03 2018
@@ -13,6 +13,7 @@ add_clang_library(clangTidyAbseilModule
   RedundantStrcatCallsCheck.cpp
   StrCatAppendCheck.cpp
   StringFindStartswithCheck.cpp
+  UpgradeDurationConversionsCheck.cpp
 
   LINK_LIBS
   clangAST

Added: clang-tools-extra/trunk/clang-tidy/abseil/UpgradeDurationConversionsCheck.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/abseil/UpgradeDurationConversionsCheck.cpp?rev=348633&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/abseil/UpgradeDurationConversionsCheck.cpp (added)
+++ clang-tools-extra/trunk/clang-tidy/abseil/UpgradeDurationConversionsCheck.cpp Fri Dec  7 12:03:03 2018
@@ -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

Added: clang-tools-extra/trunk/clang-tidy/abseil/UpgradeDurationConversionsCheck.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/abseil/UpgradeDurationConversionsCheck.h?rev=348633&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/abseil/UpgradeDurationConversionsCheck.h (added)
+++ clang-tools-extra/trunk/clang-tidy/abseil/UpgradeDurationConversionsCheck.h Fri Dec  7 12:03:03 2018
@@ -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

Modified: clang-tools-extra/trunk/docs/ReleaseNotes.rst
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/docs/ReleaseNotes.rst?rev=348633&r1=348632&r2=348633&view=diff
==============================================================================
--- clang-tools-extra/trunk/docs/ReleaseNotes.rst (original)
+++ clang-tools-extra/trunk/docs/ReleaseNotes.rst Fri Dec  7 12:03:03 2018
@@ -129,6 +129,13 @@ Improvements to clang-tidy
   which means this type can't represent all values which are part of the
   iteration range.
 
+- New :doc:`abseil-upgrade-duration-conversions
+  <clang-tidy/checks/abseil-upgrade-duration-conversions>` check.
+
+  Finds calls to ``absl::Duration`` arithmetic operators and factories whose
+  argument needs an explicit cast to continue compiling after upcoming API
+  changes.
+
 - New :doc:`cppcoreguidelines-macro-usage
   <clang-tidy/checks/cppcoreguidelines-macro-usage>` check.
 

Added: clang-tools-extra/trunk/docs/clang-tidy/checks/abseil-upgrade-duration-conversions.rst
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/docs/clang-tidy/checks/abseil-upgrade-duration-conversions.rst?rev=348633&view=auto
==============================================================================
--- clang-tools-extra/trunk/docs/clang-tidy/checks/abseil-upgrade-duration-conversions.rst (added)
+++ clang-tools-extra/trunk/docs/clang-tidy/checks/abseil-upgrade-duration-conversions.rst Fri Dec  7 12:03:03 2018
@@ -0,0 +1,43 @@
+.. title:: clang-tidy - abseil-upgrade-duration-conversions
+
+abseil-upgrade-duration-conversions
+===================================
+
+Finds calls to ``absl::Duration`` arithmetic operators and factories whose
+argument needs an explicit cast to continue compiling after upcoming API
+changes.
+
+The operators ``*=``, ``/=``, ``*``, and ``/`` for ``absl::Duration`` currently
+accept an argument of class type that is convertible to an arithmetic type. Such
+a call currently converts the value to an ``int64_t``, even in a case such as
+``std::atomic<float>`` that would result in lossy conversion.
+
+Additionally, the ``absl::Duration`` factory functions (``absl::Hours``,
+``absl::Minutes``, etc) currently accept an ``int64_t`` or a floating-point
+type. Similar to the arithmetic operators, calls with an argument of class type
+that is convertible to an arithmetic type go through the ``int64_t`` path.
+
+These operators and factories will be changed to only accept arithmetic types to
+prevent unintended behavior. After these changes are released, passing an
+argument of class type will no longer compile, even if the type is implicitly
+convertible to an arithmetic type.
+
+Here are example fixes created by this check:
+
+.. code-block:: c++
+
+  std::atomic<int> a;
+  absl::Duration d = absl::Milliseconds(a);
+  d *= a;
+
+becomes
+
+.. code-block:: c++
+
+  std::atomic<int> a;
+  absl::Duration d = absl::Milliseconds(static_cast<int64_t>(a));
+  d *= static_cast<int64_t>(a);
+
+Note that this check always adds a cast to ``int64_t`` in order to preserve the
+current behavior of user code. It is possible that this uncovers unintended
+behavior due to types implicitly convertible to a floating-point type.

Modified: clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst?rev=348633&r1=348632&r2=348633&view=diff
==============================================================================
--- clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst (original)
+++ clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst Fri Dec  7 12:03:03 2018
@@ -14,6 +14,7 @@ Clang-Tidy Checks
    abseil-redundant-strcat-calls
    abseil-string-find-startswith
    abseil-str-cat-append
+   abseil-upgrade-duration-conversions
    android-cloexec-accept
    android-cloexec-accept4
    android-cloexec-creat

Added: clang-tools-extra/trunk/test/clang-tidy/abseil-upgrade-duration-conversions.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/abseil-upgrade-duration-conversions.cpp?rev=348633&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/abseil-upgrade-duration-conversions.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/abseil-upgrade-duration-conversions.cpp Fri Dec  7 12:03:03 2018
@@ -0,0 +1,473 @@
+// RUN: %check_clang_tidy %s abseil-upgrade-duration-conversions %t
+
+using int64_t = long long;
+
+// Partial implementation of relevant APIs from
+// https://github.com/abseil/abseil-cpp/blob/master/absl/time/time.h
+namespace absl {
+
+class Duration {
+public:
+  Duration &operator*=(int64_t r);
+  Duration &operator*=(float r);
+  Duration &operator*=(double r);
+  template <typename T> Duration &operator*=(T r);
+
+  Duration &operator/=(int64_t r);
+  Duration &operator/=(float r);
+  Duration &operator/=(double r);
+  template <typename T> Duration &operator/=(T r);
+};
+
+template <typename T> Duration operator*(Duration lhs, T rhs);
+template <typename T> Duration operator*(T lhs, Duration rhs);
+template <typename T> Duration operator/(Duration lhs, T rhs);
+
+constexpr Duration Nanoseconds(int64_t n);
+constexpr Duration Microseconds(int64_t n);
+constexpr Duration Milliseconds(int64_t n);
+constexpr Duration Seconds(int64_t n);
+constexpr Duration Minutes(int64_t n);
+constexpr Duration Hours(int64_t n);
+
+template <typename T> struct EnableIfFloatImpl {};
+template <> struct EnableIfFloatImpl<float> { typedef int Type; };
+template <> struct EnableIfFloatImpl<double> { typedef int Type; };
+template <> struct EnableIfFloatImpl<long double> { typedef int Type; };
+template <typename T> using EnableIfFloat = typename EnableIfFloatImpl<T>::Type;
+
+template <typename T, EnableIfFloat<T> = 0> Duration Nanoseconds(T n);
+template <typename T, EnableIfFloat<T> = 0> Duration Microseconds(T n);
+template <typename T, EnableIfFloat<T> = 0> Duration Milliseconds(T n);
+template <typename T, EnableIfFloat<T> = 0> Duration Seconds(T n);
+template <typename T, EnableIfFloat<T> = 0> Duration Minutes(T n);
+template <typename T, EnableIfFloat<T> = 0> Duration Hours(T n);
+
+} // namespace absl
+
+template <typename T> struct ConvertibleTo {
+  operator T() const;
+};
+
+template <typename T>
+ConvertibleTo<T> operator+(ConvertibleTo<T>, ConvertibleTo<T>);
+
+template <typename T>
+ConvertibleTo<T> operator*(ConvertibleTo<T>, ConvertibleTo<T>);
+
+void arithmeticOperatorBasicPositive() {
+  absl::Duration d;
+  d *= ConvertibleTo<int64_t>();
+  // CHECK-MESSAGES: [[@LINE-1]]:8: warning: implicit conversion to 'int64_t' is deprecated in this context; use an explicit cast instead
+  // CHECK-FIXES: d *= static_cast<int64_t>(ConvertibleTo<int64_t>());
+  d /= ConvertibleTo<int64_t>();
+  // CHECK-MESSAGES: [[@LINE-1]]:8: warning: implicit conversion to 'int64_t' is deprecated in this context; use an explicit cast instead
+  // CHECK-FIXES: d /= static_cast<int64_t>(ConvertibleTo<int64_t>());
+  d = ConvertibleTo<int64_t>() * d;
+  // CHECK-MESSAGES: [[@LINE-1]]:7: warning: implicit conversion to 'int64_t' is deprecated in this context; use an explicit cast instead
+  // CHECK-FIXES: d = static_cast<int64_t>(ConvertibleTo<int64_t>()) * d;
+  d = d * ConvertibleTo<int64_t>();
+  // CHECK-MESSAGES: [[@LINE-1]]:11: warning: implicit conversion to 'int64_t' is deprecated in this context; use an explicit cast instead
+  // CHECK-FIXES: d = d * static_cast<int64_t>(ConvertibleTo<int64_t>());
+  d = d / ConvertibleTo<int64_t>();
+  // CHECK-MESSAGES: [[@LINE-1]]:11: warning: implicit conversion to 'int64_t' is deprecated in this context; use an explicit cast instead
+  // CHECK-FIXES: d = d / static_cast<int64_t>(ConvertibleTo<int64_t>());
+  d.operator*=(ConvertibleTo<int64_t>());
+  // CHECK-MESSAGES: [[@LINE-1]]:16: warning: implicit conversion to 'int64_t' is deprecated in this context; use an explicit cast instead
+  // CHECK-FIXES: d.operator*=(static_cast<int64_t>(ConvertibleTo<int64_t>()));
+  d.operator/=(ConvertibleTo<int64_t>());
+  // CHECK-MESSAGES: [[@LINE-1]]:16: warning: implicit conversion to 'int64_t' is deprecated in this context; use an explicit cast instead
+  // CHECK-FIXES: d.operator/=(static_cast<int64_t>(ConvertibleTo<int64_t>()));
+  d = operator*(ConvertibleTo<int64_t>(), d);
+  // CHECK-MESSAGES: [[@LINE-1]]:17: warning: implicit conversion to 'int64_t' is deprecated in this context; use an explicit cast instead
+  // CHECK-FIXES: d = operator*(static_cast<int64_t>(ConvertibleTo<int64_t>()), d);
+  d = operator*(d, ConvertibleTo<int64_t>());
+  // CHECK-MESSAGES: [[@LINE-1]]:20: warning: implicit conversion to 'int64_t' is deprecated in this context; use an explicit cast instead
+  // CHECK-FIXES: d = operator*(d, static_cast<int64_t>(ConvertibleTo<int64_t>()));
+  d = operator/(d, ConvertibleTo<int64_t>());
+  // CHECK-MESSAGES: [[@LINE-1]]:20: warning: implicit conversion to 'int64_t' is deprecated in this context; use an explicit cast instead
+  // CHECK-FIXES: d = operator/(d, static_cast<int64_t>(ConvertibleTo<int64_t>()));
+  ConvertibleTo<int64_t> c;
+  d *= (c + c) * c + c;
+  // CHECK-MESSAGES: [[@LINE-1]]:8: warning: implicit conversion to 'int64_t' is deprecated in this context; use an explicit cast instead
+  // CHECK-FIXES: d *= static_cast<int64_t>((c + c) * c + c)
+  d /= (c + c) * c + c;
+  // CHECK-MESSAGES: [[@LINE-1]]:8: warning: implicit conversion to 'int64_t' is deprecated in this context; use an explicit cast instead
+  // CHECK-FIXES: d /= static_cast<int64_t>((c + c) * c + c)
+  d = d * c * c;
+  // CHECK-MESSAGES: [[@LINE-1]]:11: warning: implicit conversion to 'int64_t' is deprecated in this context; use an explicit cast instead
+  // CHECK-MESSAGES: [[@LINE-2]]:15: warning: implicit conversion to 'int64_t' is deprecated in this context; use an explicit cast instead
+  // CHECK-FIXES: d = d * static_cast<int64_t>(c) * static_cast<int64_t>(c)
+  d = c * d * c;
+  // CHECK-MESSAGES: [[@LINE-1]]:7: warning: implicit conversion to 'int64_t' is deprecated in this context; use an explicit cast instead
+  // CHECK-MESSAGES: [[@LINE-2]]:15: warning: implicit conversion to 'int64_t' is deprecated in this context; use an explicit cast instead
+  // CHECK-FIXES: d = static_cast<int64_t>(c) * d * static_cast<int64_t>(c)
+  d = d / c * c;
+  // CHECK-MESSAGES: [[@LINE-1]]:11: warning: implicit conversion to 'int64_t' is deprecated in this context; use an explicit cast instead
+  // CHECK-MESSAGES: [[@LINE-2]]:15: warning: implicit conversion to 'int64_t' is deprecated in this context; use an explicit cast instead
+  // CHECK-FIXES: d = d / static_cast<int64_t>(c) * static_cast<int64_t>(c)
+}
+
+void arithmeticOperatorBasicNegative() {
+  absl::Duration d;
+  d *= char{1};
+  d *= 1;
+  d *= int64_t{1};
+  d *= 1.0f;
+  d *= 1.0;
+  d *= 1.0l;
+  d /= char{1};
+  d /= 1;
+  d /= int64_t{1};
+  d /= 1.0f;
+  d /= 1.0;
+  d /= 1.0l;
+  d = d * char{1};
+  d = d * 1;
+  d = d * int64_t{1};
+  d = d * 1.0f;
+  d = d * 1.0;
+  d = d * 1.0l;
+  d = char{1} * d;
+  d = 1 * d;
+  d = int64_t{1} * d;
+  d = 1.0f * d;
+  d = 1.0 * d;
+  d = 1.0l * d;
+  d = d / char{1};
+  d = d / 1;
+  d = d / int64_t{1};
+  d = d / 1.0f;
+  d = d / 1.0;
+  d = d / 1.0l;
+
+  d *= static_cast<int>(ConvertibleTo<int>());
+  d *= (int)ConvertibleTo<int>();
+  d *= int(ConvertibleTo<int>());
+  d /= static_cast<int>(ConvertibleTo<int>());
+  d /= (int)ConvertibleTo<int>();
+  d /= int(ConvertibleTo<int>());
+  d = static_cast<int>(ConvertibleTo<int>()) * d;
+  d = (int)ConvertibleTo<int>() * d;
+  d = int(ConvertibleTo<int>()) * d;
+  d = d * static_cast<int>(ConvertibleTo<int>());
+  d = d * (int)ConvertibleTo<int>();
+  d = d * int(ConvertibleTo<int>());
+  d = d / static_cast<int>(ConvertibleTo<int>());
+  d = d / (int)ConvertibleTo<int>();
+  d = d / int(ConvertibleTo<int>());
+
+  d *= 1 + ConvertibleTo<int>();
+  d /= 1 + ConvertibleTo<int>();
+  d = (1 + ConvertibleTo<int>()) * d;
+  d = d * (1 + ConvertibleTo<int>());
+  d = d / (1 + ConvertibleTo<int>());
+}
+
+template <typename T> void templateForOpsSpecialization(T) {}
+template <>
+void templateForOpsSpecialization<absl::Duration>(absl::Duration d) {
+  d *= ConvertibleTo<int64_t>();
+  // CHECK-MESSAGES: [[@LINE-1]]:8: warning: implicit conversion to 'int64_t' is deprecated in this context; use an explicit cast instead
+  // CHECK-FIXES: d *= static_cast<int64_t>(ConvertibleTo<int64_t>());
+}
+
+template <int N> void arithmeticNonTypeTemplateParamSpecialization() {
+  absl::Duration d;
+  d *= N;
+}
+
+template <> void arithmeticNonTypeTemplateParamSpecialization<5>() {
+  absl::Duration d;
+  d *= ConvertibleTo<int>();
+  // CHECK-MESSAGES: [[@LINE-1]]:8: warning: implicit conversion to 'int64_t' is deprecated in this context; use an explicit cast instead
+  // CHECK-FIXES: d *= static_cast<int64_t>(ConvertibleTo<int>());
+}
+
+template <typename T> void templateOpsFix() {
+  absl::Duration d;
+  d *= ConvertibleTo<int64_t>();
+  // CHECK-MESSAGES: [[@LINE-1]]:8: warning: implicit conversion to 'int64_t' is deprecated in this context; use an explicit cast instead
+  // CHECK-FIXES: d *= static_cast<int64_t>(ConvertibleTo<int64_t>());
+}
+
+template <typename T, typename U> void templateOpsWarnOnly(T t, U u) {
+  t *= u;
+  // CHECK-MESSAGES: [[@LINE-1]]:8: warning: implicit conversion to 'int64_t' is deprecated in this context; use an explicit cast instead
+  absl::Duration d;
+  d *= u;
+  // CHECK-MESSAGES: [[@LINE-1]]:8: warning: implicit conversion to 'int64_t' is deprecated in this context; use an explicit cast instead
+}
+
+template <typename T> struct TemplateTypeOpsWarnOnly {
+  void memberA(T t) {
+    d *= t;
+    // CHECK-MESSAGES: [[@LINE-1]]:10: warning: implicit conversion to 'int64_t' is deprecated in this context; use an explicit cast instead
+  }
+  template <typename U, typename V> void memberB(U u, V v) {
+    u *= v;
+    // CHECK-MESSAGES: [[@LINE-1]]:10: warning: implicit conversion to 'int64_t' is deprecated in this context; use an explicit cast instead
+    d *= v;
+    // CHECK-MESSAGES: [[@LINE-1]]:10: warning: implicit conversion to 'int64_t' is deprecated in this context; use an explicit cast instead
+  }
+
+  absl::Duration d;
+};
+
+template <typename T, typename U>
+void templateOpsInstantiationBeforeDefinition(T t, U u);
+
+void arithmeticOperatorsInTemplates() {
+  templateForOpsSpecialization(5);
+  templateForOpsSpecialization(absl::Duration());
+  arithmeticNonTypeTemplateParamSpecialization<1>();
+  arithmeticNonTypeTemplateParamSpecialization<5>();
+  templateOpsFix<int>();
+  templateOpsWarnOnly(absl::Duration(), ConvertibleTo<int>());
+  templateOpsInstantiationBeforeDefinition(absl::Duration(),
+                                           ConvertibleTo<int>());
+  TemplateTypeOpsWarnOnly<ConvertibleTo<int>> t;
+  t.memberA(ConvertibleTo<int>());
+  t.memberB(absl::Duration(), ConvertibleTo<int>());
+}
+
+template <typename T, typename U>
+void templateOpsInstantiationBeforeDefinition(T t, U u) {
+  t *= u;
+  // CHECK-MESSAGES: [[@LINE-1]]:8: warning: implicit conversion to 'int64_t' is deprecated in this context; use an explicit cast instead
+  absl::Duration d;
+  d *= u;
+  // CHECK-MESSAGES: [[@LINE-1]]:8: warning: implicit conversion to 'int64_t' is deprecated in this context; use an explicit cast instead
+}
+
+#define FUNCTION_MACRO(x) x
+#define CONVERTIBLE_TMP ConvertibleTo<int>()
+#define ONLY_WARN_INSIDE_MACRO_ARITHMETIC_OP d *= ConvertibleTo<int>()
+
+#define T_OBJECT T()
+#define T_CALL_EXPR d *= T()
+
+template <typename T> void arithmeticTemplateAndMacro() {
+  absl::Duration d;
+  d *= T_OBJECT;
+  // CHECK-MESSAGES: [[@LINE-1]]:8: warning: implicit conversion to 'int64_t' is deprecated in this context; use an explicit cast instead
+  d *= CONVERTIBLE_TMP;
+  // CHECK-MESSAGES: [[@LINE-1]]:8: warning: implicit conversion to 'int64_t' is deprecated in this context; use an explicit cast instead
+  // CHECK-FIXES: d *= static_cast<int64_t>(CONVERTIBLE_TMP);
+  T_CALL_EXPR;
+  // CHECK-MESSAGES: [[@LINE-1]]:3: warning: implicit conversion to 'int64_t' is deprecated in this context; use an explicit cast instead
+}
+
+#define TEMPLATE_MACRO(type)                                                   \
+  template <typename T> void TemplateInMacro(T t) {                            \
+    type d;                                                                    \
+    d *= t;                                                                    \
+  }
+
+TEMPLATE_MACRO(absl::Duration)
+// CHECK-MESSAGES: [[@LINE-1]]:1: warning: implicit conversion to 'int64_t' is deprecated in this context; use an explicit cast instead
+
+void arithmeticOperatorsInMacros() {
+  absl::Duration d;
+  d = FUNCTION_MACRO(d * ConvertibleTo<int>());
+  // CHECK-MESSAGES: [[@LINE-1]]:26: warning: implicit conversion to 'int64_t' is deprecated in this context; use an explicit cast instead
+  // CHECK-FIXES: d = FUNCTION_MACRO(d * static_cast<int64_t>(ConvertibleTo<int>()));
+  d *= FUNCTION_MACRO(ConvertibleTo<int>());
+  // CHECK-MESSAGES: [[@LINE-1]]:23: warning: implicit conversion to 'int64_t' is deprecated in this context; use an explicit cast instead
+  // CHECK-FIXES: d *= static_cast<int64_t>(FUNCTION_MACRO(ConvertibleTo<int>()));
+  d *= CONVERTIBLE_TMP;
+  // CHECK-MESSAGES: [[@LINE-1]]:8: warning: implicit conversion to 'int64_t' is deprecated in this context; use an explicit cast instead
+  // CHECK-FIXES: d *= static_cast<int64_t>(CONVERTIBLE_TMP);
+  ONLY_WARN_INSIDE_MACRO_ARITHMETIC_OP;
+  // CHECK-MESSAGES: [[@LINE-1]]:3: warning: implicit conversion to 'int64_t' is deprecated in this context; use an explicit cast instead
+  arithmeticTemplateAndMacro<ConvertibleTo<int>>();
+  TemplateInMacro(ConvertibleTo<int>());
+}
+
+void factoryFunctionPositive() {
+  // User defined conversion:
+  (void)absl::Nanoseconds(ConvertibleTo<int64_t>());
+  // CHECK-MESSAGES: [[@LINE-1]]:27: warning: implicit conversion to 'int64_t' is deprecated in this context; use an explicit cast instead
+  // CHECK-FIXES: (void)absl::Nanoseconds(static_cast<int64_t>(ConvertibleTo<int64_t>()));
+  (void)absl::Microseconds(ConvertibleTo<int64_t>());
+  // CHECK-MESSAGES: [[@LINE-1]]:28: warning: implicit conversion to 'int64_t' is deprecated in this context; use an explicit cast instead
+  // CHECK-FIXES: (void)absl::Microseconds(static_cast<int64_t>(ConvertibleTo<int64_t>()));
+  (void)absl::Milliseconds(ConvertibleTo<int64_t>());
+  // CHECK-MESSAGES: [[@LINE-1]]:28: warning: implicit conversion to 'int64_t' is deprecated in this context; use an explicit cast instead
+  // CHECK-FIXES: (void)absl::Milliseconds(static_cast<int64_t>(ConvertibleTo<int64_t>()));
+  (void)absl::Seconds(ConvertibleTo<int64_t>());
+  // CHECK-MESSAGES: [[@LINE-1]]:23: warning: implicit conversion to 'int64_t' is deprecated in this context; use an explicit cast instead
+  // CHECK-FIXES: (void)absl::Seconds(static_cast<int64_t>(ConvertibleTo<int64_t>()));
+  (void)absl::Minutes(ConvertibleTo<int64_t>());
+  // CHECK-MESSAGES: [[@LINE-1]]:23: warning: implicit conversion to 'int64_t' is deprecated in this context; use an explicit cast instead
+  // CHECK-FIXES: (void)absl::Minutes(static_cast<int64_t>(ConvertibleTo<int64_t>()));
+  (void)absl::Hours(ConvertibleTo<int64_t>());
+  // CHECK-MESSAGES: [[@LINE-1]]:21: warning: implicit conversion to 'int64_t' is deprecated in this context; use an explicit cast instead
+  // CHECK-FIXES: (void)absl::Hours(static_cast<int64_t>(ConvertibleTo<int64_t>()));
+
+  // User defined conversion to integral type, followed by built-in conversion:
+  (void)absl::Nanoseconds(ConvertibleTo<char>());
+  // CHECK-MESSAGES: [[@LINE-1]]:27: warning: implicit conversion to 'int64_t' is deprecated in this context; use an explicit cast instead
+  // CHECK-FIXES: (void)absl::Nanoseconds(static_cast<int64_t>(ConvertibleTo<char>()));
+  (void)absl::Microseconds(ConvertibleTo<char>());
+  // CHECK-MESSAGES: [[@LINE-1]]:28: warning: implicit conversion to 'int64_t' is deprecated in this context; use an explicit cast instead
+  // CHECK-FIXES: (void)absl::Microseconds(static_cast<int64_t>(ConvertibleTo<char>()));
+  (void)absl::Milliseconds(ConvertibleTo<char>());
+  // CHECK-MESSAGES: [[@LINE-1]]:28: warning: implicit conversion to 'int64_t' is deprecated in this context; use an explicit cast instead
+  // CHECK-FIXES: (void)absl::Milliseconds(static_cast<int64_t>(ConvertibleTo<char>()));
+  (void)absl::Seconds(ConvertibleTo<char>());
+  // CHECK-MESSAGES: [[@LINE-1]]:23: warning: implicit conversion to 'int64_t' is deprecated in this context; use an explicit cast instead
+  // CHECK-FIXES: (void)absl::Seconds(static_cast<int64_t>(ConvertibleTo<char>()));
+  (void)absl::Minutes(ConvertibleTo<char>());
+  // CHECK-MESSAGES: [[@LINE-1]]:23: warning: implicit conversion to 'int64_t' is deprecated in this context; use an explicit cast instead
+  // CHECK-FIXES: (void)absl::Minutes(static_cast<int64_t>(ConvertibleTo<char>()));
+  (void)absl::Hours(ConvertibleTo<char>());
+  // CHECK-MESSAGES: [[@LINE-1]]:21: warning: implicit conversion to 'int64_t' is deprecated in this context; use an explicit cast instead
+  // CHECK-FIXES: (void)absl::Hours(static_cast<int64_t>(ConvertibleTo<char>()));
+
+  // User defined conversion to floating point type, followed by built-in conversion:
+  (void)absl::Nanoseconds(ConvertibleTo<float>());
+  // CHECK-MESSAGES: [[@LINE-1]]:27: warning: implicit conversion to 'int64_t' is deprecated in this context; use an explicit cast instead
+  // CHECK-FIXES: (void)absl::Nanoseconds(static_cast<int64_t>(ConvertibleTo<float>()));
+  (void)absl::Microseconds(ConvertibleTo<float>());
+  // CHECK-MESSAGES: [[@LINE-1]]:28: warning: implicit conversion to 'int64_t' is deprecated in this context; use an explicit cast instead
+  // CHECK-FIXES: (void)absl::Microseconds(static_cast<int64_t>(ConvertibleTo<float>()));
+  (void)absl::Milliseconds(ConvertibleTo<float>());
+  // CHECK-MESSAGES: [[@LINE-1]]:28: warning: implicit conversion to 'int64_t' is deprecated in this context; use an explicit cast instead
+  // CHECK-FIXES: (void)absl::Milliseconds(static_cast<int64_t>(ConvertibleTo<float>()));
+  (void)absl::Seconds(ConvertibleTo<float>());
+  // CHECK-MESSAGES: [[@LINE-1]]:23: warning: implicit conversion to 'int64_t' is deprecated in this context; use an explicit cast instead
+  // CHECK-FIXES: (void)absl::Seconds(static_cast<int64_t>(ConvertibleTo<float>()));
+  (void)absl::Minutes(ConvertibleTo<float>());
+  // CHECK-MESSAGES: [[@LINE-1]]:23: warning: implicit conversion to 'int64_t' is deprecated in this context; use an explicit cast instead
+  // CHECK-FIXES: (void)absl::Minutes(static_cast<int64_t>(ConvertibleTo<float>()));
+  (void)absl::Hours(ConvertibleTo<float>());
+  // CHECK-MESSAGES: [[@LINE-1]]:21: warning: implicit conversion to 'int64_t' is deprecated in this context; use an explicit cast instead
+  // CHECK-FIXES: (void)absl::Hours(static_cast<int64_t>(ConvertibleTo<float>()));
+}
+
+void factoryFunctionNegative() {
+  (void)absl::Nanoseconds(char{1});
+  (void)absl::Nanoseconds(1);
+  (void)absl::Nanoseconds(int64_t{1});
+  (void)absl::Nanoseconds(1.0f);
+  (void)absl::Microseconds(char{1});
+  (void)absl::Microseconds(1);
+  (void)absl::Microseconds(int64_t{1});
+  (void)absl::Microseconds(1.0f);
+  (void)absl::Milliseconds(char{1});
+  (void)absl::Milliseconds(1);
+  (void)absl::Milliseconds(int64_t{1});
+  (void)absl::Milliseconds(1.0f);
+  (void)absl::Seconds(char{1});
+  (void)absl::Seconds(1);
+  (void)absl::Seconds(int64_t{1});
+  (void)absl::Seconds(1.0f);
+  (void)absl::Minutes(char{1});
+  (void)absl::Minutes(1);
+  (void)absl::Minutes(int64_t{1});
+  (void)absl::Minutes(1.0f);
+  (void)absl::Hours(char{1});
+  (void)absl::Hours(1);
+  (void)absl::Hours(int64_t{1});
+  (void)absl::Hours(1.0f);
+
+  (void)absl::Nanoseconds(static_cast<int>(ConvertibleTo<int>()));
+  (void)absl::Microseconds(static_cast<int>(ConvertibleTo<int>()));
+  (void)absl::Milliseconds(static_cast<int>(ConvertibleTo<int>()));
+  (void)absl::Seconds(static_cast<int>(ConvertibleTo<int>()));
+  (void)absl::Minutes(static_cast<int>(ConvertibleTo<int>()));
+  (void)absl::Hours(static_cast<int>(ConvertibleTo<int>()));
+}
+
+template <typename T> void templateForFactorySpecialization(T) {}
+template <> void templateForFactorySpecialization<ConvertibleTo<int>>(ConvertibleTo<int> c) {
+  (void)absl::Nanoseconds(c);
+  // CHECK-MESSAGES: [[@LINE-1]]:27: warning: implicit conversion to 'int64_t' is deprecated in this context; use an explicit cast instead
+  // CHECK-FIXES: (void)absl::Nanoseconds(static_cast<int64_t>(c));
+}
+
+template <int N> void factoryNonTypeTemplateParamSpecialization() {
+  (void)absl::Nanoseconds(N);
+}
+
+template <> void factoryNonTypeTemplateParamSpecialization<5>() {
+  (void)absl::Nanoseconds(ConvertibleTo<int>());
+  // CHECK-MESSAGES: [[@LINE-1]]:27: warning: implicit conversion to 'int64_t' is deprecated in this context; use an explicit cast instead
+  // CHECK-FIXES: (void)absl::Nanoseconds(static_cast<int64_t>(ConvertibleTo<int>()));
+}
+
+template <typename T> void templateFactoryFix() {
+  (void)absl::Nanoseconds(ConvertibleTo<int>());
+  // CHECK-MESSAGES: [[@LINE-1]]:27: warning: implicit conversion to 'int64_t' is deprecated in this context; use an explicit cast instead
+  // CHECK-FIXES: (void)absl::Nanoseconds(static_cast<int64_t>(ConvertibleTo<int>()));
+}
+
+template <typename T> void templateFactoryWarnOnly(T t) {
+  (void)absl::Nanoseconds(t);
+  // CHECK-MESSAGES: [[@LINE-1]]:27: warning: implicit conversion to 'int64_t' is deprecated in this context; use an explicit cast instead
+}
+
+template <typename T> void templateFactoryInstantiationBeforeDefinition(T t);
+
+template <typename T> struct TemplateTypeFactoryWarnOnly {
+  void memberA(T t) {
+    (void)absl::Nanoseconds(t);
+    // CHECK-MESSAGES: [[@LINE-1]]:29: warning: implicit conversion to 'int64_t' is deprecated in this context; use an explicit cast instead
+  }
+  template <typename U> void memberB(U u) {
+    (void)absl::Nanoseconds(u);
+    // CHECK-MESSAGES: [[@LINE-1]]:29: warning: implicit conversion to 'int64_t' is deprecated in this context; use an explicit cast instead
+  }
+};
+
+void factoryInTemplates() {
+  templateForFactorySpecialization(5);
+  templateForFactorySpecialization(ConvertibleTo<int>());
+  factoryNonTypeTemplateParamSpecialization<1>();
+  factoryNonTypeTemplateParamSpecialization<5>();
+  templateFactoryFix<int>();
+  templateFactoryWarnOnly(ConvertibleTo<int>());
+  templateFactoryInstantiationBeforeDefinition(ConvertibleTo<int>());
+  TemplateTypeFactoryWarnOnly<ConvertibleTo<int>> t;
+  t.memberA(ConvertibleTo<int>());
+  t.memberB(ConvertibleTo<int>());
+}
+
+template <typename T> void templateFactoryInstantiationBeforeDefinition(T t) {
+  (void)absl::Nanoseconds(t);
+  // CHECK-MESSAGES: [[@LINE-1]]:27: warning: implicit conversion to 'int64_t' is deprecated in this context; use an explicit cast instead
+}
+
+#define ONLY_WARN_INSIDE_MACRO_FACTORY                                         \
+  (void)absl::Nanoseconds(ConvertibleTo<int>())
+#define T_CALL_FACTORTY_INSIDE_MACRO (void)absl::Nanoseconds(T())
+
+template <typename T> void factoryTemplateAndMacro() {
+  (void)absl::Nanoseconds(T_OBJECT);
+  // CHECK-MESSAGES: [[@LINE-1]]:27: warning: implicit conversion to 'int64_t' is deprecated in this context; use an explicit cast instead
+  (void)absl::Nanoseconds(CONVERTIBLE_TMP);
+  // CHECK-MESSAGES: [[@LINE-1]]:27: warning: implicit conversion to 'int64_t' is deprecated in this context; use an explicit cast instead
+  // CHECK-FIXES: (void)absl::Nanoseconds(static_cast<int64_t>(CONVERTIBLE_TMP))
+  T_CALL_FACTORTY_INSIDE_MACRO;
+  // CHECK-MESSAGES: [[@LINE-1]]:3: warning: implicit conversion to 'int64_t' is deprecated in this context; use an explicit cast instead
+}
+
+#define TEMPLATE_FACTORY_MACRO(factory)                                        \
+  template <typename T> void TemplateFactoryInMacro(T t) { (void)factory(t); }
+
+TEMPLATE_FACTORY_MACRO(absl::Nanoseconds)
+// CHECK-MESSAGES: [[@LINE-1]]:1: warning: implicit conversion to 'int64_t' is deprecated in this context; use an explicit cast instead
+
+void factoryInMacros() {
+  (void)absl::Nanoseconds(FUNCTION_MACRO(ConvertibleTo<int>()));
+  // CHECK-MESSAGES: [[@LINE-1]]:42: warning: implicit conversion to 'int64_t' is deprecated in this context; use an explicit cast instead
+  // CHECK-FIXES: (void)absl::Nanoseconds(static_cast<int64_t>(FUNCTION_MACRO(ConvertibleTo<int>())));
+  (void)absl::Nanoseconds(CONVERTIBLE_TMP);
+  // CHECK-MESSAGES: [[@LINE-1]]:27: warning: implicit conversion to 'int64_t' is deprecated in this context; use an explicit cast instead
+  // CHECK-FIXES: (void)absl::Nanoseconds(static_cast<int64_t>(CONVERTIBLE_TMP))
+  ONLY_WARN_INSIDE_MACRO_FACTORY;
+  // CHECK-MESSAGES: [[@LINE-1]]:3: warning: implicit conversion to 'int64_t' is deprecated in this context; use an explicit cast instead
+  factoryTemplateAndMacro<ConvertibleTo<int>>();
+  TemplateFactoryInMacro(ConvertibleTo<int>());
+}




More information about the cfe-commits mailing list