[clang-tools-extra] d0e8911 - [clangd] Fix fixAll not shown when there is only one unused-include and missing-include diagnostics.

Haojian Wu via cfe-commits cfe-commits at lists.llvm.org
Mon May 15 05:06:48 PDT 2023


Author: Haojian Wu
Date: 2023-05-15T14:02:20+02:00
New Revision: d0e89116aff224ac2d8d3f88029ae44e12c9b6cc

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

LOG: [clangd] Fix fixAll not shown when there is only one unused-include and missing-include diagnostics.

Discovered during the review in https://reviews.llvm.org/D149437#inline-1444851.

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

Added: 
    

Modified: 
    clang-tools-extra/clangd/IncludeCleaner.cpp
    clang-tools-extra/clangd/unittests/IncludeCleanerTests.cpp

Removed: 
    


################################################################################
diff  --git a/clang-tools-extra/clangd/IncludeCleaner.cpp b/clang-tools-extra/clangd/IncludeCleaner.cpp
index 3b913d851abe2..22d0808235f7f 100644
--- a/clang-tools-extra/clangd/IncludeCleaner.cpp
+++ b/clang-tools-extra/clangd/IncludeCleaner.cpp
@@ -440,8 +440,9 @@ IncludeCleanerFindings computeIncludeCleanerFindings(ParsedAST &AST) {
   return {std::move(UnusedIncludes), std::move(MissingIncludes)};
 }
 
