[clang] [Clang][Diagnose] New feature: Primary support for nested/indented diagnostic in sarif. (PR #174106)
via cfe-commits
cfe-commits at lists.llvm.org
Sat Jan 10 22:30:34 PST 2026
https://github.com/anonymouspc updated https://github.com/llvm/llvm-project/pull/174106
>From 5b3a97ccca6e1ee89c35edac55aa06a35e5b5473 Mon Sep 17 00:00:00 2001
From: anonymous <shyeyian at icloud.com>
Date: Thu, 1 Jan 2026 02:00:40 +0800
Subject: [PATCH 01/21] Logically define sarif-tree.
We know that the `clang++` diagnostics is **logically** a tree, which means that one error/warning often corresponds to several notes (and maybe recursively more notes). Let's take an example, a typical `clang++` diagnostics might looks like:
```
error: invalid binary operand '+' to A and B.
note: candidate 1
note: why candidate 1 is invalid
note: candidate 2
note: why candidate 2 is invalid
error: static assertion failed.
note: in instantiation of C
note: in instantiation of D
note: concept/constraints not satisfied.
```
This commit rewrites the logical-data-structure of sarif into a tree (see `SARIFDiagnostic::Node`), that is:
- when the `DiagnosticRenderer` emits diagnostics, `SARIFDiagnostic` organize them into a recursive tree;
- when the `SARIFDiagnostic` destructs, it flush them all into the `SarifDocumentWriter`.
---
.../include/clang/Frontend/SARIFDiagnostic.h | 89 +++--
clang/lib/Frontend/SARIFDiagnostic.cpp | 314 +++++++++++-------
2 files changed, 258 insertions(+), 145 deletions(-)
diff --git a/clang/include/clang/Frontend/SARIFDiagnostic.h b/clang/include/clang/Frontend/SARIFDiagnostic.h
index 7a6f27eb3b9fa..70b5c80b68812 100644
--- a/clang/include/clang/Frontend/SARIFDiagnostic.h
+++ b/clang/include/clang/Frontend/SARIFDiagnostic.h
@@ -14,9 +14,13 @@
#ifndef LLVM_CLANG_FRONTEND_SARIFDIAGNOSTIC_H
#define LLVM_CLANG_FRONTEND_SARIFDIAGNOSTIC_H
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/DiagnosticOptions.h"
+#include "clang/Basic/LangOptions.h"
#include "clang/Basic/Sarif.h"
+#include "clang/Basic/SourceLocation.h"
#include "clang/Frontend/DiagnosticRenderer.h"
-#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/SmallVector.h"
namespace clang {
@@ -25,7 +29,7 @@ class SARIFDiagnostic : public DiagnosticRenderer {
SARIFDiagnostic(raw_ostream &OS, const LangOptions &LangOpts,
DiagnosticOptions &DiagOpts, SarifDocumentWriter *Writer);
- ~SARIFDiagnostic() = default;
+ ~SARIFDiagnostic();
SARIFDiagnostic &operator=(const SARIFDiagnostic &&) = delete;
SARIFDiagnostic(SARIFDiagnostic &&) = delete;
@@ -36,7 +40,7 @@ class SARIFDiagnostic : public DiagnosticRenderer {
void emitDiagnosticMessage(FullSourceLoc Loc, PresumedLoc PLoc,
DiagnosticsEngine::Level Level, StringRef Message,
ArrayRef<CharSourceRange> Ranges,
- DiagOrStoredDiag D) override;
+ DiagOrStoredDiag Diag) override;
void emitDiagnosticLoc(FullSourceLoc Loc, PresumedLoc PLoc,
DiagnosticsEngine::Level Level,
@@ -55,28 +59,63 @@ class SARIFDiagnostic : public DiagnosticRenderer {
StringRef ModuleName) override;
private:
- // Shared between SARIFDiagnosticPrinter and this renderer.
- SarifDocumentWriter *Writer;
-
- SarifResult addLocationToResult(SarifResult Result, FullSourceLoc Loc,
- PresumedLoc PLoc,
- ArrayRef<CharSourceRange> Ranges,
- const Diagnostic &Diag);
-
- SarifResult addRelatedLocationToResult(SarifResult Result, FullSourceLoc Loc,
- PresumedLoc PLoc);
-
- llvm::SmallVector<CharSourceRange>
- getSarifLocation(FullSourceLoc Loc, PresumedLoc PLoc,
- ArrayRef<CharSourceRange> Ranges);
-
- SarifRule addDiagnosticLevelToRule(SarifRule Rule,
- DiagnosticsEngine::Level Level);
-
- llvm::StringRef emitFilename(StringRef Filename, const SourceManager &SM);
-
- llvm::SmallVector<std::pair<FullSourceLoc, PresumedLoc>>
- RelatedLocationsCache;
+ class Node {
+ public:
+ // Subclasses
+ struct Result {
+ DiagnosticsEngine::Level Level;
+ std::string Message;
+ DiagOrStoredDiag Diag;
+ };
+
+ struct Option {
+ const LangOptions* LangOptsPtr;
+ const DiagnosticOptions* DiagnosticOptsPtr;
+ };
+
+ struct Location {
+ FullSourceLoc Loc;
+ PresumedLoc PLoc;
+ llvm::SmallVector<CharSourceRange> Ranges;
+
+ // Methods to construct a llvm-style location.
+ llvm::SmallVector<CharSourceRange> getCharSourceRangesWithOption(Option);
+ };
+
+ // Constructor
+ Node(Result Result_, Option Option_, int Nesting);
+
+ // Operations on building a node-tree.
+ // Arguments and results are all in node-style.
+ Node& getParent();
+ Node& getForkableParent();
+ llvm::SmallVector<std::unique_ptr<Node>>& getChildrenPtrs();
+ Node& addChildResult(Result);
+ Node& addLocation(Location);
+ Node& addRelatedLocation(Location);
+
+ // Methods to access underlying data for other llvm-components to read from it.
+ // Arguments and results are all in llvm-style.
+ unsigned getDiagID();
+ DiagnosticsEngine::Level getLevel();
+ std::string getDiagnosticMessage();
+ llvm::SmallVector<CharSourceRange> getLocations();
+ llvm::SmallVector<CharSourceRange> getRelatedLocations();
+ int getNesting();
+
+ private:
+ Result Result_;
+ llvm::SmallVector<Location> Locations;
+ llvm::SmallVector<Location> RelatedLocations;
+ Option Option_;
+ int Nesting;
+ Node* ParentPtr = nullptr;
+ llvm::SmallVector<std::unique_ptr<Node>> ChildrenPtrs = {};
+ };
+
+ Node Root;
+ Node* Current = &Root;
+ SarifDocumentWriter *Writer; // Shared between SARIFDiagnosticPrinter and this renderer.
};
} // end namespace clang
diff --git a/clang/lib/Frontend/SARIFDiagnostic.cpp b/clang/lib/Frontend/SARIFDiagnostic.cpp
index 0179307bcbac3..930d1b1383ddb 100644
--- a/clang/lib/Frontend/SARIFDiagnostic.cpp
+++ b/clang/lib/Frontend/SARIFDiagnostic.cpp
@@ -7,108 +7,210 @@
//===----------------------------------------------------------------------===//
#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) {
- const auto *Diag = D.dyn_cast<const Diagnostic *>();
+ 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)});
+}
- if (!Diag)
- return;
+void SARIFDiagnostic::emitIncludeLocation(FullSourceLoc Loc, PresumedLoc PLoc) {
+ Current = &Current->addRelatedLocation(Node::Location{Loc, PLoc, {}});
+}
- SarifRule Rule = SarifRule::create().setRuleId(std::to_string(Diag->getID()));
+void SARIFDiagnostic::emitImportLocation(FullSourceLoc Loc, PresumedLoc PLoc, StringRef ModuleName) {
+ Current = &Current->addRelatedLocation(Node::Location{Loc, PLoc, {}});
+}
- Rule = addDiagnosticLevelToRule(Rule, Level);
+SARIFDiagnostic::Node::Node(Result Result_, Option Option_, int Nesting)
+ : Result_(std::move(Result_)), Option_(std::move(Option_)), Nesting(Nesting) {}
- unsigned RuleIdx = Writer->createRule(Rule);
+SARIFDiagnostic::Node& SARIFDiagnostic::Node::getParent() {
+ assert(ParentPtr && "getParent() of SARIFDiagnostic::Root!");
+ return *ParentPtr;
+}
- SarifResult Result =
- SarifResult::create(RuleIdx).setDiagnosticMessage(Message);
+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;
+}
- if (Loc.isValid())
- Result = addLocationToResult(Result, Loc, PLoc, Ranges, *Diag);
+llvm::SmallVector<std::unique_ptr<SARIFDiagnostic::Node>>& SARIFDiagnostic::Node::getChildrenPtrs() {
+ return ChildrenPtrs;
+}
- for (auto &[RelLoc, RelPLoc] : RelatedLocationsCache)
- Result = addRelatedLocationToResult(Result, RelLoc, RelPLoc);
- RelatedLocationsCache.clear();
+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();
+}
- Writer->appendResult(Result);
+SARIFDiagnostic::Node& SARIFDiagnostic::Node::addLocation(Location Location) {
+ Locations.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});
+SARIFDiagnostic::Node& SARIFDiagnostic::Node::addRelatedLocation(Location Location) {
+ RelatedLocations.push_back(std::move(Location));
+ return *this;
}
-void SARIFDiagnostic::emitImportLocation(FullSourceLoc Loc, PresumedLoc PLoc,
- StringRef ModuleName) {
- 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();
}
-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);
+DiagnosticsEngine::Level SARIFDiagnostic::Node::getLevel() {
+ return Result_.Level;
}
-SarifResult SARIFDiagnostic::addRelatedLocationToResult(SarifResult Result,
- FullSourceLoc Loc,
- PresumedLoc PLoc) {
- auto Locations = getSarifLocation(Loc, PLoc, {});
- return Result.addRelatedLocations(Locations);
+std::string SARIFDiagnostic::Node::getDiagnosticMessage() {
+ return Result_.Message;
}
-llvm::SmallVector<CharSourceRange>
-SARIFDiagnostic::getSarifLocation(FullSourceLoc Loc, PresumedLoc PLoc,
- ArrayRef<CharSourceRange> Ranges) {
- SmallVector<CharSourceRange> 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;
+}
+
+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::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());
}
}
return {};
@@ -135,11 +237,11 @@ SARIFDiagnostic::getSarifLocation(FullSourceLoc Loc, PresumedLoc PLoc,
if (BInfo.first != CaretFileID || EInfo.first != CaretFileID)
continue;
- // Add in the length of the token, so that we cover multi-char
+ // add in the length of the token, so that we cover multi-char
// tokens.
unsigned TokSize = 0;
if (IsTokenRange)
- TokSize = Lexer::MeasureTokenLength(E, SM, LangOpts);
+ TokSize = Lexer::MeasureTokenLength(E, SM, *Option.LangOptsPtr);
FullSourceLoc BF(B, SM), EF(E, SM);
SourceLocation BeginLoc = SM.translateLineCol(
@@ -149,15 +251,15 @@ SARIFDiagnostic::getSarifLocation(FullSourceLoc Loc, PresumedLoc PLoc,
Locations.push_back(
CharSourceRange{SourceRange{BeginLoc, EndLoc}, /* ITR = */ false});
- // FIXME: Additional ranges should use presumed location in both
+ // FIXME: additional ranges should use presumed location in both
// Text and SARIF diagnostics.
}
auto &SM = Loc.getManager();
auto FID = PLoc.getFileID();
// Visual Studio 2010 or earlier expects column number to be off by one.
- unsigned int ColNo = (LangOpts.MSCompatibilityVersion &&
- !LangOpts.isCompatibleWithMSVC(LangOptions::MSVC2012))
+ unsigned int ColNo = (Option.LangOptsPtr->MSCompatibilityVersion &&
+ !Option.LangOptsPtr->isCompatibleWithMSVC(LangOptions::MSVC2012))
? PLoc.getColumn() - 1
: PLoc.getColumn();
SourceLocation DiagLoc = SM.translateLineCol(FID, PLoc.getLine(), ColNo);
@@ -170,67 +272,39 @@ SARIFDiagnostic::getSarifLocation(FullSourceLoc Loc, PresumedLoc PLoc,
return Locations;
}
-SarifRule
-SARIFDiagnostic::addDiagnosticLevelToRule(SarifRule Rule,
- DiagnosticsEngine::Level Level) {
- auto Config = SarifReportingConfiguration::create();
-
- switch (Level) {
- case DiagnosticsEngine::Note:
- Config = Config.setLevel(SarifResultLevel::Note);
- break;
- case DiagnosticsEngine::Remark:
- Config = Config.setLevel(SarifResultLevel::None);
- break;
- case DiagnosticsEngine::Warning:
- Config = Config.setLevel(SarifResultLevel::Warning);
- break;
- case DiagnosticsEngine::Error:
- Config = Config.setLevel(SarifResultLevel::Error).setRank(50);
- break;
- case DiagnosticsEngine::Fatal:
- Config = Config.setLevel(SarifResultLevel::Error).setRank(100);
- break;
- case DiagnosticsEngine::Ignored:
- assert(false && "Invalid diagnostic type");
- }
-
- return Rule.setDefaultConfiguration(Config);
-}
-
-llvm::StringRef SARIFDiagnostic::emitFilename(StringRef Filename,
- const SourceManager &SM) {
- if (DiagOpts.AbsolutePath) {
- auto File = SM.getFileManager().getOptionalFileRef(Filename);
- if (File) {
- // We want to print a simplified absolute path, i. e. without "dots".
- //
- // The hardest part here are the paths like "<part1>/<link>/../<part2>".
- // On Unix-like systems, we cannot just collapse "<link>/..", because
- // paths are resolved sequentially, and, thereby, the path
- // "<part1>/<part2>" may point to a different location. That is why
- // we use FileManager::getCanonicalName(), which expands all indirections
- // with llvm::sys::fs::real_path() and caches the result.
- //
- // On the other hand, it would be better to preserve as much of the
- // original path as possible, because that helps a user to recognize it.
- // real_path() expands all links, which is sometimes too much. Luckily,
- // on Windows we can just use llvm::sys::path::remove_dots(), because,
- // on that system, both aforementioned paths point to the same place.
-#ifdef _WIN32
- SmallString<256> TmpFilename = File->getName();
- SM.getFileManager().makeAbsolutePath(TmpFilename);
- llvm::sys::path::native(TmpFilename);
- llvm::sys::path::remove_dots(TmpFilename, /* remove_dot_dot */ true);
- Filename = StringRef(TmpFilename.data(), TmpFilename.size());
-#else
- Filename = SM.getFileManager().getCanonicalName(*File);
-#endif
- }
- }
-
- return Filename;
-}
+// llvm::StringRef SARIFDiagnostic::EmitFilename(StringRef Filename,
+// const SourceManager &SM) {
+// if (DiagOpts.AbsolutePath) {
+// auto File = SM.getFileManager().getOptionalFileRef(Filename);
+// if (File) {
+// // We want to print a simplified absolute path, i. e. without "dots".
+// //
+// // The hardest part here are the paths like "<part1>/<link>/../<part2>".
+// // On Unix-like systems, we cannot just collapse "<link>/..", because
+// // paths are resolved sequentially, and, thereby, the path
+// // "<part1>/<part2>" may point to a different location. That is why
+// // we use FileManager::getCanonicalName(), which expands all indirections
+// // with llvm::sys::fs::real_path() and caches the result.
+// //
+// // On the other hand, it would be better to preserve as much of the
+// // original path as possible, because that helps a user to recognize it.
+// // real_path() expands all links, which is sometimes too much. Luckily,
+// // on Windows we can just use llvm::sys::path::remove_dots(), because,
+// // on that system, both aforementioned paths point to the same place.
+// #ifdef _WIN32
+// SmallString<256> TmpFilename = File->getName();
+// llvm::sys::fs::make_absolute(TmpFilename);
+// llvm::sys::path::native(TmpFilename);
+// llvm::sys::path::remove_dots(TmpFilename, /* remove_dot_dot */ true);
+// Filename = StringRef(TmpFilename.data(), TmpFilename.size());
+// #else
+// Filename = SM.getFileManager().getCanonicalName(*File);
+// #endif
+// }
+// }
+
+// return Filename;
+// }
/// Print out the file/line/column information and include trace.
///
>From 3a067d9291d6b29693b6e251db04774979f5e4e6 Mon Sep 17 00:00:00 2001
From: anonymous <shyeyian at icloud.com>
Date: Thu, 1 Jan 2026 02:10:42 +0800
Subject: [PATCH 02/21] Physically define sarif-tree.
**Physically**, the sarif diagnostics format has a plain structure, that is:
- one `result` may carry several `Location`s and several `relatedLocation`s
- a `Location` is the place where error occurs, e.g. `main.cpp:3:4`,
- a `relatedLocation` is either a
- `In file included from...` location, or a
- *`child-result`*, who takes message, location, and **nesting**.
- which **logically** corresponds a `clang++` note diagnostic.
In this commit, we expand the definition of `SarifResult::RelatedLocations` from `vector<CharSourceRange>` into `vector<variant<SarifChildResult, CharSourceRange>>`, and, at the same time update the corresponding serialization function for `relatedLocations`.
*(Note that GCC also makes sarif output in the same way: put child `results` into `relatedLocations` and then mark them with `properties.nestingLevel`)*.
---
clang/include/clang/Basic/Sarif.h | 44 ++++++++++++++++++++++++++++++-
clang/lib/Basic/Sarif.cpp | 18 +++++++++++--
2 files changed, 59 insertions(+), 3 deletions(-)
diff --git a/clang/include/clang/Basic/Sarif.h b/clang/include/clang/Basic/Sarif.h
index 6f82d253876d9..9be91f7467f40 100644
--- a/clang/include/clang/Basic/Sarif.h
+++ b/clang/include/clang/Basic/Sarif.h
@@ -44,6 +44,7 @@
#include <initializer_list>
#include <optional>
#include <string>
+#include <variant>
namespace clang {
@@ -295,6 +296,42 @@ class SarifRule {
}
};
+/// A SARIF child-result is
+/// - logically, a sub-result (e.g. note) belonging to a SARIF result (e.g. error, warning)
+/// - physically, a RelatedLocation in a SARIF result (same level as "in file included from..." locations)
+class SarifChildResult {
+ friend class clang::SarifDocumentWriter;
+
+ std::string DiagnosticMessage;
+ llvm::SmallVector<CharSourceRange> Locations;
+ int Nesting;
+ std::optional<SarifResultLevel> LevelOverride;
+
+public:
+ static SarifChildResult create() { return SarifChildResult(); }
+
+ SarifChildResult setDiagnosticMessage(llvm::StringRef Message) {
+ DiagnosticMessage = Message.str();
+ return *this;
+ }
+
+ SarifChildResult addLocations(llvm::ArrayRef<CharSourceRange> DiagLocs) {
+#ifndef NDEBUG
+ for (const auto &Loc : DiagLocs) {
+ assert(Loc.isCharRange() &&
+ "SARIF Child Results require character granular source ranges!");
+ }
+#endif
+ Locations.append(DiagLocs.begin(), DiagLocs.end());
+ return *this;
+ }
+
+ SarifChildResult setNesting(int Nest) {
+ Nesting = Nest;
+ return *this;
+ }
+};
+
/// A SARIF result (also called a "reporting item") is a unit of output
/// produced when one of the tool's \c reportingDescriptor encounters a match
/// on the file being analysed by the tool.
@@ -325,7 +362,7 @@ class SarifResult {
std::string HostedViewerURI;
llvm::SmallDenseMap<StringRef, std::string, 4> PartialFingerprints;
llvm::SmallVector<CharSourceRange, 8> Locations;
- llvm::SmallVector<CharSourceRange, 8> RelatedLocations;
+ llvm::SmallVector<std::variant<SarifChildResult, CharSourceRange>, 8> RelatedLocations; // A RelatedLocation is either a ChildResult or a plain "in file included from..." Location.
llvm::SmallVector<ThreadFlow, 8> ThreadFlows;
std::optional<SarifResultLevel> LevelOverride;
@@ -378,6 +415,11 @@ class SarifResult {
return *this;
}
+ SarifResult addRelatedLocations(llvm::ArrayRef<SarifChildResult> ChildResults) {
+ RelatedLocations.append(ChildResults.begin(), ChildResults.end());
+ return *this;
+ }
+
SarifResult setThreadFlows(llvm::ArrayRef<ThreadFlow> ThreadFlowResults) {
ThreadFlows.assign(ThreadFlowResults.begin(), ThreadFlowResults.end());
return *this;
diff --git a/clang/lib/Basic/Sarif.cpp b/clang/lib/Basic/Sarif.cpp
index 448de96d474af..1da7c6731d650 100644
--- a/clang/lib/Basic/Sarif.cpp
+++ b/clang/lib/Basic/Sarif.cpp
@@ -406,8 +406,22 @@ void SarifDocumentWriter::appendResult(const SarifResult &Result) {
if (!Result.RelatedLocations.empty()) {
json::Array ReLocs;
- for (auto &Range : Result.RelatedLocations) {
- ReLocs.emplace_back(createLocation(createPhysicalLocation(Range)));
+ for (auto &RelatedLocation : Result.RelatedLocations) {
+ if (RelatedLocation.index() == 0) { // variant is a SarifChildResult
+ const SarifChildResult& ChildResult = std::get<0>(RelatedLocation);
+ json::Object Object;
+ Object.insert({"message", createMessage(ChildResult.DiagnosticMessage)});
+ if (ChildResult.Locations.size() >= 1)
+ for (auto& kv : createLocation(createPhysicalLocation(ChildResult.Locations[0])))
+ Object.insert({kv.getFirst(), kv.getSecond()});
+ Object.insert({
+ "properties", json::Object{{"nestingLevel", ChildResult.Nesting}}
+ });
+ ReLocs.emplace_back(std::move(Object));
+ } else { // variant is a CharSourceRange
+ const CharSourceRange& Range = std::get<1>(RelatedLocation);
+ ReLocs.emplace_back(createLocation(createPhysicalLocation(Range)));
+ }
}
Ret["relatedLocations"] = std::move(ReLocs);
}
>From 3649928862c8752c5020efad3cab66b344769535 Mon Sep 17 00:00:00 2001
From: anonymous <shyeyian at icloud.com>
Date: Thu, 1 Jan 2026 02:13:29 +0800
Subject: [PATCH 03/21] Adjust the printer logic.
Now the `SARIFDiagnotic` flushes all the diagnostics (at one time) when it destructs, so we need to adjust the sequence of `SARIFDiagnosticPrinter` in order that the `Writer->endRun()` happens **after** the `SARIFDiagnostic` flushes.
---
clang/lib/Frontend/SARIFDiagnosticPrinter.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/clang/lib/Frontend/SARIFDiagnosticPrinter.cpp b/clang/lib/Frontend/SARIFDiagnosticPrinter.cpp
index 988159693389b..2d1225c823c86 100644
--- a/clang/lib/Frontend/SARIFDiagnosticPrinter.cpp
+++ b/clang/lib/Frontend/SARIFDiagnosticPrinter.cpp
@@ -38,11 +38,11 @@ void SARIFDiagnosticPrinter::BeginSourceFile(const LangOptions &LO,
void SARIFDiagnosticPrinter::EndSourceFile() {
assert(SARIFDiag && "SARIFDiagnostic has not been set.");
- Writer->endRun();
+ SARIFDiag.reset();
llvm::json::Value Value(Writer->createDocument());
OS << "\n" << Value << "\n\n";
OS.flush();
- SARIFDiag.reset();
+ Writer->endRun();
}
void SARIFDiagnosticPrinter::HandleDiagnostic(DiagnosticsEngine::Level Level,
>From 0f0ef838154d93ceaeb08db944fbb7db85bb12c6 Mon Sep 17 00:00:00 2001
From: anonymous <shyeyian at icloud.com>
Date: Thu, 1 Jan 2026 02:17:17 +0800
Subject: [PATCH 04/21] Disable sarif warnings.
Currently the `-Wsarif-format-unstable` warning happens **before** the `SARIFDiagnostic` works, This warning message will not appear in the `json` output, instead, it triggers in text-mode before the json output. To make the `clang++` output machine-parsable, let's remove this warning (or move this warning into the json).
In my perspective, after many efforts now the sarif mode seems ok to be used. Let's remove the `-Wsarif-format-unstable` warning.
---
clang/include/clang/Basic/DiagnosticDriverKinds.td | 4 ----
clang/lib/Driver/ToolChains/Clang.cpp | 3 ---
2 files changed, 7 deletions(-)
diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td
index af5387b2c8f02..bbcbc040d330e 100644
--- a/clang/include/clang/Basic/DiagnosticDriverKinds.td
+++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td
@@ -854,10 +854,6 @@ def err_drv_invalid_empty_dxil_validator_version : Error<
"invalid validator version : %0; if validator major version is 0, minor "
"version must also be 0">;
-def warn_drv_sarif_format_unstable : Warning<
- "diagnostic formatting in SARIF mode is currently unstable">,
- InGroup<DiagGroup<"sarif-format-unstable">>;
-
def warn_drv_loongarch_conflicting_implied_val : Warning<
"ignoring '%0' as it conflicts with that implied by '%1' (%2)">,
InGroup<OptionIgnored>;
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index 4399eb475be75..c66e5c32f0626 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -4262,9 +4262,6 @@ static void RenderDiagnosticsOptions(const Driver &D, const ArgList &Args,
if (const Arg *A = Args.getLastArg(options::OPT_fdiagnostics_format_EQ)) {
CmdArgs.push_back("-fdiagnostics-format");
CmdArgs.push_back(A->getValue());
- if (StringRef(A->getValue()) == "sarif" ||
- StringRef(A->getValue()) == "SARIF")
- D.Diag(diag::warn_drv_sarif_format_unstable);
}
if (const Arg *A = Args.getLastArg(
>From cab0781a2e9c87d63daf0d705a812d137abec873 Mon Sep 17 00:00:00 2001
From: anonymous <shyeyian at icloud.com>
Date: Thu, 1 Jan 2026 02:18:27 +0800
Subject: [PATCH 05/21] Update test.
Update these corresponding test for `SARIFDiagnostic` and the `relatedLocations` (with child results).
---
clang/unittests/Basic/SarifTest.cpp | 12 +++++++++---
1 file changed, 9 insertions(+), 3 deletions(-)
diff --git a/clang/unittests/Basic/SarifTest.cpp b/clang/unittests/Basic/SarifTest.cpp
index 42e85085d646e..74dd2d12b9446 100644
--- a/clang/unittests/Basic/SarifTest.cpp
+++ b/clang/unittests/Basic/SarifTest.cpp
@@ -290,7 +290,7 @@ TEST_F(SarifDocumentWriterTest, checkSerializingResultsWithCustomRuleConfig) {
TEST_F(SarifDocumentWriterTest, checkSerializingArtifacts) {
// GIVEN:
const std::string ExpectedOutput =
- R"({"$schema":"https://docs.oasis-open.org/sarif/sarif/v2.1.0/cos02/schemas/sarif-schema-2.1.0.json","runs":[{"artifacts":[{"length":40,"location":{"index":0,"uri":"file:///main.cpp"},"mimeType":"text/plain","roles":["resultFile"]}],"columnKind":"unicodeCodePoints","results":[{"level":"error","locations":[{"physicalLocation":{"artifactLocation":{"index":0,"uri":"file:///main.cpp"},"region":{"endColumn":14,"startColumn":14,"startLine":3}}}],"message":{"text":"expected ';' after top level declarator"},"relatedLocations":[{"physicalLocation":{"artifactLocation":{"index":0,"uri":"file:///main.cpp"},"region":{"endColumn":14,"startColumn":14,"startLine":3}}}],"ruleId":"clang.unittest","ruleIndex":0}],"tool":{"driver":{"fullName":"sarif test runner","informationUri":"https://clang.llvm.org/docs/UsersManual.html","language":"en-US","name":"sarif test","rules":[{"defaultConfiguration":{"enabled":true,"level":"warning","rank":-1},"fullDescription":{"text":"Example rule created during unit tests"},"id":"clang.unittest","name":"clang unit test"}],"version":"1.0.0"}}}],"version":"2.1.0"})";
+ "{\"$schema\":\"https://docs.oasis-open.org/sarif/sarif/v2.1.0/cos02/schemas/sarif-schema-2.1.0.json\",\"runs\":[{\"artifacts\":[{\"length\":40,\"location\":{\"index\":0,\"uri\":\"file:///main.cpp\"},\"mimeType\":\"text/plain\",\"roles\":[\"resultFile\"]}],\"columnKind\":\"unicodeCodePoints\",\"results\":[{\"level\":\"error\",\"locations\":[{\"physicalLocation\":{\"artifactLocation\":{\"index\":0,\"uri\":\"file:///main.cpp\"},\"region\":{\"endColumn\":14,\"startColumn\":14,\"startLine\":3}}}],\"message\":{\"text\":\"expected ';' after top level declarator\"},\"relatedLocations\":[{\"physicalLocation\":{\"artifactLocation\":{\"index\":0,\"uri\":\"file:///main.cpp\"},\"region\":{\"endColumn\":14,\"startColumn\":14,\"startLine\":3}}},{\"message\":{\"text\":\"in instantiation of 'float x = 0.0'\"},\"physicalLocation\":{\"artifactLocation\":{\"index\":0,\"uri\":\"file:///main.cpp\"},\"region\":{\"endColumn\":14,\"startColumn\":14,\"startLine\":3}},\"properties\":{\"nestingLevel\":1}}],\"ruleId\":\"clang.unittest\",\"ruleIndex\":0}],\"tool\":{\"driver\":{\"fullName\":\"sarif test runner\",\"informationUri\":\"https://clang.llvm.org/docs/UsersManual.html\",\"language\":\"en-US\",\"name\":\"sarif test\",\"rules\":[{\"defaultConfiguration\":{\"enabled\":true,\"level\":\"warning\",\"rank\":-1},\"fullDescription\":{\"text\":\"Example rule created during unit tests\"},\"id\":\"clang.unittest\",\"name\":\"clang unit test\"}],\"version\":\"1.0.0\"}}}],\"version\":\"2.1.0\"}";
SarifDocumentWriter Writer{SourceMgr};
const SarifRule &Rule =
@@ -316,10 +316,16 @@ TEST_F(SarifDocumentWriterTest, checkSerializingArtifacts) {
const SarifResult &Result =
SarifResult::create(RuleIdx)
+ .setDiagnosticLevel(SarifResultLevel::Error)
+ .setDiagnosticMessage("expected ';' after top level declarator")
.addLocations(DiagLocs)
.addRelatedLocations(DiagLocs)
- .setDiagnosticMessage("expected ';' after top level declarator")
- .setDiagnosticLevel(SarifResultLevel::Error);
+ .addRelatedLocations({
+ SarifChildResult::create()
+ .setDiagnosticMessage("in instantiation of 'float x = 0.0'")
+ .addLocations(DiagLocs)
+ .setNesting(1)
+ });
Writer.appendResult(Result);
std::string Output = serializeSarifDocument(Writer.createDocument());
>From 43b9fd672513e5ecf96b59fa0fd0e745cdfd10de Mon Sep 17 00:00:00 2001
From: anonymous <shyeyian at icloud.com>
Date: Thu, 1 Jan 2026 02:42:38 +0800
Subject: [PATCH 06/21] clang-format
---
clang/include/clang/Basic/Sarif.h | 13 +-
.../include/clang/Frontend/SARIFDiagnostic.h | 107 +++++++--------
clang/lib/Basic/Sarif.cpp | 15 ++-
clang/lib/Frontend/SARIFDiagnostic.cpp | 124 +++++++++++-------
clang/unittests/Basic/SarifTest.cpp | 41 +++++-
5 files changed, 178 insertions(+), 122 deletions(-)
diff --git a/clang/include/clang/Basic/Sarif.h b/clang/include/clang/Basic/Sarif.h
index 9be91f7467f40..b7f8175b5ee16 100644
--- a/clang/include/clang/Basic/Sarif.h
+++ b/clang/include/clang/Basic/Sarif.h
@@ -297,8 +297,10 @@ class SarifRule {
};
/// A SARIF child-result is
-/// - logically, a sub-result (e.g. note) belonging to a SARIF result (e.g. error, warning)
-/// - physically, a RelatedLocation in a SARIF result (same level as "in file included from..." locations)
+/// - logically, a sub-result (e.g. note) belonging to a SARIF result (e.g.
+/// error, warning)
+/// - physically, a RelatedLocation in a SARIF result (same level as "in file
+/// included from..." locations)
class SarifChildResult {
friend class clang::SarifDocumentWriter;
@@ -362,7 +364,9 @@ class SarifResult {
std::string HostedViewerURI;
llvm::SmallDenseMap<StringRef, std::string, 4> PartialFingerprints;
llvm::SmallVector<CharSourceRange, 8> Locations;
- llvm::SmallVector<std::variant<SarifChildResult, CharSourceRange>, 8> RelatedLocations; // A RelatedLocation is either a ChildResult or a plain "in file included from..." Location.
+ llvm::SmallVector<std::variant<SarifChildResult, CharSourceRange>, 8>
+ RelatedLocations; // A RelatedLocation is either a ChildResult or a plain
+ // "in file included from..." Location.
llvm::SmallVector<ThreadFlow, 8> ThreadFlows;
std::optional<SarifResultLevel> LevelOverride;
@@ -415,7 +419,8 @@ class SarifResult {
return *this;
}
- SarifResult addRelatedLocations(llvm::ArrayRef<SarifChildResult> ChildResults) {
+ SarifResult
+ addRelatedLocations(llvm::ArrayRef<SarifChildResult> ChildResults) {
RelatedLocations.append(ChildResults.begin(), ChildResults.end());
return *this;
}
diff --git a/clang/include/clang/Frontend/SARIFDiagnostic.h b/clang/include/clang/Frontend/SARIFDiagnostic.h
index 70b5c80b68812..a396e645cb505 100644
--- a/clang/include/clang/Frontend/SARIFDiagnostic.h
+++ b/clang/include/clang/Frontend/SARIFDiagnostic.h
@@ -60,62 +60,63 @@ class SARIFDiagnostic : public DiagnosticRenderer {
private:
class Node {
- public:
- // Subclasses
- struct Result {
- DiagnosticsEngine::Level Level;
- std::string Message;
- DiagOrStoredDiag Diag;
- };
-
- struct Option {
- const LangOptions* LangOptsPtr;
- const DiagnosticOptions* DiagnosticOptsPtr;
- };
-
- struct Location {
- FullSourceLoc Loc;
- PresumedLoc PLoc;
- llvm::SmallVector<CharSourceRange> Ranges;
-
- // Methods to construct a llvm-style location.
- llvm::SmallVector<CharSourceRange> getCharSourceRangesWithOption(Option);
- };
-
- // Constructor
- Node(Result Result_, Option Option_, int Nesting);
-
- // Operations on building a node-tree.
- // Arguments and results are all in node-style.
- Node& getParent();
- Node& getForkableParent();
- llvm::SmallVector<std::unique_ptr<Node>>& getChildrenPtrs();
- Node& addChildResult(Result);
- Node& addLocation(Location);
- Node& addRelatedLocation(Location);
-
- // Methods to access underlying data for other llvm-components to read from it.
- // Arguments and results are all in llvm-style.
- unsigned getDiagID();
- DiagnosticsEngine::Level getLevel();
- std::string getDiagnosticMessage();
- llvm::SmallVector<CharSourceRange> getLocations();
- llvm::SmallVector<CharSourceRange> getRelatedLocations();
- int getNesting();
-
- private:
- Result Result_;
- llvm::SmallVector<Location> Locations;
- llvm::SmallVector<Location> RelatedLocations;
- Option Option_;
- int Nesting;
- Node* ParentPtr = nullptr;
- llvm::SmallVector<std::unique_ptr<Node>> ChildrenPtrs = {};
+ public:
+ // Subclasses
+ struct Result {
+ DiagnosticsEngine::Level Level;
+ std::string Message;
+ DiagOrStoredDiag Diag;
+ };
+
+ struct Option {
+ const LangOptions *LangOptsPtr;
+ const DiagnosticOptions *DiagnosticOptsPtr;
+ };
+
+ struct Location {
+ FullSourceLoc Loc;
+ PresumedLoc PLoc;
+ llvm::SmallVector<CharSourceRange> Ranges;
+
+ // Methods to construct a llvm-style location.
+ llvm::SmallVector<CharSourceRange> getCharSourceRangesWithOption(Option);
+ };
+
+ // Constructor
+ Node(Result Result_, Option Option_, int Nesting);
+
+ // Operations on building a node-tree.
+ // Arguments and results are all in node-style.
+ Node &getParent();
+ Node &getForkableParent();
+ llvm::SmallVector<std::unique_ptr<Node>> &getChildrenPtrs();
+ Node &addChildResult(Result);
+ Node &addLocation(Location);
+ Node &addRelatedLocation(Location);
+
+ // Methods to access underlying data for other llvm-components to read from
+ // it. Arguments and results are all in llvm-style.
+ unsigned getDiagID();
+ DiagnosticsEngine::Level getLevel();
+ std::string getDiagnosticMessage();
+ llvm::SmallVector<CharSourceRange> getLocations();
+ llvm::SmallVector<CharSourceRange> getRelatedLocations();
+ int getNesting();
+
+ private:
+ Result Result_;
+ llvm::SmallVector<Location> Locations;
+ llvm::SmallVector<Location> RelatedLocations;
+ Option Option_;
+ int Nesting;
+ Node *ParentPtr = nullptr;
+ llvm::SmallVector<std::unique_ptr<Node>> ChildrenPtrs = {};
};
Node Root;
- Node* Current = &Root;
- SarifDocumentWriter *Writer; // Shared between SARIFDiagnosticPrinter and this renderer.
+ Node *Current = &Root;
+ SarifDocumentWriter
+ *Writer; // Shared between SARIFDiagnosticPrinter and this renderer.
};
} // end namespace clang
diff --git a/clang/lib/Basic/Sarif.cpp b/clang/lib/Basic/Sarif.cpp
index 1da7c6731d650..bf7a603606a4c 100644
--- a/clang/lib/Basic/Sarif.cpp
+++ b/clang/lib/Basic/Sarif.cpp
@@ -408,18 +408,19 @@ void SarifDocumentWriter::appendResult(const SarifResult &Result) {
json::Array ReLocs;
for (auto &RelatedLocation : Result.RelatedLocations) {
if (RelatedLocation.index() == 0) { // variant is a SarifChildResult
- const SarifChildResult& ChildResult = std::get<0>(RelatedLocation);
+ const SarifChildResult &ChildResult = std::get<0>(RelatedLocation);
json::Object Object;
- Object.insert({"message", createMessage(ChildResult.DiagnosticMessage)});
+ Object.insert(
+ {"message", createMessage(ChildResult.DiagnosticMessage)});
if (ChildResult.Locations.size() >= 1)
- for (auto& kv : createLocation(createPhysicalLocation(ChildResult.Locations[0])))
+ for (auto &kv :
+ createLocation(createPhysicalLocation(ChildResult.Locations[0])))
Object.insert({kv.getFirst(), kv.getSecond()});
- Object.insert({
- "properties", json::Object{{"nestingLevel", ChildResult.Nesting}}
- });
+ Object.insert({"properties",
+ json::Object{{"nestingLevel", ChildResult.Nesting}}});
ReLocs.emplace_back(std::move(Object));
} else { // variant is a CharSourceRange
- const CharSourceRange& Range = std::get<1>(RelatedLocation);
+ const CharSourceRange &Range = std::get<1>(RelatedLocation);
ReLocs.emplace_back(createLocation(createPhysicalLocation(Range)));
}
}
diff --git a/clang/lib/Frontend/SARIFDiagnostic.cpp b/clang/lib/Frontend/SARIFDiagnostic.cpp
index 930d1b1383ddb..1e35d6df4e095 100644
--- a/clang/lib/Frontend/SARIFDiagnostic.cpp
+++ b/clang/lib/Frontend/SARIFDiagnostic.cpp
@@ -26,9 +26,9 @@
namespace clang {
-// In sarif mode,
-// a diagnostics 'group' have 1 top-level error/warning and several sub-level notes.
-// For example:
+// 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'.
@@ -46,24 +46,24 @@ namespace clang {
SARIFDiagnostic::SARIFDiagnostic(raw_ostream &OS, const LangOptions &LangOpts,
DiagnosticOptions &DiagOpts,
SarifDocumentWriter *Writer)
- : DiagnosticRenderer(LangOpts, DiagOpts),
- Root(Node::Result(), Node::Option{&LangOpts, &DiagOpts}, /*Nesting=*/-1), // The root does not represents a diagnostic.
- Current(&Root),
- 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);
- }
+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() {
@@ -115,62 +115,78 @@ void SARIFDiagnostic::emitDiagnosticMessage(
DiagOrStoredDiag Diag) {
if (Level >= DiagnosticsEngine::Level::Warning) {
- Current = &Root; // If this is a top-level error/warning, repoint Current to Root.
+ 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
+ ->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)});
+ 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)});
}
void SARIFDiagnostic::emitIncludeLocation(FullSourceLoc Loc, PresumedLoc PLoc) {
Current = &Current->addRelatedLocation(Node::Location{Loc, PLoc, {}});
}
-void SARIFDiagnostic::emitImportLocation(FullSourceLoc Loc, PresumedLoc PLoc, StringRef ModuleName) {
+void SARIFDiagnostic::emitImportLocation(FullSourceLoc Loc, PresumedLoc PLoc,
+ StringRef ModuleName) {
Current = &Current->addRelatedLocation(Node::Location{Loc, PLoc, {}});
}
SARIFDiagnostic::Node::Node(Result Result_, Option Option_, int Nesting)
- : Result_(std::move(Result_)), Option_(std::move(Option_)), Nesting(Nesting) {}
+ : Result_(std::move(Result_)), Option_(std::move(Option_)),
+ Nesting(Nesting) {}
-SARIFDiagnostic::Node& SARIFDiagnostic::Node::getParent() {
+SARIFDiagnostic::Node &SARIFDiagnostic::Node::getParent() {
assert(ParentPtr && "getParent() of SARIFDiagnostic::Root!");
return *ParentPtr;
}
-SARIFDiagnostic::Node& SARIFDiagnostic::Node::getForkableParent() {
- Node* Ptr = this;
- while (Ptr->getLevel() <= DiagnosticsEngine::Note) // The forkable node here "is and only is" warning/error/fatal.
+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;
}
-llvm::SmallVector<std::unique_ptr<SARIFDiagnostic::Node>>& SARIFDiagnostic::Node::getChildrenPtrs() {
+llvm::SmallVector<std::unique_ptr<SARIFDiagnostic::Node>> &
+SARIFDiagnostic::Node::getChildrenPtrs() {
return ChildrenPtrs;
}
-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));
+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();
}
-SARIFDiagnostic::Node& SARIFDiagnostic::Node::addLocation(Location Location) {
+SARIFDiagnostic::Node &SARIFDiagnostic::Node::addLocation(Location Location) {
Locations.push_back(std::move(Location));
return *this;
}
-SARIFDiagnostic::Node& SARIFDiagnostic::Node::addRelatedLocation(Location Location) {
+SARIFDiagnostic::Node &
+SARIFDiagnostic::Node::addRelatedLocation(Location Location) {
RelatedLocations.push_back(std::move(Location));
return *this;
}
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();
+ return llvm::isa<const Diagnostic *>(Result_.Diag)
+ ? Result_.Diag.dyn_cast<const Diagnostic *>()->getID()
+ : Result_.Diag.dyn_cast<const StoredDiagnostic *>()->getID();
}
DiagnosticsEngine::Level SARIFDiagnostic::Node::getLevel() {
@@ -183,34 +199,36 @@ std::string SARIFDiagnostic::Node::getDiagnosticMessage() {
llvm::SmallVector<CharSourceRange> SARIFDiagnostic::Node::getLocations() {
llvm::SmallVector<CharSourceRange> CharSourceRanges;
- std::for_each(Locations.begin(), Locations.end(), [&] (Location& Location) {
- CharSourceRanges.append(Location.getCharSourceRangesWithOption(Option_));
+ std::for_each(Locations.begin(), Locations.end(), [&](Location &Location) {
+ CharSourceRanges.append(Location.getCharSourceRangesWithOption(Option_));
});
return CharSourceRanges;
}
-llvm::SmallVector<CharSourceRange> SARIFDiagnostic::Node::getRelatedLocations() {
+llvm::SmallVector<CharSourceRange>
+SARIFDiagnostic::Node::getRelatedLocations() {
llvm::SmallVector<CharSourceRange> CharSourceRanges;
- std::for_each(RelatedLocations.begin(), RelatedLocations.end(), [&] (Location& RelatedLocation) {
- CharSourceRanges.append(RelatedLocation.getCharSourceRangesWithOption(Option_));
- });
+ std::for_each(RelatedLocations.begin(), RelatedLocations.end(),
+ [&](Location &RelatedLocation) {
+ CharSourceRanges.append(
+ RelatedLocation.getCharSourceRangesWithOption(Option_));
+ });
return CharSourceRanges;
}
-int SARIFDiagnostic::Node::getNesting() {
- return Nesting;
-}
+int SARIFDiagnostic::Node::getNesting() { return Nesting; }
-llvm::SmallVector<CharSourceRange> SARIFDiagnostic::Node::Location::getCharSourceRangesWithOption(Option Option) {
+llvm::SmallVector<CharSourceRange>
+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());
+ // EmitFilename(FE->getName(), Loc.getManager());
}
}
return {};
@@ -258,10 +276,11 @@ llvm::SmallVector<CharSourceRange> SARIFDiagnostic::Node::Location::getCharSourc
auto &SM = Loc.getManager();
auto FID = PLoc.getFileID();
// Visual Studio 2010 or earlier expects column number to be off by one.
- unsigned int ColNo = (Option.LangOptsPtr->MSCompatibilityVersion &&
- !Option.LangOptsPtr->isCompatibleWithMSVC(LangOptions::MSVC2012))
- ? PLoc.getColumn() - 1
- : PLoc.getColumn();
+ unsigned int ColNo =
+ (Option.LangOptsPtr->MSCompatibilityVersion &&
+ !Option.LangOptsPtr->isCompatibleWithMSVC(LangOptions::MSVC2012))
+ ? PLoc.getColumn() - 1
+ : PLoc.getColumn();
SourceLocation DiagLoc = SM.translateLineCol(FID, PLoc.getLine(), ColNo);
// FIXME(llvm-project/issues/57366): Properly process #line directives.
@@ -279,15 +298,18 @@ llvm::SmallVector<CharSourceRange> SARIFDiagnostic::Node::Location::getCharSourc
// if (File) {
// // We want to print a simplified absolute path, i. e. without "dots".
// //
-// // The hardest part here are the paths like "<part1>/<link>/../<part2>".
+// // The hardest part here are the paths like
+// "<part1>/<link>/../<part2>".
// // On Unix-like systems, we cannot just collapse "<link>/..", because
// // paths are resolved sequentially, and, thereby, the path
// // "<part1>/<part2>" may point to a different location. That is why
-// // we use FileManager::getCanonicalName(), which expands all indirections
+// // we use FileManager::getCanonicalName(), which expands all
+// indirections
// // with llvm::sys::fs::real_path() and caches the result.
// //
// // On the other hand, it would be better to preserve as much of the
-// // original path as possible, because that helps a user to recognize it.
+// // original path as possible, because that helps a user to recognize
+// it.
// // real_path() expands all links, which is sometimes too much. Luckily,
// // on Windows we can just use llvm::sys::path::remove_dots(), because,
// // on that system, both aforementioned paths point to the same place.
diff --git a/clang/unittests/Basic/SarifTest.cpp b/clang/unittests/Basic/SarifTest.cpp
index 74dd2d12b9446..bc19a74ba9148 100644
--- a/clang/unittests/Basic/SarifTest.cpp
+++ b/clang/unittests/Basic/SarifTest.cpp
@@ -290,7 +290,35 @@ TEST_F(SarifDocumentWriterTest, checkSerializingResultsWithCustomRuleConfig) {
TEST_F(SarifDocumentWriterTest, checkSerializingArtifacts) {
// GIVEN:
const std::string ExpectedOutput =
- "{\"$schema\":\"https://docs.oasis-open.org/sarif/sarif/v2.1.0/cos02/schemas/sarif-schema-2.1.0.json\",\"runs\":[{\"artifacts\":[{\"length\":40,\"location\":{\"index\":0,\"uri\":\"file:///main.cpp\"},\"mimeType\":\"text/plain\",\"roles\":[\"resultFile\"]}],\"columnKind\":\"unicodeCodePoints\",\"results\":[{\"level\":\"error\",\"locations\":[{\"physicalLocation\":{\"artifactLocation\":{\"index\":0,\"uri\":\"file:///main.cpp\"},\"region\":{\"endColumn\":14,\"startColumn\":14,\"startLine\":3}}}],\"message\":{\"text\":\"expected ';' after top level declarator\"},\"relatedLocations\":[{\"physicalLocation\":{\"artifactLocation\":{\"index\":0,\"uri\":\"file:///main.cpp\"},\"region\":{\"endColumn\":14,\"startColumn\":14,\"startLine\":3}}},{\"message\":{\"text\":\"in instantiation of 'float x = 0.0'\"},\"physicalLocation\":{\"artifactLocation\":{\"index\":0,\"uri\":\"file:///main.cpp\"},\"region\":{\"endColumn\":14,\"startColumn\":14,\"startLine\":3}},\"properties\":{\"nestingLevel\":1}}],\"ruleId\":\"clang.unittest\",\"ruleIndex\":0}],\"tool\":{\"driver\":{\"fullName\":\"sarif test runner\",\"informationUri\":\"https://clang.llvm.org/docs/UsersManual.html\",\"language\":\"en-US\",\"name\":\"sarif test\",\"rules\":[{\"defaultConfiguration\":{\"enabled\":true,\"level\":\"warning\",\"rank\":-1},\"fullDescription\":{\"text\":\"Example rule created during unit tests\"},\"id\":\"clang.unittest\",\"name\":\"clang unit test\"}],\"version\":\"1.0.0\"}}}],\"version\":\"2.1.0\"}";
+ "{\"$schema\":\"https://docs.oasis-open.org/sarif/sarif/v2.1.0/cos02/"
+ "schemas/"
+ "sarif-schema-2.1.0.json\",\"runs\":[{\"artifacts\":[{\"length\":40,"
+ "\"location\":{\"index\":0,\"uri\":\"file:///"
+ "main.cpp\"},\"mimeType\":\"text/"
+ "plain\",\"roles\":[\"resultFile\"]}],\"columnKind\":"
+ "\"unicodeCodePoints\",\"results\":[{\"level\":\"error\",\"locations\":[{"
+ "\"physicalLocation\":{\"artifactLocation\":{\"index\":0,\"uri\":\"file:/"
+ "//"
+ "main.cpp\"},\"region\":{\"endColumn\":14,\"startColumn\":14,"
+ "\"startLine\":3}}}],\"message\":{\"text\":\"expected ';' after top "
+ "level "
+ "declarator\"},\"relatedLocations\":[{\"physicalLocation\":{"
+ "\"artifactLocation\":{\"index\":0,\"uri\":\"file:///"
+ "main.cpp\"},\"region\":{\"endColumn\":14,\"startColumn\":14,"
+ "\"startLine\":3}}},{\"message\":{\"text\":\"in instantiation of 'float "
+ "x = "
+ "0.0'\"},\"physicalLocation\":{\"artifactLocation\":{\"index\":0,\"uri\":"
+ "\"file:///"
+ "main.cpp\"},\"region\":{\"endColumn\":14,\"startColumn\":14,"
+ "\"startLine\":3}},\"properties\":{\"nestingLevel\":1}}],\"ruleId\":"
+ "\"clang.unittest\",\"ruleIndex\":0}],\"tool\":{\"driver\":{\"fullName\":"
+ "\"sarif test "
+ "runner\",\"informationUri\":\"https://clang.llvm.org/docs/"
+ "UsersManual.html\",\"language\":\"en-US\",\"name\":\"sarif "
+ "test\",\"rules\":[{\"defaultConfiguration\":{\"enabled\":true,\"level\":"
+ "\"warning\",\"rank\":-1},\"fullDescription\":{\"text\":\"Example rule "
+ "created during unit tests\"},\"id\":\"clang.unittest\",\"name\":\"clang "
+ "unit test\"}],\"version\":\"1.0.0\"}}}],\"version\":\"2.1.0\"}";
SarifDocumentWriter Writer{SourceMgr};
const SarifRule &Rule =
@@ -320,12 +348,11 @@ TEST_F(SarifDocumentWriterTest, checkSerializingArtifacts) {
.setDiagnosticMessage("expected ';' after top level declarator")
.addLocations(DiagLocs)
.addRelatedLocations(DiagLocs)
- .addRelatedLocations({
- SarifChildResult::create()
- .setDiagnosticMessage("in instantiation of 'float x = 0.0'")
- .addLocations(DiagLocs)
- .setNesting(1)
- });
+ .addRelatedLocations(
+ {SarifChildResult::create()
+ .setDiagnosticMessage("in instantiation of 'float x = 0.0'")
+ .addLocations(DiagLocs)
+ .setNesting(1)});
Writer.appendResult(Result);
std::string Output = serializeSarifDocument(Writer.createDocument());
>From 73b2da43e6dda7b5de31a97587237df5ca1f4f03 Mon Sep 17 00:00:00 2001
From: anonymous <shyeyian at icloud.com>
Date: Thu, 1 Jan 2026 02:48:36 +0800
Subject: [PATCH 07/21] Update release notes
---
clang/docs/ReleaseNotes.rst | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index f62298938af93..cc5af9e616e1c 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -509,6 +509,10 @@ Improvements to Clang's diagnostics
carries messages like 'In file included from ...' or 'In module ...'.
Now the include/import locations are written into `sarif.run.result.relatedLocations`.
+- Add nested/indented diagnose support when enabling ``-fdiagnostics-format=sarif``.
+ Now the notes are recursively mounted under error/warnings, and the diagnostics can
+ be parsed into a nested/indented tree.
+
- Clang now generates a fix-it for C++20 designated initializers when the
initializers do not match the declaration order in the structure.
>From 37500cbf027800add5ef39070c1f070d1425eead Mon Sep 17 00:00:00 2001
From: anonymous <shyeyian at icloud.com>
Date: Thu, 1 Jan 2026 02:52:17 +0800
Subject: [PATCH 08/21] Update `unittests/Basic/SarifTest.cpp` to keep the
R"(loooong-string)" style unified.
---
clang/unittests/Basic/SarifTest.cpp | 30 +----------------------------
1 file changed, 1 insertion(+), 29 deletions(-)
diff --git a/clang/unittests/Basic/SarifTest.cpp b/clang/unittests/Basic/SarifTest.cpp
index bc19a74ba9148..bd3da526fdd36 100644
--- a/clang/unittests/Basic/SarifTest.cpp
+++ b/clang/unittests/Basic/SarifTest.cpp
@@ -290,35 +290,7 @@ TEST_F(SarifDocumentWriterTest, checkSerializingResultsWithCustomRuleConfig) {
TEST_F(SarifDocumentWriterTest, checkSerializingArtifacts) {
// GIVEN:
const std::string ExpectedOutput =
- "{\"$schema\":\"https://docs.oasis-open.org/sarif/sarif/v2.1.0/cos02/"
- "schemas/"
- "sarif-schema-2.1.0.json\",\"runs\":[{\"artifacts\":[{\"length\":40,"
- "\"location\":{\"index\":0,\"uri\":\"file:///"
- "main.cpp\"},\"mimeType\":\"text/"
- "plain\",\"roles\":[\"resultFile\"]}],\"columnKind\":"
- "\"unicodeCodePoints\",\"results\":[{\"level\":\"error\",\"locations\":[{"
- "\"physicalLocation\":{\"artifactLocation\":{\"index\":0,\"uri\":\"file:/"
- "//"
- "main.cpp\"},\"region\":{\"endColumn\":14,\"startColumn\":14,"
- "\"startLine\":3}}}],\"message\":{\"text\":\"expected ';' after top "
- "level "
- "declarator\"},\"relatedLocations\":[{\"physicalLocation\":{"
- "\"artifactLocation\":{\"index\":0,\"uri\":\"file:///"
- "main.cpp\"},\"region\":{\"endColumn\":14,\"startColumn\":14,"
- "\"startLine\":3}}},{\"message\":{\"text\":\"in instantiation of 'float "
- "x = "
- "0.0'\"},\"physicalLocation\":{\"artifactLocation\":{\"index\":0,\"uri\":"
- "\"file:///"
- "main.cpp\"},\"region\":{\"endColumn\":14,\"startColumn\":14,"
- "\"startLine\":3}},\"properties\":{\"nestingLevel\":1}}],\"ruleId\":"
- "\"clang.unittest\",\"ruleIndex\":0}],\"tool\":{\"driver\":{\"fullName\":"
- "\"sarif test "
- "runner\",\"informationUri\":\"https://clang.llvm.org/docs/"
- "UsersManual.html\",\"language\":\"en-US\",\"name\":\"sarif "
- "test\",\"rules\":[{\"defaultConfiguration\":{\"enabled\":true,\"level\":"
- "\"warning\",\"rank\":-1},\"fullDescription\":{\"text\":\"Example rule "
- "created during unit tests\"},\"id\":\"clang.unittest\",\"name\":\"clang "
- "unit test\"}],\"version\":\"1.0.0\"}}}],\"version\":\"2.1.0\"}";
+ R"({"$schema":"https://docs.oasis-open.org/sarif/sarif/v2.1.0/cos02/schemas/sarif-schema-2.1.0.json","runs":[{"artifacts":[{"length":40,"location":{"index":0,"uri":"file:///main.cpp"},"mimeType":"text/plain","roles":["resultFile"]}],"columnKind":"unicodeCodePoints","results":[{"level":"error","locations":[{"physicalLocation":{"artifactLocation":{"index":0,"uri":"file:///main.cpp"},"region":{"endColumn":14,"startColumn":14,"startLine":3}}}],"message":{"text":"expected ';' after top level declarator"},"relatedLocations":[{"physicalLocation":{"artifactLocation":{"index":0,"uri":"file:///main.cpp"},"region":{"endColumn":14,"startColumn":14,"startLine":3}}},{"message":{"text":"in instantiation of 'float x = 0.0'"},"physicalLocation":{"artifactLocation":{"index":0,"uri":"file:///main.cpp"},"region":{"endColumn":14,"startColumn":14,"startLine":3}},"properties":{"nestingLevel":1}}],"ruleId":"clang.unittest","ruleIndex":0}],"tool":{"driver":{"fullName":"sarif test runner","informationUri":"https://clang.llvm.org/docs/UsersManual.html","language":"en-US","name":"sarif test","rules":[{"defaultConfiguration":{"enabled":true,"level":"warning","rank":-1},"fullDescription":{"text":"Example rule created during unit tests"},"id":"clang.unittest","name":"clang unit test"}],"version":"1.0.0"}}}],"version":"2.1.0"})";
SarifDocumentWriter Writer{SourceMgr};
const SarifRule &Rule =
>From 61121d31ce5392d100b0b1f494f07689a08d9e8f Mon Sep 17 00:00:00 2001
From: anonymous <shyeyian at icloud.com>
Date: Thu, 1 Jan 2026 17:40:30 +0800
Subject: [PATCH 09/21] Revert "Disable sarif warnings."
This reverts commit 4a463f58b19ba3f60cda2fb425dfdbd6f9645321.
---
clang/include/clang/Basic/DiagnosticDriverKinds.td | 4 ++++
clang/lib/Driver/ToolChains/Clang.cpp | 3 +++
2 files changed, 7 insertions(+)
diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td
index bbcbc040d330e..af5387b2c8f02 100644
--- a/clang/include/clang/Basic/DiagnosticDriverKinds.td
+++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td
@@ -854,6 +854,10 @@ def err_drv_invalid_empty_dxil_validator_version : Error<
"invalid validator version : %0; if validator major version is 0, minor "
"version must also be 0">;
+def warn_drv_sarif_format_unstable : Warning<
+ "diagnostic formatting in SARIF mode is currently unstable">,
+ InGroup<DiagGroup<"sarif-format-unstable">>;
+
def warn_drv_loongarch_conflicting_implied_val : Warning<
"ignoring '%0' as it conflicts with that implied by '%1' (%2)">,
InGroup<OptionIgnored>;
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index c66e5c32f0626..4399eb475be75 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -4262,6 +4262,9 @@ static void RenderDiagnosticsOptions(const Driver &D, const ArgList &Args,
if (const Arg *A = Args.getLastArg(options::OPT_fdiagnostics_format_EQ)) {
CmdArgs.push_back("-fdiagnostics-format");
CmdArgs.push_back(A->getValue());
+ if (StringRef(A->getValue()) == "sarif" ||
+ StringRef(A->getValue()) == "SARIF")
+ D.Diag(diag::warn_drv_sarif_format_unstable);
}
if (const Arg *A = Args.getLastArg(
>From fd1cb42a7dacf2eabef8a1135377be31144d74c8 Mon Sep 17 00:00:00 2001
From: anonymous <shyeyian at icloud.com>
Date: Sat, 3 Jan 2026 12:56:13 +0800
Subject: [PATCH 10/21] Code Review: using `std::get_if` on `std::variant`.
---
clang/lib/Basic/Sarif.cpp | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/clang/lib/Basic/Sarif.cpp b/clang/lib/Basic/Sarif.cpp
index bf7a603606a4c..5e7b0ab69ff6c 100644
--- a/clang/lib/Basic/Sarif.cpp
+++ b/clang/lib/Basic/Sarif.cpp
@@ -407,21 +407,21 @@ void SarifDocumentWriter::appendResult(const SarifResult &Result) {
if (!Result.RelatedLocations.empty()) {
json::Array ReLocs;
for (auto &RelatedLocation : Result.RelatedLocations) {
- if (RelatedLocation.index() == 0) { // variant is a SarifChildResult
- const SarifChildResult &ChildResult = std::get<0>(RelatedLocation);
+ const SarifChildResult* ChildResultPtr = std::get_if<SarifChildResult>(&RelatedLocation);
+ const CharSourceRange* CharSourceRangePtr = std::get_if<CharSourceRange>(&RelatedLocation);
+ if (ChildResultPtr) {
json::Object Object;
Object.insert(
- {"message", createMessage(ChildResult.DiagnosticMessage)});
- if (ChildResult.Locations.size() >= 1)
+ {"message", createMessage(ChildResultPtr->DiagnosticMessage)});
+ if (ChildResultPtr->Locations.size() >= 1)
for (auto &kv :
- createLocation(createPhysicalLocation(ChildResult.Locations[0])))
+ createLocation(createPhysicalLocation(ChildResultPtr->Locations[0])))
Object.insert({kv.getFirst(), kv.getSecond()});
Object.insert({"properties",
- json::Object{{"nestingLevel", ChildResult.Nesting}}});
+ json::Object{{"nestingLevel", ChildResultPtr->Nesting}}});
ReLocs.emplace_back(std::move(Object));
- } else { // variant is a CharSourceRange
- const CharSourceRange &Range = std::get<1>(RelatedLocation);
- ReLocs.emplace_back(createLocation(createPhysicalLocation(Range)));
+ } else if (CharSourceRangePtr) {
+ ReLocs.emplace_back(createLocation(createPhysicalLocation(*CharSourceRangePtr)));
}
}
Ret["relatedLocations"] = std::move(ReLocs);
>From 386761d8724455d427f90d82e4e98b9de91e5008 Mon Sep 17 00:00:00 2001
From: anonymous <shyeyian at icloud.com>
Date: Sat, 3 Jan 2026 13:05:51 +0800
Subject: [PATCH 11/21] Code Review: using member helper functions instead of
anonymous namespace ones.
---
.../include/clang/Frontend/SARIFDiagnostic.h | 2 ++
clang/lib/Frontend/SARIFDiagnostic.cpp | 22 ++++++++-----------
2 files changed, 11 insertions(+), 13 deletions(-)
diff --git a/clang/include/clang/Frontend/SARIFDiagnostic.h b/clang/include/clang/Frontend/SARIFDiagnostic.h
index a396e645cb505..fefb95e26d9f9 100644
--- a/clang/include/clang/Frontend/SARIFDiagnostic.h
+++ b/clang/include/clang/Frontend/SARIFDiagnostic.h
@@ -93,6 +93,8 @@ class SARIFDiagnostic : public DiagnosticRenderer {
Node &addChildResult(Result);
Node &addLocation(Location);
Node &addRelatedLocation(Location);
+ template <class Func>
+ void recursiveForEach(Func&&);
// Methods to access underlying data for other llvm-components to read from
// it. Arguments and results are all in llvm-style.
diff --git a/clang/lib/Frontend/SARIFDiagnostic.cpp b/clang/lib/Frontend/SARIFDiagnostic.cpp
index 1e35d6df4e095..d8864cd1a25a7 100644
--- a/clang/lib/Frontend/SARIFDiagnostic.cpp
+++ b/clang/lib/Frontend/SARIFDiagnostic.cpp
@@ -54,18 +54,6 @@ SARIFDiagnostic::SARIFDiagnostic(raw_ostream &OS, const LangOptions &LangOpts,
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.
@@ -95,7 +83,7 @@ SARIFDiagnostic::~SARIFDiagnostic() {
.setDiagnosticMessage(TopLevelDiagnosticsPtr->getDiagnosticMessage())
.addLocations(TopLevelDiagnosticsPtr->getLocations())
.addRelatedLocations(TopLevelDiagnosticsPtr->getRelatedLocations());
- RecursiveFor(*TopLevelDiagnosticsPtr, [] (Node& Node) -> auto& { return Node.getChildrenPtrs(); }, [&] (Node& Node) { // For each (recursive) ChildResults.
+ TopLevelDiagnosticsPtr->recursiveForEach([&] (Node& Node) { // For each (recursive) ChildResults.
Result.addRelatedLocations({
SarifChildResult::create()
.setDiagnosticMessage(Node.getDiagnosticMessage())
@@ -183,6 +171,14 @@ SARIFDiagnostic::Node::addRelatedLocation(Location Location) {
return *this;
}
+template <class Func>
+void SARIFDiagnostic::Node::recursiveForEach(Func&& Function) {
+ for (auto &&ChildPtr : getChildrenPtrs()) {
+ Function(*ChildPtr);
+ ChildPtr->recursiveForEach(std::forward<Func&&>(Function));
+ }
+}
+
unsigned SARIFDiagnostic::Node::getDiagID() {
return llvm::isa<const Diagnostic *>(Result_.Diag)
? Result_.Diag.dyn_cast<const Diagnostic *>()->getID()
>From b46b8c86cbc9b2fd842495182953a9318cc76475 Mon Sep 17 00:00:00 2001
From: anonymous <shyeyian at icloud.com>
Date: Sat, 3 Jan 2026 13:09:13 +0800
Subject: [PATCH 12/21] Code Review: remove informal comments
---
clang/lib/Frontend/SARIFDiagnostic.cpp | 17 -----------------
1 file changed, 17 deletions(-)
diff --git a/clang/lib/Frontend/SARIFDiagnostic.cpp b/clang/lib/Frontend/SARIFDiagnostic.cpp
index d8864cd1a25a7..752cc61654dd5 100644
--- a/clang/lib/Frontend/SARIFDiagnostic.cpp
+++ b/clang/lib/Frontend/SARIFDiagnostic.cpp
@@ -26,23 +26,6 @@
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)
>From 779a6032d1c0f9b303d3869615457b692189c746 Mon Sep 17 00:00:00 2001
From: anonymous <shyeyian at icloud.com>
Date: Sat, 3 Jan 2026 13:12:08 +0800
Subject: [PATCH 13/21] Code Review: add `{}`-initialized param comments.
---
clang/lib/Frontend/SARIFDiagnostic.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/lib/Frontend/SARIFDiagnostic.cpp b/clang/lib/Frontend/SARIFDiagnostic.cpp
index 752cc61654dd5..82ca90023401c 100644
--- a/clang/lib/Frontend/SARIFDiagnostic.cpp
+++ b/clang/lib/Frontend/SARIFDiagnostic.cpp
@@ -103,7 +103,7 @@ void SARIFDiagnostic::emitDiagnosticMessage(
}
void SARIFDiagnostic::emitIncludeLocation(FullSourceLoc Loc, PresumedLoc PLoc) {
- Current = &Current->addRelatedLocation(Node::Location{Loc, PLoc, {}});
+ Current = &Current->addRelatedLocation(Node::Location{Loc, PLoc, /*Ranges=*/{}});
}
void SARIFDiagnostic::emitImportLocation(FullSourceLoc Loc, PresumedLoc PLoc,
>From ac0d01980e8d15e34b71f13e6422201f1e3e8b97 Mon Sep 17 00:00:00 2001
From: anonymous <shyeyian at icloud.com>
Date: Sat, 3 Jan 2026 13:18:30 +0800
Subject: [PATCH 14/21] Code Review: using `llvm::for_each()`
---
clang/lib/Frontend/SARIFDiagnostic.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/clang/lib/Frontend/SARIFDiagnostic.cpp b/clang/lib/Frontend/SARIFDiagnostic.cpp
index 82ca90023401c..e30513d5d31bd 100644
--- a/clang/lib/Frontend/SARIFDiagnostic.cpp
+++ b/clang/lib/Frontend/SARIFDiagnostic.cpp
@@ -178,7 +178,7 @@ std::string SARIFDiagnostic::Node::getDiagnosticMessage() {
llvm::SmallVector<CharSourceRange> SARIFDiagnostic::Node::getLocations() {
llvm::SmallVector<CharSourceRange> CharSourceRanges;
- std::for_each(Locations.begin(), Locations.end(), [&](Location &Location) {
+ llvm::for_each(Locations, [&](Location &Location) {
CharSourceRanges.append(Location.getCharSourceRangesWithOption(Option_));
});
return CharSourceRanges;
@@ -187,7 +187,7 @@ llvm::SmallVector<CharSourceRange> SARIFDiagnostic::Node::getLocations() {
llvm::SmallVector<CharSourceRange>
SARIFDiagnostic::Node::getRelatedLocations() {
llvm::SmallVector<CharSourceRange> CharSourceRanges;
- std::for_each(RelatedLocations.begin(), RelatedLocations.end(),
+ llvm::for_each(RelatedLocations,
[&](Location &RelatedLocation) {
CharSourceRanges.append(
RelatedLocation.getCharSourceRangesWithOption(Option_));
>From a0a0ea5d65458a1d6893dae73c1576db7001c6d2 Mon Sep 17 00:00:00 2001
From: anonymous <shyeyian at icloud.com>
Date: Sat, 3 Jan 2026 13:39:24 +0800
Subject: [PATCH 15/21] Code Review: purge `emitFilename()`.
---
clang/lib/Frontend/SARIFDiagnostic.cpp | 46 +-------------------------
1 file changed, 1 insertion(+), 45 deletions(-)
diff --git a/clang/lib/Frontend/SARIFDiagnostic.cpp b/clang/lib/Frontend/SARIFDiagnostic.cpp
index e30513d5d31bd..168f867fe72b4 100644
--- a/clang/lib/Frontend/SARIFDiagnostic.cpp
+++ b/clang/lib/Frontend/SARIFDiagnostic.cpp
@@ -203,14 +203,7 @@ SARIFDiagnostic::Node::Location::getCharSourceRangesWithOption(Option Option) {
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());
- }
- }
- return {};
+ // At least add the file name if available.
}
FileID CaretFileID = Loc.getExpansionLoc().getFileID();
@@ -270,43 +263,6 @@ SARIFDiagnostic::Node::Location::getCharSourceRangesWithOption(Option Option) {
return Locations;
}
-// llvm::StringRef SARIFDiagnostic::EmitFilename(StringRef Filename,
-// const SourceManager &SM) {
-// if (DiagOpts.AbsolutePath) {
-// auto File = SM.getFileManager().getOptionalFileRef(Filename);
-// if (File) {
-// // We want to print a simplified absolute path, i. e. without "dots".
-// //
-// // The hardest part here are the paths like
-// "<part1>/<link>/../<part2>".
-// // On Unix-like systems, we cannot just collapse "<link>/..", because
-// // paths are resolved sequentially, and, thereby, the path
-// // "<part1>/<part2>" may point to a different location. That is why
-// // we use FileManager::getCanonicalName(), which expands all
-// indirections
-// // with llvm::sys::fs::real_path() and caches the result.
-// //
-// // On the other hand, it would be better to preserve as much of the
-// // original path as possible, because that helps a user to recognize
-// it.
-// // real_path() expands all links, which is sometimes too much. Luckily,
-// // on Windows we can just use llvm::sys::path::remove_dots(), because,
-// // on that system, both aforementioned paths point to the same place.
-// #ifdef _WIN32
-// SmallString<256> TmpFilename = File->getName();
-// llvm::sys::fs::make_absolute(TmpFilename);
-// llvm::sys::path::native(TmpFilename);
-// llvm::sys::path::remove_dots(TmpFilename, /* remove_dot_dot */ true);
-// Filename = StringRef(TmpFilename.data(), TmpFilename.size());
-// #else
-// Filename = SM.getFileManager().getCanonicalName(*File);
-// #endif
-// }
-// }
-
-// return Filename;
-// }
-
/// Print out the file/line/column information and include trace.
///
/// This method handlen the emission of the diagnostic location information.
>From bb1dd4dfc26271c19ec928dce9fb15cd639a1f41 Mon Sep 17 00:00:00 2001
From: anonymous <shyeyian at icloud.com>
Date: Sat, 3 Jan 2026 13:42:28 +0800
Subject: [PATCH 16/21] Code Review: comment style.
---
clang/lib/Frontend/SARIFDiagnostic.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/clang/lib/Frontend/SARIFDiagnostic.cpp b/clang/lib/Frontend/SARIFDiagnostic.cpp
index 168f867fe72b4..3088aea62773c 100644
--- a/clang/lib/Frontend/SARIFDiagnostic.cpp
+++ b/clang/lib/Frontend/SARIFDiagnostic.cpp
@@ -97,7 +97,7 @@ void SARIFDiagnostic::emitDiagnosticMessage(
}
Current = &Current->addChildResult(
Node::Result{Level, std::string(Message),
- Diag}); // add child to the parent error/warning/note Node.
+ Diag}); // Add child to the parent error/warning/note Node.
Current = &Current->addLocation(
Node::Location{Loc, PLoc, llvm::SmallVector<CharSourceRange>(Ranges)});
}
@@ -227,7 +227,7 @@ SARIFDiagnostic::Node::Location::getCharSourceRangesWithOption(Option Option) {
if (BInfo.first != CaretFileID || EInfo.first != CaretFileID)
continue;
- // add in the length of the token, so that we cover multi-char
+ // Add in the length of the token, so that we cover multi-char
// tokens.
unsigned TokSize = 0;
if (IsTokenRange)
>From 4b069c0b3dcb2e190207864ad2bdb256a43ee759 Mon Sep 17 00:00:00 2001
From: anonymous <shyeyian at icloud.com>
Date: Sun, 4 Jan 2026 13:54:58 +0800
Subject: [PATCH 17/21] Code Review: remove `SARIFDiagnostic::Node::Option`.
---
.../include/clang/Frontend/SARIFDiagnostic.h | 15 +++-----
clang/lib/Frontend/SARIFDiagnostic.cpp | 37 ++++++++++---------
2 files changed, 24 insertions(+), 28 deletions(-)
diff --git a/clang/include/clang/Frontend/SARIFDiagnostic.h b/clang/include/clang/Frontend/SARIFDiagnostic.h
index fefb95e26d9f9..6eb45dd645f09 100644
--- a/clang/include/clang/Frontend/SARIFDiagnostic.h
+++ b/clang/include/clang/Frontend/SARIFDiagnostic.h
@@ -68,22 +68,17 @@ class SARIFDiagnostic : public DiagnosticRenderer {
DiagOrStoredDiag Diag;
};
- struct Option {
- const LangOptions *LangOptsPtr;
- const DiagnosticOptions *DiagnosticOptsPtr;
- };
-
struct Location {
FullSourceLoc Loc;
PresumedLoc PLoc;
llvm::SmallVector<CharSourceRange> Ranges;
// Methods to construct a llvm-style location.
- llvm::SmallVector<CharSourceRange> getCharSourceRangesWithOption(Option);
+ llvm::SmallVector<CharSourceRange> getCharSourceRangesWithOption(SARIFDiagnostic&);
};
// Constructor
- Node(Result Result_, Option Option_, int Nesting);
+ Node(Result Result_, int Nesting);
// Operations on building a node-tree.
// Arguments and results are all in node-style.
@@ -101,15 +96,14 @@ class SARIFDiagnostic : public DiagnosticRenderer {
unsigned getDiagID();
DiagnosticsEngine::Level getLevel();
std::string getDiagnosticMessage();
- llvm::SmallVector<CharSourceRange> getLocations();
- llvm::SmallVector<CharSourceRange> getRelatedLocations();
+ llvm::SmallVector<CharSourceRange> getLocations(SARIFDiagnostic&);
+ llvm::SmallVector<CharSourceRange> getRelatedLocations(SARIFDiagnostic&);
int getNesting();
private:
Result Result_;
llvm::SmallVector<Location> Locations;
llvm::SmallVector<Location> RelatedLocations;
- Option Option_;
int Nesting;
Node *ParentPtr = nullptr;
llvm::SmallVector<std::unique_ptr<Node>> ChildrenPtrs = {};
@@ -117,6 +111,7 @@ class SARIFDiagnostic : public DiagnosticRenderer {
Node Root;
Node *Current = &Root;
+ const LangOptions* LangOptsPtr;
SarifDocumentWriter
*Writer; // Shared between SARIFDiagnosticPrinter and this renderer.
};
diff --git a/clang/lib/Frontend/SARIFDiagnostic.cpp b/clang/lib/Frontend/SARIFDiagnostic.cpp
index 3088aea62773c..d7554be467d92 100644
--- a/clang/lib/Frontend/SARIFDiagnostic.cpp
+++ b/clang/lib/Frontend/SARIFDiagnostic.cpp
@@ -30,9 +30,11 @@ SARIFDiagnostic::SARIFDiagnostic(raw_ostream &OS, const LangOptions &LangOpts,
DiagnosticOptions &DiagOpts,
SarifDocumentWriter *Writer)
: DiagnosticRenderer(LangOpts, DiagOpts),
- Root(Node::Result(), Node::Option{&LangOpts, &DiagOpts},
+ Root(Node::Result(),
/*Nesting=*/-1), // The root does not represents a diagnostic.
- Current(&Root), Writer(Writer) {
+ Current(&Root),
+ LangOptsPtr(&LangOpts),
+ Writer(Writer) {
// Don't print 'X warnings and Y errors generated'.
DiagOpts.ShowCarets = false;
}
@@ -64,16 +66,16 @@ SARIFDiagnostic::~SARIFDiagnostic() {
SarifResult Result = SarifResult::create(RuleIndex)
.setDiagnosticMessage(TopLevelDiagnosticsPtr->getDiagnosticMessage())
- .addLocations(TopLevelDiagnosticsPtr->getLocations())
- .addRelatedLocations(TopLevelDiagnosticsPtr->getRelatedLocations());
+ .addLocations(TopLevelDiagnosticsPtr->getLocations(*this))
+ .addRelatedLocations(TopLevelDiagnosticsPtr->getRelatedLocations(*this));
TopLevelDiagnosticsPtr->recursiveForEach([&] (Node& Node) { // For each (recursive) ChildResults.
Result.addRelatedLocations({
SarifChildResult::create()
.setDiagnosticMessage(Node.getDiagnosticMessage())
- .addLocations(Node.getLocations())
+ .addLocations(Node.getLocations(*this))
.setNesting(Node.getNesting())
});
- Result.addRelatedLocations(Node.getRelatedLocations());
+ Result.addRelatedLocations(Node.getRelatedLocations(*this));
});
Writer->appendResult(Result); // Write into Writer
}
@@ -111,8 +113,8 @@ void SARIFDiagnostic::emitImportLocation(FullSourceLoc Loc, PresumedLoc PLoc,
Current = &Current->addRelatedLocation(Node::Location{Loc, PLoc, {}});
}
-SARIFDiagnostic::Node::Node(Result Result_, Option Option_, int Nesting)
- : Result_(std::move(Result_)), Option_(std::move(Option_)),
+SARIFDiagnostic::Node::Node(Result Result_, int Nesting)
+ : Result_(std::move(Result_)),
Nesting(Nesting) {}
SARIFDiagnostic::Node &SARIFDiagnostic::Node::getParent() {
@@ -137,8 +139,7 @@ SARIFDiagnostic::Node::getChildrenPtrs() {
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));
+ std::make_unique<Node>(Node::Result(std::move(ChildResult)), Nesting + 1));
ChildrenPtrs.back()->ParentPtr = this; // I am the parent of this new child.
return *ChildrenPtrs.back();
}
@@ -176,21 +177,21 @@ std::string SARIFDiagnostic::Node::getDiagnosticMessage() {
return Result_.Message;
}
-llvm::SmallVector<CharSourceRange> SARIFDiagnostic::Node::getLocations() {
+llvm::SmallVector<CharSourceRange> SARIFDiagnostic::Node::getLocations(SARIFDiagnostic& SARIFDiag) {
llvm::SmallVector<CharSourceRange> CharSourceRanges;
llvm::for_each(Locations, [&](Location &Location) {
- CharSourceRanges.append(Location.getCharSourceRangesWithOption(Option_));
+ CharSourceRanges.append(Location.getCharSourceRangesWithOption(SARIFDiag));
});
return CharSourceRanges;
}
llvm::SmallVector<CharSourceRange>
-SARIFDiagnostic::Node::getRelatedLocations() {
+SARIFDiagnostic::Node::getRelatedLocations(SARIFDiagnostic& SARIFDiag) {
llvm::SmallVector<CharSourceRange> CharSourceRanges;
llvm::for_each(RelatedLocations,
[&](Location &RelatedLocation) {
CharSourceRanges.append(
- RelatedLocation.getCharSourceRangesWithOption(Option_));
+ RelatedLocation.getCharSourceRangesWithOption(SARIFDiag));
});
return CharSourceRanges;
}
@@ -198,7 +199,7 @@ SARIFDiagnostic::Node::getRelatedLocations() {
int SARIFDiagnostic::Node::getNesting() { return Nesting; }
llvm::SmallVector<CharSourceRange>
-SARIFDiagnostic::Node::Location::getCharSourceRangesWithOption(Option Option) {
+SARIFDiagnostic::Node::Location::getCharSourceRangesWithOption(SARIFDiagnostic& SARIFDiag) {
SmallVector<CharSourceRange> Locations = {};
if (PLoc.isInvalid()) {
@@ -231,7 +232,7 @@ SARIFDiagnostic::Node::Location::getCharSourceRangesWithOption(Option Option) {
// tokens.
unsigned TokSize = 0;
if (IsTokenRange)
- TokSize = Lexer::MeasureTokenLength(E, SM, *Option.LangOptsPtr);
+ TokSize = Lexer::MeasureTokenLength(E, SM, *SARIFDiag.LangOptsPtr);
FullSourceLoc BF(B, SM), EF(E, SM);
SourceLocation BeginLoc = SM.translateLineCol(
@@ -249,8 +250,8 @@ SARIFDiagnostic::Node::Location::getCharSourceRangesWithOption(Option Option) {
auto FID = PLoc.getFileID();
// Visual Studio 2010 or earlier expects column number to be off by one.
unsigned int ColNo =
- (Option.LangOptsPtr->MSCompatibilityVersion &&
- !Option.LangOptsPtr->isCompatibleWithMSVC(LangOptions::MSVC2012))
+ (SARIFDiag.LangOptsPtr->MSCompatibilityVersion &&
+ !SARIFDiag.LangOptsPtr->isCompatibleWithMSVC(LangOptions::MSVC2012))
? PLoc.getColumn() - 1
: PLoc.getColumn();
SourceLocation DiagLoc = SM.translateLineCol(FID, PLoc.getLine(), ColNo);
>From 5a70276c84b8656407e70807d65b8d9242d1ec9e Mon Sep 17 00:00:00 2001
From: anonymous <shyeyian at icloud.com>
Date: Tue, 6 Jan 2026 15:33:18 +0800
Subject: [PATCH 18/21] Code Review: comment style and root-node.level
---
clang/lib/Frontend/SARIFDiagnostic.cpp | 19 +++++++++----------
1 file changed, 9 insertions(+), 10 deletions(-)
diff --git a/clang/lib/Frontend/SARIFDiagnostic.cpp b/clang/lib/Frontend/SARIFDiagnostic.cpp
index d7554be467d92..7d7b864a77a49 100644
--- a/clang/lib/Frontend/SARIFDiagnostic.cpp
+++ b/clang/lib/Frontend/SARIFDiagnostic.cpp
@@ -30,7 +30,7 @@ SARIFDiagnostic::SARIFDiagnostic(raw_ostream &OS, const LangOptions &LangOpts,
DiagnosticOptions &DiagOpts,
SarifDocumentWriter *Writer)
: DiagnosticRenderer(LangOpts, DiagOpts),
- Root(Node::Result(),
+ Root(Node::Result{/*Level=*/DiagnosticsEngine::Level::Error, /*Message=*/"", /*Diag=*/nullptr},
/*Nesting=*/-1), // The root does not represents a diagnostic.
Current(&Root),
LangOptsPtr(&LangOpts),
@@ -48,16 +48,16 @@ SARIFDiagnostic::~SARIFDiagnostic() {
.setDefaultConfiguration(
SarifReportingConfiguration::create()
.setLevel(
- TopLevelDiagnosticsPtr->getLevel() == DiagnosticsEngine::Level::Note ? SarifResultLevel::Note :
- TopLevelDiagnosticsPtr->getLevel() == DiagnosticsEngine::Level::Remark ? SarifResultLevel::Note :
+ 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 :
+ 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::Warning ? 0 :
+ TopLevelDiagnosticsPtr->getLevel() == DiagnosticsEngine::Level::Error ? 50 :
TopLevelDiagnosticsPtr->getLevel() == DiagnosticsEngine::Level::Fatal ? 100 :
(assert(false && "Invalid diagnostic type"), 0)
)
@@ -124,9 +124,8 @@ SARIFDiagnostic::Node &SARIFDiagnostic::Node::getParent() {
SARIFDiagnostic::Node &SARIFDiagnostic::Node::getForkableParent() {
Node *Ptr = this;
- while (Ptr->getLevel() <=
- DiagnosticsEngine::Note) // The forkable node here "is and only is"
- // warning/error/fatal.
+ // The forkable node here "is and only is" warning/error/fatal.
+ while (Ptr->getLevel() <= DiagnosticsEngine::Note)
Ptr = &Ptr->getParent();
return *Ptr;
}
>From a0201921956def6635e5d8cedc182f4cd6442d35 Mon Sep 17 00:00:00 2001
From: anonymous <shyeyian at icloud.com>
Date: Tue, 6 Jan 2026 16:00:12 +0800
Subject: [PATCH 19/21] Style fix on `SARIFDiagnostic.meow(LangOptions)`
---
.../include/clang/Frontend/SARIFDiagnostic.h | 6 ++---
clang/lib/Frontend/SARIFDiagnostic.cpp | 27 +++++++++----------
2 files changed, 16 insertions(+), 17 deletions(-)
diff --git a/clang/include/clang/Frontend/SARIFDiagnostic.h b/clang/include/clang/Frontend/SARIFDiagnostic.h
index 6eb45dd645f09..a2b2fee47c4e4 100644
--- a/clang/include/clang/Frontend/SARIFDiagnostic.h
+++ b/clang/include/clang/Frontend/SARIFDiagnostic.h
@@ -74,7 +74,7 @@ class SARIFDiagnostic : public DiagnosticRenderer {
llvm::SmallVector<CharSourceRange> Ranges;
// Methods to construct a llvm-style location.
- llvm::SmallVector<CharSourceRange> getCharSourceRangesWithOption(SARIFDiagnostic&);
+ llvm::SmallVector<CharSourceRange> getCharSourceRangesWithOption(const LangOptions& LangOpts);
};
// Constructor
@@ -96,8 +96,8 @@ class SARIFDiagnostic : public DiagnosticRenderer {
unsigned getDiagID();
DiagnosticsEngine::Level getLevel();
std::string getDiagnosticMessage();
- llvm::SmallVector<CharSourceRange> getLocations(SARIFDiagnostic&);
- llvm::SmallVector<CharSourceRange> getRelatedLocations(SARIFDiagnostic&);
+ llvm::SmallVector<CharSourceRange> getLocations(const LangOptions& LangOpts);
+ llvm::SmallVector<CharSourceRange> getRelatedLocations(const LangOptions& LangOpts);
int getNesting();
private:
diff --git a/clang/lib/Frontend/SARIFDiagnostic.cpp b/clang/lib/Frontend/SARIFDiagnostic.cpp
index 7d7b864a77a49..03df46ea59afc 100644
--- a/clang/lib/Frontend/SARIFDiagnostic.cpp
+++ b/clang/lib/Frontend/SARIFDiagnostic.cpp
@@ -9,7 +9,7 @@
#include "clang/Frontend/SARIFDiagnostic.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/DiagnosticOptions.h"
-#include "clang/Basic/DiagnosticSema.h"
+#include "clang/Basic/LangOptions.h"
#include "clang/Basic/Sarif.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/SourceManager.h"
@@ -21,7 +21,6 @@
#include "llvm/Support/ConvertUTF.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Locale.h"
-#include <algorithm>
#include <string>
namespace clang {
@@ -66,16 +65,16 @@ SARIFDiagnostic::~SARIFDiagnostic() {
SarifResult Result = SarifResult::create(RuleIndex)
.setDiagnosticMessage(TopLevelDiagnosticsPtr->getDiagnosticMessage())
- .addLocations(TopLevelDiagnosticsPtr->getLocations(*this))
- .addRelatedLocations(TopLevelDiagnosticsPtr->getRelatedLocations(*this));
+ .addLocations(TopLevelDiagnosticsPtr->getLocations(*LangOptsPtr))
+ .addRelatedLocations(TopLevelDiagnosticsPtr->getRelatedLocations(*LangOptsPtr));
TopLevelDiagnosticsPtr->recursiveForEach([&] (Node& Node) { // For each (recursive) ChildResults.
Result.addRelatedLocations({
SarifChildResult::create()
.setDiagnosticMessage(Node.getDiagnosticMessage())
- .addLocations(Node.getLocations(*this))
+ .addLocations(Node.getLocations(*LangOptsPtr))
.setNesting(Node.getNesting())
});
- Result.addRelatedLocations(Node.getRelatedLocations(*this));
+ Result.addRelatedLocations(Node.getRelatedLocations(*LangOptsPtr));
});
Writer->appendResult(Result); // Write into Writer
}
@@ -176,21 +175,21 @@ std::string SARIFDiagnostic::Node::getDiagnosticMessage() {
return Result_.Message;
}
-llvm::SmallVector<CharSourceRange> SARIFDiagnostic::Node::getLocations(SARIFDiagnostic& SARIFDiag) {
+llvm::SmallVector<CharSourceRange> SARIFDiagnostic::Node::getLocations(const LangOptions& LangOpts) {
llvm::SmallVector<CharSourceRange> CharSourceRanges;
llvm::for_each(Locations, [&](Location &Location) {
- CharSourceRanges.append(Location.getCharSourceRangesWithOption(SARIFDiag));
+ CharSourceRanges.append(Location.getCharSourceRangesWithOption(LangOpts));
});
return CharSourceRanges;
}
llvm::SmallVector<CharSourceRange>
-SARIFDiagnostic::Node::getRelatedLocations(SARIFDiagnostic& SARIFDiag) {
+SARIFDiagnostic::Node::getRelatedLocations(const LangOptions& LangOpts) {
llvm::SmallVector<CharSourceRange> CharSourceRanges;
llvm::for_each(RelatedLocations,
[&](Location &RelatedLocation) {
CharSourceRanges.append(
- RelatedLocation.getCharSourceRangesWithOption(SARIFDiag));
+ RelatedLocation.getCharSourceRangesWithOption(LangOpts));
});
return CharSourceRanges;
}
@@ -198,7 +197,7 @@ SARIFDiagnostic::Node::getRelatedLocations(SARIFDiagnostic& SARIFDiag) {
int SARIFDiagnostic::Node::getNesting() { return Nesting; }
llvm::SmallVector<CharSourceRange>
-SARIFDiagnostic::Node::Location::getCharSourceRangesWithOption(SARIFDiagnostic& SARIFDiag) {
+SARIFDiagnostic::Node::Location::getCharSourceRangesWithOption(const LangOptions& LangOpts) {
SmallVector<CharSourceRange> Locations = {};
if (PLoc.isInvalid()) {
@@ -231,7 +230,7 @@ SARIFDiagnostic::Node::Location::getCharSourceRangesWithOption(SARIFDiagnostic&
// tokens.
unsigned TokSize = 0;
if (IsTokenRange)
- TokSize = Lexer::MeasureTokenLength(E, SM, *SARIFDiag.LangOptsPtr);
+ TokSize = Lexer::MeasureTokenLength(E, SM, LangOpts);
FullSourceLoc BF(B, SM), EF(E, SM);
SourceLocation BeginLoc = SM.translateLineCol(
@@ -249,8 +248,8 @@ SARIFDiagnostic::Node::Location::getCharSourceRangesWithOption(SARIFDiagnostic&
auto FID = PLoc.getFileID();
// Visual Studio 2010 or earlier expects column number to be off by one.
unsigned int ColNo =
- (SARIFDiag.LangOptsPtr->MSCompatibilityVersion &&
- !SARIFDiag.LangOptsPtr->isCompatibleWithMSVC(LangOptions::MSVC2012))
+ (LangOpts.MSCompatibilityVersion &&
+ !LangOpts.isCompatibleWithMSVC(LangOptions::MSVC2012))
? PLoc.getColumn() - 1
: PLoc.getColumn();
SourceLocation DiagLoc = SM.translateLineCol(FID, PLoc.getLine(), ColNo);
>From 3e74953909a2474f036abf53d8ff669f8abb68f3 Mon Sep 17 00:00:00 2001
From: anonymous <shyeyian at icloud.com>
Date: Thu, 8 Jan 2026 17:17:40 +0800
Subject: [PATCH 20/21] Tiny fix: code style
---
clang/lib/Frontend/SARIFDiagnostic.cpp | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/clang/lib/Frontend/SARIFDiagnostic.cpp b/clang/lib/Frontend/SARIFDiagnostic.cpp
index 03df46ea59afc..95bc0abd9943a 100644
--- a/clang/lib/Frontend/SARIFDiagnostic.cpp
+++ b/clang/lib/Frontend/SARIFDiagnostic.cpp
@@ -76,7 +76,7 @@ SARIFDiagnostic::~SARIFDiagnostic() {
});
Result.addRelatedLocations(Node.getRelatedLocations(*LangOptsPtr));
});
- Writer->appendResult(Result); // Write into Writer
+ Writer->appendResult(Result); // Write into Writer.
}
// clang-format on
}
@@ -85,7 +85,6 @@ void SARIFDiagnostic::emitDiagnosticMessage(
FullSourceLoc Loc, PresumedLoc PLoc, DiagnosticsEngine::Level Level,
StringRef Message, ArrayRef<clang::CharSourceRange> Ranges,
DiagOrStoredDiag Diag) {
-
if (Level >= DiagnosticsEngine::Level::Warning) {
Current =
&Root; // If this is a top-level error/warning, repoint Current to Root.
>From 7adabf973ec0a1f414421690d6b50ace7e64f75b Mon Sep 17 00:00:00 2001
From: anonymous <shyeyian at icloud.com>
Date: Sun, 11 Jan 2026 13:51:14 +0800
Subject: [PATCH 21/21] Code Review [big change]: move "X warnings and Y errors
generated" into sarif, and make the `~SARIFDiagnostic()` trivial.
---
clang/include/clang/Basic/Diagnostic.h | 4 +++
clang/include/clang/Basic/Sarif.h | 7 +++++
.../include/clang/Frontend/CompilerInstance.h | 2 +-
.../include/clang/Frontend/SARIFDiagnostic.h | 6 +++--
.../clang/Frontend/SARIFDiagnosticPrinter.h | 11 +++-----
clang/lib/Basic/Diagnostic.cpp | 6 +++++
clang/lib/Basic/Sarif.cpp | 23 ++++++++++++++++
clang/lib/Frontend/CompilerInstance.cpp | 14 +++++-----
clang/lib/Frontend/SARIFDiagnostic.cpp | 19 +++++++++++---
clang/lib/Frontend/SARIFDiagnosticPrinter.cpp | 26 ++++++++++++++-----
10 files changed, 91 insertions(+), 27 deletions(-)
diff --git a/clang/include/clang/Basic/Diagnostic.h b/clang/include/clang/Basic/Diagnostic.h
index c6e931d0c9517..8d1bac7b65007 100644
--- a/clang/include/clang/Basic/Diagnostic.h
+++ b/clang/include/clang/Basic/Diagnostic.h
@@ -51,6 +51,7 @@ class FileSystem;
namespace clang {
+class CompilerInstance;
class DeclContext;
class Diagnostic;
class DiagnosticBuilder;
@@ -1788,6 +1789,9 @@ class DiagnosticConsumer {
/// warnings and errors.
virtual void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
const Diagnostic &Info);
+
+ /// At the end of a compilation, print the number of warnings/errors.
+ virtual void PrintDiagnosticStats(StringRef Message, CompilerInstance& Compiler);
};
/// A diagnostic client that ignores all diagnostics.
diff --git a/clang/include/clang/Basic/Sarif.h b/clang/include/clang/Basic/Sarif.h
index b7f8175b5ee16..6b0ebcdfcbb49 100644
--- a/clang/include/clang/Basic/Sarif.h
+++ b/clang/include/clang/Basic/Sarif.h
@@ -544,6 +544,13 @@ class SarifDocumentWriter {
/// to \ref createRule.
void appendResult(const SarifResult &SarifResult);
+ /// Append a new Invocation to the currently in-flight run,
+ ///
+ /// \pre
+ /// There must be a run associated with the document, failing to do so will
+ /// cause undefined behaviour.
+ void appendInvocation(const std::vector<std::string>& CommandLine, bool ExecutionSuccessful, StringRef Message);
+
/// Return the SARIF document in its current state.
/// Calling this will trigger a copy of the internal state including all
/// reported diagnostics, resulting in an expensive call.
diff --git a/clang/include/clang/Frontend/CompilerInstance.h b/clang/include/clang/Frontend/CompilerInstance.h
index d0b41e9f18a1b..046aa0dea6a81 100644
--- a/clang/include/clang/Frontend/CompilerInstance.h
+++ b/clang/include/clang/Frontend/CompilerInstance.h
@@ -241,7 +241,7 @@ class CompilerInstance : public ModuleLoader {
bool ExecuteAction(FrontendAction &Act);
/// At the end of a compilation, print the number of warnings/errors.
- void printDiagnosticStats();
+ std::string getDiagnosticStats();
/// Load the list of plugins requested in the \c FrontendOptions.
void LoadRequestedPlugins();
diff --git a/clang/include/clang/Frontend/SARIFDiagnostic.h b/clang/include/clang/Frontend/SARIFDiagnostic.h
index a2b2fee47c4e4..96d309732f9d3 100644
--- a/clang/include/clang/Frontend/SARIFDiagnostic.h
+++ b/clang/include/clang/Frontend/SARIFDiagnostic.h
@@ -29,13 +29,15 @@ class SARIFDiagnostic : public DiagnosticRenderer {
SARIFDiagnostic(raw_ostream &OS, const LangOptions &LangOpts,
DiagnosticOptions &DiagOpts, SarifDocumentWriter *Writer);
- ~SARIFDiagnostic();
-
SARIFDiagnostic &operator=(const SARIFDiagnostic &&) = delete;
SARIFDiagnostic(SARIFDiagnostic &&) = delete;
SARIFDiagnostic &operator=(const SARIFDiagnostic &) = delete;
SARIFDiagnostic(const SARIFDiagnostic &) = delete;
+ void writeResult();
+ void setLangOptions(const LangOptions& LangOpts);
+ void emitInvocation(CompilerInstance& Compiler, bool Successful, StringRef Message);
+
protected:
void emitDiagnosticMessage(FullSourceLoc Loc, PresumedLoc PLoc,
DiagnosticsEngine::Level Level, StringRef Message,
diff --git a/clang/include/clang/Frontend/SARIFDiagnosticPrinter.h b/clang/include/clang/Frontend/SARIFDiagnosticPrinter.h
index 3406ed16c2fba..23022584b33f1 100644
--- a/clang/include/clang/Frontend/SARIFDiagnosticPrinter.h
+++ b/clang/include/clang/Frontend/SARIFDiagnosticPrinter.h
@@ -17,7 +17,8 @@
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/Sarif.h"
-#include "llvm/ADT/IntrusiveRefCntPtr.h"
+#include "clang/Frontend/CompilerInvocation.h"
+#include "clang/Frontend/SARIFDiagnostic.h"
#include "llvm/ADT/StringRef.h"
#include <memory>
@@ -42,13 +43,6 @@ class SARIFDiagnosticPrinter : public DiagnosticConsumer {
/// used.
void setPrefix(llvm::StringRef Value) { Prefix = Value; }
- bool hasSarifWriter() const { return Writer != nullptr; }
-
- SarifDocumentWriter &getSarifWriter() const {
- assert(Writer && "SarifWriter not set!");
- return *Writer;
- }
-
void setSarifWriter(std::unique_ptr<SarifDocumentWriter> SarifWriter) {
Writer = std::move(SarifWriter);
}
@@ -57,6 +51,7 @@ class SARIFDiagnosticPrinter : public DiagnosticConsumer {
void EndSourceFile() override;
void HandleDiagnostic(DiagnosticsEngine::Level Level,
const Diagnostic &Info) override;
+ void PrintDiagnosticStats(StringRef Message, CompilerInstance& Compiler) override;
private:
raw_ostream &OS;
diff --git a/clang/lib/Basic/Diagnostic.cpp b/clang/lib/Basic/Diagnostic.cpp
index 4802478c379bb..235dc4760ba16 100644
--- a/clang/lib/Basic/Diagnostic.cpp
+++ b/clang/lib/Basic/Diagnostic.cpp
@@ -22,6 +22,7 @@
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/Specifiers.h"
#include "clang/Basic/TokenKinds.h"
+#include "clang/Frontend/CompilerInstance.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringExtras.h"
@@ -775,6 +776,11 @@ void DiagnosticConsumer::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
++NumErrors;
}
+void DiagnosticConsumer::PrintDiagnosticStats(StringRef Message, CompilerInstance& Compiler) {
+ if (Compiler.getDiagnosticOpts().ShowCarets)
+ Compiler.getVerboseOutputStream() << Message;
+}
+
/// ModifierIs - Return true if the specified modifier matches specified string.
template <std::size_t StrLen>
static bool ModifierIs(const char *Modifier, unsigned ModifierLen,
diff --git a/clang/lib/Basic/Sarif.cpp b/clang/lib/Basic/Sarif.cpp
index 5e7b0ab69ff6c..fd6bc72ea7399 100644
--- a/clang/lib/Basic/Sarif.cpp
+++ b/clang/lib/Basic/Sarif.cpp
@@ -23,6 +23,7 @@
#include "llvm/Support/ConvertUTF.h"
#include "llvm/Support/JSON.h"
#include "llvm/Support/Path.h"
+#include "llvm/Support/Program.h"
#include <optional>
#include <string>
@@ -446,6 +447,28 @@ void SarifDocumentWriter::appendResult(const SarifResult &Result) {
Results->emplace_back(std::move(Ret));
}
+void SarifDocumentWriter::appendInvocation(const std::vector<std::string>& CommandLine, bool ExecutionSuccessful, StringRef Message) {
+ // In clang++, the appendInvocation always happens after all runs have been created.
+ // Clang first prints diagnostics on each frontend input file,
+ // and finally prints the diagnostics stats (X warnings and Y errors generated) which corresponds to toolExecutionNotifications here.
+ auto &LastRun = *Runs.back().getAsObject();
+ if (LastRun.find("invocations") == LastRun.end())
+ LastRun.insert({"invocations", json::Array()});
+ LastRun.getArray("invocations")->push_back(
+ json::Object{
+ {"commandLine", llvm::join(CommandLine, " ")},
+ {"executionSuccessful", ExecutionSuccessful},
+ {"exitCode", ExecutionSuccessful ? 0 : 1}, // See clang/tools/driver/cc1_main.cpp, the process exit code is either 0 or 1.
+ {"toolExecutionNotifications", json::Array{
+ json::Object{
+ {"level", "note"},
+ {"message", createMessage(Message)}
+ }
+ }}
+ }
+ );
+}
+
json::Object SarifDocumentWriter::createDocument() {
// Flush all temporaries to their destinations if needed.
endRun();
diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp
index 088538c7449d2..45de104545575 100644
--- a/clang/lib/Frontend/CompilerInstance.cpp
+++ b/clang/lib/Frontend/CompilerInstance.cpp
@@ -1010,8 +1010,8 @@ bool CompilerInstance::ExecuteAction(FrontendAction &Act) {
}
}
- printDiagnosticStats();
-
+ getDiagnosticClient().PrintDiagnosticStats(getDiagnosticStats(), *this);
+
if (getFrontendOpts().ShowStats) {
if (hasFileManager()) {
getFileManager().PrintStats();
@@ -1037,12 +1037,12 @@ bool CompilerInstance::ExecuteAction(FrontendAction &Act) {
return !getDiagnostics().getClient()->getNumErrors();
}
-
-void CompilerInstance::printDiagnosticStats() {
+std::string CompilerInstance::getDiagnosticStats() {
if (!getDiagnosticOpts().ShowCarets)
- return;
+ return "";
- raw_ostream &OS = getVerboseOutputStream();
+ std::string Message = "";
+ llvm::raw_string_ostream OS(Message);
// We can have multiple diagnostics sharing one diagnostic client.
// Get the total number of warnings/errors from the client.
@@ -1068,6 +1068,8 @@ void CompilerInstance::printDiagnosticStats() {
}
OS << ".\n";
}
+
+ return Message;
}
void CompilerInstance::LoadRequestedPlugins() {
diff --git a/clang/lib/Frontend/SARIFDiagnostic.cpp b/clang/lib/Frontend/SARIFDiagnostic.cpp
index 95bc0abd9943a..65ea78f852e83 100644
--- a/clang/lib/Frontend/SARIFDiagnostic.cpp
+++ b/clang/lib/Frontend/SARIFDiagnostic.cpp
@@ -13,6 +13,8 @@
#include "clang/Basic/Sarif.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/SourceManager.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/DiagnosticRenderer.h"
#include "clang/Lex/Lexer.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallVector.h"
@@ -34,11 +36,9 @@ SARIFDiagnostic::SARIFDiagnostic(raw_ostream &OS, const LangOptions &LangOpts,
Current(&Root),
LangOptsPtr(&LangOpts),
Writer(Writer) {
- // Don't print 'X warnings and Y errors generated'.
- DiagOpts.ShowCarets = false;
}
-SARIFDiagnostic::~SARIFDiagnostic() {
+void SARIFDiagnostic::writeResult() {
// clang-format off
for (auto& TopLevelDiagnosticsPtr : Root.getChildrenPtrs()) { // For each top-level error/warnings.
unsigned DiagID = TopLevelDiagnosticsPtr->getDiagID();
@@ -79,6 +79,19 @@ SARIFDiagnostic::~SARIFDiagnostic() {
Writer->appendResult(Result); // Write into Writer.
}
// clang-format on
+ Root.getChildrenPtrs().clear(); // Reset the result cache
+}
+
+void SARIFDiagnostic::setLangOptions(const LangOptions& LangOpts) {
+ LangOptsPtr = &LangOpts;
+}
+
+void SARIFDiagnostic::emitInvocation(CompilerInstance& Compiler, bool Successful, StringRef Message) {
+ Writer->appendInvocation(
+ /*CommandLine=*/Compiler.getInvocation().getCC1CommandLine(),
+ /*ExecutionSuccessful=*/Successful,
+ /*ToolExecutionNotification=*/Message
+ );
}
void SARIFDiagnostic::emitDiagnosticMessage(
diff --git a/clang/lib/Frontend/SARIFDiagnosticPrinter.cpp b/clang/lib/Frontend/SARIFDiagnosticPrinter.cpp
index 2d1225c823c86..48db6790b941d 100644
--- a/clang/lib/Frontend/SARIFDiagnosticPrinter.cpp
+++ b/clang/lib/Frontend/SARIFDiagnosticPrinter.cpp
@@ -11,14 +11,17 @@
//===----------------------------------------------------------------------===//
#include "clang/Frontend/SARIFDiagnosticPrinter.h"
+#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/Sarif.h"
+#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/DiagnosticRenderer.h"
#include "clang/Frontend/SARIFDiagnostic.h"
#include "clang/Lex/Lexer.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/JSON.h"
#include "llvm/Support/raw_ostream.h"
+#include <optional>
namespace clang {
@@ -29,19 +32,17 @@ SARIFDiagnosticPrinter::SARIFDiagnosticPrinter(raw_ostream &OS,
void SARIFDiagnosticPrinter::BeginSourceFile(const LangOptions &LO,
const Preprocessor *PP) {
// Build the SARIFDiagnostic utility.
- assert(hasSarifWriter() && "Writer not set!");
- assert(!SARIFDiag && "SARIFDiagnostic already set.");
- SARIFDiag = std::make_unique<SARIFDiagnostic>(OS, LO, DiagOpts, &*Writer);
+ if (!SARIFDiag)
+ SARIFDiag = std::make_unique<SARIFDiagnostic>(OS, LO, DiagOpts, &*Writer);
+ else
+ SARIFDiag->setLangOptions(LO);
// Initialize the SARIF object.
Writer->createRun("clang", Prefix);
}
void SARIFDiagnosticPrinter::EndSourceFile() {
assert(SARIFDiag && "SARIFDiagnostic has not been set.");
- SARIFDiag.reset();
- llvm::json::Value Value(Writer->createDocument());
- OS << "\n" << Value << "\n\n";
- OS.flush();
+ SARIFDiag->writeResult();
Writer->endRun();
}
@@ -76,4 +77,15 @@ void SARIFDiagnosticPrinter::HandleDiagnostic(DiagnosticsEngine::Level Level,
FullSourceLoc(Info.getLocation(), Info.getSourceManager()), Level,
DiagMessageStream.str(), Info.getRanges(), Info.getFixItHints(), &Info);
}
+
+void SARIFDiagnosticPrinter::PrintDiagnosticStats(StringRef Message, CompilerInstance& Compiler) {
+ if (Compiler.getDiagnosticOpts().ShowCarets)
+ SARIFDiag->emitInvocation(
+ /*Compiler=*/Compiler,
+ /*Successul=*/getNumErrors() == 0,
+ /*Message=*/Message);
+ llvm::json::Value Value(Writer->createDocument());
+ OS << "\n" << Value << "\n\n";
+ OS.flush();
+}
} // namespace clang
More information about the cfe-commits
mailing list