njames93 created this revision.
njames93 added reviewers: aaron.ballman, alexfh, hokein.
njames93 added projects: clang, clang-tools-extra.
Herald added subscribers: xazax.hun, mgorny.

Adds a new clang-tidy check that detects postfix increments and decrements that 
can be swapped for their prefix counterparts. Tried to be as thorough as 
possible with detecting if the result of the operation is used by a parent. I 
ran this check over llvm and clang lib and the result would build OK.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D72553

Files:
  clang-tools-extra/clang-tidy/llvm/CMakeLists.txt
  clang-tools-extra/clang-tidy/llvm/LLVMTidyModule.cpp
  clang-tools-extra/clang-tidy/llvm/PreferPreincrementCheck.cpp
  clang-tools-extra/clang-tidy/llvm/PreferPreincrementCheck.h
  clang-tools-extra/docs/ReleaseNotes.rst
  clang-tools-extra/docs/clang-tidy/checks/list.rst
  clang-tools-extra/docs/clang-tidy/checks/llvm-prefer-preincrement.rst
  
clang-tools-extra/test/clang-tidy/checkers/llvm-prefer-preincrement-disable-cpp-opcalls.cpp
  clang-tools-extra/test/clang-tidy/checkers/llvm-prefer-preincrement.c
  clang-tools-extra/test/clang-tidy/checkers/llvm-prefer-preincrement.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/llvm-prefer-preincrement.cpp
