summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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/DurationDivisionCheck.cpp59
-rw-r--r--clang-tools-extra/clang-tidy/abseil/DurationDivisionCheck.h35
-rw-r--r--clang-tools-extra/docs/ReleaseNotes.rst7
-rw-r--r--clang-tools-extra/docs/clang-tidy/checks/list.rst1
-rw-r--r--clang-tools-extra/test/clang-tidy/abseil-duration-division.cpp75
7 files changed, 181 insertions, 0 deletions
diff --git a/clang-tools-extra/clang-tidy/abseil/AbseilTidyModule.cpp b/clang-tools-extra/clang-tidy/abseil/AbseilTidyModule.cpp
index 8e427f05873..061fc7c4d13 100644
--- a/clang-tools-extra/clang-tidy/abseil/AbseilTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/abseil/AbseilTidyModule.cpp
@@ -10,6 +10,7 @@
#include "../ClangTidy.h"
#include "../ClangTidyModule.h"
#include "../ClangTidyModuleRegistry.h"
+#include "DurationDivisionCheck.h"
#include "StringFindStartswithCheck.h"
namespace clang {
@@ -19,6 +20,8 @@ namespace abseil {
class AbseilModule : public ClangTidyModule {
public:
void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override {
+ CheckFactories.registerCheck<DurationDivisionCheck>(
+ "abseil-duration-division");
CheckFactories.registerCheck<StringFindStartswithCheck>(
"abseil-string-find-startswith");
}
diff --git a/clang-tools-extra/clang-tidy/abseil/CMakeLists.txt b/clang-tools-extra/clang-tidy/abseil/CMakeLists.txt
index dd59dcf0c20..a2478fd428e 100644
--- a/clang-tools-extra/clang-tidy/abseil/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/abseil/CMakeLists.txt
@@ -2,6 +2,7 @@ set(LLVM_LINK_COMPONENTS support)
add_clang_library(clangTidyAbseilModule
AbseilTidyModule.cpp
+ DurationDivisionCheck.cpp
StringFindStartswithCheck.cpp
LINK_LIBS
diff --git a/clang-tools-extra/clang-tidy/abseil/DurationDivisionCheck.cpp b/clang-tools-extra/clang-tidy/abseil/DurationDivisionCheck.cpp
new file mode 100644
index 00000000000..5edc15875eb
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/abseil/DurationDivisionCheck.cpp
@@ -0,0 +1,59 @@
+//===--- DurationDivisionCheck.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 "DurationDivisionCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+namespace clang {
+namespace tidy {
+namespace abseil {
+
+using namespace clang::ast_matchers;
+
+void DurationDivisionCheck::registerMatchers(MatchFinder *finder) {
+ if (!getLangOpts().CPlusPlus)
+ return;
+
+ const auto DurationExpr =
+ expr(hasType(cxxRecordDecl(hasName("::absl::Duration"))));
+ finder->addMatcher(
+ implicitCastExpr(
+ hasSourceExpression(ignoringParenCasts(
+ cxxOperatorCallExpr(hasOverloadedOperatorName("/"),
+ hasArgument(0, DurationExpr),
+ hasArgument(1, DurationExpr))
+ .bind("OpCall"))),
+ hasImplicitDestinationType(qualType(unless(isInteger()))),
+ unless(hasParent(cxxStaticCastExpr())),
+ unless(hasParent(cStyleCastExpr())),
+ unless(isInTemplateInstantiation())),
+ this);
+}
+
+void DurationDivisionCheck::check(const MatchFinder::MatchResult &result) {
+ const auto *OpCall = result.Nodes.getNodeAs<CXXOperatorCallExpr>("OpCall");
+ diag(OpCall->getOperatorLoc(),
+ "operator/ on absl::Duration objects performs integer division; "
+ "did you mean to use FDivDuration()?")
+ << FixItHint::CreateInsertion(OpCall->getBeginLoc(),
+ "absl::FDivDuration(")
+ << FixItHint::CreateReplacement(
+ SourceRange(OpCall->getOperatorLoc(), OpCall->getOperatorLoc()),
+ ", ")
+ << FixItHint::CreateInsertion(
+ Lexer::getLocForEndOfToken(
+ result.SourceManager->getSpellingLoc(OpCall->getEndLoc()), 0,
+ *result.SourceManager, result.Context->getLangOpts()),
+ ")");
+}
+
+} // namespace abseil
+} // namespace tidy
+} // namespace clang
diff --git a/clang-tools-extra/clang-tidy/abseil/DurationDivisionCheck.h b/clang-tools-extra/clang-tidy/abseil/DurationDivisionCheck.h
new file mode 100644
index 00000000000..932d0296636
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/abseil/DurationDivisionCheck.h
@@ -0,0 +1,35 @@
+//===--- DurationDivisionCheck.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_DURATIONDIVISIONCHECK_H_
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ABSEIL_DURATIONDIVISIONCHECK_H_
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace abseil {
+
+// Find potential incorrect uses of integer division of absl::Duration objects.
+//
+// For the user-facing documentation see:
+// http://clang.llvm.org/extra/clang-tidy/checks/abseil-duration-division.html
+
+class DurationDivisionCheck : public ClangTidyCheck {
+public:
+ using ClangTidyCheck::ClangTidyCheck;
+ void registerMatchers(ast_matchers::MatchFinder *finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &result) override;
+};
+
+} // namespace abseil
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ABSEIL_DURATIONDIVISIONCHECK_H_
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 83d5e017cae..cea98b334e3 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -57,6 +57,13 @@ The improvements are...
Improvements to clang-tidy
--------------------------
+- New :doc:`abseil-duration-division
+ <clang-tidy/checks/abseil-duration-division>` check.
+
+ Checks for uses of ``absl::Duration`` division that is done in a
+ floating-point context, and recommends the use of a function that
+ returns a floating-point value.
+
- New :doc:`readability-magic-numbers
<clang-tidy/checks/readability-magic-numbers>` check.
diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst
index 25515670c42..696905b50d2 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/list.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst
@@ -4,6 +4,7 @@ Clang-Tidy Checks
=================
.. toctree::
+ abseil-duration-division
abseil-string-find-startswith
android-cloexec-accept
android-cloexec-accept4
diff --git a/clang-tools-extra/test/clang-tidy/abseil-duration-division.cpp b/clang-tools-extra/test/clang-tidy/abseil-duration-division.cpp
new file mode 100644
index 00000000000..51d012f1538
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/abseil-duration-division.cpp
@@ -0,0 +1,75 @@
+// RUN: %check_clang_tidy %s abseil-duration-division %t
+
+namespace absl {
+
+class Duration {};
+
+int operator/(Duration lhs, Duration rhs);
+
+double FDivDuration(Duration num, Duration den);
+
+} // namespace absl
+
+void TakesDouble(double);
+
+#define MACRO_EQ(x, y) (x == y)
+#define MACRO_DIVEQ(x,y,z) (x/y == z)
+#define CHECK(x) (x)
+
+void Positives() {
+ absl::Duration d;
+
+ const double num_double = d/d;
+ // CHECK-MESSAGES: [[@LINE-1]]:30: warning: operator/ on absl::Duration objects performs integer division; did you mean to use FDivDuration()? [abseil-duration-division]
+ // CHECK-FIXES: const double num_double = absl::FDivDuration(d, d);
+ const float num_float = d/d;
+ // CHECK-MESSAGES: [[@LINE-1]]:28: warning: operator/ on absl::Duration objects
+ // CHECK-FIXES: const float num_float = absl::FDivDuration(d, d);
+ const auto SomeVal = 1.0 + d/d;
+ // CHECK-MESSAGES: [[@LINE-1]]:31: warning: operator/ on absl::Duration objects
+ // CHECK-FIXES: const auto SomeVal = 1.0 + absl::FDivDuration(d, d);
+ if (MACRO_EQ(d/d, 0.0)) {}
+ // CHECK-MESSAGES: [[@LINE-1]]:17: warning: operator/ on absl::Duration objects
+ // CHECK-FIXES: if (MACRO_EQ(absl::FDivDuration(d, d), 0.0)) {}
+ if (CHECK(MACRO_EQ(d/d, 0.0))) {}
+ // CHECK-MESSAGES: [[@LINE-1]]:23: warning: operator/ on absl::Duration objects
+ // CHECK-FIXES: if (CHECK(MACRO_EQ(absl::FDivDuration(d, d), 0.0))) {}
+
+ // This one generates a message, but no fix.
+ if (MACRO_DIVEQ(d, d, 0.0)) {}
+ // CHECK-MESSAGES: [[@LINE-1]]:7: warning: operator/ on absl::Duration objects
+ // CHECK-FIXES: if (MACRO_DIVEQ(d, d, 0.0)) {}
+
+ TakesDouble(d/d);
+ // CHECK-MESSAGES: [[@LINE-1]]:16: warning: operator/ on absl::Duration objects
+ // CHECK-FIXES: TakesDouble(absl::FDivDuration(d, d));
+}
+
+void TakesInt(int);
+template <class T>
+void TakesGeneric(T);
+
+void Negatives() {
+ absl::Duration d;
+ const int num_int = d/d;
+ const long num_long = d/d;
+ const short num_short = d/d;
+ const char num_char = d/d;
+ const auto num_auto = d/d;
+ const auto SomeVal = 1 + d/d;
+
+ TakesInt(d/d);
+ TakesGeneric(d/d);
+ // Explicit cast should disable the warning.
+ const double num_cast1 = static_cast<double>(d/d);
+ const double num_cast2 = (double)(d/d);
+}
+
+template <class T>
+double DoubleDivision(T t1, T t2) {return t1/t2;}
+
+//This also won't trigger a warning
+void TemplateDivision() {
+ absl::Duration d;
+ DoubleDivision(d, d);
+}
OpenPOWER on IntegriCloud