[clang-tools-extra] 7452e05 - [include-cleaner] Implement IWYU begin_keep/end_keep pragma support.

Viktoriia Bakalova via cfe-commits cfe-commits at lists.llvm.org
Tue Nov 29 06:54:56 PST 2022


Author: Viktoriia Bakalova
Date: 2022-11-29T14:51:20Z
New Revision: 7452e053e5921113ef59ccab04acc0999bf2ecc2

URL: https://github.com/llvm/llvm-project/commit/7452e053e5921113ef59ccab04acc0999bf2ecc2
DIFF: https://github.com/llvm/llvm-project/commit/7452e053e5921113ef59ccab04acc0999bf2ecc2.diff

LOG: [include-cleaner] Implement IWYU begin_keep/end_keep pragma support.

Implement support for begin_keep/end_keep pragmas.

Differential Revision: https://reviews.llvm.org/D138797

Added: 
    

Modified: 
    clang-tools-extra/include-cleaner/lib/Record.cpp
    clang-tools-extra/include-cleaner/unittests/RecordTest.cpp

Removed: 
    


################################################################################
diff  --git a/clang-tools-extra/include-cleaner/lib/Record.cpp b/clang-tools-extra/include-cleaner/lib/Record.cpp
index ac3315abb882c..5a9ec6d0aadcf 100644
--- a/clang-tools-extra/include-cleaner/lib/Record.cpp
+++ b/clang-tools-extra/include-cleaner/lib/Record.cpp
@@ -187,9 +187,7 @@ class PragmaIncludes::RecordPragma : public PPCallbacks, public CommentHandler {
     FileID HashFID = SM.getFileID(HashLoc);
     int HashLine = SM.getLineNumber(HashFID, SM.getFileOffset(HashLoc));
     checkForExport(HashFID, HashLine, File ? &File->getFileEntry() : nullptr);
-
-    if (InMainFile && LastPragmaKeepInMainFileLine == HashLine)
-      Out->ShouldKeep.insert(HashLine);
+    checkForKeep(HashLine);
   }
 
   void checkForExport(FileID IncludingFile, int HashLine,
@@ -213,6 +211,18 @@ class PragmaIncludes::RecordPragma : public PPCallbacks, public CommentHandler {
       ExportStack.pop_back();
   }
 
+  void checkForKeep(int HashLine) {
+    if (!InMainFile || KeepStack.empty())
+      return;
+    KeepPragma &Top = KeepStack.back();
+    // Check if the current include is covered by a keep pragma.
+    if ((Top.Block && HashLine > Top.SeenAtLine) || Top.SeenAtLine == HashLine)
+      Out->ShouldKeep.insert(HashLine);
+
+    if (!Top.Block)
+      KeepStack.pop_back(); // Pop immediately for single-line keep pragma.
+  }
+
   bool HandleComment(Preprocessor &PP, SourceRange Range) override {
     auto &SM = PP.getSourceManager();
     auto Pragma =
@@ -257,23 +267,14 @@ class PragmaIncludes::RecordPragma : public PPCallbacks, public CommentHandler {
     }
 
     if (InMainFile) {
-      if (!Pragma->startswith("keep"))
-        return false;
-      // Given:
-      //
-      // #include "foo.h"
-      // #include "bar.h" // IWYU pragma: keep
-      //
-      // The order in which the callbacks will be triggered:
-      //
-      // 1. InclusionDirective("foo.h")
-      // 2. handleCommentInMainFile("// IWYU pragma: keep")
-      // 3. InclusionDirective("bar.h")
-      //
-      // This code stores the last location of "IWYU pragma: keep" comment in
-      // the main file, so that when next InclusionDirective is called, it will
-      // know that the next inclusion is behind the IWYU pragma.
-      LastPragmaKeepInMainFileLine = CommentLine;
+      if (Pragma->startswith("keep")) {
+        KeepStack.push_back({CommentLine, false});
+      } else if (Pragma->starts_with("begin_keep")) {
+        KeepStack.push_back({CommentLine, true});
+      } else if (Pragma->starts_with("end_keep") && !KeepStack.empty()) {
+        assert(KeepStack.back().Block);
+        KeepStack.pop_back();
+      }
     }
     return false;
   }
@@ -288,8 +289,7 @@ class PragmaIncludes::RecordPragma : public PPCallbacks, public CommentHandler {
   llvm::BumpPtrAllocator Arena;
   /// Intern table for strings. Contents are on the arena.
   llvm::StringSaver UniqueStrings;
-  // Track the last line "IWYU pragma: keep" was seen in the main file, 1-based.
-  int LastPragmaKeepInMainFileLine = -1;
+
   struct ExportPragma {
     // The line number where we saw the begin_exports or export pragma.
     int SeenAtLine = 0; // 1-based line number.
@@ -303,6 +303,16 @@ class PragmaIncludes::RecordPragma : public PPCallbacks, public CommentHandler {
   };
   // A stack for tracking all open begin_exports or single-line export.
   std::vector<ExportPragma> ExportStack;
+
+  struct KeepPragma {
+    // The line number where we saw the begin_keep or keep pragma.
+    int SeenAtLine = 0; // 1-based line number.
+    // true if it is a block begin/end_keep pragma; false if it is a
+    // single-line keep pragma.
+    bool Block = false;
+  };
+  // A stack for tracking all open begin_keep pragmas or single-line keeps.
+  std::vector<KeepPragma> KeepStack;
 };
 
 void PragmaIncludes::record(const CompilerInstance &CI) {

diff  --git a/clang-tools-extra/include-cleaner/unittests/RecordTest.cpp b/clang-tools-extra/include-cleaner/unittests/RecordTest.cpp
index 0cc163751fd70..1076891473431 100644
--- a/clang-tools-extra/include-cleaner/unittests/RecordTest.cpp
+++ b/clang-tools-extra/include-cleaner/unittests/RecordTest.cpp
@@ -311,35 +311,68 @@ class PragmaIncludeTest : public ::testing::Test {
 };
 
 TEST_F(PragmaIncludeTest, IWYUKeep) {
-  Inputs.Code = R"cpp(// Line 1
-    #include "keep1.h" // IWYU pragma: keep
-    #include "keep2.h" /* IWYU pragma: keep */
+  llvm::Annotations MainFile(R"cpp(
+    $keep1^#include "keep1.h" // IWYU pragma: keep
+    $keep2^#include "keep2.h" /* IWYU pragma: keep */
+
+    $export1^#include "export1.h" // IWYU pragma: export
+    $begin_exports^// IWYU pragma: begin_exports
+    $export2^#include "export2.h"
+    $export3^#include "export3.h"
+    $end_exports^// IWYU pragma: end_exports
+
+    $normal^#include "normal.h"
+
+    $begin_keep^// IWYU pragma: begin_keep 
+    $keep3^#include "keep3.h"
+    $end_keep^// IWYU pragma: end_keep
+
+    // IWYU pragma: begin_keep 
+    $keep4^#include "keep4.h"
+    // IWYU pragma: begin_keep
+    $keep5^#include "keep5.h"
+    // IWYU pragma: end_keep
+    $keep6^#include "keep6.h"
+    // IWYU pragma: end_keep
+  )cpp");
 
-    #include "export1.h" // IWYU pragma: export // line 5
-    // IWYU pragma: begin_exports
-    #include "export2.h" // Line 7
-    #include "export3.h"
-    // IWYU pragma: end_exports
+  auto OffsetToLineNum = [&MainFile](size_t Offset) {
+    int Count = MainFile.code().substr(0, Offset).count('\n');
+    return Count + 1;
+  };
 
-    #include "normal.h" // Line 11
-  )cpp";
-  createEmptyFiles({"keep1.h", "keep2.h", "export1.h", "export2.h", "export3.h",
+  Inputs.Code = MainFile.code();
+  createEmptyFiles({"keep1.h", "keep2.h", "keep3.h", "keep4.h", "keep5.h",
+                    "keep6.h", "export1.h", "export2.h", "export3.h",
                     "normal.h"});
 
   TestAST Processed = build();
   EXPECT_FALSE(PI.shouldKeep(1));
+
   // Keep
-  EXPECT_TRUE(PI.shouldKeep(2));
-  EXPECT_TRUE(PI.shouldKeep(3));
+  EXPECT_TRUE(PI.shouldKeep(OffsetToLineNum(MainFile.point("keep1"))));
+  EXPECT_TRUE(PI.shouldKeep(OffsetToLineNum(MainFile.point("keep2"))));
 
-  // Exports
-  EXPECT_TRUE(PI.shouldKeep(5));
-  EXPECT_TRUE(PI.shouldKeep(7));
-  EXPECT_TRUE(PI.shouldKeep(8));
-  EXPECT_FALSE(PI.shouldKeep(6)); // no # directive
-  EXPECT_FALSE(PI.shouldKeep(9)); // no # directive
+  EXPECT_FALSE(PI.shouldKeep(
+      OffsetToLineNum(MainFile.point("begin_keep")))); // no # directive
+  EXPECT_TRUE(PI.shouldKeep(OffsetToLineNum(MainFile.point("keep3"))));
+  EXPECT_FALSE(PI.shouldKeep(
+      OffsetToLineNum(MainFile.point("end_keep")))); // no # directive
+
+  EXPECT_TRUE(PI.shouldKeep(OffsetToLineNum(MainFile.point("keep4"))));
+  EXPECT_TRUE(PI.shouldKeep(OffsetToLineNum(MainFile.point("keep5"))));
+  EXPECT_TRUE(PI.shouldKeep(OffsetToLineNum(MainFile.point("keep6"))));
 
-  EXPECT_FALSE(PI.shouldKeep(11));
+  // Exports
+  EXPECT_TRUE(PI.shouldKeep(OffsetToLineNum(MainFile.point("export1"))));
+  EXPECT_TRUE(PI.shouldKeep(OffsetToLineNum(MainFile.point("export2"))));
+  EXPECT_TRUE(PI.shouldKeep(OffsetToLineNum(MainFile.point("export3"))));
+  EXPECT_FALSE(PI.shouldKeep(
+      OffsetToLineNum(MainFile.point("begin_exports")))); // no # directive
+  EXPECT_FALSE(PI.shouldKeep(
+      OffsetToLineNum(MainFile.point("end_exports")))); // no # directive
+
+  EXPECT_FALSE(PI.shouldKeep(OffsetToLineNum(MainFile.point("normal"))));
 }
 
 TEST_F(PragmaIncludeTest, IWYUPrivate) {


        


More information about the cfe-commits mailing list