===================================================================
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/llvm-prefer-preincrement.cpp
@@ -0,0 +1,82 @@
+// RUN: %check_clang_tidy %s llvm-prefer-preincrement %t
+
+template <typename T>
+class Iterator {
+  T *Current;
+
+public:
+  Iterator(T *Pointer) : Current(Pointer) {}
+  T &operator*() const { return *Current; }
+  Iterator &operator++() { return ++Current, *this; }
+  Iterator operator++(int) {
+    Iterator Copy = *this;
+    ++Current;
+    return Copy;
+  }
+  Iterator &operator--() { return --Current, *this; }
+  Iterator operator--(int) {
+    Iterator Copy = *this;
+    --Current;
+    return Copy;
+  }
+};
+
+template <typename T>
+class PostfixIterator {
+  T *Current;
+
+public:
+  PostfixIterator(T *Pointer) : Current(Pointer) {}
+  T &operator*() const { return *Current; }
+  PostfixIterator operator++(int) {
+    PostfixIterator Copy = *this;
+    ++Current;
+    return Copy;
+  }
+  PostfixIterator operator--(int) {
+    PostfixIterator Copy = *this;
+    --Current;
+    return Copy;
+  }
+};
+
+void foo() {
+  int Array[32];
+  Iterator<int> It(&Array[0]);
+  It++;
+  // CHECK-MESSAGES: [[@LINE-1]]:3: warning: Use Pre-incriment instead of Post-incriment
+  // CHECK-FIXES: {{^}}  ++It;
+  It--;
+  // CHECK-MESSAGES: [[@LINE-1]]:3: warning: Use Pre-decriment instead of Post-decriment
+  // CHECK-FIXES: {{^}}  --It;
+  (*It)++;
+  // CHECK-MESSAGES: [[@LINE-1]]:3: warning: Use Pre-incriment instead of Post-incriment
+  // CHECK-FIXES: {{^}}  ++(*It);
+  (*It)--;
+  // CHECK-MESSAGES: [[@LINE-1]]:3: warning: Use Pre-decriment instead of Post-decriment
+  // CHECK-FIXES: {{^}}  --(*It);
+
+  *It++;
+  // CHECK-MESSAGES-NOT: [[@LINE-1]]:{{\d*}}: warning: Use Pre-incriment instead of Post-incriment
+  *It--;
+  // CHECK-MESSAGES-NOT: [[@LINE-1]]:{{\d*}}: warning: Use Pre-decriment instead of Post-decriment
+
+  PostfixIterator<int> PfIt(&Array[0]);
+  PfIt++;
+  // CHECK-MESSAGES-NOT: [[@LINE-1]]:{{\d*}}: warning: Use Pre-incriment instead of Post-incriment
+  // CHECK-FIXES-NOT: {{^}}  ++PfIt;
+  PfIt--;
+  // CHECK-MESSAGES-NOT: [[@LINE-1]]:{{\d*}}: warning: Use Pre-decriment instead of Post-decriment
+  // CHECK-FIXES-NOT: {{^}}  --PfIt;
+  (*PfIt)++;
+  // CHECK-MESSAGES: [[@LINE-1]]:3: warning: Use Pre-incriment instead of Post-incriment
+  // CHECK-FIXES: {{^}}  ++(*PfIt);
+  (*PfIt)--;
+  // CHECK-MESSAGES: [[@LINE-1]]:3: warning: Use Pre-decriment instead of Post-decriment
+  // CHECK-FIXES: {{^}}  --(*PfIt);
+
+  *PfIt++;
+  // CHECK-MESSAGES-NOT: [[@LINE-1]]:{{\d*}}: warning: Use Pre-incriment instead of Post-incriment
+  *PfIt--;
+  // CHECK-MESSAGES-NOT: [[@LINE-1]]:{{\d*}}: warning: Use Pre-decriment instead of Post-decriment
+}
Index: clang-tools-extra/test/clang-tidy/checkers/llvm-prefer-preincrement.c
===================================================================
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/llvm-prefer-preincrement.c
@@ -0,0 +1,123 @@
+// RUN: %check_clang_tidy %s llvm-prefer-preincrement %t
+
+#define INC(X) X++
+#define DEC(X) X--
+
+void foo(int A) {
+  for (int I = 0; I < 10; I++) {
+    // CHECK-MESSAGES: [[@LINE-1]]:27: warning: Use Pre-incriment instead of Post-incriment
+    // CHECK-FIXES: {{^}}  for (int I = 0; I < 10; ++I) {
+  }
+  for (int I = 0; I < 10; ++I) {
+    // CHECK-MESSAGES-NOT: [[@LINE-1]]:{{\d*}}: warning: Use Pre-incriment instead of Post-incriment
+  }
+  for (int I = 0; I < 10; A = I++) {
+    // CHECK-MESSAGES-NOT: [[@LINE-1]]:{{\d*}}: warning: Use Pre-incriment instead of Post-incriment
+  }
+
+  for (int I = 10; I < 0; I--) {
+    // CHECK-MESSAGES: [[@LINE-1]]:27: warning: Use Pre-decriment instead of Post-decriment
+    // CHECK-FIXES: {{^}}  for (int I = 10; I < 0; --I) {
+  }
+  for (int I = 10; I < 0; --I) {
+    // CHECK-MESSAGES-NOT: [[@LINE-1]]:{{\d*}}: warning: Use Pre-decriment instead of Post-decriment
+  }
+  for (int I = 10; I < 0; A = I--) {
+    // CHECK-MESSAGES-NOT: [[@LINE-1]]:{{\d*}}: warning: Use Pre-decriment instead of Post-decriment
+  }
+
+  for (int I = 0; I < 10; INC(I)) {
+    // CHECK-MESSAGES: [[@LINE-1]]:31: warning: Use Pre-incriment instead of Post-incriment
+  }
+  for (int I = 0; I < 10; DEC(I)) {
+    // CHECK-MESSAGES: [[@LINE-1]]:31: warning: Use Pre-decriment instead of Post-decriment
+  }
+  for (int I = 0; I < 10; A = INC(I)) {
+    // CHECK-MESSAGES-NOT: [[@LINE-1]]:{{\d*}}: warning: Use Pre-incriment instead of Post-incriment
+  }
+}
+
+void bar(int *Begin, int *End) {
+  for (int *I = Begin; I != End;) {
+    *I++ = 0;
+    // CHECK-MESSAGES-NOT: [[@LINE-1]]:{{\d*}}: warning: Use Pre-incriment instead of Post-incriment
+  }
+  for (int *I = Begin; I != End; I++) {
+    // CHECK-MESSAGES: [[@LINE-1]]:34: warning: Use Pre-incriment instead of Post-incriment
+    // CHECK-FIXES: {{^}}  for (int *I = Begin; I != End; ++I) {
+    *I = 0;
+  }
+  for (int *I = Begin; I != End; ++I) {
+    // CHECK-MESSAGES-NOT: [[@LINE-1]]:{{\d*}}: warning: Use Pre-incriment instead of Post-incriment
+    *I = 0;
+  }
+  for (int *I = Begin; I != End; I++){
+    // CHECK-MESSAGES: [[@LINE-1]]:34: warning: Use Pre-incriment instead of Post-incriment
+    // CHECK-FIXES: {{^}}  for (int *I = Begin; I != End; ++I) {
+    (*I)++; // c1
+    // CHECK-MESSAGES: [[@LINE-1]]:5: warning: Use Pre-incriment instead of Post-incriment
+    // CHECK-FIXES: {{^}}    ++(*I); // c1
+    (*I)++; // c2
+    // CHECK-MESSAGES: [[@LINE-1]]:5: warning: Use Pre-incriment instead of Post-incriment
+    // CHECK-FIXES: {{^}}    ++(*I); // c2
+    (*I)++; // c3
+    // CHECK-MESSAGES: [[@LINE-1]]:5: warning: Use Pre-incriment instead of Post-incriment
+    // CHECK-FIXES: {{^}}    ++(*I); // c3
+  }
+}
+
+int handle(int);
+
+void baz(){
+  int I = 0;
+  handle(I++);
+  // CHECK-MESSAGES-NOT: [[@LINE-1]]:{{\d*}}: warning: Use Pre-incriment instead of Post-incriment
+  int J = I++;
+  // CHECK-MESSAGES-NOT: [[@LINE-1]]:{{\d*}}: warning: Use Pre-incriment instead of Post-incriment
+  if (J++) {
+  }
+  // CHECK-MESSAGES-NOT: [[@LINE-2]]:{{\d*}}: warning: Use Pre-incriment instead of Post-incriment
+  switch (J++) {}
+  // CHECK-MESSAGES-NOT: [[@LINE-1]]:{{\d*}}: warning: Use Pre-incriment instead of Post-incriment
+  while (J++) {
+  }
+  // CHECK-MESSAGES-NOT: [[@LINE-2]]:{{\d*}}: warning: Use Pre-incriment instead of Post-incriment
+  do {
+  } while (J++);
+  // CHECK-MESSAGES-NOT: [[@LINE-1]]:{{\d*}}: warning: Use Pre-incriment instead of Post-incriment
+  for (; J++;) {
+  }
+  // CHECK-MESSAGES-NOT: [[@LINE-2]]:{{\d*}}: warning: Use Pre-incriment instead of Post-incriment
+  J++ ? J-- : J++;
+  // CHECK-MESSAGES-NOT: [[@LINE-1]]:{{\d*}}: warning: Use Pre-incriment instead of Post-incriment
+  J++ ?: J--;
+  // CHECK-MESSAGES-NOT: [[@LINE-1]]:{{\d*}}: warning: Use Pre-incriment instead of Post-incriment
+  J++;
+  // CHECK-MESSAGES: [[@LINE-1]]:{{3}}: warning: Use Pre-incriment instead of Post-incriment
+  // CHECK-FIXES: {{^}}  ++J;
+}
+
+struct Foo {
+  int Bar;
+};
+
+struct Baz {
+  struct Foo Bar;
+};
+
+int foobar(struct Baz Foobar, struct Foo *Bar) {
+  Foobar.Bar.Bar++;
+  // CHECK-MESSAGES: [[@LINE-1]]:3: warning: Use Pre-incriment instead of Post-incriment
+  // CHECK-FIXES: {{^}}  ++Foobar.Bar.Bar;
+  Bar->Bar++;
+  // CHECK-MESSAGES: [[@LINE-1]]:3: warning: Use Pre-incriment instead of Post-incriment
+  // CHECK-FIXES: {{^}}  ++Bar->Bar;
+  Foobar.
+  Bar.
+  Bar++;
+  // CHECK-MESSAGES: [[@LINE-3]]:3: warning: Use Pre-incriment instead of Post-incriment
+  // CHECK-FIXES:      {{^}}  ++Foobar.
+  // CHECK-FIXES-NEXT: {{^}}  Bar.
+  // CHECK-FIXES-NEXT: {{^}}  Bar;
+  return Bar->Bar++;
+}
Index: clang-tools-extra/test/clang-tidy/checkers/llvm-prefer-preincrement-disable-cpp-opcalls.cpp
===================================================================
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/llvm-prefer-preincrement-disable-cpp-opcalls.cpp
@@ -0,0 +1,84 @@
+// RUN: %check_clang_tidy %s llvm-prefer-preincrement %t -- \
+// RUN: -config='{CheckOptions: \
+// RUN:  [{key: llvm-prefer-preincrement.TransformCxxOpCalls, value: 0}]}'
+
+template <typename T>
+class Iterator {
+  T *Current;
+
+public:
+  Iterator(T *Pointer) : Current(Pointer) {}
+  T &operator*() const { return *Current; }
+  Iterator &operator++() { return ++Current, *this; }
+  Iterator operator++(int) {
+    Iterator Copy = *this;
+    ++Current;
+    return Copy;
+  }
+  Iterator &operator--() { return --Current, *this; }
+  Iterator operator--(int) {
+    Iterator Copy = *this;
+    --Current;
+    return Copy;
+  }
+};
+
+template <typename T>
+class PostfixIterator {
+  T *Current;
+
+public:
+  PostfixIterator(T *Pointer) : Current(Pointer) {}
+  T &operator*() const { return *Current; }
+  PostfixIterator operator++(int) {
+    PostfixIterator Copy = *this;
+    ++Current;
+    return Copy;
+  }
+  PostfixIterator operator--(int) {
+    PostfixIterator Copy = *this;
+    --Current;
+    return Copy;
+  }
+};
+
+void foo() {
+  int Array[32];
+  Iterator<int> It(&Array[0]);
+  It++;
+  // CHECK-MESSAGES-NOT: [[@LINE-1]]:{{\d*}}: warning: Use Pre-incriment instead of Post-incriment
+  // CHECK-FIXES-NOT: {{^}}  ++It;
+  It--;
+  // CHECK-MESSAGES-NOT: [[@LINE-1]]:{{\d*}}: warning: Use Pre-decriment instead of Post-decriment
+  // CHECK-FIXES-NOT: {{^}}  --It;
+  (*It)++;
+  // CHECK-MESSAGES: [[@LINE-1]]:3: warning: Use Pre-incriment instead of Post-incriment
+  // CHECK-FIXES: {{^}}  ++(*It);
+  (*It)--;
+  // CHECK-MESSAGES: [[@LINE-1]]:3: warning: Use Pre-decriment instead of Post-decriment
+  // CHECK-FIXES: {{^}}  --(*It);
+
+  *It++;
+  // CHECK-MESSAGES-NOT: [[@LINE-1]]:{{\d*}}: warning: Use Pre-incriment instead of Post-incriment
+  *It--;
+  // CHECK-MESSAGES-NOT: [[@LINE-1]]:{{\d*}}: warning: Use Pre-decriment instead of Post-decriment
+
+  PostfixIterator<int> PfIt(&Array[0]);
+  PfIt++;
+  // CHECK-MESSAGES-NOT: [[@LINE-1]]:{{\d*}}: warning: Use Pre-incriment instead of Post-incriment
+  // CHECK-FIXES-NOT: {{^}}  ++PfIt;
+  PfIt--;
+  // CHECK-MESSAGES-NOT: [[@LINE-1]]:{{\d*}}: warning: Use Pre-decriment instead of Post-decriment
+  // CHECK-FIXES-NOT: {{^}}  --PfIt;
+  (*PfIt)++;
+  // CHECK-MESSAGES: [[@LINE-1]]:3: warning: Use Pre-incriment instead of Post-incriment
+  // CHECK-FIXES: {{^}}  ++(*PfIt);
+  (*PfIt)--;
+  // CHECK-MESSAGES: [[@LINE-1]]:3: warning: Use Pre-decriment instead of Post-decriment
+  // CHECK-FIXES: {{^}}  --(*PfIt);
+
+  *PfIt++;
+  // CHECK-MESSAGES-NOT: [[@LINE-1]]:4: warning: Use Pre-incriment instead of Post-incriment
+  *PfIt--;
+  // CHECK-MESSAGES-NOT: [[@LINE-1]]:4: warning: Use Pre-decriment instead of Post-decriment
+}
Index: clang-tools-extra/docs/clang-tidy/checks/llvm-prefer-preincrement.rst
===================================================================
--- /dev/null
+++ clang-tools-extra/docs/clang-tidy/checks/llvm-prefer-preincrement.rst
@@ -0,0 +1,33 @@
+.. title:: clang-tidy - llvm-prefer-preincrement
+
+llvm-prefer-preincrement
+========================
+
+Flags usages of the unary postfix incriment and decriment operators where the
+result isnt used which could be replaced with the more efficient prefix variety.
+
+.. code-block:: c++
+
+  // Finds these
+  for (int I = 0; I < 10; I++) {}
+  (*Ptr)++;
+  // Replaces with
+  for (int I = 0; I < 10; ++I) {}
+  ++(*Ptr);
+
+  // Doesn't replace these
+  *Ptr++ = 0;
+  call(I++);
+  Index = I++;
+
+Options
+-------
+
+.. option:: TransformCxxOpCalls
+
+   Enables checking postfix operations on classes and structures that overload
+   both the prefix and postfix operator ``++`` or ``--``.
+   Default value is 1.
+
+This check helps to enforce this `LLVM Coding Standards recommendation
+<https://llvm.org/docs/CodingStandards.html#prefer-preincrement>`_.
Index: clang-tools-extra/docs/clang-tidy/checks/list.rst
===================================================================
--- clang-tools-extra/docs/clang-tidy/checks/list.rst
+++ clang-tools-extra/docs/clang-tidy/checks/list.rst
@@ -176,6 +176,7 @@
    `llvm-include-order <llvm-include-order.html>`_, "Yes"
    `llvm-namespace-comment <llvm-namespace-comment.html>`_,
    `llvm-prefer-isa-or-dyn-cast-in-conditionals <llvm-prefer-isa-or-dyn-cast-in-conditionals.html>`_, "Yes"
