diff options
author | Miklos Vajna <vmiklos@vmiklos.hu> | 2019-01-11 07:59:47 +0000 |
---|---|---|
committer | Miklos Vajna <vmiklos@vmiklos.hu> | 2019-01-11 07:59:47 +0000 |
commit | 98ef5337c9dfab72ad8f93a83b6429dfd0da168e (patch) | |
tree | ca8a7fb7c972c6b88dcf918f44ff6b2358864325 /clang-tools-extra | |
parent | Revert "[SelectionDAGBuilder] Refactor GetRegistersForValue. NFCI." (diff) | |
download | llvm-project-98ef5337c9dfab72ad8f93a83b6429dfd0da168e.tar.gz llvm-project-98ef5337c9dfab72ad8f93a83b6429dfd0da168e.tar.bz2 llvm-project-98ef5337c9dfab72ad8f93a83b6429dfd0da168e.zip |
[clang-tidy] new check 'readability-redundant-preprocessor'
Finds potentially redundant preprocessor directives.
Reviewed By: aaron.ballman
Differential Revision: https://reviews.llvm.org/D54349
llvm-svn: 350922
Diffstat (limited to 'clang-tools-extra')
10 files changed, 340 insertions, 0 deletions
diff --git a/clang-tools-extra/clang-tidy/readability/CMakeLists.txt b/clang-tools-extra/clang-tidy/readability/CMakeLists.txt index c429b8126ce8..b48e307e6153 100644 --- a/clang-tools-extra/clang-tidy/readability/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/readability/CMakeLists.txt @@ -24,6 +24,7 @@ add_clang_library(clangTidyReadabilityModule RedundantDeclarationCheck.cpp RedundantFunctionPtrDereferenceCheck.cpp RedundantMemberInitCheck.cpp + RedundantPreprocessorCheck.cpp RedundantSmartptrGetCheck.cpp RedundantStringCStrCheck.cpp RedundantStringInitCheck.cpp diff --git a/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp b/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp index 8dab29688d21..e032d1f6887c 100644 --- a/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp +++ b/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp @@ -31,6 +31,7 @@ #include "RedundantDeclarationCheck.h" #include "RedundantFunctionPtrDereferenceCheck.h" #include "RedundantMemberInitCheck.h" +#include "RedundantPreprocessorCheck.h" #include "RedundantSmartptrGetCheck.h" #include "RedundantStringCStrCheck.h" #include "RedundantStringInitCheck.h" @@ -83,6 +84,8 @@ public: "readability-redundant-function-ptr-dereference"); CheckFactories.registerCheck<RedundantMemberInitCheck>( "readability-redundant-member-init"); + CheckFactories.registerCheck<RedundantPreprocessorCheck>( + "readability-redundant-preprocessor"); CheckFactories.registerCheck<SimplifySubscriptExprCheck>( "readability-simplify-subscript-expr"); CheckFactories.registerCheck<StaticAccessedThroughInstanceCheck>( diff --git a/clang-tools-extra/clang-tidy/readability/RedundantPreprocessorCheck.cpp b/clang-tools-extra/clang-tidy/readability/RedundantPreprocessorCheck.cpp new file mode 100644 index 000000000000..352e234644d9 --- /dev/null +++ b/clang-tools-extra/clang-tidy/readability/RedundantPreprocessorCheck.cpp @@ -0,0 +1,109 @@ +//===--- RedundantPreprocessorCheck.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 "RedundantPreprocessorCheck.h" +#include "clang/Frontend/CompilerInstance.h" + +namespace clang { +namespace tidy { +namespace readability { + +namespace { +/// Information about an opening preprocessor directive. +struct PreprocessorEntry { + SourceLocation Loc; + /// Condition used after the preprocessor directive. + std::string Condition; +}; + +class RedundantPreprocessorCallbacks : public PPCallbacks { + enum DirectiveKind { DK_If = 0, DK_Ifdef = 1, DK_Ifndef = 2 }; + +public: + explicit RedundantPreprocessorCallbacks(ClangTidyCheck &Check, + Preprocessor &PP) + : Check(Check), PP(PP), + WarningDescription("nested redundant %select{#if|#ifdef|#ifndef}0; " + "consider removing it"), + NoteDescription("previous %select{#if|#ifdef|#ifndef}0 was here") {} + + void If(SourceLocation Loc, SourceRange ConditionRange, + ConditionValueKind ConditionValue) override { + StringRef Condition = + Lexer::getSourceText(CharSourceRange::getTokenRange(ConditionRange), + PP.getSourceManager(), PP.getLangOpts()); + CheckMacroRedundancy(Loc, Condition, IfStack, DK_If, DK_If, true); + } + + void Ifdef(SourceLocation Loc, const Token &MacroNameTok, + const MacroDefinition &MacroDefinition) override { + std::string MacroName = PP.getSpelling(MacroNameTok); + CheckMacroRedundancy(Loc, MacroName, IfdefStack, DK_Ifdef, DK_Ifdef, true); + CheckMacroRedundancy(Loc, MacroName, IfndefStack, DK_Ifdef, DK_Ifndef, + false); + } + + void Ifndef(SourceLocation Loc, const Token &MacroNameTok, + const MacroDefinition &MacroDefinition) override { + std::string MacroName = PP.getSpelling(MacroNameTok); + CheckMacroRedundancy(Loc, MacroName, IfndefStack, DK_Ifndef, DK_Ifndef, + true); + CheckMacroRedundancy(Loc, MacroName, IfdefStack, DK_Ifndef, DK_Ifdef, + false); + } + + void Endif(SourceLocation Loc, SourceLocation IfLoc) override { + if (!IfStack.empty() && IfLoc == IfStack.back().Loc) + IfStack.pop_back(); + if (!IfdefStack.empty() && IfLoc == IfdefStack.back().Loc) + IfdefStack.pop_back(); + if (!IfndefStack.empty() && IfLoc == IfndefStack.back().Loc) + IfndefStack.pop_back(); + } + +private: + void CheckMacroRedundancy(SourceLocation Loc, StringRef MacroName, + SmallVector<PreprocessorEntry, 4> &Stack, + DirectiveKind WarningKind, DirectiveKind NoteKind, + bool Store) { + if (PP.getSourceManager().isInMainFile(Loc)) { + for (const auto &Entry : Stack) { + if (Entry.Condition == MacroName) { + Check.diag(Loc, WarningDescription) << WarningKind; + Check.diag(Entry.Loc, NoteDescription, DiagnosticIDs::Note) + << NoteKind; + } + } + } + + if (Store) + // This is an actual directive to be remembered. + Stack.push_back({Loc, MacroName}); + } + + ClangTidyCheck &Check; + Preprocessor &PP; + SmallVector<PreprocessorEntry, 4> IfStack; + SmallVector<PreprocessorEntry, 4> IfdefStack; + SmallVector<PreprocessorEntry, 4> IfndefStack; + const std::string WarningDescription; + const std::string NoteDescription; +}; +} // namespace + +void RedundantPreprocessorCheck::registerPPCallbacks( + CompilerInstance &Compiler) { + Compiler.getPreprocessor().addPPCallbacks( + ::llvm::make_unique<RedundantPreprocessorCallbacks>( + *this, Compiler.getPreprocessor())); +} + +} // namespace readability +} // namespace tidy +} // namespace clang diff --git a/clang-tools-extra/clang-tidy/readability/RedundantPreprocessorCheck.h b/clang-tools-extra/clang-tidy/readability/RedundantPreprocessorCheck.h new file mode 100644 index 000000000000..d44076568a70 --- /dev/null +++ b/clang-tools-extra/clang-tidy/readability/RedundantPreprocessorCheck.h @@ -0,0 +1,35 @@ +//===--- RedundantPreprocessorCheck.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_READABILITY_REDUNDANTPREPROCESSORCHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_REDUNDANTPREPROCESSORCHECK_H + +#include "../ClangTidy.h" + +namespace clang { +namespace tidy { +namespace readability { + +/// This check flags redundant preprocessor directives: nested directives with +/// the same condition. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/readability-redundant-preprocessor.html +class RedundantPreprocessorCheck : public ClangTidyCheck { +public: + RedundantPreprocessorCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + void registerPPCallbacks(CompilerInstance &Compiler) override; +}; + +} // namespace readability +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_REDUNDANTPREPROCESSORCHECK_H diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index f6cdc3efbdc0..8731dc73c648 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -244,6 +244,11 @@ Improvements to clang-tidy Detects usage of magic numbers, numbers that are used as literals instead of introduced via constants or symbols. +- New :doc:`readability-redundant-preprocessor + <clang-tidy/checks/readability-redundant-preprocessor>` check. + + Finds potentially redundant preprocessor directives. + - New :doc:`readability-uppercase-literal-suffix <clang-tidy/checks/readability-uppercase-literal-suffix>` check. diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst index b4a60e76c8ef..080e747bdfad 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/list.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst @@ -254,6 +254,7 @@ Clang-Tidy Checks readability-redundant-declaration readability-redundant-function-ptr-dereference readability-redundant-member-init + readability-redundant-preprocessor readability-redundant-smartptr-get readability-redundant-string-cstr readability-redundant-string-init diff --git a/clang-tools-extra/docs/clang-tidy/checks/readability-redundant-preprocessor.rst b/clang-tools-extra/docs/clang-tidy/checks/readability-redundant-preprocessor.rst new file mode 100644 index 000000000000..f013a3417d3b --- /dev/null +++ b/clang-tools-extra/docs/clang-tidy/checks/readability-redundant-preprocessor.rst @@ -0,0 +1,61 @@ +.. title:: clang-tidy - readability-redundant-preprocessor + +readability-redundant-preprocessor +================================== + +Finds potentially redundant preprocessor directives. At the moment the +following cases are detected: + +* `#ifdef` .. `#endif` pairs which are nested inside an outer pair with the + same condition. For example: + +.. code-block:: c++ + + #ifdef FOO + #ifdef FOO // inner ifdef is considered redundant + void f(); + #endif + #endif + +* Same for `#ifndef` .. `#endif` pairs. For example: + +.. code-block:: c++ + + #ifndef FOO + #ifndef FOO // inner ifndef is considered redundant + void f(); + #endif + #endif + +* `#ifndef` inside an `#ifdef` with the same condition: + +.. code-block:: c++ + + #ifdef FOO + #ifndef FOO // inner ifndef is considered redundant + void f(); + #endif + #endif + +* `#ifdef` inside an `#ifndef` with the same condition: + +.. code-block:: c++ + + #ifndef FOO + #ifdef FOO // inner ifdef is considered redundant + void f(); + #endif + #endif + +* `#if` .. `#endif` pairs which are nested inside an outer pair with the same + condition. For example: + +.. code-block:: c++ + + #define FOO 4 + #if FOO == 4 + #if FOO == 4 // inner if is considered redundant + void f(); + #endif + #endif + diff --git a/clang-tools-extra/test/clang-tidy/readability-redundant-preprocessor-ifdef.cpp b/clang-tools-extra/test/clang-tidy/readability-redundant-preprocessor-ifdef.cpp new file mode 100644 index 000000000000..72b608b1c2c0 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/readability-redundant-preprocessor-ifdef.cpp @@ -0,0 +1,36 @@ +// RUN: %check_clang_tidy %s readability-redundant-preprocessor %t -- -- -DFOO + +// Positive testing. +#ifdef FOO +// CHECK-NOTES: [[@LINE+1]]:2: warning: nested redundant #ifdef; consider removing it [readability-redundant-preprocessor] +#ifdef FOO +// CHECK-NOTES: [[@LINE-3]]:2: note: previous #ifdef was here +void f(); +#endif +#endif + +// Positive testing of inverted condition. +#ifdef FOO +// CHECK-NOTES: [[@LINE+1]]:2: warning: nested redundant #ifndef; consider removing it [readability-redundant-preprocessor] +#ifndef FOO +// CHECK-NOTES: [[@LINE-3]]:2: note: previous #ifdef was here +void f2(); +#endif +#endif + +// Negative testing. +#ifdef BAR +void g(); +#endif + +#ifdef FOO +#ifdef BAR +void h(); +#endif +#endif + +#ifdef FOO +#ifndef BAR +void i(); +#endif +#endif diff --git a/clang-tools-extra/test/clang-tidy/readability-redundant-preprocessor.cpp b/clang-tools-extra/test/clang-tidy/readability-redundant-preprocessor.cpp new file mode 100644 index 000000000000..6cffd8f43899 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/readability-redundant-preprocessor.cpp @@ -0,0 +1,84 @@ +// RUN: %check_clang_tidy %s readability-redundant-preprocessor %t -- -- -I %S + +// Positive testing. +#ifndef FOO +// CHECK-NOTES: [[@LINE+1]]:2: warning: nested redundant #ifndef; consider removing it [readability-redundant-preprocessor] +#ifndef FOO +// CHECK-NOTES: [[@LINE-3]]:2: note: previous #ifndef was here +void f(); +#endif +#endif + +// Positive testing of inverted condition. +#ifndef FOO +// CHECK-NOTES: [[@LINE+1]]:2: warning: nested redundant #ifdef; consider removing it [readability-redundant-preprocessor] +#ifdef FOO +// CHECK-NOTES: [[@LINE-3]]:2: note: previous #ifndef was here +void f2(); +#endif +#endif + +// Negative testing. +#include "readability-redundant-preprocessor.h" + +#ifndef BAR +void g(); +#endif + +#ifndef FOO +#ifndef BAR +void h(); +#endif +#endif + +#ifndef FOO +#ifdef BAR +void i(); +#endif +#endif + +// Positive #if testing. +#define FOO 4 + +#if FOO == 4 +// CHECK-NOTES: [[@LINE+1]]:2: warning: nested redundant #if; consider removing it [readability-redundant-preprocessor] +#if FOO == 4 +// CHECK-NOTES: [[@LINE-3]]:2: note: previous #if was here +void j(); +#endif +#endif + +#if FOO == 3 + 1 +// CHECK-NOTES: [[@LINE+1]]:2: warning: nested redundant #if; consider removing it [readability-redundant-preprocessor] +#if FOO == 3 + 1 +// CHECK-NOTES: [[@LINE-3]]:2: note: previous #if was here +void j(); +#endif +#endif + +#if FOO == \ + 4 +// CHECK-NOTES: [[@LINE+1]]:2: warning: nested redundant #if; consider removing it [readability-redundant-preprocessor] +#if FOO == \ + 4 +// CHECK-NOTES: [[@LINE-5]]:2: note: previous #if was here +void j(); +#endif +#endif + +// Negative #if testing. +#define BAR 4 + +#if FOO == 4 +#if BAR == 4 +void k(); +#endif +#endif + +#if FOO == \ + 4 +#if BAR == \ + 5 +void k(); +#endif +#endif diff --git a/clang-tools-extra/test/clang-tidy/readability-redundant-preprocessor.h b/clang-tools-extra/test/clang-tidy/readability-redundant-preprocessor.h new file mode 100644 index 000000000000..dfe5f9733afb --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/readability-redundant-preprocessor.h @@ -0,0 +1,5 @@ +#ifndef FOO +#ifndef FOO // this would warn, but not in a header +void f(); +#endif +#endif |