================
@@ -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();
----------------
Sirraide wrote:
I’d put the comment before the loop since this formatting is a bit
horrible—also what level does the root note have? It might be a good idea to
set it e.g. to `Error` so we don’t get a `nullptr` dereference here in case we
*somehow* end up emitting notes w/o a warning/error (though we should probably
just assert somewhere if that happens).
https://github.com/llvm/llvm-project/pull/174106
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits