[clang] [clang-tools-extra] [llvm] [clang] Introduce diagnostics suppression mappings (PR #112517)

kadir çetinkaya via cfe-commits cfe-commits at lists.llvm.org
Tue Oct 29 07:06:54 PDT 2024


================
@@ -477,6 +486,109 @@ void DiagnosticsEngine::setSeverityForAll(diag::Flavor Flavor,
       setSeverity(Diag, Map, Loc);
 }
 
+namespace {
+class WarningsSpecialCaseList : public llvm::SpecialCaseList {
+public:
+  static std::unique_ptr<WarningsSpecialCaseList>
+  create(const llvm::MemoryBuffer &MB, std::string &Err) {
+    auto SCL = std::make_unique<WarningsSpecialCaseList>();
+    if (!SCL->createInternal(&MB, Err))
+      return nullptr;
+    return SCL;
+  }
+
+  // Section names refer to diagnostic groups, which cover multiple individual
+  // diagnostics. Expand diagnostic groups here to individual diagnostics.
+  // A diagnostic can have multiple diagnostic groups associated with it, we let
+  // the last section take precedence in such cases.
+  void processSections(DiagnosticsEngine &Diags) {
+    // Drop the default section introduced by special case list, we only support
+    // exact diagnostic group names.
+    Sections.erase("*");
+    // Make sure we iterate sections by their line numbers.
+    std::vector<std::pair<unsigned, const llvm::StringMapEntry<Section> *>>
+        LineAndSectionEntry;
+    LineAndSectionEntry.reserve(Sections.size());
+    for (const auto &Entry : Sections) {
+      LineAndSectionEntry.emplace_back(
+          Entry.second.SectionMatcher->Globs.at(Entry.first()).second, &Entry);
+    }
+    llvm::sort(LineAndSectionEntry);
+    static constexpr auto kFlavor = clang::diag::Flavor::WarningOrError;
+    for (const auto &[_, SectionEntry] : LineAndSectionEntry) {
+      SmallVector<diag::kind, 256> GroupDiags;
+      llvm::StringRef DiagGroup = SectionEntry->getKey();
+      if (Diags.getDiagnosticIDs()->getDiagnosticsInGroup(kFlavor, DiagGroup,
+                                                          GroupDiags)) {
+        StringRef Suggestion =
+            DiagnosticIDs::getNearestOption(kFlavor, DiagGroup);
+        Diags.Report(diag::warn_unknown_diag_option)
+            << static_cast<unsigned>(kFlavor) << DiagGroup
+            << !Suggestion.empty() << Suggestion;
+        continue;
+      }
+      for (diag::kind D : GroupDiags)
+        DiagToSection[D] = &SectionEntry->getValue();
+    }
+  }
+
+  bool isDiagSuppressed(diag::kind D, llvm::StringRef FilePath) const {
+    auto Section = DiagToSection.find(D);
+    if (Section == DiagToSection.end())
+      return false;
+    auto &DiagEntries = Section->second->Entries;
+    auto SrcEntries = DiagEntries.find("src");
+    if (SrcEntries == DiagEntries.end())
+      return false;
+    return globsMatches(SrcEntries->second, FilePath);
+  }
+
+private:
+  // Find the longest glob pattern that matches FilePath amongst
+  // CategoriesToMatchers, return true iff the match exists and belongs to a
+  // positive category.
+  bool globsMatches(llvm::StringMap<Matcher> CategoriesToMatchers,
+                    llvm::StringRef FilePath) const {
+    llvm::StringRef LongestMatch;
+    bool LongestIsPositive = false;
+    for (const auto &[Category, Matcher] : CategoriesToMatchers) {
+      bool IsPositive = Category != "emit";
+      for (const auto &[Pattern, Glob] : Matcher.Globs) {
+        if (Pattern.size() < LongestMatch.size())
+          continue;
+        if (!Glob.first.match(FilePath))
+          continue;
+        LongestMatch = Pattern;
+        LongestIsPositive = IsPositive;
+      }
+    }
+    return LongestIsPositive;
+  }
+
+  llvm::DenseMap<diag::kind, const Section *> DiagToSection;
+};
+} // namespace
+
+void DiagnosticsEngine::setDiagSuppressionMapping(llvm::MemoryBuffer &MB) {
+  std::string Err;
+  auto SCL = WarningsSpecialCaseList::create(MB, Err);
----------------
kadircet wrote:

again, i do think despite the coding standards saying that, code in practice is much more flexible than that and I think it actually has its positives. developer doesn't need to think thoroughly about naming when it isn't so useful.  for example the name of the SpecialCaseList object (IMO) doesn't really matter here, it's an implementation detail that isn't visible to any reader outside of these 5 lines. whereas "important" objects that are keeping track of some invariants/state as logic does something is still quite important (e.g. logic that finds longest match), hence such objects have more descriptive names (and its worth putting the effort).

i think the same applies across other parts of the codebase and this file. so i'd rather keep them like this. I am happy to make adjustments if you feel like there are bits of the logic that can benefit from more descriptive names though.

https://github.com/llvm/llvm-project/pull/112517


More information about the cfe-commits mailing list