zturner updated this revision to Diff 67777.
zturner added a comment.

Seems like dropping all non-main-file include directives is wrong because then 
it won't be able to detect errors in "non user code".  Seems like the real fix 
is to bucket the include directives by file in which they were declared in, and 
then process each bucket in order.  This way we process all include directives, 
including those in non-user code, but block analysis is done at a per-file 
level.


https://reviews.llvm.org/D23434

Files:
  clang-tidy/llvm/IncludeOrderCheck.cpp
  test/clang-tidy/Inputs/Headers/cross-file-a.h
  test/clang-tidy/Inputs/Headers/cross-file-b.h
  test/clang-tidy/Inputs/Headers/cross-file-c.h
  test/clang-tidy/llvm-include-order.cpp

Index: test/clang-tidy/llvm-include-order.cpp
===================================================================
--- test/clang-tidy/llvm-include-order.cpp
+++ test/clang-tidy/llvm-include-order.cpp
@@ -35,3 +35,8 @@
 
 // CHECK-FIXES: #include "a.h"
 // CHECK-FIXES-NEXT: #include "b.h"
+
+// CHECK-MESSAGES-NOT: [[@LINE+1]]:1: warning: #includes are not sorted properly
+#include "cross-file-c.h"
+// This line number should correspond to the position of the #include in cross-file-c.h
+#include "cross-file-a.h"
Index: test/clang-tidy/Inputs/Headers/cross-file-c.h
===================================================================
--- /dev/null
+++ test/clang-tidy/Inputs/Headers/cross-file-c.h
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+// The line number of the following include should match the location of the
+// corresponding comment in llvm-include-order.cpp
+#include "cross-file-b.h"
Index: clang-tidy/llvm/IncludeOrderCheck.cpp
===================================================================
--- clang-tidy/llvm/IncludeOrderCheck.cpp
+++ clang-tidy/llvm/IncludeOrderCheck.cpp
@@ -12,6 +12,8 @@
 #include "clang/Lex/PPCallbacks.h"
 #include "clang/Lex/Preprocessor.h"
 
