Hi alexfh,
This check looks for redundant header file inclusion.
Every time a `#include` is processed in the main file, it checks a vector of
filenames to see if the included file has already been included. If so, it
issues a warning and a replacement to remove the entire line containing the
duplicated include directive.
When a macro is defined or undefined in the main file, the vector of filenames
is cleared. This enables the following use case:
```
class LangOptionsBase {
public:
// Define simple language options (with no accessors).
#define LANGOPT(Name, Bits, Default, Description) unsigned Name : Bits;
#define ENUM_LANGOPT(Name, Type, Bits, Default, Description)
#include "clang/Basic/LangOptions.def"
protected:
// Define language options of enumeration type. These are private, and will
// have accessors (below).
#define LANGOPT(Name, Bits, Default, Description)
#define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \
unsigned Name : Bits;
#include "clang/Basic/LangOptions.def"
};
```
Since macros are redefined between the inclusion of `LangOptions.def`, they are
not flagged as redundant.
http://reviews.llvm.org/D7982
Files:
clang-tidy/readability/CMakeLists.txt
clang-tidy/readability/ReadabilityTidyModule.cpp
clang-tidy/readability/RedundantInclude.cpp
clang-tidy/readability/RedundantInclude.h
test/clang-tidy/readability-redundant-include.cpp
test/clang-tidy/readability-redundant-include.h
test/clang-tidy/types.h
EMAIL PREFERENCES
http://reviews.llvm.org/settings/panel/emailpreferences/
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,18 +33,19 @@
"readability-else-after-return");
CheckFactories.registerCheck<FunctionSizeCheck>(
"readability-function-size");
+ CheckFactories.registerCheck<RedundantInclude>(
+ "readability-redundant-include");
CheckFactories.registerCheck<RedundantSmartptrGet>(
"readability-redundant-smartptr-get");
- CheckFactories.registerCheck<ShrinkToFitCheck>(
- "readability-shrink-to-fit");
+ CheckFactories.registerCheck<ShrinkToFitCheck>("readability-shrink-to-fit");
}
};
} // namespace readability
// Register the MiscTidyModule using this statically initialized variable.
static ClangTidyModuleRegistry::Add<readability::ReadabilityModule>
-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.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 <algorithm>
+#include <vector>
+
+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<StringRef> 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<RedundantIncludeCallbacks>(
+ *this, Compiler.getSourceManager()));
+}
+
+} // namespace readability
+} // namespace tidy
+} // namespace clang
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 <clang/Frontend/CompilerInstance.h>
+#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: 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 <string.h>
+int b;
+#include <string.h>
+int c;
+// CHECK-MESSAGES: :[[@LINE-2]]:1: warning: redundant include [readability-redundant-include]
+// CHECK-FIXES: {{^int a;$}}
+// CHECK-FIXES-NEXT: {{^#include <string.h>$}}
+// CHECK-FIXES-NEXT: {{^int b;$}}
+// CHECK-FIXES-NEXT: {{^int c;$}}
+
+int d;
+#include <iostream>
+int e;
+#include <iostream> // extra stuff that will also be removed
+int f;
+// CHECK-MESSAGES: :[[@LINE-2]]:1: warning: {{.*}}
+// CHECK-FIXES: {{^int d;$}}
+// CHECK-FIXES-NEXT: {{^#include <iostream>$}}
+// 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 <sys/types.h>
+int k;
+#include <sys/types.h>
+int l;
+// CHECK-MESSAGES: :[[@LINE-2]]:1: warning: {{.*}}
+// CHECK-FIXES: {{^int j;$}}
+// CHECK-FIXES-NEXT: {{^#include <sys/types.h>$}}
+// CHECK-FIXES-NEXT: {{^int k;$}}
+// CHECK-FIXES-NEXT: {{^int l;$}}
+
+int m;
+ # include <string.h> // 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 <sys/types.h>
+int p;
+// CHECK-FIXES: {{^int o;$}}
+// CHECK-FIXES-NEXT: {{^#include <sys/types.h>$}}
+// CHECK-FIXES-NEXT: {{^int p;$}}
+
+// undefining a macro resets the cache
+#undef ARBITRARY_MACRO
+int q;
+#include <sys/types.h>
+int r;
+// CHECK-FIXES: {{^int q;$}}
+// CHECK-FIXES-NEXT: {{^#include <sys/types.h>$}}
+// 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
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits