Prazek updated this revision to Diff 81617.
Prazek marked an inline comment as done.
Prazek added a comment.

- Small fixes


https://reviews.llvm.org/D27806

Files:
  clang-tidy/obvious/CMakeLists.txt
  clang-tidy/obvious/InvalidRangeCheck.cpp
  clang-tidy/obvious/InvalidRangeCheck.h
  clang-tidy/obvious/ObviousTidyModule.cpp
  docs/ReleaseNotes.rst
  docs/clang-tidy/checks/list.rst
  docs/clang-tidy/checks/obvious-invalid-range.rst
  test/clang-tidy/obvious-invalid-range.cpp

Index: test/clang-tidy/obvious-invalid-range.cpp
===================================================================
--- /dev/null
+++ test/clang-tidy/obvious-invalid-range.cpp
@@ -0,0 +1,47 @@
+// RUN: %check_clang_tidy %s obvious-invalid-range %t
+
+namespace std {
+
+template <class InputIterator, class OutputIterator>
+OutputIterator copy(InputIterator first, InputIterator last, OutputIterator result) {
+  return result;
+}
+
+template <class InputIterator, class OutputIterator>
+OutputIterator move(InputIterator first, InputIterator last, OutputIterator result) {
+  return result;
+}
+
+template <typename T>
+T move(T &&) { return T(); }
+
+template <class InputIterator, typename Val>
+void fill(InputIterator first, InputIterator last, const Val &v) {
+}
+
+template <typename T>
+class vector {
+public:
+  T *begin();
+  T *end();
+};
+}
+
+void test_copy() {
+  std::vector<int> v, v2;
+  std::copy(v.begin(), v2.end(), v2.begin());
+  // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: call to algorithm with begin and end from different objects [obvious-invalid-range]
+
+  std::copy(v.begin(), v.end(), v2.begin());
+}
+
+void test_move() {
+  std::vector<int> v;
+  auto &v2 = v;
+  std::move(v.begin(), v2.end(), v2.begin());
+  // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: call to algorithm with begin and end from different objects
+
+  std::move(v.begin(), v.end(), v2.begin());
+  std::move(v.begin());
+  test_copy();
+}
Index: docs/clang-tidy/checks/obvious-invalid-range.rst
===================================================================
--- /dev/null
+++ docs/clang-tidy/checks/obvious-invalid-range.rst
@@ -0,0 +1,17 @@
+.. title:: clang-tidy - obvious-invalid-range
+
+obvious-invalid-range
+=====================
+
+This check finds invalid calls to algorithms with obviously invalid range of
+iterators like:
+
+.. code-block:: c++
+    std::fill(v.begin(), v2.end(), it);
+
+It checks if first and second argument of call is method call to ``begin()``
+and ``end()``, but on different objects (having different name).
+
+By default it looks for all algorithms from ``<algorithm>``. This can be
+changed by using ``AlgorithmNames`` option, where empty list means that any
+function name will be accepted.
Index: docs/clang-tidy/checks/list.rst
===================================================================
--- docs/clang-tidy/checks/list.rst
+++ docs/clang-tidy/checks/list.rst
@@ -118,6 +118,7 @@
    modernize-use-using
    mpi-buffer-deref
    mpi-type-mismatch
+   obvious-invalid-range
    performance-faster-string-find
    performance-for-range-copy
    performance-implicit-cast-in-loop
Index: docs/ReleaseNotes.rst
===================================================================
--- docs/ReleaseNotes.rst
+++ docs/ReleaseNotes.rst
@@ -114,6 +114,15 @@
 
   Flags MPI function calls with a buffer type and MPI data type mismatch.
 
+- New obvious module with checks for obvious bugs that probably won't be found
+  in working code, but can be found while looking for an obvious bug in broken
+  code.
+- New `obvious-invalid-range
+  <http://clang.llvm.org/extra/clang-tidy/checks/obvious-invalid-range.html>`_ check
+
+  Warns if algorithm is used with ``.begin()`` and ``.end()`` from different
+  container.
+
 - New `performance-inefficient-string-concatenation
   <http://clang.llvm.org/extra/clang-tidy/checks/performance-inefficient-string-concatenation.html>`_ check
 
Index: clang-tidy/obvious/ObviousTidyModule.cpp
===================================================================
--- clang-tidy/obvious/ObviousTidyModule.cpp
+++ clang-tidy/obvious/ObviousTidyModule.cpp
@@ -11,6 +11,7 @@
 #include "../ClangTidyModule.h"
 #include "../ClangTidyModuleRegistry.h"
 
+#include "InvalidRangeCheck.h"
 using namespace clang::ast_matchers;
 
 namespace clang {
@@ -20,7 +21,7 @@
 class ObviousModule : public ClangTidyModule {
 public:
   void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override {
-    // Add obvious checks here.
+    CheckFactories.registerCheck<InvalidRangeCheck>("obvious-invalid-range");
   }
 };
 
Index: clang-tidy/obvious/InvalidRangeCheck.h
===================================================================
--- /dev/null
+++ clang-tidy/obvious/InvalidRangeCheck.h
@@ -0,0 +1,40 @@
+//===--- InvalidRangeCheck.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_OBVIOUS_INVALID_RANGE_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_OBVIOUS_INVALID_RANGE_H
+
+#include "../ClangTidy.h"
+#include <string>
+#include <vector>
+
+namespace clang {
+namespace tidy {
+namespace obvious {
+
+/// Find invalid call to algorithm with obviously invalid range of iterators.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/obvious-invalid-range.html
+class InvalidRangeCheck : public ClangTidyCheck {
+public:
+  InvalidRangeCheck(StringRef Name, ClangTidyContext *Context);
+  void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+  void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+  void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+
+private:
+  std::vector<std::string> AlgorithmNames;
+};
+
+} // namespace obvious
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_OBVIOUS_INVALID_RANGE_H
Index: clang-tidy/obvious/InvalidRangeCheck.cpp
===================================================================
--- /dev/null
+++ clang-tidy/obvious/InvalidRangeCheck.cpp
@@ -0,0 +1,97 @@
+//===--- InvalidRangeCheck.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 "InvalidRangeCheck.h"
+#include "../utils/OptionsUtils.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace obvious {
+
+const std::string CXX_AlgorithmNames =
+    "std::for_each; std::find; std::find_if; std::find_end; "
+    "std::find_first_of; std::adjacent_find; std::count; std::count_if;"
+    "std::mismatch; std::equal; std::search; std::copy; "
+    "std::copy_backward; std::swap_ranges; std::transform; std::replace"
+    "std::replace_if; std::replace_copy; std::replace_copy_if; std::fill; "
+    "std::fill_n; std::generate; std::generate_n; std::remove; std::remove_if"
+    "std::remove_copy; std::remove_copy_if; std::unique; std::unique_copy;"
+    "std::reverse; std::reverse_copy; std::rotate; std::rotate_copy; "
+    "std::random_shuffle; std::partition; std::stable_partition; std::sort;"
+    "std::stable_sort; std::partial_sort; std::partial_sort_copy; "
+    "std::nth_element; std::lower_bound; std::upper_bound; std::equal_range;"
+    "std::binary_search; std::merge; std::inplace_merge; std::includes; "
+    "std::set_union; std::set_intersection; std::set_difference; "
+    "std::set_symetric_difference; std::push_heap; std::pop_heap"
+    "std::make_heap; std::sort_heap; std::min; std::max; std::min_element; "
+    "std::max_element; std::lexicographical_compare; std::next_permutation; "
+    "std::prev_permutation";
+
+const auto CXX11_AlgorithmNames =
+    CXX_AlgorithmNames + "; "
+    "std::all_of; std::any_of; std::none_of; std::find_if_not; "
+    "std::is_permutation; std::copy_n; std::copy_if; std::move; "
+    "std::move_backward; std::shuffle; std::is_partitioned;"
+    "std::partition_copy; std::partition_point; std::is_sorted"
+    "std::is_sorted_until; std::is_heap; std::is_heap_until; std::minmax; "
+    "std::minmax_element";
+
+InvalidRangeCheck::InvalidRangeCheck(StringRef Name, ClangTidyContext *Context)
+    : ClangTidyCheck(Name, Context),
+      AlgorithmNames(utils::options::parseStringList(Options.get(
+          "AlgorithmNames", getLangOpts().CPlusPlus11 ? CXX11_AlgorithmNames
+                                                      : CXX_AlgorithmNames))) {}
+
+void InvalidRangeCheck::registerMatchers(MatchFinder *Finder) {
+  if (!getLangOpts().CPlusPlus)
+    return;
+
+  // Not so small vector. 80 because there are about that many algorithms.
+  const auto Names =
+      SmallVector<StringRef, 80>(AlgorithmNames.begin(), AlgorithmNames.end());
+
+  auto CallsAlgorithm = hasDeclaration(
+      functionDecl(Names.size() > 0 ? hasAnyName(Names) : anything()));
+
+  auto MemberCallWithName = [](StringRef MethodName, StringRef BindThisName) {
+    return cxxMemberCallExpr(
+        hasDeclaration(cxxMethodDecl(hasName(MethodName))),
+        onImplicitObjectArgument(declRefExpr().bind(BindThisName)));
+  };
+  // FIXME: match for std::begin(arg) and std::end(arg2)
+  // FIXME: some algorithms like std::list::splice(It, list, It, It) take
+  // range as 3rd and 4th argument.
+  Finder->addMatcher(
+      callExpr(hasArgument(0, MemberCallWithName("begin", "first_arg")),
+               hasArgument(1, MemberCallWithName("end", "second_arg")),
+               CallsAlgorithm),
+      this);
+}
+
+void InvalidRangeCheck::check(const MatchFinder::MatchResult &Result) {
+  const auto *FirstArg = Result.Nodes.getNodeAs<DeclRefExpr>("first_arg");
+  const auto *SecondArg = Result.Nodes.getNodeAs<DeclRefExpr>("second_arg");
+  if (FirstArg->getNameInfo().getAsString() ==
+      SecondArg->getNameInfo().getAsString())
+    return;
+
+  diag(FirstArg->getExprLoc(),
+       "call to algorithm with begin and end from different objects");
+}
+
+void InvalidRangeCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
+  Options.store(Opts, "AlgorithmNames",
+                utils::options::serializeStringList(AlgorithmNames));
+}
+
+} // namespace obvious
+} // namespace tidy
+} // namespace clang
Index: clang-tidy/obvious/CMakeLists.txt
===================================================================
--- clang-tidy/obvious/CMakeLists.txt
+++ clang-tidy/obvious/CMakeLists.txt
@@ -2,6 +2,7 @@
 
 add_clang_library(clangTidyObviousModule
   ObviousTidyModule.cpp
+  InvalidRangeCheck.cpp
 
   LINK_LIBS
   clangAST
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to