Index: clang-tidy/readability/CMakeLists.txt =================================================================== --- clang-tidy/readability/CMakeLists.txt +++ clang-tidy/readability/CMakeLists.txt @@ -7,6 +7,7 @@ FunctionSize.cpp NamespaceCommentCheck.cpp ReadabilityTidyModule.cpp + RedundantInclude.cpp RedundantSmartptrGet.cpp ShrinkToFitCheck.cpp Index: clang-tidy/readability/ReadabilityTidyModule.cpp =================================================================== --- clang-tidy/readability/ReadabilityTidyModule.cpp +++ clang-tidy/readability/ReadabilityTidyModule.cpp @@ -14,6 +14,7 @@ #include "ContainerSizeEmpty.h" #include "ElseAfterReturnCheck.h" #include "FunctionSize.h" +#include "RedundantInclude.h" #include "RedundantSmartptrGet.h" #include "ShrinkToFitCheck.h" @@ -32,10 +33,11 @@ "readability-else-after-return"); CheckFactories.registerCheck( "readability-function-size"); + CheckFactories.registerCheck( + "readability-redundant-include"); CheckFactories.registerCheck( "readability-redundant-smartptr-get"); - CheckFactories.registerCheck( - "readability-shrink-to-fit"); + CheckFactories.registerCheck("readability-shrink-to-fit"); } }; @@ -43,7 +45,7 @@ // Register the MiscTidyModule using this statically initialized variable. static ClangTidyModuleRegistry::Add -X("readability-module", "Adds readability-related checks."); + X("readability-module", "Adds readability-related checks."); // This anchor is used to force the linker to link in the generated object file // and thus register the MiscModule. Index: clang-tidy/readability/RedundantInclude.h =================================================================== --- /dev/null +++ clang-tidy/readability/RedundantInclude.h @@ -0,0 +1,32 @@ +//===--- RedundantInclude.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_REDUNDANT_INCLUDE_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_REDUNDANT_INCLUDE_H + +#include +#include "../ClangTidy.h" + +namespace clang { +namespace tidy { +namespace readability { + +class RedundantInclude : public ClangTidyCheck { +public: + RedundantInclude(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_REDUNDANT_INCLUDE_H Index: clang-tidy/readability/RedundantInclude.cpp =================================================================== --- /dev/null +++ clang-tidy/readability/RedundantInclude.cpp @@ -0,0 +1,101 @@ +//===--- RedundantInclude.cpp - clang-tidy-----------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "RedundantInclude.h" +#include "../ClangTidy.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Lex/Preprocessor.h" +#include +#include + +namespace clang { +namespace tidy { +namespace readability { + +namespace { + +SourceLocation AdvanceBeyondCurrentLine(SourceManager &SM, SourceLocation Start, + int Offset) { + const auto Id = SM.getFileID(Start); + const auto LineNumber = SM.getSpellingLineNumber(Start); + while (SM.getFileID(Start) == Id && + SM.getSpellingLineNumber(Start.getLocWithOffset(Offset)) == + LineNumber) { + Start = Start.getLocWithOffset(Offset); + } + return Start; +} + +class RedundantIncludeCallbacks : public PPCallbacks { +public: + RedundantIncludeCallbacks(RedundantInclude &Check, SourceManager &SM) + : Check_(Check), SM_(SM) {} + + void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok, + StringRef FileName, bool IsAngled, + CharSourceRange FilenameRange, const FileEntry *File, + StringRef SearchPath, StringRef RelativePath, + const Module *Imported) override; + + void MacroDefined(const Token &MacroNameTok, + const MacroDirective *MD) override; + + void MacroUndefined(const Token &MacroNameTok, + const MacroDirective *MD) override; + +private: + std::vector Files_; + RedundantInclude &Check_; + SourceManager &SM_; +}; + +void RedundantIncludeCallbacks::InclusionDirective( + SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName, + bool IsAngled, CharSourceRange FilenameRange, const FileEntry *File, + StringRef SearchPath, StringRef RelativePath, const Module *Imported) { + if (!SM_.isInMainFile(HashLoc)) { + return; + } + + if (std::find(Files_.cbegin(), Files_.cend(), FileName) != Files_.end()) { + const auto Start = + AdvanceBeyondCurrentLine(SM_, HashLoc, -1).getLocWithOffset(-1); + const auto End = AdvanceBeyondCurrentLine(SM_, FilenameRange.getEnd(), 1); + Check_.diag(HashLoc, "redundant include") + << FixItHint::CreateRemoval(SourceRange(Start, End)); + } else { + Files_.push_back(FileName); + } +} + +void RedundantIncludeCallbacks::MacroDefined(const Token &MacroNameTok, + const MacroDirective *MD) { + if (SM_.isInMainFile(MacroNameTok.getLocation())) { + Files_.clear(); + } +} + +void RedundantIncludeCallbacks::MacroUndefined(const Token &MacroNameTok, + const MacroDirective *MD) { + if (SM_.isInMainFile(MacroNameTok.getLocation())) { + Files_.clear(); + } +} + +} // namespace + +void RedundantInclude::registerPPCallbacks(CompilerInstance &Compiler) { + Compiler.getPreprocessor().addPPCallbacks( + llvm::make_unique( + *this, Compiler.getSourceManager())); +} + +} // namespace readability +} // namespace tidy +} // namespace clang Index: test/clang-tidy/readability-redundant-include.cpp =================================================================== --- /dev/null +++ test/clang-tidy/readability-redundant-include.cpp @@ -0,0 +1,73 @@ +// RUN: $(dirname %s)/check_clang_tidy.sh %s readability-redundant-include %t -- -std=c++11 -I$(dirname %s) +// REQUIRES: shell + +int a; +#include +int b; +#include +int c; +// CHECK-MESSAGES: :[[@LINE-2]]:1: warning: redundant include [readability-redundant-include] +// CHECK-FIXES: {{^int a;$}} +// CHECK-FIXES-NEXT: {{^#include $}} +// CHECK-FIXES-NEXT: {{^int b;$}} +// CHECK-FIXES-NEXT: {{^int c;$}} + +int d; +#include +int e; +#include // extra stuff that will also be removed +int f; +// CHECK-MESSAGES: :[[@LINE-2]]:1: warning: {{.*}} +// CHECK-FIXES: {{^int d;$}} +// CHECK-FIXES-NEXT: {{^#include $}} +// CHECK-FIXES-NEXT: {{^int e;$}} +// CHECK-FIXES-NEXT: {{^int f;$}} + +int g; +#include "readability-redundant-include.h" +int h; +#include "readability-redundant-include.h" +int i; +// CHECK-MESSAGES: :[[@LINE-2]]:1: warning: {{.*}} +// CHECK-FIXES: {{^int g;$}} +// CHECK-FIXES-NEXT: {{^#include "readability-redundant-include.h"$}} +// CHECK-FIXES-NEXT: {{^int h;$}} +// CHECK-FIXES-NEXT: {{^int i;$}} + +#include "types.h" + +int j; +#include +int k; +#include +int l; +// CHECK-MESSAGES: :[[@LINE-2]]:1: warning: {{.*}} +// CHECK-FIXES: {{^int j;$}} +// CHECK-FIXES-NEXT: {{^#include $}} +// CHECK-FIXES-NEXT: {{^int k;$}} +// CHECK-FIXES-NEXT: {{^int l;$}} + +int m; + # include // lots of space +int n; +// CHECK-MESSAGES: :[[@LINE-2]]:9: warning: {{.*}} +// CHECK-FIXES: {{^int m;$}} +// CHECK-FIXES-NEXT: {{^int n;$}} + +// defining a macro in the main file resets the included file cache +#define ARBITRARY_MACRO +int o; +#include +int p; +// CHECK-FIXES: {{^int o;$}} +// CHECK-FIXES-NEXT: {{^#include $}} +// CHECK-FIXES-NEXT: {{^int p;$}} + +// undefining a macro resets the cache +#undef ARBITRARY_MACRO +int q; +#include +int r; +// CHECK-FIXES: {{^int q;$}} +// CHECK-FIXES-NEXT: {{^#include $}} +// CHECK-FIXES-NEXT: {{^int r;$}} Index: test/clang-tidy/types.h =================================================================== --- /dev/null +++ test/clang-tidy/types.h @@ -0,0 +1 @@ +// empty file used by readability-redundant-include.cpp