================
@@ -7,108 +7,228 @@
 
//===----------------------------------------------------------------------===//
 
 #include "clang/Frontend/SARIFDiagnostic.h"
-#include "clang/Basic/CharInfo.h"
+#include "clang/Basic/Diagnostic.h"
 #include "clang/Basic/DiagnosticOptions.h"
-#include "clang/Basic/FileManager.h"
+#include "clang/Basic/DiagnosticSema.h"
 #include "clang/Basic/Sarif.h"
 #include "clang/Basic/SourceLocation.h"
 #include "clang/Basic/SourceManager.h"
 #include "clang/Lex/Lexer.h"
 #include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/SmallString.h"
-#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Support/Casting.h"
 #include "llvm/Support/ConvertUTF.h"
 #include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/ErrorOr.h"
 #include "llvm/Support/Locale.h"
-#include "llvm/Support/Path.h"
-#include "llvm/Support/raw_ostream.h"
 #include <algorithm>
 #include <string>
 
 namespace clang {
 
+// In sarif mode,
+// a diagnostics 'group' have 1 top-level error/warning and several sub-level
+// notes. For example:
+//
+// error: static assertion failed.
+//   note: in instantiation of 'cat::meow'.
+//     note: because concept 'paper_tiger' would be invalid.
+// error: invalid operands to binary expression 'cat::meow' and 'dog::wolf'.
+//   note: candidate function not viable.
+//     note: no known conversion from 'tiger::meooooow' to 'cat::meow'
+//   note: candidate function ignored.
+//     note: constraints not satisfied.
+//   note: ... (candidates)
+//     note: ... (reasons)
+//   note: too many candidates.
+// error: too many errors occured, stopping now.
+
 SARIFDiagnostic::SARIFDiagnostic(raw_ostream &OS, const LangOptions &LangOpts,
                                  DiagnosticOptions &DiagOpts,
                                  SarifDocumentWriter *Writer)
-    : DiagnosticRenderer(LangOpts, DiagOpts), Writer(Writer) {}
+    : DiagnosticRenderer(LangOpts, DiagOpts),
+      Root(Node::Result(), Node::Option{&LangOpts, &DiagOpts},
+           /*Nesting=*/-1), // The root does not represents a diagnostic.
+      Current(&Root), Writer(Writer) {
+  // Don't print 'X warnings and Y errors generated'.
+  DiagOpts.ShowCarets = false;
+}
+
+// helper function
+namespace {
+template <class NodeType, class IterateFuncType, class ApplyFuncType>
+void RecursiveFor(NodeType &&Node, IterateFuncType &&IterateFunc,
+                  ApplyFuncType &&ApplyFunc) {
+  for (auto &&Child : IterateFunc(Node)) {
+    ApplyFunc(*Child);
+    RecursiveFor(*Child, IterateFunc, ApplyFunc);
+  }
+}
+} // namespace
+
+SARIFDiagnostic::~SARIFDiagnostic() {
+  // clang-format off
+  for (auto& TopLevelDiagnosticsPtr : Root.getChildrenPtrs()) { // For each 
top-level error/warnings.
+    unsigned DiagID = TopLevelDiagnosticsPtr->getDiagID();
+    SarifRule Rule = SarifRule::create() // Each top-level error/warning has a 
corresponding Rule.
+      .setRuleId(std::to_string(DiagID))
+      .setDefaultConfiguration(
+        SarifReportingConfiguration::create()
+          .setLevel(
+            TopLevelDiagnosticsPtr->getLevel() == 
DiagnosticsEngine::Level::Note    ? SarifResultLevel::Note :
+            TopLevelDiagnosticsPtr->getLevel() == 
DiagnosticsEngine::Level::Remark  ? SarifResultLevel::Note :
+            TopLevelDiagnosticsPtr->getLevel() == 
DiagnosticsEngine::Level::Warning ? SarifResultLevel::Warning :
+            TopLevelDiagnosticsPtr->getLevel() == 
DiagnosticsEngine::Level::Error   ? SarifResultLevel::Error :
+            TopLevelDiagnosticsPtr->getLevel() == 
DiagnosticsEngine::Level::Fatal   ? SarifResultLevel::Error :
+                                         (assert(false && "Invalid diagnostic 
type"), SarifResultLevel::None)
+          )
+          .setRank(
+            TopLevelDiagnosticsPtr->getLevel() <= 
DiagnosticsEngine::Level::Warning ? 0  :
+            TopLevelDiagnosticsPtr->getLevel() == 
DiagnosticsEngine::Level::Error   ? 50 :
+            TopLevelDiagnosticsPtr->getLevel() == 
DiagnosticsEngine::Level::Fatal   ? 100 :
+                                         (assert(false && "Invalid diagnostic 
type"), 0)
+          )
+      );
+    unsigned RuleIndex = Writer->createRule(Rule); // Write into Writer.
+
+    SarifResult Result = SarifResult::create(RuleIndex)
+      .setDiagnosticMessage(TopLevelDiagnosticsPtr->getDiagnosticMessage())
+      .addLocations(TopLevelDiagnosticsPtr->getLocations())
+      .addRelatedLocations(TopLevelDiagnosticsPtr->getRelatedLocations());
+    RecursiveFor(*TopLevelDiagnosticsPtr, [] (Node& Node) -> auto& { return 
Node.getChildrenPtrs(); }, [&] (Node& Node) { // For each (recursive) 
ChildResults.
+      Result.addRelatedLocations({
+        SarifChildResult::create()
+          .setDiagnosticMessage(Node.getDiagnosticMessage())
+          .addLocations(Node.getLocations())
+          .setNesting(Node.getNesting())
+      });
+      Result.addRelatedLocations(Node.getRelatedLocations());
+    });
+    Writer->appendResult(Result); // Write into Writer
+  }
+  // clang-format on
+}
 
-// FIXME(llvm-project/issues/57323): Refactor Diagnostic classes.
 void SARIFDiagnostic::emitDiagnosticMessage(
     FullSourceLoc Loc, PresumedLoc PLoc, DiagnosticsEngine::Level Level,
     StringRef Message, ArrayRef<clang::CharSourceRange> Ranges,
-    DiagOrStoredDiag D) {
+    DiagOrStoredDiag Diag) {
+
+  if (Level >= DiagnosticsEngine::Level::Warning) {
+    Current =
+        &Root; // If this is a top-level error/warning, repoint Current to 
Root.
+  } else {
+    if (Message.starts_with("candidate"))
+      Current =
+          &Current
+               ->getForkableParent(); // If this is an forked-case note, 
repoint
+                                      // Current to the nearest forkable Node.
+  }
+  Current = &Current->addChildResult(
+      Node::Result{Level, std::string(Message),
+                   Diag}); // add child to the parent error/warning/note Node.
+  Current = &Current->addLocation(
+      Node::Location{Loc, PLoc, llvm::SmallVector<CharSourceRange>(Ranges)});
+}
 
-  const auto *Diag = D.dyn_cast<const Diagnostic *>();
+void SARIFDiagnostic::emitIncludeLocation(FullSourceLoc Loc, PresumedLoc PLoc) 
{
+  Current = &Current->addRelatedLocation(Node::Location{Loc, PLoc, {}});
+}
 
-  if (!Diag)
-    return;
+void SARIFDiagnostic::emitImportLocation(FullSourceLoc Loc, PresumedLoc PLoc,
+                                         StringRef ModuleName) {
+  Current = &Current->addRelatedLocation(Node::Location{Loc, PLoc, {}});
+}
 
-  SarifRule Rule = 
SarifRule::create().setRuleId(std::to_string(Diag->getID()));
+SARIFDiagnostic::Node::Node(Result Result_, Option Option_, int Nesting)
+    : Result_(std::move(Result_)), Option_(std::move(Option_)),
+      Nesting(Nesting) {}
 
-  Rule = addDiagnosticLevelToRule(Rule, Level);
+SARIFDiagnostic::Node &SARIFDiagnostic::Node::getParent() {
+  assert(ParentPtr && "getParent() of SARIFDiagnostic::Root!");
+  return *ParentPtr;
+}
 
-  unsigned RuleIdx = Writer->createRule(Rule);
+SARIFDiagnostic::Node &SARIFDiagnostic::Node::getForkableParent() {
+  Node *Ptr = this;
+  while (Ptr->getLevel() <=
+         DiagnosticsEngine::Note) // The forkable node here "is and only is"
+                                  // warning/error/fatal.
+    Ptr = &Ptr->getParent();
+  return *Ptr;
+}
 
-  SarifResult Result =
-      SarifResult::create(RuleIdx).setDiagnosticMessage(Message);
+llvm::SmallVector<std::unique_ptr<SARIFDiagnostic::Node>> &
+SARIFDiagnostic::Node::getChildrenPtrs() {
+  return ChildrenPtrs;
+}
 
-  if (Loc.isValid())
-    Result = addLocationToResult(Result, Loc, PLoc, Ranges, *Diag);
+SARIFDiagnostic::Node &
+SARIFDiagnostic::Node::addChildResult(Result ChildResult) {
+  ChildrenPtrs.push_back(
+      std::make_unique<Node>(Node::Result(std::move(ChildResult)),
+                             Node::Option(std::move(Option_)), Nesting + 1));
+  ChildrenPtrs.back()->ParentPtr = this; // I am the parent of this new child.
+  return *ChildrenPtrs.back();
+}
 
-  for (auto &[RelLoc, RelPLoc] : RelatedLocationsCache)
-    Result = addRelatedLocationToResult(Result, RelLoc, RelPLoc);
-  RelatedLocationsCache.clear();
+SARIFDiagnostic::Node &SARIFDiagnostic::Node::addLocation(Location Location) {
+  Locations.push_back(std::move(Location));
+  return *this;
+}
 
-  Writer->appendResult(Result);
+SARIFDiagnostic::Node &
+SARIFDiagnostic::Node::addRelatedLocation(Location Location) {
+  RelatedLocations.push_back(std::move(Location));
+  return *this;
 }
 
-void SARIFDiagnostic::emitIncludeLocation(FullSourceLoc Loc, PresumedLoc PLoc) 
{
-  // We always emit include location before results, for example:
-  //
-  // In file included from ...
-  // In file included from ...
-  // error: ...
-  //
-  // At this time We cannot peek the SarifRule. But what we
-  // do is to push it into a cache and wait for next time
-  // \ref SARIFDiagnostic::emitDiagnosticMessage to pick it up.
-  RelatedLocationsCache.push_back({Loc, PLoc});
+unsigned SARIFDiagnostic::Node::getDiagID() {
+  return llvm::isa<const Diagnostic *>(Result_.Diag)
+             ? Result_.Diag.dyn_cast<const Diagnostic *>()->getID()
+             : Result_.Diag.dyn_cast<const StoredDiagnostic *>()->getID();
 }
 
-void SARIFDiagnostic::emitImportLocation(FullSourceLoc Loc, PresumedLoc PLoc,
-                                         StringRef ModuleName) {
-  RelatedLocationsCache.push_back({Loc, PLoc});
+DiagnosticsEngine::Level SARIFDiagnostic::Node::getLevel() {
+  return Result_.Level;
+}
+
+std::string SARIFDiagnostic::Node::getDiagnosticMessage() {
+  return Result_.Message;
 }
 
-SarifResult SARIFDiagnostic::addLocationToResult(
-    SarifResult Result, FullSourceLoc Loc, PresumedLoc PLoc,
-    ArrayRef<CharSourceRange> Ranges, const Diagnostic &Diag) {
-  auto Locations = getSarifLocation(Loc, PLoc, Ranges);
-  return Result.addLocations(Locations);
+llvm::SmallVector<CharSourceRange> SARIFDiagnostic::Node::getLocations() {
+  llvm::SmallVector<CharSourceRange> CharSourceRanges;
+  std::for_each(Locations.begin(), Locations.end(), [&](Location &Location) {
+    CharSourceRanges.append(Location.getCharSourceRangesWithOption(Option_));
+  });
+  return CharSourceRanges;
 }
 
-SarifResult SARIFDiagnostic::addRelatedLocationToResult(SarifResult Result,
-                                                        FullSourceLoc Loc,
-                                                        PresumedLoc PLoc) {
-  auto Locations = getSarifLocation(Loc, PLoc, {});
-  return Result.addRelatedLocations(Locations);
+llvm::SmallVector<CharSourceRange>
+SARIFDiagnostic::Node::getRelatedLocations() {
+  llvm::SmallVector<CharSourceRange> CharSourceRanges;
+  std::for_each(RelatedLocations.begin(), RelatedLocations.end(),
+                [&](Location &RelatedLocation) {
+                  CharSourceRanges.append(
+                      RelatedLocation.getCharSourceRangesWithOption(Option_));
+                });
+  return CharSourceRanges;
 }
 
+int SARIFDiagnostic::Node::getNesting() { return Nesting; }
+
 llvm::SmallVector<CharSourceRange>
-SARIFDiagnostic::getSarifLocation(FullSourceLoc Loc, PresumedLoc PLoc,
-                                  ArrayRef<CharSourceRange> Ranges) {
+SARIFDiagnostic::Node::Location::getCharSourceRangesWithOption(Option Option) {
   SmallVector<CharSourceRange> Locations = {};
 
   if (PLoc.isInvalid()) {
+    // FIXME(llvm-project/issues/57366): File-only locations
     // At least add the file name if available:
     FileID FID = Loc.getFileID();
     if (FID.isValid()) {
       if (OptionalFileEntryRef FE = Loc.getFileEntryRef()) {
-        emitFilename(FE->getName(), Loc.getManager());
-        // FIXME(llvm-project/issues/57366): File-only locations
+        // EmitFilename(FE->getName(), Loc.getManager());
----------------
Sirraide wrote:

What exactly happened here? Are we just not emitting the filename anymore?

https://github.com/llvm/llvm-project/pull/174106
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to