Index: clang-tidy/readability/CMakeLists.txt =================================================================== --- clang-tidy/readability/CMakeLists.txt +++ clang-tidy/readability/CMakeLists.txt @@ -3,6 +3,7 @@ add_clang_library(clangTidyReadabilityModule BracesAroundStatementsCheck.cpp ContainerSizeEmpty.cpp + DuplicateIncludeCheck.cpp ElseAfterReturnCheck.cpp FunctionSize.cpp NamespaceCommentCheck.cpp Index: clang-tidy/readability/DuplicateIncludeCheck.h =================================================================== --- /dev/null +++ clang-tidy/readability/DuplicateIncludeCheck.h @@ -0,0 +1,36 @@ +//===--- DuplicateIncludeCheck.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_DUPLICATE_INCLUDE_CHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_DUPLICATE_INCLUDE_CHECK_H + +#include +#include "../ClangTidy.h" + +namespace clang { +namespace tidy { +namespace readability { + +/// \brief Find and remove duplicate #include directives. +/// +/// Only consecutive include directives without any other preprocessor +/// directives between them are analyzed. +class DuplicateIncludeCheck : public ClangTidyCheck { +public: + DuplicateIncludeCheck(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_DUPLICATE_INCLUDE_CHECK_H Index: clang-tidy/readability/DuplicateIncludeCheck.cpp =================================================================== --- /dev/null +++ clang-tidy/readability/DuplicateIncludeCheck.cpp @@ -0,0 +1,101 @@ +//===--- DuplicateIncludeCheck.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 "DuplicateIncludeCheck.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 FileID Id = SM.getFileID(Start); + const unsigned LineNumber = SM.getSpellingLineNumber(Start); + while (SM.getFileID(Start) == Id && + SM.getSpellingLineNumber(Start.getLocWithOffset(Offset)) == + LineNumber) { + Start = Start.getLocWithOffset(Offset); + } + return Start; +} + +class DuplicateIncludeCallbacks : public PPCallbacks { +public: + DuplicateIncludeCallbacks(DuplicateIncludeCheck &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_; + DuplicateIncludeCheck &Check_; + SourceManager &SM_; +}; + +void DuplicateIncludeCallbacks::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, "duplicate include") + << FixItHint::CreateRemoval(SourceRange(Start, End)); + } else { + Files_.push_back(FileName); + } +} + +void DuplicateIncludeCallbacks::MacroDefined(const Token &MacroNameTok, + const MacroDirective *MD) { + if (SM_.isInMainFile(MacroNameTok.getLocation())) { + Files_.clear(); + } +} + +void DuplicateIncludeCallbacks::MacroUndefined(const Token &MacroNameTok, + const MacroDirective *MD) { + if (SM_.isInMainFile(MacroNameTok.getLocation())) { + Files_.clear(); + } +} + +} // namespace + +void DuplicateIncludeCheck::registerPPCallbacks(CompilerInstance &Compiler) { + Compiler.getPreprocessor().addPPCallbacks( + llvm::make_unique( + *this, Compiler.getSourceManager())); +} + +} // namespace readability +} // namespace tidy +} // namespace clang Index: clang-tidy/readability/ReadabilityTidyModule.cpp =================================================================== --- clang-tidy/readability/ReadabilityTidyModule.cpp +++ clang-tidy/readability/ReadabilityTidyModule.cpp @@ -12,6 +12,7 @@ #include "../ClangTidyModuleRegistry.h" #include "BracesAroundStatementsCheck.h" #include "ContainerSizeEmpty.h" +#include "DuplicateIncludeCheck.h" #include "ElseAfterReturnCheck.h" #include "FunctionSize.h" #include "RedundantSmartptrGet.h" @@ -28,14 +29,15 @@ "readability-braces-around-statements"); CheckFactories.registerCheck( "readability-container-size-empty"); + CheckFactories.registerCheck( + "readability-duplicate-include"); CheckFactories.registerCheck( "readability-else-after-return"); CheckFactories.registerCheck( "readability-function-size"); 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: test/clang-tidy/readability-duplicate-include.cpp =================================================================== --- /dev/null +++ test/clang-tidy/readability-duplicate-include.cpp @@ -0,0 +1,73 @@ +// RUN: $(dirname %s)/check_clang_tidy.sh %s readability-duplicate-include %t -- -std=c++11 -I$(dirname %s) +// REQUIRES: shell + +int a; +#include +int b; +#include +int c; +// CHECK-MESSAGES: :[[@LINE-2]]:1: warning: duplicate include [readability-duplicate-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-duplicate-include.h" +int h; +#include "readability-duplicate-include.h" +int i; +// CHECK-MESSAGES: :[[@LINE-2]]:1: warning: {{.*}} +// CHECK-FIXES: {{^int g;$}} +// CHECK-FIXES-NEXT: {{^#include "readability-duplicate-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