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 @@ -13,6 +13,7 @@ LINK_LIBS clangTidy + clangTidyPerformanceModule clangTidyReadabilityModule clangTidyUtils 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 @@ -9,6 +9,7 @@ #include "../ClangTidy.h" #include "../ClangTidyModule.h" #include "../ClangTidyModuleRegistry.h" +#include "../performance/PreferPreIncrementCheck.h" #include "../readability/ElseAfterReturnCheck.h" #include "../readability/NamespaceCommentCheck.h" #include "../readability/QualifiedAutoCheck.h" @@ -33,6 +34,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( diff --git a/clang-tools-extra/clang-tidy/performance/CMakeLists.txt b/clang-tools-extra/clang-tidy/performance/CMakeLists.txt --- a/clang-tools-extra/clang-tidy/performance/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/performance/CMakeLists.txt @@ -15,6 +15,7 @@ NoAutomaticMoveCheck.cpp NoexceptMoveConstructorCheck.cpp PerformanceTidyModule.cpp + PreferPreIncrementCheck.cpp TriviallyDestructibleCheck.cpp TypePromotionInMathFnCheck.cpp UnnecessaryCopyInitialization.cpp 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 @@ -19,6 +19,7 @@ #include "MoveConstructorInitCheck.h" #include "NoAutomaticMoveCheck.h" #include "NoexceptMoveConstructorCheck.h" +#include "PreferPreIncrementCheck.h" #include "TriviallyDestructibleCheck.h" #include "TypePromotionInMathFnCheck.h" #include "UnnecessaryCopyInitialization.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/clang-tidy/performance/PreferPreIncrementCheck.h b/clang-tools-extra/clang-tidy/performance/PreferPreIncrementCheck.h new file mode 100644 --- /dev/null +++ b/clang-tools-extra/clang-tidy/performance/PreferPreIncrementCheck.h @@ -0,0 +1,42 @@ +//===--- 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_PERFORMANCE_PREFERPREINCREMENTCHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_PREFERPREINCREMENTCHECK_H + +#include "../ClangTidyCheck.h" + +namespace clang { +namespace tidy { +namespace performance { + +/// 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/performance-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: + void processMatch(SourceRange Range, SourceLocation OperatorLoc, + bool IsIncrement, bool WarnOnly); + + const bool TransformCxxOpCalls; + const bool TransformDependentType; +}; + +} // namespace performance +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_PREFERPREINCREMENTCHECK_H diff --git a/clang-tools-extra/clang-tidy/performance/PreferPreIncrementCheck.cpp b/clang-tools-extra/clang-tidy/performance/PreferPreIncrementCheck.cpp new file mode 100644 --- /dev/null +++ b/clang-tools-extra/clang-tidy/performance/PreferPreIncrementCheck.cpp @@ -0,0 +1,124 @@ +//===--- 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/ASTMatchers/ASTMatchers.h" +#include "clang/Tooling/FixIt.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace performance { + +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", true)), + TransformDependentType(Options.get("TransformDependentType", false)) {} + +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, + unless(isInTemplateInstantiation())) + .bind("op++"), + this); + Finder->addMatcher(unaryOperator(isOperator(UnaryOperatorKind::UO_PostDec), + UnusedInParent, + unless(isInTemplateInstantiation())) + .bind("op--"), + this); + + if (!getLangOpts().CPlusPlus || !TransformCxxOpCalls) + return; + + auto FindCxxOpCalls = [&](llvm::StringRef PostfixName) { + Finder->addMatcher( + cxxOperatorCallExpr( + UnusedInParent, unless(isInTemplateInstantiation()), + callee(cxxMethodDecl( + hasName(PostfixName), parameterCountIs(1), + hasParent(cxxRecordDecl(hasMethod(cxxMethodDecl( + hasName(PostfixName), parameterCountIs(0)))))))) + .bind(PostfixName), + this); + }; + FindCxxOpCalls("operator++"); + FindCxxOpCalls("operator--"); +} + +void PreferPreIncrementCheck::processMatch(SourceRange Range, + SourceLocation OperatorLoc, + bool IsIncrement, bool WarnOnly) { + // 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 (WarnOnly) + return; + if (OperatorLoc.isMacroID() || Range.getBegin().isMacroID() || + Range.getEnd().isMacroID()) + return; + Diag << tooling::fixit::createRemoval(OperatorLoc); + Diag << FixItHint::CreateInsertion(Range.getBegin(), + IsIncrement ? "++" : "--"); +} + +void PreferPreIncrementCheck::check(const MatchFinder::MatchResult &Result) { + auto ShouldWarnOnly = [&](const Expr *E) -> bool { + return !TransformDependentType && E->getType()->isDependentType(); + }; + if (const auto *UnaryOp = Result.Nodes.getNodeAs("op++")) + return processMatch(UnaryOp->getSourceRange(), UnaryOp->getOperatorLoc(), + true, ShouldWarnOnly(UnaryOp)); + if (const auto *UnaryOp = Result.Nodes.getNodeAs("op--")) + return processMatch(UnaryOp->getSourceRange(), UnaryOp->getOperatorLoc(), + false, ShouldWarnOnly(UnaryOp)); + if (const auto *OpCall = + Result.Nodes.getNodeAs("operator++")) + return processMatch(OpCall->getSourceRange(), OpCall->getOperatorLoc(), + true, ShouldWarnOnly(OpCall)); + if (const auto *OpCall = + Result.Nodes.getNodeAs("operator--")) + return processMatch(OpCall->getSourceRange(), OpCall->getOperatorLoc(), + false, ShouldWarnOnly(OpCall)); +} + +} // namespace performance +} // namespace tidy +} // namespace clang 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 @@ -106,11 +106,25 @@ Finds condition variables in nested ``if`` statements that were also checked in the outer ``if`` statement and were not changed. +- New :doc:`performance-prefer-pre-increment + ` check. + + Flags usages of postfix increment and decrement which could be swapped for + their prefix alternatives. + - New :doc:`readability-function-cognitive-complexity ` check. Flags functions with Cognitive Complexity metric exceeding the configured limit. +New check aliases +^^^^^^^^^^^^^^^^^ + +- New alias :doc:`llvm-prefer-pre-increment + ` to + :doc:`performance-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 @@ -262,6 +262,7 @@ `performance-move-constructor-init `_, "Yes" `performance-no-automatic-move `_, `performance-noexcept-move-constructor `_, "Yes" + `performance-prefer-pre-increment `_, "Yes" `performance-trivially-destructible `_, "Yes" `performance-type-promotion-in-math-fn `_, "Yes" `performance-unnecessary-copy-initialization `_, @@ -428,4 +429,5 @@ `hicpp-use-override `_, `modernize-use-override `_, "Yes" `hicpp-vararg `_, `cppcoreguidelines-pro-type-vararg `_, `llvm-else-after-return `_, `readability-else-after-return `_, "Yes" + `llvm-prefer-pre-increment `_, `performance-prefer-pre-increment `_, "Yes" `llvm-qualified-auto `_, `readability-qualified-auto `_, "Yes" 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,10 @@ +.. title:: clang-tidy - llvm-prefer-pre-increment +.. meta:: + :http-equiv=refresh: 5;URL=performance-prefer-pre-increment.html + +llvm-prefer-pre-increment +========================= + +The llvm-prefer-pre-increment check is an alias, please see +`performance-prefer-pre-increment `_ +for more information. 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,57 @@ +.. title:: clang-tidy - performance-prefer-pre-increment + +performance-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 + + When set to `1`, this enables checking postfix operations on classes and + structures that overload both the prefix and postfix operator ``++`` or + ``--``. + Default value is `1`. + +.. option:: TransformDependentType + + When set to `1`, this will change all postfix operators that are template + dependent to their prefix variation. This can cause errors if instantiations + don't overload the prefix ``++`` or ``--`` operator. + Default value is `0`. + +.. code-block:: c++ + + template + void Inc(T& val) { + val++; + } + +When `TransformDependentType` is set to `1` becomes: + +.. code-block:: c++ + + template + void Inc(T& val) { + ++val; + } + +This check helps to enforce this `LLVM Coding Standards recommendation +`_. diff --git a/clang-tools-extra/test/clang-tidy/checkers/Inputs/performance-prefer-pre-increment/iterator.h b/clang-tools-extra/test/clang-tidy/checkers/Inputs/performance-prefer-pre-increment/iterator.h new file mode 100644 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/Inputs/performance-prefer-pre-increment/iterator.h @@ -0,0 +1,44 @@ +#ifndef PERFORMANCE_PREFER_PRE_INCREMENT_ITERATOR_H +#define PERFORMANCE_PREFER_PRE_INCREMENT_ITERATOR_H + +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; + } +}; + +#endif // PERFORMANCE_PREFER_PRE_INCREMENT_ITERATOR_H diff --git a/clang-tools-extra/test/clang-tidy/checkers/performance-prefer-pre-increment-disable-cpp-opcalls.cpp b/clang-tools-extra/test/clang-tidy/checkers/performance-prefer-pre-increment-disable-cpp-opcalls.cpp new file mode 100644 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/performance-prefer-pre-increment-disable-cpp-opcalls.cpp @@ -0,0 +1,47 @@ +// RUN: %check_clang_tidy %s performance-prefer-pre-increment %t -- \ +// RUN: -config='{CheckOptions: \ +// RUN: [{key: performance-prefer-pre-increment.TransformCxxOpCalls, value: 0}]}' \ +// RUN: -- -I%S/Inputs/performance-prefer-pre-increment + +#include "iterator.h" + +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/performance-prefer-pre-increment.c b/clang-tools-extra/test/clang-tidy/checkers/performance-prefer-pre-increment.c new file mode 100644 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/performance-prefer-pre-increment.c @@ -0,0 +1,128 @@ +// RUN: %check_clang_tidy %s performance-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 +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wgnu-conditional-omitted-operand" + J++ ?: J--; + // CHECK-MESSAGES-NOT: [[@LINE-1]]:{{\d*}}: warning: Use pre-increment instead of post-increment +#pragma clang diagnostic pop + 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; + // clang-format off + 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; + // clang-format on + return Bar->Bar++; +} diff --git a/clang-tools-extra/test/clang-tidy/checkers/performance-prefer-pre-increment.cpp b/clang-tools-extra/test/clang-tidy/checkers/performance-prefer-pre-increment.cpp new file mode 100644 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/performance-prefer-pre-increment.cpp @@ -0,0 +1,63 @@ +// RUN: %check_clang_tidy %s performance-prefer-pre-increment %t -- -- \ +// RUN: -I%S/Inputs/performance-prefer-pre-increment + +#include "iterator.h" + +class IntIterator : public Iterator { + using Iterator::Iterator; +}; + +void foo() { + int Array[32]; + Iterator It(&Array[0]); + It++; // fooNormal + // CHECK-MESSAGES: [[@LINE-1]]:3: warning: Use pre-increment instead of post-increment + // CHECK-FIXES: {{^}} ++It; // fooNormal + It--; // fooNormal + // CHECK-MESSAGES: [[@LINE-1]]:3: warning: Use pre-decrement instead of post-decrement + // CHECK-FIXES: {{^}} --It; // fooNormal + (*It)++; // fooNormal + // CHECK-MESSAGES: [[@LINE-1]]:3: warning: Use pre-increment instead of post-increment + // CHECK-FIXES: {{^}} ++(*It); // fooNormal + (*It)--; // fooNormal + // CHECK-MESSAGES: [[@LINE-1]]:3: warning: Use pre-decrement instead of post-decrement + // CHECK-FIXES: {{^}} --(*It); // fooNormal + *It++; // fooNormal + *It--; // fooNormal + + PostfixIterator PfIt(&Array[0]); + PfIt++; // fooPostfix + PfIt--; // fooPostfix + (*PfIt)++; // fooPostfix + // CHECK-MESSAGES: [[@LINE-1]]:3: warning: Use pre-increment instead of post-increment + // CHECK-FIXES: {{^}} ++(*PfIt); // fooPostfix + (*PfIt)--; // fooPostfix + // CHECK-MESSAGES: [[@LINE-1]]:3: warning: Use pre-decrement instead of post-decrement + // CHECK-FIXES: {{^}} --(*PfIt); // fooPostfix + *PfIt++; // fooPostfix + *PfIt--; // fooPostfix + + IntIterator IntIt(&Array[0]); + IntIt++; + // CHECK-MESSAGES: [[@LINE-1]]:3: warning: Use pre-increment instead of post-increment + // CHECK-FIXES: {{^}} ++IntIt; + IntIt--; + // CHECK-MESSAGES: [[@LINE-1]]:3: warning: Use pre-decrement instead of post-decrement + // CHECK-FIXES: {{^}} --IntIt; + (*IntIt)++; + // CHECK-MESSAGES: [[@LINE-1]]:3: warning: Use pre-increment instead of post-increment + // CHECK-FIXES: {{^}} ++(*IntIt); + (*IntIt)--; + // CHECK-MESSAGES: [[@LINE-1]]:3: warning: Use pre-decrement instead of post-decrement + // CHECK-FIXES: {{^}} --(*IntIt); + *IntIt++; + *IntIt--; +} + +template +void tempDependent() { + typename T::iterator it; + it++; //depType + // CHECK-MESSAGES: [[@LINE-1]]:3: warning: Use pre-increment instead of post-increment + // CHECK-FIXES-NOT: {{^}} ++it; //depType +}