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

Reply via email to