kbobyrev created this revision.
kbobyrev added a reviewer: sammccall.
Herald added subscribers: usaxena95, arphaman.
Herald added a project: All.
kbobyrev requested review of this revision.
Herald added subscribers: cfe-commits, MaskRay, ilya-biryukov.
Herald added a project: clang-tools-extra.

This introduces filtering out inclusions based on the resolved path. This
mechanism will be important for disabling warnings for headers that we can not
diagnose correctly yet.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D123488

Files:
  clang-tools-extra/clangd/Config.h
  clang-tools-extra/clangd/ConfigCompile.cpp
  clang-tools-extra/clangd/ConfigFragment.h
  clang-tools-extra/clangd/IncludeCleaner.cpp
  clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp

Index: clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp
===================================================================
--- clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp
+++ clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp
@@ -1675,6 +1675,9 @@
   Annotations Test(R"cpp(
 $fix[[  $diag[[#include "unused.h"]]
 ]]
+  // These two will be ignored by the filter.
+  #include "ignore.h"
+  #include "ignore_regex.h"
   #include "used.h"
 
   #include <system_header.h>
@@ -1693,12 +1696,22 @@
     #pragma once
     void used() {}
   )cpp";
+  TU.AdditionalFiles["ignore.h"] = R"cpp(
+    #pragma once
+    void ignore() {}
+  )cpp";
+  TU.AdditionalFiles["ignore_regex.h"] = R"cpp(
+    #pragma once
+    void ignore_regex() {}
+  )cpp";
   TU.AdditionalFiles["system/system_header.h"] = "";
   TU.ExtraArgs = {"-isystem" + testPath("system")};
   // Off by default.
   EXPECT_THAT(*TU.build().getDiagnostics(), IsEmpty());
   Config Cfg;
   Cfg.Diagnostics.UnusedIncludes = Config::UnusedIncludesPolicy::Strict;
+  // Set filtering.
+  Cfg.Diagnostics.Includes.IgnoreHeader.emplace_back(llvm::Regex("ignore.*.h"));
   WithContextValue WithCfg(Config::Key, std::move(Cfg));
   EXPECT_THAT(
       *TU.build().getDiagnostics(),
Index: clang-tools-extra/clangd/IncludeCleaner.cpp
===================================================================
--- clang-tools-extra/clangd/IncludeCleaner.cpp
+++ clang-tools-extra/clangd/IncludeCleaner.cpp
@@ -23,10 +23,12 @@
 #include "clang/Lex/HeaderSearch.h"
 #include "clang/Lex/Preprocessor.h"
 #include "clang/Tooling/Syntax/Tokens.h"
+#include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/STLFunctionalExtras.h"
 #include "llvm/ADT/StringSet.h"
 #include "llvm/Support/FormatVariadic.h"
 #include "llvm/Support/Path.h"
+#include "llvm/Support/Regex.h"
 
 namespace clang {
 namespace clangd {
@@ -233,7 +235,8 @@
   }
 }
 
-static bool mayConsiderUnused(const Inclusion &Inc, ParsedAST &AST) {
+static bool mayConsiderUnused(const Inclusion &Inc, ParsedAST &AST,
+                              llvm::ArrayRef<llvm::Regex> IgnoreHeader) {
   if (Inc.BehindPragmaKeep)
     return false;
 
@@ -258,6 +261,12 @@
          FE->getName());
     return false;
   }
+  for (auto &Matcher : IgnoreHeader) {
+    if (Matcher.match(Inc.Resolved)) {
+      dlog("{0} header is filterred out", FE->getName());
+      return false;
+    }
+  }
   return true;
 }
 
@@ -369,6 +378,7 @@
           const llvm::DenseSet<IncludeStructure::HeaderID> &ReferencedFiles,
           const llvm::StringSet<> &ReferencedPublicHeaders) {
   trace::Span Tracer("IncludeCleaner::getUnused");
+  const Config &Cfg = Config::current();
   std::vector<const Inclusion *> Unused;
   for (const Inclusion &MFI : AST.getIncludeStructure().MainFileIncludes) {
     if (!MFI.HeaderID)
@@ -377,7 +387,8 @@
       continue;
     auto IncludeID = static_cast<IncludeStructure::HeaderID>(*MFI.HeaderID);
     bool Used = ReferencedFiles.contains(IncludeID);
-    if (!Used && !mayConsiderUnused(MFI, AST)) {
+    if (!Used &&
+        !mayConsiderUnused(MFI, AST, Cfg.Diagnostics.Includes.IgnoreHeader)) {
       dlog("{0} was not used, but is not eligible to be diagnosed as unused",
            MFI.Written);
       continue;
Index: clang-tools-extra/clangd/ConfigFragment.h
===================================================================
--- clang-tools-extra/clangd/ConfigFragment.h
+++ clang-tools-extra/clangd/ConfigFragment.h
@@ -232,6 +232,15 @@
     /// - None
     llvm::Optional<Located<std::string>> UnusedIncludes;
 
+    /// Controls IncludeCleaner diagnostics.
+    struct IncludesBlock {
+      /// Regexes that will be used to avoid diagnosing certain includes. These
+      /// regexes are anchored on the right and will be matched against the
+      /// resolved include path.
+      std::vector<Located<std::string>> IgnoreHeader;
+    };
+    IncludesBlock Includes;
+
     /// Controls how clang-tidy will run over the code base.
     ///
     /// The settings are merged with any settings found in .clang-tidy
Index: clang-tools-extra/clangd/ConfigCompile.cpp
===================================================================
--- clang-tools-extra/clangd/ConfigCompile.cpp
+++ clang-tools-extra/clangd/ConfigCompile.cpp
@@ -432,6 +432,7 @@
         Out.Apply.push_back([Val](const Params &, Config &C) {
           C.Diagnostics.UnusedIncludes = *Val;
         });
+    compile(std::move(F.Includes));
 
     compile(std::move(F.ClangTidy));
   }
@@ -507,6 +508,31 @@
     }
   }
 
+  void compile(Fragment::DiagnosticsBlock::IncludesBlock &&F) {
+#ifdef CLANGD_PATH_CASE_INSENSITIVE
+    static llvm::Regex::RegexFlags Flags = llvm::Regex::IgnoreCase;
+#else
+    static llvm::Regex::RegexFlags Flags = llvm::Regex::NoFlags;
+#endif
+    for (auto &HeaderPattern : F.IgnoreHeader) {
+      // Anchor on the right.
+      std::string AnchoredPattern = "(" + *HeaderPattern + ")$";
+      llvm::Regex CompiledRegex(AnchoredPattern, Flags);
+      std::string RegexError;
+      if (!CompiledRegex.isValid(RegexError)) {
+        diag(Warning,
+             llvm::formatv("Incorrect regular expression: {0}", *HeaderPattern)
+                 .str(),
+             HeaderPattern.Range);
+        continue;
+      }
+      Out.Apply.push_back([&CompiledRegex](const Params &, Config &C) {
+        C.Diagnostics.Includes.IgnoreHeader.emplace_back(
+            std::move(CompiledRegex));
+      });
+    }
+  }
+
   void compile(Fragment::CompletionBlock &&F) {
     if (F.AllScopes) {
       Out.Apply.push_back(
Index: clang-tools-extra/clangd/Config.h
===================================================================
--- clang-tools-extra/clangd/Config.h
+++ clang-tools-extra/clangd/Config.h
@@ -29,6 +29,7 @@
 #include "llvm/ADT/Optional.h"
 #include "llvm/ADT/StringMap.h"
 #include "llvm/ADT/StringSet.h"
+#include "llvm/Support/Regex.h"
 #include <string>
 #include <vector>
 
@@ -100,6 +101,12 @@
     } ClangTidy;
 
     UnusedIncludesPolicy UnusedIncludes = None;
+
+    /// IncludeCleaner will not diagnose usages of these headers matched by
+    /// these regexes.
+    struct {
+      std::vector<llvm::Regex> IgnoreHeader;
+    } Includes;
   } Diagnostics;
 
   /// Style of the codebase.
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to