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

Boaz Brickner via cfe-commits cfe-commits at lists.llvm.org
Fri Nov 8 01:44:02 PST 2024


================
@@ -477,6 +486,136 @@ void DiagnosticsEngine::setSeverityForAll(diag::Flavor Flavor,
       setSeverity(Diag, Map, Loc);
 }
 
+namespace {
+// FIXME: We should isolate the parser from SpecialCaseList and just use it
+// here.
+class WarningsSpecialCaseList : public llvm::SpecialCaseList {
+public:
+  static std::unique_ptr<WarningsSpecialCaseList>
+  create(const llvm::MemoryBuffer &Input, std::string &Err);
+
+  // 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);
+
+  bool isDiagSuppressed(diag::kind DiagId, llvm::StringRef FilePath) const;
+
+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(const llvm::StringMap<Matcher> &CategoriesToMatchers,
+                    llvm::StringRef FilePath) const;
+
+  llvm::DenseMap<diag::kind, const Section *> DiagToSection;
+};
+} // namespace
+
+std::unique_ptr<WarningsSpecialCaseList>
+WarningsSpecialCaseList::create(const llvm::MemoryBuffer &Input,
+                                std::string &Err) {
+  auto WarningSuppressionList = std::make_unique<WarningsSpecialCaseList>();
+  if (!WarningSuppressionList->createInternal(&Input, Err))
+    return nullptr;
+  return WarningSuppressionList;
+}
+
+void WarningsSpecialCaseList::processSections(DiagnosticsEngine &Diags) {
+  // Drop the default section introduced by special case list, we only support
+  // exact diagnostic group names.
+  // FIXME: We should make this configurable in the parser instead.
+  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) {
+    llvm::StringRef DiagName = Entry.first();
+    // Each section has a matcher with that section's name, attached to that
+    // line.
+    const auto &DiagSectionMatcher = Entry.second.SectionMatcher;
+    unsigned DiagLine = DiagSectionMatcher->Globs.at(DiagName).second;
+    LineAndSectionEntry.emplace_back(DiagLine, &Entry);
+  }
+  llvm::sort(LineAndSectionEntry);
+  static constexpr auto WarningFlavor = clang::diag::Flavor::WarningOrError;
+  for (const auto &[_, SectionEntry] : LineAndSectionEntry) {
+    SmallVector<diag::kind> GroupDiags;
+    llvm::StringRef DiagGroup = SectionEntry->getKey();
+    if (Diags.getDiagnosticIDs()->getDiagnosticsInGroup(
+            WarningFlavor, DiagGroup, GroupDiags)) {
+      StringRef Suggestion =
+          DiagnosticIDs::getNearestOption(WarningFlavor, DiagGroup);
+      Diags.Report(diag::warn_unknown_diag_option)
+          << static_cast<unsigned>(WarningFlavor) << DiagGroup
+          << !Suggestion.empty() << Suggestion;
+      continue;
+    }
+    for (diag::kind Diag : GroupDiags)
+      // We're intentionally overwriting any previous mappings here to make sure
+      // latest one takes precedence.
+      DiagToSection[Diag] = &SectionEntry->getValue();
+  }
+}
+
+void DiagnosticsEngine::setDiagSuppressionMapping(llvm::MemoryBuffer &Input) {
+  std::string Err;
+  auto WarningSuppressionList = WarningsSpecialCaseList::create(Input, Err);
+  if (!WarningSuppressionList) {
+    Report(diag::err_drv_malformed_warning_suppression_mapping)
+        << Input.getBufferIdentifier() << Err;
+    return;
+  }
+  WarningSuppressionList->processSections(*this);
+  DiagSuppressionMapping =
+      [WarningSuppressionList(std::move(WarningSuppressionList))](
+          diag::kind DiagId, llvm::StringRef Path) {
+        return WarningSuppressionList->isDiagSuppressed(DiagId, Path);
+      };
+}
+
+bool WarningsSpecialCaseList::isDiagSuppressed(diag::kind DiagId,
+                                               llvm::StringRef FilePath) const {
+  const Section *DiagSection = DiagToSection.lookup(DiagId);
+  if (!DiagSection)
+    return false;
+  const SectionEntries &EntityTypeToCategories = DiagSection->Entries;
+  auto SrcEntriesIt = EntityTypeToCategories.find("src");
+  if (SrcEntriesIt == EntityTypeToCategories.end())
+    return false;
+  const llvm::StringMap<llvm::SpecialCaseList::Matcher> &CategoriesToMatchers =
+      SrcEntriesIt->second;
----------------
bricknerb wrote:

Thanks, makes sense!
Now I feel like adding this functionality :).

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


More information about the cfe-commits mailing list