+   `llvm-prefer-preincrement <llvm-prefer-preincrement.html>`_, "Yes"
    `llvm-prefer-register-over-unsigned <llvm-prefer-register-over-unsigned.html>`_, "Yes"
    `llvm-twine-local <llvm-twine-local.html>`_, "Yes"
    `misc-definitions-in-headers <misc-definitions-in-headers.html>`_, "Yes"
Index: clang-tools-extra/docs/ReleaseNotes.rst
===================================================================
--- clang-tools-extra/docs/ReleaseNotes.rst
+++ clang-tools-extra/docs/ReleaseNotes.rst
@@ -136,6 +136,12 @@
   Checks Linux kernel code to see if it uses the results from the functions in
   ``linux/err.h``.
 
+- New :doc:`llvm-prefer-preincrement
+  <clang-tidy/checks/llvm-prefer-preincrement>` check.
+
+  Flags usages of postfix incriment and decriment which could be swapped for
+  their prefix alternatives.
+
 - New :doc:`llvm-prefer-register-over-unsigned
   <clang-tidy/checks/llvm-prefer-register-over-unsigned>` check.
 
Index: clang-tools-extra/clang-tidy/llvm/PreferPreincrementCheck.h
===================================================================
--- /dev/null
+++ clang-tools-extra/clang-tidy/llvm/PreferPreincrementCheck.h
@@ -0,0 +1,38 @@
+//===--- PreferPreincrementCheck.h - clang-tidy -----------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_LLVM_PREFERPREINCREMENTCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_LLVM_PREFERPREINCREMENTCHECK_H
+
+#include "../ClangTidyCheck.h"
+
+namespace clang {
+namespace tidy {
+namespace llvm_check {
+
+///  Flags usages of postfix incriment and decriment which could be swapped for
+///  their prefix alternatives.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/llvm-prefer-preincrement.html
+class PreferPreincrementCheck : public ClangTidyCheck {
+public:
+  PreferPreincrementCheck(StringRef Name, ClangTidyContext *Context);
+  void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+  void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+  void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+  const bool TransformCxxOpCalls;
+};
+
+} // namespace llvm_check
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_LLVM_PREFERPREINCREMENTCHECK_H
Index: clang-tools-extra/clang-tidy/llvm/PreferPreincrementCheck.cpp
===================================================================
--- /dev/null
+++ clang-tools-extra/clang-tidy/llvm/PreferPreincrementCheck.cpp
@@ -0,0 +1,106 @@
+//===--- PreferPreincrementCheck.cpp - clang-tidy -------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "PreferPreincrementCheck.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Tooling/FixIt.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace llvm_check {
+
+namespace {
+AST_MATCHER(UnaryOperator, isPostfix) { return Node.isPostfix(); }
+} // namespace
+
+PreferPreincrementCheck::PreferPreincrementCheck(StringRef Name,
+                                                 ClangTidyContext *Context)
+    : ClangTidyCheck(Name, Context),
+      TransformCxxOpCalls(Options.get("TransformCxxOpCalls", 1) != 0) {}
+
+void PreferPreincrementCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
+  Options.store(Opts, "TransformCxxOpCalls", TransformCxxOpCalls);
+}
+
+void PreferPreincrementCheck::registerMatchers(MatchFinder *Finder) {
+  // Ignore all unary ops with a parent decl or expr, those use the value
+  // returned. Reordering those would change the behaviour of the expression.
+  // FIXME: Add any more parents which could use the result of the operation.
+  auto BadParents =
+      unless(anyOf(hasParent(decl()), hasParent(expr()),
+                   hasParent(returnStmt()), hasParent(cxxThrowExpr())));
+  auto BoundExpr = expr().bind("ignore");
+  auto BoundChecks =
+      anyOf(hasParent(ifStmt(hasCondition(BoundExpr))),
+            hasParent(forStmt(hasCondition(BoundExpr))),
+            hasParent(switchStmt(hasCondition(BoundExpr))),
+            hasParent(whileStmt(hasCondition(BoundExpr))),
+            hasParent(doStmt(hasCondition(BoundExpr))),
+            hasParent(conditionalOperator(hasCondition(BoundExpr))),
+            hasParent(binaryConditionalOperator(hasCondition(BoundExpr))));
+
+  auto UnusedInParent =
+      allOf(BadParents, unless(allOf(BoundChecks, equalsBoundNode("ignore"))));
+
+  Finder->addMatcher(unaryOperator(isPostfix(), UnusedInParent).bind("op"),
+                     this);
+
+  if (!getLangOpts().CPlusPlus || !TransformCxxOpCalls)
+    return;
+
+  auto FindCxxOpCalls = [&](llvm::StringRef PostfixName) {
+    Finder->addMatcher(
+        cxxOperatorCallExpr(
+            UnusedInParent,
+            callee(cxxMethodDecl(
+                hasName(PostfixName), parameterCountIs(1),
+                hasParent(cxxRecordDecl(hasMethod(cxxMethodDecl(
+                    hasName(PostfixName), parameterCountIs(0))))))))
+            .bind(PostfixName),
+        this);
+  };
+  FindCxxOpCalls("operator++");
+  FindCxxOpCalls("operator--");
+}
+
+void PreferPreincrementCheck::check(const MatchFinder::MatchResult &Result) {
+  auto Apply = [&](SourceRange Range, SourceLocation OpLoc,
+                   const Expr &Expression, bool IsIncriment) {
+    // Warn for all occurances, but don't fix macro usage.
+    DiagnosticBuilder Diag =
+        diag(Range.getBegin(), "Use Pre-%0 instead of Post-%0")
+        << (IsIncriment ? "incriment" : "decriment");
+    if (OpLoc.isMacroID() || Range.getBegin().isMacroID() ||
+        Range.getEnd().isMacroID())
+      return;
+    auto ReplText =
+        ((IsIncriment ? "++" : "--") +
+         tooling::fixit::getText(Expression, *Result.Context).rtrim(("-+")))
+            .str();
+    Diag << FixItHint::CreateReplacement(Range, ReplText);
+  };
+
+  if (const auto *UnaryOp = Result.Nodes.getNodeAs<UnaryOperator>("op"))
+    Apply(UnaryOp->getSourceRange(), UnaryOp->getOperatorLoc(),
+          *UnaryOp->getSubExpr(),
+          UnaryOp->getOpcode() == UnaryOperatorKind::UO_PostInc);
+  if (const auto *OpCall =
+          Result.Nodes.getNodeAs<CXXOperatorCallExpr>("operator++"))
+    Apply(OpCall->getSourceRange(), OpCall->getOperatorLoc(),
+          *OpCall->getExprStmt(), true);
+  if (const auto *OpCall =
+          Result.Nodes.getNodeAs<CXXOperatorCallExpr>("operator--"))
+    Apply(OpCall->getSourceRange(), OpCall->getOperatorLoc(),
+          *OpCall->getExprStmt(), false);
+}
+
+} // namespace llvm_check
+} // namespace tidy
+} // namespace clang
Index: clang-tools-extra/clang-tidy/llvm/LLVMTidyModule.cpp
===================================================================
--- clang-tools-extra/clang-tidy/llvm/LLVMTidyModule.cpp
+++ clang-tools-extra/clang-tidy/llvm/LLVMTidyModule.cpp
@@ -13,6 +13,7 @@
 #include "HeaderGuardCheck.h"
 #include "IncludeOrderCheck.h"
 #include "PreferIsaOrDynCastInConditionalsCheck.h"
+#include "PreferPreincrementCheck.h"
 #include "PreferRegisterOverUnsignedCheck.h"
 #include "TwineLocalCheck.h"
 
@@ -29,6 +30,8 @@
         "llvm-namespace-comment");
     CheckFactories.registerCheck<PreferIsaOrDynCastInConditionalsCheck>(
         "llvm-prefer-isa-or-dyn-cast-in-conditionals");
+    CheckFactories.registerCheck<PreferPreincrementCheck>(
+        "llvm-prefer-preincrement");
     CheckFactories.registerCheck<PreferRegisterOverUnsignedCheck>(
         "llvm-prefer-register-over-unsigned");
     CheckFactories.registerCheck<TwineLocalCheck>("llvm-twine-local");
Index: clang-tools-extra/clang-tidy/llvm/CMakeLists.txt
===================================================================
--- clang-tools-extra/clang-tidy/llvm/CMakeLists.txt
+++ clang-tools-extra/clang-tidy/llvm/CMakeLists.txt
@@ -5,6 +5,7 @@
   IncludeOrderCheck.cpp
   LLVMTidyModule.cpp
   PreferIsaOrDynCastInConditionalsCheck.cpp
+  PreferPreincrementCheck.cpp
   PreferRegisterOverUnsignedCheck.cpp
   TwineLocalCheck.cpp
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to