Index: clang-tidy/readability/CMakeLists.txt =================================================================== --- clang-tidy/readability/CMakeLists.txt +++ clang-tidy/readability/CMakeLists.txt @@ -20,6 +20,7 @@ NamespaceCommentCheck.cpp NonConstParameterCheck.cpp ReadabilityTidyModule.cpp + RedundantPpCheck.cpp RedundantControlFlowCheck.cpp RedundantDeclarationCheck.cpp RedundantFunctionPtrDereferenceCheck.cpp Index: clang-tidy/readability/ReadabilityTidyModule.cpp =================================================================== --- clang-tidy/readability/ReadabilityTidyModule.cpp +++ clang-tidy/readability/ReadabilityTidyModule.cpp @@ -31,6 +31,7 @@ #include "RedundantDeclarationCheck.h" #include "RedundantFunctionPtrDereferenceCheck.h" #include "RedundantMemberInitCheck.h" +#include "RedundantPpCheck.h" #include "RedundantSmartptrGetCheck.h" #include "RedundantStringCStrCheck.h" #include "RedundantStringInitCheck.h" @@ -79,6 +80,7 @@ "readability-misleading-indentation"); CheckFactories.registerCheck( "readability-misplaced-array-index"); + CheckFactories.registerCheck("readability-redundant-pp"); CheckFactories.registerCheck( "readability-redundant-function-ptr-dereference"); CheckFactories.registerCheck( Index: clang-tidy/readability/RedundantPpCheck.h =================================================================== --- /dev/null +++ clang-tidy/readability/RedundantPpCheck.h @@ -0,0 +1,34 @@ +//===--- RedundantPpCheck.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_REDUNDANTPPCHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_REDUNDANTPPCHECK_H + +#include "../ClangTidy.h" + +namespace clang { +namespace tidy { +namespace readability { + +/// This check flags redundant preprocessor usage. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/readability-redundant-pp.html +class RedundantPpCheck : public ClangTidyCheck { +public: + RedundantPpCheck(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_REDUNDANTPPCHECK_H Index: clang-tidy/readability/RedundantPpCheck.cpp =================================================================== --- /dev/null +++ clang-tidy/readability/RedundantPpCheck.cpp @@ -0,0 +1,94 @@ +//===--- RedundantPpCheck.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 "RedundantPpCheck.h" +#include "clang/Frontend/CompilerInstance.h" + +namespace clang { +namespace tidy { +namespace readability { + +namespace { +struct Entry { + SourceLocation Loc; + std::string MacroName; +}; + +class RedundantPPCallbacks : public PPCallbacks { +public: + explicit RedundantPPCallbacks(ClangTidyCheck &Check, + Preprocessor &Preprocessor); + + void Ifdef(clang::SourceLocation aLoc, const clang::Token &rMacroNameTok, + const clang::MacroDefinition &rMacroDefinition) override; + void Ifndef(clang::SourceLocation aLoc, const clang::Token &rMacroNameTok, + const clang::MacroDefinition &rMacroDefinition) override; + void Endif(clang::SourceLocation aLoc, clang::SourceLocation aIfLoc) override; + +private: + ClangTidyCheck &Check; + Preprocessor &PP; + std::vector IfdefStack; + std::vector IfndefStack; +}; +} // namespace + +void RedundantPpCheck::registerPPCallbacks(CompilerInstance &Compiler) { + Compiler.getPreprocessor().addPPCallbacks( + ::llvm::make_unique(*this, + Compiler.getPreprocessor())); +} + +RedundantPPCallbacks::RedundantPPCallbacks(ClangTidyCheck &Check, + Preprocessor &PP) + : Check(Check), PP(PP) {} + +void RedundantPPCallbacks::Ifdef( + clang::SourceLocation Loc, const clang::Token &MacroNameTok, + const clang::MacroDefinition & /*MacroDefinition*/) { + std::string MacroName = PP.getSpelling(MacroNameTok); + if (PP.getSourceManager().isInMainFile(Loc)) { + for (const auto &Entry : IfdefStack) { + if (Entry.MacroName == MacroName) { + Check.diag(Loc, "nested redundant ifdef; consider removing it"); + Check.diag(Entry.Loc, "previous ifdef was here", DiagnosticIDs::Note); + } + } + } + + IfdefStack.push_back({Loc, MacroName}); +} + +void RedundantPPCallbacks::Ifndef( + clang::SourceLocation Loc, const clang::Token &MacroNameTok, + const clang::MacroDefinition & /*MacroDefinition*/) { + std::string MacroName = PP.getSpelling(MacroNameTok); + if (PP.getSourceManager().isInMainFile(Loc)) { + for (const auto &Entry : IfndefStack) { + if (Entry.MacroName == MacroName) { + Check.diag(Loc, "nested redundant ifndef; consider removing it"); + Check.diag(Entry.Loc, "previous ifndef was here", DiagnosticIDs::Note); + } + } + } + + IfndefStack.push_back({Loc, MacroName}); +} + +void RedundantPPCallbacks::Endif(clang::SourceLocation /*Loc*/, + clang::SourceLocation IfLoc) { + if (!IfdefStack.empty() && IfLoc == IfdefStack.back().Loc) + IfdefStack.pop_back(); + if (!IfndefStack.empty() && IfLoc == IfndefStack.back().Loc) + IfndefStack.pop_back(); +} + +} // namespace readability +} // namespace tidy +} // namespace clang Index: docs/ReleaseNotes.rst =================================================================== --- docs/ReleaseNotes.rst +++ docs/ReleaseNotes.rst @@ -67,6 +67,12 @@ Improvements to clang-tidy -------------------------- +- New :doc:`readability-redundant-pp + ` check. + + Finds potentially redundant preprocessor usage. + + - New :doc:`abseil-duration-division ` check. Index: docs/clang-tidy/checks/list.rst =================================================================== --- docs/clang-tidy/checks/list.rst +++ docs/clang-tidy/checks/list.rst @@ -240,6 +240,7 @@ readability-misplaced-array-index readability-named-parameter readability-non-const-parameter + readability-redundant-pp readability-redundant-control-flow readability-redundant-declaration readability-redundant-function-ptr-dereference Index: docs/clang-tidy/checks/readability-redundant-pp.rst =================================================================== --- /dev/null +++ docs/clang-tidy/checks/readability-redundant-pp.rst @@ -0,0 +1,11 @@ +.. title:: clang-tidy - readability-redundant-pp + +readability-redundant-pp +========================= + +Finds potentially redundant preprocessor usage. At the moment the following cases are detected: + +* `#ifdef` .. `#endif` pairs which are nested inside an outer pair with the + same condition. + +* Same for `#ifndef` .. `#endif` pairs. Index: test/clang-tidy/readability-redundant-pp-ifdef.cpp =================================================================== --- /dev/null +++ test/clang-tidy/readability-redundant-pp-ifdef.cpp @@ -0,0 +1,21 @@ +// RUN: %check_clang_tidy %s readability-redundant-pp %t -- -- -DFOO + +// Positive testing. +#ifdef FOO +// CHECK-NOTES: [[@LINE+1]]:2: warning: nested redundant ifdef; consider removing it [readability-redundant-pp] +#ifdef FOO +// CHECK-NOTES: [[@LINE-3]]:2: note: previous ifdef was here +void f(); +#endif +#endif + +// Negative testing. +#ifdef BAR +void g(); +#endif + +#ifdef FOO +#ifdef BAR +void h(); +#endif +#endif Index: test/clang-tidy/readability-redundant-pp.cpp =================================================================== --- /dev/null +++ test/clang-tidy/readability-redundant-pp.cpp @@ -0,0 +1,21 @@ +// RUN: %check_clang_tidy %s readability-redundant-pp %t + +// Positive testing. +#ifndef FOO +// CHECK-NOTES: [[@LINE+1]]:2: warning: nested redundant ifndef; consider removing it [readability-redundant-pp] +#ifndef FOO +// CHECK-NOTES: [[@LINE-3]]:2: note: previous ifndef was here +void f(); +#endif +#endif + +// Negative testing. +#ifndef BAR +void g(); +#endif + +#ifndef FOO +#ifndef BAR +void h(); +#endif +#endif