diff --git a/clang-tools-extra/clang-tidy/llvm/CMakeLists.txt b/clang-tools-extra/clang-tidy/llvm/CMakeLists.txt --- a/clang-tools-extra/clang-tidy/llvm/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/llvm/CMakeLists.txt @@ -5,6 +5,7 @@ IncludeOrderCheck.cpp LLVMTidyModule.cpp PreferIsaOrDynCastInConditionalsCheck.cpp + PreferPreIncrementCheck.cpp PreferRegisterOverUnsignedCheck.cpp TwineLocalCheck.cpp diff --git a/clang-tools-extra/clang-tidy/llvm/LLVMTidyModule.cpp b/clang-tools-extra/clang-tidy/llvm/LLVMTidyModule.cpp --- a/clang-tools-extra/clang-tidy/llvm/LLVMTidyModule.cpp +++ b/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( "llvm-prefer-isa-or-dyn-cast-in-conditionals"); + CheckFactories.registerCheck( + "llvm-prefer-pre-increment"); CheckFactories.registerCheck( "llvm-prefer-register-over-unsigned"); CheckFactories.registerCheck("llvm-twine-local"); diff --git a/clang-tools-extra/clang-tidy/llvm/PreferPreIncrementCheck.h b/clang-tools-extra/clang-tidy/llvm/PreferPreIncrementCheck.h new file mode 100644 --- /dev/null +++ b/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 increment and decrement which could be swapped for +/// their prefix alternatives. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/llvm-prefer-pre-increment.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 diff --git a/clang-tools-extra/clang-tidy/llvm/PreferPreIncrementCheck.cpp b/clang-tools-extra/clang-tidy/llvm/PreferPreIncrementCheck.cpp new file mode 100644 --- /dev/null +++ b/clang-tools-extra/clang-tidy/llvm/PreferPreIncrementCheck.cpp @@ -0,0 +1,118 @@ +//===--- 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" +#include "llvm/ADT/SmallVector.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace llvm_check { + +namespace { +AST_MATCHER_P(UnaryOperator, isOperator, UnaryOperatorKind, Opcode) { + return Node.getOpcode() == Opcode; +} +} // 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(isOperator(UnaryOperatorKind::UO_PostInc), UnusedInParent) + .bind("op++"), + this); + Finder->addMatcher( + unaryOperator(isOperator(UnaryOperatorKind::UO_PostDec), 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 IsIncrement) { + // Warn for all occurances, but don't fix macro usage. + DiagnosticBuilder Diag = + diag(Range.getBegin(), "Use Pre-%0 instead of Post-%0") + << (IsIncrement ? "increment" : "decrement"); + if (OpLoc.isMacroID() || Range.getBegin().isMacroID() || + Range.getEnd().isMacroID()) + return; + llvm::SmallVector Buffer; + Diag << FixItHint::CreateReplacement( + Range, + ((IsIncrement ? "++" : "--") + + tooling::fixit::getText(Expression, *Result.Context).rtrim(("-+"))) + .toStringRef(Buffer)); + }; + + if (const auto *UnaryOp = Result.Nodes.getNodeAs("op++")) + return Apply(UnaryOp->getSourceRange(), UnaryOp->getOperatorLoc(), + *UnaryOp->getSubExpr(), true); + if (const auto *UnaryOp = Result.Nodes.getNodeAs("op--")) + return Apply(UnaryOp->getSourceRange(), UnaryOp->getOperatorLoc(), + *UnaryOp->getSubExpr(), false); + if (const auto *OpCall = + Result.Nodes.getNodeAs("operator++")) + return Apply(OpCall->getSourceRange(), OpCall->getOperatorLoc(), + *OpCall->getExprStmt(), true); + if (const auto *OpCall = + Result.Nodes.getNodeAs("operator--")) + return Apply(OpCall->getSourceRange(), OpCall->getOperatorLoc(), + *OpCall->getExprStmt(), false); +} + +} // namespace llvm_check +} // namespace tidy +} // namespace clang diff --git a/clang-tools-extra/clang-tidy/performance/PerformanceTidyModule.cpp b/clang-tools-extra/clang-tidy/performance/PerformanceTidyModule.cpp --- a/clang-tools-extra/clang-tidy/performance/PerformanceTidyModule.cpp +++ b/clang-tools-extra/clang-tidy/performance/PerformanceTidyModule.cpp @@ -9,6 +9,7 @@ #include "../ClangTidy.h" #include "../ClangTidyModule.h" #include "../ClangTidyModuleRegistry.h" +#include "../llvm/PreferPreIncrementCheck.h" #include "FasterStringFindCheck.h" #include "ForRangeCopyCheck.h" #include "ImplicitConversionInLoopCheck.h" @@ -51,6 +52,8 @@ "performance-no-automatic-move"); CheckFactories.registerCheck( "performance-noexcept-move-constructor"); + CheckFactories.registerCheck( + "performance-prefer-pre-increment"); CheckFactories.registerCheck( "performance-trivially-destructible"); CheckFactories.registerCheck( diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/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-pre-increment + ` check. + + Flags usages of postfix increment and decrement which could be swapped for + their prefix alternatives. + - New :doc:`llvm-prefer-register-over-unsigned ` check. @@ -179,6 +185,11 @@ :doc:`bugprone-bad-signal-to-kill-thread ` was added. +- New alias :doc:`performance-prefer-pre-increment + ` to + :doc:`llvm-prefer-pre-increment + ` was added. + Changes in existing checks ^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst --- a/clang-tools-extra/docs/clang-tidy/checks/list.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst @@ -176,6 +176,7 @@ `llvm-include-order `_, "Yes" `llvm-namespace-comment `_, `llvm-prefer-isa-or-dyn-cast-in-conditionals `_, "Yes" + `llvm-prefer-pre-increment `_, "Yes" `llvm-prefer-register-over-unsigned `_, "Yes" `llvm-twine-local `_, "Yes" `misc-definitions-in-headers `_, "Yes" @@ -397,6 +398,7 @@ `hicpp-use-nullptr `_, `modernize-use-nullptr `_, "Yes" `hicpp-use-override `_, `modernize-use-override `_, "Yes" `hicpp-vararg `_, `cppcoreguidelines-pro-type-vararg `_, + `performance-prefer-pre-increment `_, `llvm-prefer-pre-increment `_, "Yes" .. toctree:: :glob: diff --git a/clang-tools-extra/docs/clang-tidy/checks/llvm-prefer-pre-increment.rst b/clang-tools-extra/docs/clang-tidy/checks/llvm-prefer-pre-increment.rst new file mode 100644 --- /dev/null +++ b/clang-tools-extra/docs/clang-tidy/checks/llvm-prefer-pre-increment.rst @@ -0,0 +1,33 @@ +.. title:: clang-tidy - llvm-prefer-pre-increment + +llvm-prefer-pre-increment +========================= + +Flags usages of the unary postfix increment and decrement 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 +`_. diff --git a/clang-tools-extra/docs/clang-tidy/checks/performance-prefer-pre-increment.rst b/clang-tools-extra/docs/clang-tidy/checks/performance-prefer-pre-increment.rst new file mode 100644 --- /dev/null +++ b/clang-tools-extra/docs/clang-tidy/checks/performance-prefer-pre-increment.rst @@ -0,0 +1,10 @@ +.. title:: clang-tidy - performance-prefer-pre-increment +.. meta:: + :http-equiv=refresh: 5;URL=llvm-prefer-pre-increment.html + +performance-prefer-pre-increment +================================ + +The performance-prefer-pre-incrementcheck is an alias, please see +`llvm-prefer-pre-increment `_ +for more information. diff --git a/clang-tools-extra/test/clang-tidy/checkers/llvm-prefer-pre-increment-disable-cpp-opcalls.cpp b/clang-tools-extra/test/clang-tidy/checkers/llvm-prefer-pre-increment-disable-cpp-opcalls.cpp new file mode 100644 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/llvm-prefer-pre-increment-disable-cpp-opcalls.cpp @@ -0,0 +1,84 @@ +// RUN: %check_clang_tidy %s llvm-prefer-pre-increment %t -- \ +// RUN: -config='{CheckOptions: \ +// RUN: [{key: llvm-prefer-pre-increment.TransformCxxOpCalls, value: 0}]}' + +template +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 +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 It(&Array[0]); + It++; + // CHECK-MESSAGES-NOT: [[@LINE-1]]:{{\d*}}: warning: Use Pre-increment instead of Post-increment + // CHECK-FIXES-NOT: {{^}} ++It; + It--; + // CHECK-MESSAGES-NOT: [[@LINE-1]]:{{\d*}}: warning: Use Pre-decrement instead of Post-decrement + // CHECK-FIXES-NOT: {{^}} --It; + (*It)++; + // CHECK-MESSAGES: [[@LINE-1]]:3: warning: Use Pre-increment instead of Post-increment + // CHECK-FIXES: {{^}} ++(*It); + (*It)--; + // CHECK-MESSAGES: [[@LINE-1]]:3: warning: Use Pre-decrement instead of Post-decrement + // CHECK-FIXES: {{^}} --(*It); + + *It++; + // CHECK-MESSAGES-NOT: [[@LINE-1]]:{{\d*}}: warning: Use Pre-increment instead of Post-increment + *It--; + // CHECK-MESSAGES-NOT: [[@LINE-1]]:{{\d*}}: warning: Use Pre-decrement instead of Post-decrement + + PostfixIterator PfIt(&Array[0]); + PfIt++; + // CHECK-MESSAGES-NOT: [[@LINE-1]]:{{\d*}}: warning: Use Pre-increment instead of Post-increment + // CHECK-FIXES-NOT: {{^}} ++PfIt; + PfIt--; + // CHECK-MESSAGES-NOT: [[@LINE-1]]:{{\d*}}: warning: Use Pre-decrement instead of Post-decrement + // CHECK-FIXES-NOT: {{^}} --PfIt; + (*PfIt)++; + // CHECK-MESSAGES: [[@LINE-1]]:3: warning: Use Pre-increment instead of Post-increment + // CHECK-FIXES: {{^}} ++(*PfIt); + (*PfIt)--; + // CHECK-MESSAGES: [[@LINE-1]]:3: warning: Use Pre-decrement instead of Post-decrement + // CHECK-FIXES: {{^}} --(*PfIt); + + *PfIt++; + // CHECK-MESSAGES-NOT: [[@LINE-1]]:4: warning: Use Pre-increment instead of Post-increment + *PfIt--; + // CHECK-MESSAGES-NOT: [[@LINE-1]]:4: warning: Use Pre-decrement instead of Post-decrement +} diff --git a/clang-tools-extra/test/clang-tidy/checkers/llvm-prefer-pre-increment.c b/clang-tools-extra/test/clang-tidy/checkers/llvm-prefer-pre-increment.c new file mode 100644 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/llvm-prefer-pre-increment.c @@ -0,0 +1,123 @@ +// RUN: %check_clang_tidy %s llvm-prefer-pre-increment %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-increment instead of Post-increment + // 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-increment instead of Post-increment + } + for (int I = 0; I < 10; A = I++) { + // CHECK-MESSAGES-NOT: [[@LINE-1]]:{{\d*}}: warning: Use Pre-increment instead of Post-increment + } + + for (int I = 10; I < 0; I--) { + // CHECK-MESSAGES: [[@LINE-1]]:27: warning: Use Pre-decrement instead of Post-decrement + // 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-decrement instead of Post-decrement + } + for (int I = 10; I < 0; A = I--) { + // CHECK-MESSAGES-NOT: [[@LINE-1]]:{{\d*}}: warning: Use Pre-decrement instead of Post-decrement + } + + for (int I = 0; I < 10; INC(I)) { + // CHECK-MESSAGES: [[@LINE-1]]:31: warning: Use Pre-increment instead of Post-increment + } + for (int I = 0; I < 10; DEC(I)) { + // CHECK-MESSAGES: [[@LINE-1]]:31: warning: Use Pre-decrement instead of Post-decrement + } + for (int I = 0; I < 10; A = INC(I)) { + // CHECK-MESSAGES-NOT: [[@LINE-1]]:{{\d*}}: warning: Use Pre-increment instead of Post-increment + } +} + +void bar(int *Begin, int *End) { + for (int *I = Begin; I != End;) { + *I++ = 0; + // CHECK-MESSAGES-NOT: [[@LINE-1]]:{{\d*}}: warning: Use Pre-increment instead of Post-increment + } + for (int *I = Begin; I != End; I++) { + // CHECK-MESSAGES: [[@LINE-1]]:34: warning: Use Pre-increment instead of Post-increment + // 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-increment instead of Post-increment + *I = 0; + } + for (int *I = Begin; I != End; I++){ + // CHECK-MESSAGES: [[@LINE-1]]:34: warning: Use Pre-increment instead of Post-increment + // CHECK-FIXES: {{^}} for (int *I = Begin; I != End; ++I) { + (*I)++; // c1 + // CHECK-MESSAGES: [[@LINE-1]]:5: warning: Use Pre-increment instead of Post-increment + // CHECK-FIXES: {{^}} ++(*I); // c1 + (*I)++; // c2 + // CHECK-MESSAGES: [[@LINE-1]]:5: warning: Use Pre-increment instead of Post-increment + // CHECK-FIXES: {{^}} ++(*I); // c2 + (*I)++; // c3 + // CHECK-MESSAGES: [[@LINE-1]]:5: warning: Use Pre-increment instead of Post-increment + // CHECK-FIXES: {{^}} ++(*I); // c3 + } +} + +int handle(int); + +void baz(){ + int I = 0; + handle(I++); + // CHECK-MESSAGES-NOT: [[@LINE-1]]:{{\d*}}: warning: Use Pre-increment instead of Post-increment + int J = I++; + // CHECK-MESSAGES-NOT: [[@LINE-1]]:{{\d*}}: warning: Use Pre-increment instead of Post-increment + if (J++) { + } + // CHECK-MESSAGES-NOT: [[@LINE-2]]:{{\d*}}: warning: Use Pre-increment instead of Post-increment + switch (J++) {} + // CHECK-MESSAGES-NOT: [[@LINE-1]]:{{\d*}}: warning: Use Pre-increment instead of Post-increment + while (J++) { + } + // CHECK-MESSAGES-NOT: [[@LINE-2]]:{{\d*}}: warning: Use Pre-increment instead of Post-increment + do { + } while (J++); + // CHECK-MESSAGES-NOT: [[@LINE-1]]:{{\d*}}: warning: Use Pre-increment instead of Post-increment + for (; J++;) { + } + // CHECK-MESSAGES-NOT: [[@LINE-2]]:{{\d*}}: warning: Use Pre-increment instead of Post-increment + J++ ? J-- : J++; + // CHECK-MESSAGES-NOT: [[@LINE-1]]:{{\d*}}: warning: Use Pre-increment instead of Post-increment + J++ ?: J--; + // CHECK-MESSAGES-NOT: [[@LINE-1]]:{{\d*}}: warning: Use Pre-increment instead of Post-increment + J++; + // CHECK-MESSAGES: [[@LINE-1]]:{{3}}: warning: Use Pre-increment instead of Post-increment + // 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-increment instead of Post-increment + // CHECK-FIXES: {{^}} ++Foobar.Bar.Bar; + Bar->Bar++; + // CHECK-MESSAGES: [[@LINE-1]]:3: warning: Use Pre-increment instead of Post-increment + // CHECK-FIXES: {{^}} ++Bar->Bar; + Foobar. + Bar. + Bar++; + // CHECK-MESSAGES: [[@LINE-3]]:3: warning: Use Pre-increment instead of Post-increment + // CHECK-FIXES: {{^}} ++Foobar. + // CHECK-FIXES-NEXT: {{^}} Bar. + // CHECK-FIXES-NEXT: {{^}} Bar; + return Bar->Bar++; +} diff --git a/clang-tools-extra/test/clang-tidy/checkers/llvm-prefer-pre-increment.cpp b/clang-tools-extra/test/clang-tidy/checkers/llvm-prefer-pre-increment.cpp new file mode 100644 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/llvm-prefer-pre-increment.cpp @@ -0,0 +1,82 @@ +// RUN: %check_clang_tidy %s llvm-prefer-pre-increment %t + +template +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 +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 It(&Array[0]); + It++; + // CHECK-MESSAGES: [[@LINE-1]]:3: warning: Use Pre-increment instead of Post-increment + // CHECK-FIXES: {{^}} ++It; + It--; + // CHECK-MESSAGES: [[@LINE-1]]:3: warning: Use Pre-decrement instead of Post-decrement + // CHECK-FIXES: {{^}} --It; + (*It)++; + // CHECK-MESSAGES: [[@LINE-1]]:3: warning: Use Pre-increment instead of Post-increment + // CHECK-FIXES: {{^}} ++(*It); + (*It)--; + // CHECK-MESSAGES: [[@LINE-1]]:3: warning: Use Pre-decrement instead of Post-decrement + // CHECK-FIXES: {{^}} --(*It); + + *It++; + // CHECK-MESSAGES-NOT: [[@LINE-1]]:{{\d*}}: warning: Use Pre-increment instead of Post-increment + *It--; + // CHECK-MESSAGES-NOT: [[@LINE-1]]:{{\d*}}: warning: Use Pre-decrement instead of Post-decrement + + PostfixIterator PfIt(&Array[0]); + PfIt++; + // CHECK-MESSAGES-NOT: [[@LINE-1]]:{{\d*}}: warning: Use Pre-increment instead of Post-increment + // CHECK-FIXES-NOT: {{^}} ++PfIt; + PfIt--; + // CHECK-MESSAGES-NOT: [[@LINE-1]]:{{\d*}}: warning: Use Pre-decrement instead of Post-decrement + // CHECK-FIXES-NOT: {{^}} --PfIt; + (*PfIt)++; + // CHECK-MESSAGES: [[@LINE-1]]:3: warning: Use Pre-increment instead of Post-increment + // CHECK-FIXES: {{^}} ++(*PfIt); + (*PfIt)--; + // CHECK-MESSAGES: [[@LINE-1]]:3: warning: Use Pre-decrement instead of Post-decrement + // CHECK-FIXES: {{^}} --(*PfIt); + + *PfIt++; + // CHECK-MESSAGES-NOT: [[@LINE-1]]:{{\d*}}: warning: Use Pre-increment instead of Post-increment + *PfIt--; + // CHECK-MESSAGES-NOT: [[@LINE-1]]:{{\d*}}: warning: Use Pre-decrement instead of Post-decrement +}