+#include <map>
+
 namespace clang {
 namespace tidy {
 namespace llvm {
@@ -37,7 +39,9 @@
     bool IsAngled;         ///< true if this was an include with angle brackets
     bool IsMainModule;     ///< true if this was the first include in a file
   };
-  std::vector<IncludeDirective> IncludeDirectives;
+
+  typedef std::vector<IncludeDirective> FileIncludes;
+  std::map<clang::FileID, FileIncludes> IncludeDirectives;
   bool LookForMainModule;
 
   ClangTidyCheck &Check;
@@ -80,7 +84,9 @@
     ID.IsMainModule = true;
     LookForMainModule = false;
   }
-  IncludeDirectives.push_back(std::move(ID));
+
+  // Bucket the include directives by the id of the file they were declared in.
+  IncludeDirectives[SM.getFileID(HashLoc)].push_back(std::move(ID));
 }
 
 void IncludeOrderPPCallbacks::EndOfMainFile() {
@@ -95,69 +101,73 @@
   // FIXME: We should be more careful about sorting below comments as we don't
   // know if the comment refers to the next include or the whole block that
   // follows.
-  std::vector<unsigned> Blocks(1, 0);
-  for (unsigned I = 1, E = IncludeDirectives.size(); I != E; ++I)
-    if (SM.getExpansionLineNumber(IncludeDirectives[I].Loc) !=
-        SM.getExpansionLineNumber(IncludeDirectives[I - 1].Loc) + 1)
-      Blocks.push_back(I);
-  Blocks.push_back(IncludeDirectives.size()); // Sentinel value.
-
-  // Get a vector of indices.
-  std::vector<unsigned> IncludeIndices;
-  for (unsigned I = 0, E = IncludeDirectives.size(); I != E; ++I)
-    IncludeIndices.push_back(I);
-
-  // Sort the includes. We first sort by priority, then lexicographically.
-  for (unsigned BI = 0, BE = Blocks.size() - 1; BI != BE; ++BI)
-    std::sort(IncludeIndices.begin() + Blocks[BI],
-              IncludeIndices.begin() + Blocks[BI + 1],
-              [this](unsigned LHSI, unsigned RHSI) {
-      IncludeDirective &LHS = IncludeDirectives[LHSI];
-      IncludeDirective &RHS = IncludeDirectives[RHSI];
-
-      int PriorityLHS =
-          getPriority(LHS.Filename, LHS.IsAngled, LHS.IsMainModule);
-      int PriorityRHS =
-          getPriority(RHS.Filename, RHS.IsAngled, RHS.IsMainModule);
-
-      return std::tie(PriorityLHS, LHS.Filename) <
-             std::tie(PriorityRHS, RHS.Filename);
-    });
-
-  // Emit a warning for each block and fixits for all changes within that block.
-  for (unsigned BI = 0, BE = Blocks.size() - 1; BI != BE; ++BI) {
-    // Find the first include that's not in the right position.
-    unsigned I, E;
-    for (I = Blocks[BI], E = Blocks[BI + 1]; I != E; ++I)
-      if (IncludeIndices[I] != I)
-        break;
-
-    if (I == E)
-      continue;
-
-    // Emit a warning.
-    auto D = Check.diag(IncludeDirectives[I].Loc,
-                        "#includes are not sorted properly");
-
-    // Emit fix-its for all following includes in this block.
-    for (; I != E; ++I) {
-      if (IncludeIndices[I] == I)
+  for (auto &Bucket : IncludeDirectives) {
+    auto &FileDirectives = Bucket.second;
+    std::vector<unsigned> Blocks(1, 0);
+    for (unsigned I = 1, E = FileDirectives.size(); I != E; ++I)
+      if (SM.getExpansionLineNumber(FileDirectives[I].Loc) !=
+          SM.getExpansionLineNumber(FileDirectives[I - 1].Loc) + 1)
+        Blocks.push_back(I);
+    Blocks.push_back(FileDirectives.size()); // Sentinel value.
+
+    // Get a vector of indices.
+    std::vector<unsigned> IncludeIndices;
+    for (unsigned I = 0, E = FileDirectives.size(); I != E; ++I)
+      IncludeIndices.push_back(I);
+
+    // Sort the includes. We first sort by priority, then lexicographically.
+    for (unsigned BI = 0, BE = Blocks.size() - 1; BI != BE; ++BI)
+      std::sort(IncludeIndices.begin() + Blocks[BI],
+                IncludeIndices.begin() + Blocks[BI + 1],
+                [&FileDirectives](unsigned LHSI, unsigned RHSI) {
+                  IncludeDirective &LHS = FileDirectives[LHSI];
+                  IncludeDirective &RHS = FileDirectives[RHSI];
+
+                  int PriorityLHS =
+                      getPriority(LHS.Filename, LHS.IsAngled, LHS.IsMainModule);
+                  int PriorityRHS =
+                      getPriority(RHS.Filename, RHS.IsAngled, RHS.IsMainModule);
+
+                  return std::tie(PriorityLHS, LHS.Filename) <
+                         std::tie(PriorityRHS, RHS.Filename);
+                });
+
+    // Emit a warning for each block and fixits for all changes within that
+    // block.
+    for (unsigned BI = 0, BE = Blocks.size() - 1; BI != BE; ++BI) {
+      // Find the first include that's not in the right position.
+      unsigned I, E;
+      for (I = Blocks[BI], E = Blocks[BI + 1]; I != E; ++I)
+        if (IncludeIndices[I] != I)
+          break;
+
+      if (I == E)
         continue;
-      const IncludeDirective &CopyFrom = IncludeDirectives[IncludeIndices[I]];
 
-      SourceLocation FromLoc = CopyFrom.Range.getBegin();
-      const char *FromData = SM.getCharacterData(FromLoc);
-      unsigned FromLen = std::strcspn(FromData, "\n");
+      // Emit a warning.
+      auto D = Check.diag(FileDirectives[I].Loc,
+                          "#includes are not sorted properly");
+
+      // Emit fix-its for all following includes in this block.
+      for (; I != E; ++I) {
+        if (IncludeIndices[I] == I)
+          continue;
+        const IncludeDirective &CopyFrom = FileDirectives[IncludeIndices[I]];
+
+        SourceLocation FromLoc = CopyFrom.Range.getBegin();
+        const char *FromData = SM.getCharacterData(FromLoc);
+        unsigned FromLen = std::strcspn(FromData, "\n");
 
-      StringRef FixedName(FromData, FromLen);
+        StringRef FixedName(FromData, FromLen);
 
-      SourceLocation ToLoc = IncludeDirectives[I].Range.getBegin();
-      const char *ToData = SM.getCharacterData(ToLoc);
-      unsigned ToLen = std::strcspn(ToData, "\n");
-      auto ToRange =
-          CharSourceRange::getCharRange(ToLoc, ToLoc.getLocWithOffset(ToLen));
+        SourceLocation ToLoc = FileDirectives[I].Range.getBegin();
+        const char *ToData = SM.getCharacterData(ToLoc);
+        unsigned ToLen = std::strcspn(ToData, "\n");
+        auto ToRange =
+            CharSourceRange::getCharRange(ToLoc, ToLoc.getLocWithOffset(ToLen));
 
-      D << FixItHint::CreateReplacement(ToRange, FixedName);
+        D << FixItHint::CreateReplacement(ToRange, FixedName);
+      }
     }
   }
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to