-Fix removeAllUnusedIncludes(llvm::ArrayRef<Diag> UnusedIncludes) {
-  assert(!UnusedIncludes.empty());
+std::optional<Fix> removeAllUnusedIncludes(llvm::ArrayRef<Diag> UnusedIncludes) {
+  if (UnusedIncludes.empty())
+    return std::nullopt;
 
   Fix RemoveAll;
   RemoveAll.Message = "remove all unused includes";
@@ -465,8 +466,10 @@ Fix removeAllUnusedIncludes(llvm::ArrayRef<Diag> UnusedIncludes) {
   }
   return RemoveAll;
 }
-Fix addAllMissingIncludes(llvm::ArrayRef<Diag> MissingIncludeDiags) {
-  assert(!MissingIncludeDiags.empty());
+std::optional<Fix>
+addAllMissingIncludes(llvm::ArrayRef<Diag> MissingIncludeDiags) {
+  if (MissingIncludeDiags.empty())
+    return std::nullopt;
 
   Fix AddAllMissing;
   AddAllMissing.Message = "add all missing includes";
@@ -516,15 +519,11 @@ std::vector<Diag> generateIncludeCleanerDiagnostic(
     llvm::StringRef Code) {
   std::vector<Diag> UnusedIncludes = generateUnusedIncludeDiagnostics(
       AST.tuPath(), Findings.UnusedIncludes, Code);
-  std::optional<Fix> RemoveAllUnused;;
-  if (UnusedIncludes.size() > 1)
-    RemoveAllUnused = removeAllUnusedIncludes(UnusedIncludes);
+  std::optional<Fix> RemoveAllUnused = removeAllUnusedIncludes(UnusedIncludes);
 
   std::vector<Diag> MissingIncludeDiags = generateMissingIncludeDiagnostics(
       AST, Findings.MissingIncludes, Code);
-  std::optional<Fix> AddAllMissing;
-  if (MissingIncludeDiags.size() > 1)
-    AddAllMissing = addAllMissingIncludes(MissingIncludeDiags);
+  std::optional<Fix> AddAllMissing = addAllMissingIncludes(MissingIncludeDiags);
 
   std::optional<Fix> FixAll;
   if (RemoveAllUnused && AddAllMissing)
@@ -535,11 +534,16 @@ std::vector<Diag> generateIncludeCleanerDiagnostic(
     Out->Fixes.push_back(*F);
   };
   for (auto &Diag : MissingIncludeDiags) {
-    AddBatchFix(AddAllMissing, &Diag);
+    AddBatchFix(MissingIncludeDiags.size() > 1
+                    ? AddAllMissing
+                    : std::nullopt,
+                &Diag);
     AddBatchFix(FixAll, &Diag);
   }
   for (auto &Diag : UnusedIncludes) {
-    AddBatchFix(RemoveAllUnused, &Diag);
+    AddBatchFix(UnusedIncludes.size() > 1 ? RemoveAllUnused
+                                          : std::nullopt,
+                &Diag);
     AddBatchFix(FixAll, &Diag);
   }
 

diff  --git a/clang-tools-extra/clangd/unittests/IncludeCleanerTests.cpp b/clang-tools-extra/clangd/unittests/IncludeCleanerTests.cpp
index a38c01b43270f..c0831c2693c97 100644
--- a/clang-tools-extra/clangd/unittests/IncludeCleanerTests.cpp
+++ b/clang-tools-extra/clangd/unittests/IncludeCleanerTests.cpp
@@ -197,10 +197,10 @@ TEST(IncludeCleaner, GenerateMissingHeaderDiags) {
 
     ns::$bar[[Bar]] bar;
     bar.d();
-    $f[[f]](); 
+    $f[[f]]();
 
     // this should not be diagnosed, because it's ignored in the config
-    buzz(); 
+    buzz();
 
     $foobar[[foobar]]();
 
@@ -244,7 +244,7 @@ TEST(IncludeCleaner, GenerateMissingHeaderDiags) {
   TU.AdditionalFiles["foo.h"] = guard(R"cpp(
     #define BAR(x) Foo *x
     #define FOO 1
-    struct Foo{}; 
+    struct Foo{};
   )cpp");
 
   TU.Code = MainFile.code();
@@ -510,6 +510,71 @@ TEST(IncludeCleaner, FirstMatchedProvider) {
   }
 }
 
+TEST(IncludeCleaner, BatchFix) {
+  Config Cfg;
+  Cfg.Diagnostics.MissingIncludes = Config::IncludesPolicy::Strict;
+  Cfg.Diagnostics.UnusedIncludes = Config::IncludesPolicy::Strict;
+  WithContextValue Ctx(Config::Key, std::move(Cfg));
+
+  TestTU TU;
+  TU.Filename = "main.cpp";
+  TU.AdditionalFiles["foo.h"] = guard("class Foo;");
+  TU.AdditionalFiles["bar.h"] = guard("class Bar;");
+  TU.AdditionalFiles["all.h"] = guard(R"cpp(
+    #include "foo.h"
+    #include "bar.h"
+  )cpp");
+
+  TU.Code = R"cpp(
+  #include "all.h"
+
+  Foo* foo;
+  )cpp";
+  auto AST = TU.build();
+  EXPECT_THAT(
+      issueIncludeCleanerDiagnostics(AST, TU.Code),
+      UnorderedElementsAre(withFix({FixMessage("#include \"foo.h\""),
+                                    FixMessage("fix all includes")}),
+                           withFix({FixMessage("remove #include directive"),
+                                    FixMessage("fix all includes")})));
+
+  TU.Code = R"cpp(
+  #include "all.h"
+  #include "bar.h"
+
+  Foo* foo;
+  )cpp";
+  AST = TU.build();
+  EXPECT_THAT(
+      issueIncludeCleanerDiagnostics(AST, TU.Code),
+      UnorderedElementsAre(withFix({FixMessage("#include \"foo.h\""),
+                                    FixMessage("fix all includes")}),
+                           withFix({FixMessage("remove #include directive"),
+                                    FixMessage("remove all unused includes"),
+                                    FixMessage("fix all includes")}),
+                           withFix({FixMessage("remove #include directive"),
+                                   FixMessage("remove all unused includes"),
+                                    FixMessage("fix all includes")})));
+
+  TU.Code = R"cpp(
+  #include "all.h"
+
+  Foo* foo;
+  Bar* bar;
+  )cpp";
+  AST = TU.build();
+  EXPECT_THAT(
+      issueIncludeCleanerDiagnostics(AST, TU.Code),
+      UnorderedElementsAre(withFix({FixMessage("#include \"foo.h\""),
+                                    FixMessage("add all missing includes"),
+                                    FixMessage("fix all includes")}),
+                           withFix({FixMessage("#include \"bar.h\""),
+                                    FixMessage("add all missing includes"),
+                                    FixMessage("fix all includes")}),
+                           withFix({FixMessage("remove #include directive"),
+                                    FixMessage("fix all includes")})));
+}
+
 } // namespace
 } // namespace clangd
 } // namespace clang


        


More information about the cfe-commits mailing list