https://github.com/matthew-j-code updated 
https://github.com/llvm/llvm-project/pull/219182

>From 57bef2a697e270f4c58714f87dd84ba562ba05b1 Mon Sep 17 00:00:00 2001
From: "Jones, Matthew (DI SW SIM FRWK PLAT SIMFW HPC)"
 <[email protected]>
Date: Fri, 10 Jul 2026 07:11:06 -0700
Subject: [PATCH 1/8] [clang-tidy] Add SARIF output to clang-tidy

Clang-tidy is a static analysis framework, and
should therefore be able to output results in the
Static Analysis Results Interchange Format
(SARIF). This brings clang-tidy in line with clang
and clang-static-analyzer.
---
 clang-tools-extra/clang-tidy/ClangTidy.cpp    | 130 +++++++++++++-
 clang-tools-extra/clang-tidy/ClangTidy.h      |   3 +-
 .../clang-tidy/tool/ClangTidyMain.cpp         |  21 ++-
 clang-tools-extra/docs/ReleaseNotes.md        |   4 +
 .../export-SARIF-Thread-flows.cpp             | 136 +++++++++++++++
 .../export-SARIF-diagnostics-terminal.cpp     |  98 +++++++++++
 .../export-SARIF-diagnostics.cpp              | 165 ++++++++++++++++++
 .../include/clang/Frontend/SARIFDiagnostic.h  |  16 +-
 clang/lib/Frontend/SARIFDiagnostic.cpp        |  60 ++++---
 9 files changed, 593 insertions(+), 40 deletions(-)
 create mode 100644 
clang-tools-extra/test/clang-tidy/infrastructure/export-SARIF-Thread-flows.cpp
 create mode 100644 
clang-tools-extra/test/clang-tidy/infrastructure/export-SARIF-diagnostics-terminal.cpp
 create mode 100644 
clang-tools-extra/test/clang-tidy/infrastructure/export-SARIF-diagnostics.cpp

diff --git a/clang-tools-extra/clang-tidy/ClangTidy.cpp 
b/clang-tools-extra/clang-tidy/ClangTidy.cpp
index d065bb2c4bcfc..05084b33a92b3 100644
--- a/clang-tools-extra/clang-tidy/ClangTidy.cpp
+++ b/clang-tools-extra/clang-tidy/ClangTidy.cpp
@@ -24,10 +24,12 @@
 #include "clang/AST/ASTConsumer.h"
 #include "clang/ASTMatchers/ASTMatchFinder.h"
 #include "clang/Basic/DiagnosticFrontend.h"
+#include "clang/Basic/Sarif.h"
 #include "clang/Format/Format.h"
 #include "clang/Frontend/ASTConsumers.h"
 #include "clang/Frontend/CompilerInstance.h"
 #include "clang/Frontend/MultiplexConsumer.h"
+#include "clang/Frontend/SARIFDiagnostic.h"
 #include "clang/Frontend/TextDiagnosticPrinter.h"
 #include "clang/Lex/Preprocessor.h"
 #include "clang/Lex/PreprocessorOptions.h"
@@ -36,6 +38,7 @@
 #include "clang/Tooling/DiagnosticsYaml.h" // IWYU pragma: keep
 #include "clang/Tooling/Refactoring.h"
 #include "clang/Tooling/Tooling.h"
+#include "llvm/Support/Error.h"
 #include "llvm/Support/Process.h"
 #include <memory>
 #include <utility>
@@ -101,11 +104,18 @@ class AnalyzerDiagnosticConsumer : public 
ento::PathDiagnosticConsumer {
 class ErrorReporter {
 public:
   ErrorReporter(ClangTidyContext &Context, FixBehaviour ApplyFixes,
-                llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> BaseFS)
+                llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> BaseFS,
+                llvm::raw_ostream *SarifOS = nullptr)
       : Files(FileSystemOptions(), std::move(BaseFS)),
         DiagPrinter(new TextDiagnosticPrinter(llvm::outs(), DiagOpts)),
         Diags(DiagnosticIDs::create(), DiagOpts, DiagPrinter),
-        SourceMgr(Diags, Files), Context(Context), ApplyFixes(ApplyFixes) {
+        SourceMgr(Diags, Files), Context(Context), ApplyFixes(ApplyFixes),
+        SarifOS(SarifOS) {
+    if (SarifOS) {
+      SarifWriter.emplace(SourceMgr);
+      SarifWriter->createRun("clang-tidy", "clang-tidy");
+    }
+
     DiagOpts.setShowColors(Context.getOptions().UseColor.value_or(
                                llvm::sys::Process::StandardOutHasColors())
                                ? ShowColorsKind::On
@@ -195,6 +205,97 @@ class ErrorReporter {
     }
     for (const auto &Note : Error.Notes)
       reportNote(Note);
+
+    if (SarifWriter)
+      exportSarifResult(Error, Loc);
+  }
+
+  SmallVector<ThreadFlow, 8> createThreadFlows(const ClangTidyError &Error) {
+    SmallVector<ThreadFlow, 8> Flows;
+    if (!StringRef(Error.DiagnosticName).starts_with("clang-analyzer-"))
+      return Flows;
+
+    Flows.reserve(Error.Notes.size());
+    for (const tooling::DiagnosticMessage &Note : Error.Notes) {
+      tooling::FileByteRange FBR;
+      if (Note.Ranges.empty()) {
+        FBR.FilePath = Note.FilePath;
+        FBR.FileOffset = Note.FileOffset;
+        FBR.Length = 1;
+      } else {
+        FBR = Note.Ranges.front();
+      }
+      const CharSourceRange Range = getRange(FBR);
+      Flows.push_back(
+          ThreadFlow::create().setRange(Range).setMessage(Note.Message));
+    }
+    return Flows;
+  }
+
+  static std::string buildClangTidyHelpURI(StringRef Name) {
+    const auto [Module, Check] = Name.starts_with("clang-analyzer-")
+                                     ? Name.rsplit('-')
+                                     : Name.split('-');
+    return llvm::formatv(
+        "https://clang.llvm.org/extra/clang-tidy/checks/{0}/{1}.html";,
+        Module, Check);
+  }
+
+  void exportSarifResult(const ClangTidyError &Error,
+                         const SourceLocation Loc) {
+    assert(SarifWriter &&
+           "SarifWriter must be initialized to export SARIF results");
+
+    const std::pair<llvm::StringMap<size_t>::iterator, bool> RuleIndexEntry =
+        SarifRuleIdx.try_emplace(Error.DiagnosticName, 0);
+    llvm::StringMap<size_t>::iterator RuleIndexEntryIt = RuleIndexEntry.first;
+    bool Inserted = RuleIndexEntry.second;
+    size_t &RuleIndex = RuleIndexEntryIt->second;
+
+    const DiagnosticsEngine::Level EffectiveLevel =
+        Error.IsWarningAsError
+            ? DiagnosticsEngine::Error
+            : static_cast<DiagnosticsEngine::Level>(Error.DiagLevel);
+
+    if (Inserted) {
+      const StringRef Name = Error.DiagnosticName;
+      SarifRule Rule =
+          SarifRule::create().setRuleId(Name).setName(Name).setDescription(
+              Error.Message.Message);
+
+      if (!Name.starts_with("clang-diagnostic"))
+        Rule = Rule.setHelpURI(buildClangTidyHelpURI(Name));
+
+      Rule = addDiagnosticLevelToRule(Rule, EffectiveLevel);
+      RuleIndex = SarifWriter->createRule(Rule);
+    }
+
+    SarifResult Result =
+        SarifResult::create(RuleIndex)
+            .setDiagnosticMessage(Error.Message.Message)
+            .setDiagnosticLevel(getSarifResultLevel(EffectiveLevel))
+            .setThreadFlows(createThreadFlows(Error))
+            .addLocations(getResultRanges(Error, Loc));
+
+    SarifWriter->appendResult(Result);
+  }
+
+  SmallVector<CharSourceRange, 4> getResultRanges(const ClangTidyError &Error,
+                                                  SourceLocation Loc) {
+    SmallVector<CharSourceRange, 4> Ranges;
+    Ranges.reserve(Error.Message.Ranges.size());
+    for (const FileByteRange &FBR : Error.Message.Ranges)
+      Ranges.push_back(getRange(FBR));
+
+    if (Ranges.empty() && Loc.isValid()) {
+      // Some Clang-Tidy diagnostics are issued with a single location (not a
+      // range). For these, we create a range of length 1 at the diagnostic
+      // location. As, SARIF results require a character range for each
+      // location.
+      Ranges.push_back(
+          CharSourceRange::getCharRange(Loc, Loc.getLocWithOffset(1)));
+    }
+    return Ranges;
   }
 
   void finish() {
@@ -254,6 +355,8 @@ class ErrorReporter {
       if (OriginalCWD)
         VFS.setCurrentWorkingDirectory(*OriginalCWD);
     }
+    if (SarifWriter)
+      finalizeSarif();
   }
 
   unsigned getWarningsAsErrorsCount() const { return WarningsAsErrors; }
@@ -271,6 +374,14 @@ class ErrorReporter {
     return SourceMgr.getLocForStartOfFile(ID).getLocWithOffset(Offset);
   }
 
+  void finalizeSarif() {
+    assert(SarifWriter &&
+           "SarifWriter must be initialized to export SARIF results");
+    assert(SarifOS && "SarifOS must be initialized to export SARIF results");
+    llvm::json::Value Document = SarifWriter->createDocument();
+    *SarifOS << llvm::formatv("{0:2}", Document);
+  }
+
   void reportFix(const DiagnosticBuilder &Diag,
                  const llvm::StringMap<Replacements> &Fix) {
     for (const auto &FileAndReplacements : Fix) {
@@ -328,6 +439,13 @@ class ErrorReporter {
   unsigned TotalFixes = 0U;
   unsigned AppliedFixes = 0U;
   unsigned WarningsAsErrors = 0U;
+  llvm::raw_ostream *SarifOS = nullptr;
+  // ExportSarifResult is called for each SARIF rule that gets created, while a
+  // SarifWriter run is created once at ErrorReporter construction.
+  std::optional<SarifDocumentWriter> SarifWriter;
+  // SarifRuleIdx is used across multiple calls of exportSarifResult as cache 
to
+  // avoid creating duplicate SARIF rules.
+  llvm::StringMap<size_t> SarifRuleIdx;
 };
 
 class ClangTidyASTConsumer : public MultiplexConsumer {
@@ -613,7 +731,8 @@ runClangTidy(ClangTidyContext &Context, const 
CompilationDatabase &Compilations,
   Context.setEnableProfiling(EnableCheckProfile);
   Context.setProfileStoragePrefix(StoreCheckProfile);
 
-  ClangTidyDiagnosticConsumer DiagConsumer(Context, nullptr, true, 
ApplyAnyFix);
+  ClangTidyDiagnosticConsumer DiagConsumer(Context, nullptr, true, ApplyAnyFix,
+                                           true);
   auto DiagOpts = std::make_unique<DiagnosticOptions>();
   DiagnosticsEngine DE(DiagnosticIDs::create(), *DiagOpts, &DiagConsumer,
                        /*ShouldOwnClient=*/false);
@@ -668,8 +787,9 @@ runClangTidy(ClangTidyContext &Context, const 
CompilationDatabase &Compilations,
 void handleErrors(llvm::ArrayRef<ClangTidyError> Errors,
                   ClangTidyContext &Context, FixBehaviour Fix,
                   unsigned &WarningsAsErrorsCount,
-                  llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> BaseFS) {
-  ErrorReporter Reporter(Context, Fix, std::move(BaseFS));
+                  llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> BaseFS,
+                  llvm::raw_ostream *SarifOS) {
+  ErrorReporter Reporter(Context, Fix, std::move(BaseFS), SarifOS);
   llvm::vfs::FileSystem &FileSystem =
       Reporter.getSourceManager().getFileManager().getVirtualFileSystem();
   auto InitialWorkingDir = FileSystem.getCurrentWorkingDirectory();
diff --git a/clang-tools-extra/clang-tidy/ClangTidy.h 
b/clang-tools-extra/clang-tidy/ClangTidy.h
index 5fac25bd3bbca..5069cb3cca629 100644
--- a/clang-tools-extra/clang-tidy/ClangTidy.h
+++ b/clang-tools-extra/clang-tidy/ClangTidy.h
@@ -118,7 +118,8 @@ enum FixBehaviour {
 void handleErrors(llvm::ArrayRef<ClangTidyError> Errors,
                   ClangTidyContext &Context, FixBehaviour Fix,
                   unsigned &WarningsAsErrorsCount,
-                  llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> BaseFS);
+                  llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> BaseFS,
+                  llvm::raw_ostream *SarifOS = nullptr);
 
 /// Serializes replacements into YAML and writes them to the specified
 /// output stream.
diff --git a/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp 
b/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp
index 7ee556fa7c51f..cc39ae2b507bf 100644
--- a/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp
+++ b/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp
@@ -21,6 +21,7 @@
 #include "clang/Tooling/CommonOptionsParser.h"
 #include "llvm/ADT/StringSet.h"
 #include "llvm/Support/CommandLine.h"
+#include "llvm/Support/FileSystem.h"
 #include "llvm/Support/InitLLVM.h"
 #include "llvm/Support/PluginLoader.h" // IWYU pragma: keep
 #include "llvm/Support/Process.h"
@@ -311,6 +312,12 @@ code with clang-apply-replacements.
                                         cl::value_desc("filename"),
                                         cl::cat(ClangTidyCategory));
 
+static cl::opt<std::string> ExportSarif("export-sarif", desc(R"(
+File in which to store diagnostics in SARIF format.
+)"),
+                                        cl::value_desc("filename"),
+                                        cl::cat(ClangTidyCategory));
+
 static cl::opt<bool> Quiet("quiet", desc(R"(
 Run clang-tidy in quiet mode. This suppresses
 printing statistics about ignored warnings and
@@ -652,6 +659,18 @@ int clangTidyMain(int argc, const char **argv) {
     FileName = PathList.front();
 
   const SmallString<256> FilePath = makeAbsolute(FileName);
+
+  std::unique_ptr<llvm::raw_fd_ostream> SarifOS;
+  if (!ExportSarif.empty()) {
+    std::error_code EC;
+    SarifOS = std::make_unique<llvm::raw_fd_ostream>(ExportSarif, EC,
+                                                     llvm::sys::fs::OF_Text);
+    if (EC) {
+      llvm::errs() << "Error opening output file: " << EC.message() << '\n';
+      return 1;
+    }
+  }
+
   ClangTidyOptions EffectiveOptions = OptionsProvider->getOptions(FilePath);
 
   const std::vector<std::string> EnabledChecks =
@@ -754,7 +773,7 @@ int clangTidyMain(int argc, const char **argv) {
   unsigned WErrorCount = 0;
 
   handleErrors(Errors, Context, DisableFixes ? FB_NoFix : Behaviour,
-               WErrorCount, BaseFS);
+               WErrorCount, BaseFS, SarifOS.get());
 
   if (!ExportFixes.empty() && !Errors.empty()) {
     std::error_code EC;
diff --git a/clang-tools-extra/docs/ReleaseNotes.md 
b/clang-tools-extra/docs/ReleaseNotes.md
index 6fe497e5f6eaf..8c689dc337441 100644
--- a/clang-tools-extra/docs/ReleaseNotes.md
+++ b/clang-tools-extra/docs/ReleaseNotes.md
@@ -100,6 +100,10 @@ infrastructure are described first, followed by 
tool-specific sections.
   `-std=cXX-or-earlier` values, mirroring the existing `-std=cXX-or-later`.
   New construct expands to the given standard and every earlier one.
 
+- Added a new {program}`clang-tidy` command line option `-export-sarif=<file>`
+  in which clang-tidy diagnostics are exported in the `SARIF 
https://sarifweb.azurewebsites.net/`
+  format.
+
 #### New checks
 
 - New {doc}`llvm-invalid-regex-pattern
diff --git 
a/clang-tools-extra/test/clang-tidy/infrastructure/export-SARIF-Thread-flows.cpp
 
b/clang-tools-extra/test/clang-tidy/infrastructure/export-SARIF-Thread-flows.cpp
new file mode 100644
index 0000000000000..63ff3653cbc3f
--- /dev/null
+++ 
b/clang-tools-extra/test/clang-tidy/infrastructure/export-SARIF-Thread-flows.cpp
@@ -0,0 +1,136 @@
+// RUN: grep -Ev "// *[A-Z-]+:" %s > %t-input.cpp
+// RUN: clang-tidy %t-input.cpp -checks='-*,clang-analyzer*' 
-export-sarif=%t.sarif > %t.msg 2>&1
+// RUN: FileCheck -input-file=%t.msg -check-prefix=CHECK-MESSAGES %s 
-implicit-check-not='{{warning|error|note}}:'
+// RUN: FileCheck -input-file=%t.sarif -check-prefix=CHECK-SARIF %s
+void f() {
+  int *ptr = nullptr;
+  *ptr = 1;
+}
+
+//CHECK-MESSAGES: -input.cpp:3:8: warning: Dereference of null pointer (loaded 
from variable 'ptr') [clang-analyzer-core.NullDereference]
+//CHECK-MESSAGES: -input.cpp:2:3: note: 'ptr' initialized to a null pointer 
value
+//CHECK-MESSAGES: -input.cpp:3:8: note: Dereference of null pointer (loaded 
from variable 'ptr')
+
+//CHECK-SARIF: {
+//CHECK-SARIF-NEXT:   "$schema": 
"https://docs.oasis-open.org/sarif/sarif/v2.1.0/cos02/schemas/sarif-schema-2.1.0.json";,
+//CHECK-SARIF-NEXT:   "runs": [
+//CHECK-SARIF-NEXT:     {
+//CHECK-SARIF-NEXT:       "artifacts": [
+//CHECK-SARIF-NEXT:         {
+//CHECK-SARIF-NEXT:           "length": {{[0-9]+}},
+//CHECK-SARIF-NEXT:           "location": {
+//CHECK-SARIF-NEXT:             "index": 0,
+//CHECK-SARIF-NEXT:             "uri": "{{.*}}-input.cpp"
+//CHECK-SARIF-NEXT:           },
+//CHECK-SARIF-NEXT:           "mimeType": "text/plain",
+//CHECK-SARIF-NEXT:           "roles": [
+//CHECK-SARIF-NEXT:             "resultFile"
+//CHECK-SARIF-NEXT:           ]
+//CHECK-SARIF-NEXT:         }
+//CHECK-SARIF-NEXT:       ],
+//CHECK-SARIF-NEXT:       "columnKind": "unicodeCodePoints",
+//CHECK-SARIF-NEXT:       "results": [
+//CHECK-SARIF-NEXT:         {
+//CHECK-SARIF-NEXT:           "codeFlows": [
+//CHECK-SARIF-NEXT:             {
+//CHECK-SARIF-NEXT:               "threadFlows": [
+//CHECK-SARIF-NEXT:                 {
+//CHECK-SARIF-NEXT:                   "locations": [
+//CHECK-SARIF-NEXT:                     {
+//CHECK-SARIF-NEXT:                       "importance": "important",
+//CHECK-SARIF-NEXT:                       "location": {
+//CHECK-SARIF-NEXT:                         "message": {
+//CHECK-SARIF-NEXT:                           "text": "'ptr' initialized to a 
null pointer value"
+//CHECK-SARIF-NEXT:                         },
+//CHECK-SARIF-NEXT:                         "physicalLocation": {
+//CHECK-SARIF-NEXT:                           "artifactLocation": {
+//CHECK-SARIF-NEXT:                             "index": 0,
+//CHECK-SARIF-NEXT:                             "uri": "{{.*}}-input.cpp"
+//CHECK-SARIF-NEXT:                           },
+//CHECK-SARIF-NEXT:                           "region": {
+//CHECK-SARIF-NEXT:                             "endColumn": 11,
+//CHECK-SARIF-NEXT:                             "endLine": 2,
+//CHECK-SARIF-NEXT:                             "startColumn": 3,
+//CHECK-SARIF-NEXT:                             "startLine": 2
+//CHECK-SARIF-NEXT:                           }
+//CHECK-SARIF-NEXT:                         }
+//CHECK-SARIF-NEXT:                       }
+//CHECK-SARIF-NEXT:                     },
+//CHECK-SARIF-NEXT:                     {
+//CHECK-SARIF-NEXT:                       "importance": "important",
+//CHECK-SARIF-NEXT:                       "location": {
+//CHECK-SARIF-NEXT:                         "message": {
+//CHECK-SARIF-NEXT:                           "text": "Dereference of null 
pointer (loaded from variable 'ptr')"
+//CHECK-SARIF-NEXT:                         },
+//CHECK-SARIF-NEXT:                         "physicalLocation": {
+//CHECK-SARIF-NEXT:                           "artifactLocation": {
+//CHECK-SARIF-NEXT:                             "index": 0,
+//CHECK-SARIF-NEXT:                              "uri": "{{.*}}-input.cpp"
+//CHECK-SARIF-NEXT:                           },
+//CHECK-SARIF-NEXT:                           "region": {
+//CHECK-SARIF-NEXT:                             "endColumn": 7,
+//CHECK-SARIF-NEXT:                             "endLine": 3,
+//CHECK-SARIF-NEXT:                             "startColumn": 4,
+//CHECK-SARIF-NEXT:                             "startLine": 3
+//CHECK-SARIF-NEXT:                           }
+//CHECK-SARIF-NEXT:                         }
+//CHECK-SARIF-NEXT:                       }
+//CHECK-SARIF-NEXT:                     }                      
+//CHECK-SARIF-NEXT:                   ]        
+//CHECK-SARIF-NEXT:                 }
+//CHECK-SARIF-NEXT:               ]
+//CHECK-SARIF-NEXT:             }
+//CHECK-SARIF-NEXT:           ],
+//CHECK-SARIF-NEXT:           "level": "warning",
+//CHECK-SARIF-NEXT:           "locations": [
+//CHECK-SARIF-NEXT:             {
+//CHECK-SARIF-NEXT:               "physicalLocation": {
+//CHECK-SARIF-NEXT:                 "artifactLocation": {
+//CHECK-SARIF-NEXT:                   "index": 0,
+//CHECK-SARIF-NEXT:                   "uri": "{{.*}}-input.cpp"
+//CHECK-SARIF-NEXT:                 },
+//CHECK-SARIF-NEXT:                 "region": {
+//CHECK-SARIF-NEXT:                   "endColumn": 7,
+//CHECK-SARIF-NEXT:                   "endLine": 3,
+//CHECK-SARIF-NEXT:                   "startColumn": 4,
+//CHECK-SARIF-NEXT:                   "startLine": 3
+//CHECK-SARIF-NEXT:                 }
+//CHECK-SARIF-NEXT:               }
+//CHECK-SARIF-NEXT:             }
+//CHECK-SARIF-NEXT:           ],
+//CHECK-SARIF-NEXT:           "message": {
+//CHECK-SARIF-NEXT:             "text": "Dereference of null pointer (loaded 
from variable 'ptr')"
+//CHECK-SARIF-NEXT:           },
+//CHECK-SARIF-NEXT:           "ruleId": "clang-analyzer-core.NullDereference",
+//CHECK-SARIF-NEXT:           "ruleIndex": 0
+//CHECK-SARIF-NEXT:         }
+//CHECK-SARIF-NEXT:       ],
+//CHECK-SARIF-NEXT:       "tool": {
+//CHECK-SARIF-NEXT:         "driver": {
+//CHECK-SARIF-NEXT:           "fullName": "clang-tidy",
+//CHECK-SARIF-NEXT:           "informationUri": 
"https://clang.llvm.org/docs/UsersManual.html";,
+//CHECK-SARIF-NEXT:           "language": "en-US",
+//CHECK-SARIF-NEXT:           "name": "clang-tidy",
+//CHECK-SARIF-NEXT:           "rules": [
+//CHECK-SARIF-NEXT:             {
+//CHECK-SARIF-NEXT:               "defaultConfiguration": {
+//CHECK-SARIF-NEXT:                 "enabled": true,
+//CHECK-SARIF-NEXT:                 "level": "warning",
+//CHECK-SARIF-NEXT:                 "rank": -1
+//CHECK-SARIF-NEXT:               },
+//CHECK-SARIF-NEXT:               "fullDescription": {
+//CHECK-SARIF-NEXT:                 "text": "Dereference of null pointer 
(loaded from variable 'ptr')"
+//CHECK-SARIF-NEXT:               },
+//CHECK-SARIF-NEXT:               "helpUri": 
"https://clang.llvm.org/extra/clang-tidy/checks/clang-analyzer/core.NullDereference.html";,
+//CHECK-SARIF-NEXT:               "id": "clang-analyzer-core.NullDereference",
+//CHECK-SARIF-NEXT:               "name": "clang-analyzer-core.NullDereference"
+//CHECK-SARIF-NEXT:             }
+//CHECK-SARIF-NEXT:           ],
+//CHECK-SARIF-NEXT:           "version": "{{.*}}"
+//CHECK-SARIF-NEXT:         }
+//CHECK-SARIF-NEXT:       }
+//CHECK-SARIF-NEXT:     }
+//CHECK-SARIF-NEXT:   ],
+//CHECK-SARIF-NEXT:   "version": "{{.*}}"
+//CHECK-SARIF-NEXT: }
+
diff --git 
a/clang-tools-extra/test/clang-tidy/infrastructure/export-SARIF-diagnostics-terminal.cpp
 
b/clang-tools-extra/test/clang-tidy/infrastructure/export-SARIF-diagnostics-terminal.cpp
new file mode 100644
index 0000000000000..52fb3fc3a639c
--- /dev/null
+++ 
b/clang-tools-extra/test/clang-tidy/infrastructure/export-SARIF-diagnostics-terminal.cpp
@@ -0,0 +1,98 @@
+// RUN: grep -Ev "// *[A-Z-]+:" %s > %t-input.cpp
+// RUN: not clang-tidy %t-input.cpp 
-checks='-*,google-explicit-constructor,clang-diagnostic-missing-prototypes,clang-diagnostic-zero-length-array'
 
--warnings-as-errors='clang-diagnostic-missing-prototypes,google-explicit-constructor'
 -export-sarif - -- -Wmissing-prototypes -Wzero-length-array 2>/dev/null | 
FileCheck %s
+#define X(n) void n ## n() {}
+X(f)
+int a[-1];
+int b[0];
+
+void test(x);
+struct Foo {
+  member;
+  Foo(int) {}
+};
+
+//CHECK: {{^{$}}
+//CHECK-NEXT:   "$schema": 
"https://docs.oasis-open.org/sarif/sarif/v2.1.0/cos02/schemas/sarif-schema-2.1.0.json";,
+//CHECK-NEXT:   "runs": [
+//CHECK-NEXT:     {
+//CHECK-NEXT:       "artifacts": [
+//CHECK-NEXT:         {
+//CHECK-NEXT:           "length": {{[0-9]+}},
+//CHECK-NEXT:           "location": {
+//CHECK-NEXT:             "index": 0,
+//CHECK-NEXT:             "uri": "file://{{.*}}-input.cpp"
+//CHECK-NEXT:           },
+//CHECK-NEXT:           "mimeType": "text/plain",
+//CHECK-NEXT:           "roles": [
+//CHECK-NEXT:             "resultFile"
+//CHECK-NEXT:           ]
+//CHECK-NEXT:         }
+//CHECK-NEXT:       ],
+//CHECK-NEXT:       "columnKind": "unicodeCodePoints",
+//CHECK-NEXT:       "results": [
+//CHECK-NEXT:         {
+//CHECK-NEXT:           "level": "error",
+//CHECK-NEXT:           "locations": [
+//CHECK-NEXT:             {
+//CHECK-NEXT:               "physicalLocation": {
+//CHECK-NEXT:                 "artifactLocation": {
+//CHECK-NEXT:                   "index": 0,
+//CHECK-NEXT:                   "uri": "file://{{.*}}-input.cpp"
+//CHECK-NEXT:                 },
+//CHECK-NEXT:                 "region": {
+//CHECK-NEXT:                   "endColumn": 2,
+//CHECK-NEXT:                   "endLine": 2,
+//CHECK-NEXT:                   "startColumn": 1,
+//CHECK-NEXT:                   "startLine": 2
+//CHECK-NEXT:                 }
+//CHECK-NEXT:               }
+//CHECK-NEXT:             }
+//CHECK-NEXT:           ],
+//CHECK-NEXT:           "message": {
+//CHECK-NEXT:             "text": "no previous prototype for function 'ff'"
+//CHECK-NEXT:           },
+//CHECK-NEXT:           "ruleId": "clang-diagnostic-missing-prototypes",
+//CHECK-NEXT:           "ruleIndex": 0
+//CHECK-NEXT:         },
+//CHECK-NEXT:         {
+//CHECK-NEXT:           "level": "error",
+//CHECK-NEXT:           "locations": [
+//CHECK-NEXT:             {
+//CHECK-NEXT:               "physicalLocation": {
+//CHECK-NEXT:                 "artifactLocation": {
+//CHECK-NEXT:                   "index": 0,
+//CHECK-NEXT:                   "uri": "file://{{.*}}-input.cpp"
+//CHECK-NEXT:                 },
+//CHECK-NEXT:                 "region": {
+//CHECK-NEXT:                   "endColumn": 9,
+//CHECK-NEXT:                   "endLine": 3,
+//CHECK-NEXT:                   "startColumn": 7,
+//CHECK-NEXT:                   "startLine": 3
+//CHECK-NEXT:                 }
+//CHECK-NEXT:               }
+//CHECK-NEXT:             }
+//CHECK-NEXT:           ],
+//CHECK-NEXT:           "message": {
+//CHECK-NEXT:             "text": "'a' declared as an array with a negative 
size"
+//CHECK-NEXT:           },
+//CHECK-NEXT:           "ruleId": "clang-diagnostic-error",
+//CHECK-NEXT:           "ruleIndex": 1
+//CHECK-NEXT:         },
+//CHECK-NEXT:         {
+//CHECK-NEXT:           "level": "warning",
+//CHECK-NEXT:           "locations": [
+//CHECK-NEXT:              {
+//CHECK-NEXT:               "physicalLocation": {
+//CHECK-NEXT:                 "artifactLocation": {
+//CHECK-NEXT:                   "index": 0,
+//CHECK-NEXT:                    "uri": "file://{{.*}}-input.cpp"
+//CHECK-NEXT:                 },
+//CHECK-NEXT:                 "region": {
+//CHECK-NEXT:                   "endColumn": 8,
+//CHECK-NEXT:                   "endLine": 4,
+//CHECK-NEXT:                   "startColumn": 7,
+//CHECK-NEXT:                   "startLine": 4
+//CHECK-NEXT:                 }
+//CHECK-NEXT:               }
+//CHECK-NEXT:             }
+//CHECK-NEXT:           ],
\ No newline at end of file
diff --git 
a/clang-tools-extra/test/clang-tidy/infrastructure/export-SARIF-diagnostics.cpp 
b/clang-tools-extra/test/clang-tidy/infrastructure/export-SARIF-diagnostics.cpp
new file mode 100644
index 0000000000000..4ba2d3d55a4ed
--- /dev/null
+++ 
b/clang-tools-extra/test/clang-tidy/infrastructure/export-SARIF-diagnostics.cpp
@@ -0,0 +1,165 @@
+// RUN: grep -Ev "// *[A-Z-]+:" %s > %t-input.cpp
+// RUN: not clang-tidy %t-input.cpp 
-checks='-*,google-explicit-constructor,clang-diagnostic-missing-prototypes,clang-diagnostic-zero-length-array'
 
--warnings-as-errors='clang-diagnostic-missing-prototypes,google-explicit-constructor'
 -export-sarif=%t.sarif -- -Wmissing-prototypes -Wzero-length-array > %t.msg 
2>&1
+// RUN: FileCheck -input-file=%t.msg -check-prefix=CHECK-MESSAGES %s 
-implicit-check-not='{{warning|error|note}}:'
+// RUN: FileCheck -input-file=%t.sarif -check-prefix=CHECK-SARIF %s
+#define X(n) void n ## n() {}
+X(f)
+int a[-1];
+int b[0];
+
+void test(x);
+struct Foo {
+  member;
+  Foo(int) {}
+};
+
+//CHECK-MESSAGES: -input.cpp:2:1: error: no previous prototype for function 
'ff' [clang-diagnostic-missing-prototypes,-warnings-as-errors]
+//CHECK-MESSAGES: -input.cpp:1:19: note: expanded from macro 'X'
+//CHECK-MESSAGES: {{^}}note: expanded from here{{$}}
+//CHECK-MESSAGES: -input.cpp:2:1: note: declare 'static' if the function is 
not intended to be used outside of this translation unit
+//CHECK-MESSAGES: -input.cpp:1:14: note: expanded from macro 'X'
+//CHECK-MESSAGES: -input.cpp:3:7: error: 'a' declared as an array with a 
negative size [clang-diagnostic-error]
+//CHECK-MESSAGES: -input.cpp:4:7: warning: zero size arrays are an extension 
[clang-diagnostic-zero-length-array]
+//CHECK-MESSAGES: -input.cpp:6:11: error: unknown type name 'x' 
[clang-diagnostic-error]
+//CHECK-MESSAGES: -input.cpp:8:3: error: a type specifier is required for all 
declarations [clang-diagnostic-error]
+//CHECK-MESSAGES: -input.cpp:9:3: error: single-argument constructors must be 
marked explicit to avoid unintentional implicit conversions 
[google-explicit-constructor,-warnings-as-errors]
+
+//CHECK-SARIF: {
+//CHECK-SARIF-NEXT:   "$schema": 
"https://docs.oasis-open.org/sarif/sarif/v2.1.0/cos02/schemas/sarif-schema-2.1.0.json";,
+//CHECK-SARIF-NEXT:   "runs": [
+//CHECK-SARIF-NEXT:     {
+//CHECK-SARIF-NEXT:       "artifacts": [
+//CHECK-SARIF-NEXT:         {
+//CHECK-SARIF-NEXT:           "length": {{[0-9]+}},
+//CHECK-SARIF-NEXT:           "location": {
+//CHECK-SARIF-NEXT:             "index": 0,
+//CHECK-SARIF-NEXT:             "uri": "{{.*}}-input.cpp"
+//CHECK-SARIF-NEXT:           },
+//CHECK-SARIF-NEXT:           "mimeType": "text/plain",
+//CHECK-SARIF-NEXT:           "roles": [
+//CHECK-SARIF-NEXT:             "resultFile"
+//CHECK-SARIF-NEXT:           ]
+//CHECK-SARIF-NEXT:         }
+//CHECK-SARIF-NEXT:       ],
+//CHECK-SARIF-NEXT:       "columnKind": "unicodeCodePoints",
+//CHECK-SARIF-NEXT:       "results": [
+//CHECK-SARIF-NEXT:         {
+//CHECK-SARIF-NEXT:           "level": "error",
+//CHECK-SARIF-NEXT:           "locations": [
+//CHECK-SARIF-NEXT:             {
+//CHECK-SARIF-NEXT:               "physicalLocation": {
+//CHECK-SARIF-NEXT:                 "artifactLocation": {
+//CHECK-SARIF-NEXT:                   "index": 0,
+//CHECK-SARIF-NEXT:                   "uri": "{{.*}}-input.cpp"
+//CHECK-SARIF-NEXT:                 },
+//CHECK-SARIF-NEXT:                 "region": {
+//CHECK-SARIF-NEXT:                   "endColumn": 2,
+//CHECK-SARIF-NEXT:                   "endLine": 2,
+//CHECK-SARIF-NEXT:                   "startColumn": 1,
+//CHECK-SARIF-NEXT:                   "startLine": 2
+//CHECK-SARIF-NEXT:                 }
+//CHECK-SARIF-NEXT:               }
+//CHECK-SARIF-NEXT:             }
+//CHECK-SARIF-NEXT:           ],
+//CHECK-SARIF-NEXT:           "message": {
+//CHECK-SARIF-NEXT:             "text": "no previous prototype for function 
'ff'"
+//CHECK-SARIF-NEXT:           },
+//CHECK-SARIF-NEXT:           "ruleId": "clang-diagnostic-missing-prototypes",
+//CHECK-SARIF-NEXT:           "ruleIndex": 0
+//CHECK-SARIF-NEXT:         },
+//CHECK-SARIF-NEXT:         {
+//CHECK-SARIF-NEXT:           "level": "error",
+//CHECK-SARIF-NEXT:           "locations": [
+//CHECK-SARIF-NEXT:             {
+//CHECK-SARIF-NEXT:               "physicalLocation": {
+//CHECK-SARIF-NEXT:                 "artifactLocation": {
+//CHECK-SARIF-NEXT:                   "index": 0,
+//CHECK-SARIF-NEXT:                   "uri": "{{.*}}-input.cpp"
+//CHECK-SARIF-NEXT:                 },
+//CHECK-SARIF-NEXT:                 "region": {
+//CHECK-SARIF-NEXT:                   "endColumn": 9,
+//CHECK-SARIF-NEXT:                   "endLine": 3,
+//CHECK-SARIF-NEXT:                   "startColumn": 7,
+//CHECK-SARIF-NEXT:                   "startLine": 3
+//CHECK-SARIF-NEXT:                 }
+//CHECK-SARIF-NEXT:               }
+//CHECK-SARIF-NEXT:             }
+//CHECK-SARIF-NEXT:           ],
+//CHECK-SARIF-NEXT:           "message": {
+//CHECK-SARIF-NEXT:             "text": "'a' declared as an array with a 
negative size"
+//CHECK-SARIF-NEXT:           },
+//CHECK-SARIF-NEXT:           "ruleId": "clang-diagnostic-error",
+//CHECK-SARIF-NEXT:           "ruleIndex": 1
+//CHECK-SARIF-NEXT:         },
+//CHECK-SARIF-NEXT:         {
+//CHECK-SARIF-NEXT:           "level": "warning",
+//CHECK-SARIF-NEXT:           "locations": [
+//CHECK-SARIF-NEXT:             {
+//CHECK-SARIF-NEXT:               "physicalLocation": {
+//CHECK-SARIF-NEXT:                 "artifactLocation": {
+//CHECK-SARIF-NEXT:                   "index": 0,
+//CHECK-SARIF-NEXT:                   "uri": "{{.*}}-input.cpp"
+//CHECK-SARIF-NEXT:                 },
+//CHECK-SARIF-NEXT:                 "region": {
+//CHECK-SARIF-NEXT:                   "endColumn": 8,
+//CHECK-SARIF-NEXT:                   "endLine": 4,
+//CHECK-SARIF-NEXT:                   "startColumn": 7,
+//CHECK-SARIF-NEXT:                   "startLine": 4
+//CHECK-SARIF-NEXT:                 }
+//CHECK-SARIF-NEXT:               }
+//CHECK-SARIF-NEXT:             }
+//CHECK-SARIF-NEXT:           ],
+//CHECK-SARIF-NEXT:           "message": {
+//CHECK-SARIF-NEXT:             "text": "zero size arrays are an extension"
+//CHECK-SARIF-NEXT:           },
+//CHECK-SARIF-NEXT:           "ruleId": "clang-diagnostic-zero-length-array",
+//CHECK-SARIF-NEXT:           "ruleIndex": 2
+//CHECK-SARIF-NEXT:         },
+//CHECK-SARIF-NEXT:         {
+//CHECK-SARIF-NEXT:           "level": "error",
+//CHECK-SARIF-NEXT:           "locations": [
+//CHECK-SARIF-NEXT:             {
+//CHECK-SARIF-NEXT:               "physicalLocation": {
+//CHECK-SARIF-NEXT:                 "artifactLocation": {
+//CHECK-SARIF-NEXT:                   "index": 0,
+//CHECK-SARIF-NEXT:                   "uri": "{{.*}}-input.cpp" 
+//CHECK-SARIF-NEXT:                 },
+//CHECK-SARIF-NEXT:                 "region": {
+//CHECK-SARIF-NEXT:                   "endColumn": 12,
+//CHECK-SARIF-NEXT:                   "endLine": 6,
+//CHECK-SARIF-NEXT:                   "startColumn": 11,
+//CHECK-SARIF-NEXT:                   "startLine": 6
+//CHECK-SARIF-NEXT:                 }
+//CHECK-SARIF-NEXT:               }
+//CHECK-SARIF-NEXT:             }
+//CHECK-SARIF-NEXT:           ],
+//CHECK-SARIF-NEXT:           "message": {
+//CHECK-SARIF-NEXT:             "text": "unknown type name 'x'"
+//CHECK-SARIF-NEXT:           },
+//CHECK-SARIF-NEXT:           "ruleId": "clang-diagnostic-error",
+//CHECK-SARIF-NEXT:           "ruleIndex": 1
+//CHECK-SARIF-NEXT:         },
+//CHECK-SARIF-NEXT:         {
+//CHECK-SARIF-NEXT:           "level": "error",
+//CHECK-SARIF-NEXT:           "locations": [
+//CHECK-SARIF-NEXT:             {
+//CHECK-SARIF-NEXT:               "physicalLocation": {
+//CHECK-SARIF-NEXT:                 "artifactLocation": {
+//CHECK-SARIF-NEXT:                   "index": 0,
+//CHECK-SARIF-NEXT:                   "uri": "{{.*}}-input.cpp"
+//CHECK-SARIF-NEXT:                 },
+//CHECK-SARIF-NEXT:                 "region": {
+//CHECK-SARIF-NEXT:                   "endColumn": 4,
+//CHECK-SARIF-NEXT:                   "endLine": 8,
+//CHECK-SARIF-NEXT:                   "startColumn": 3,
+//CHECK-SARIF-NEXT:                   "startLine": 8
+//CHECK-SARIF-NEXT:                 }
+//CHECK-SARIF-NEXT:               }
+//CHECK-SARIF-NEXT:             }
+//CHECK-SARIF-NEXT:           ],
+//CHECK-SARIF-NEXT:           "message": {
+//CHECK-SARIF-NEXT:             "text": "a type specifier is required for all 
declarations"
+//CHECK-SARIF-NEXT:           },
+//CHECK-SARIF-NEXT:           "ruleId": "clang-diagnostic-error",
+//CHECK-SARIF-NEXT:           "ruleIndex": 1
+//CHECK-SARIF-NEXT:         },
diff --git a/clang/include/clang/Frontend/SARIFDiagnostic.h 
b/clang/include/clang/Frontend/SARIFDiagnostic.h
index 7a6f27eb3b9fa..cef565db1686a 100644
--- a/clang/include/clang/Frontend/SARIFDiagnostic.h
+++ b/clang/include/clang/Frontend/SARIFDiagnostic.h
@@ -6,8 +6,9 @@
 //
 
//===----------------------------------------------------------------------===//
 //
-// This is a utility class that provides support for constructing a SARIF 
object
-// containing diagnostics.
+// This file implements SARIF diagnostic emission, including the 
SARIFDiagnostic
+// renderer and helper utilities for mapping diagnostic levels and annotating
+// SARIF rules.
 //
 
//===----------------------------------------------------------------------===//
 
@@ -20,6 +21,14 @@
 
 namespace clang {
 
+// Maps clang DiagnosticsEngine level to SARIF result levels.
+SarifResultLevel getSarifResultLevel(DiagnosticsEngine::Level level);
+
+// Creates configuration for a SARIF rule based on the diagnostic level and 
sets
+// the rank.
+SarifRule addDiagnosticLevelToRule(SarifRule Rule,
+                                   DiagnosticsEngine::Level Level);
+
 class SARIFDiagnostic : public DiagnosticRenderer {
 public:
   SARIFDiagnostic(raw_ostream &OS, const LangOptions &LangOpts,
@@ -70,9 +79,6 @@ class SARIFDiagnostic : public DiagnosticRenderer {
   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>>
diff --git a/clang/lib/Frontend/SARIFDiagnostic.cpp 
b/clang/lib/Frontend/SARIFDiagnostic.cpp
index 5183462b76f41..b2df1772e4ee5 100644
--- a/clang/lib/Frontend/SARIFDiagnostic.cpp
+++ b/clang/lib/Frontend/SARIFDiagnostic.cpp
@@ -30,6 +30,38 @@
 
 namespace clang {
 
+SarifResultLevel getSarifResultLevel(DiagnosticsEngine::Level level) {
+  switch (level) {
+  case DiagnosticsEngine::Ignored:
+    llvm_unreachable("Invalid diagnostic type");
+  case DiagnosticsEngine::Note:
+    return SarifResultLevel::Note;
+  case DiagnosticsEngine::Remark:
+    return SarifResultLevel::None;
+  case DiagnosticsEngine::Warning:
+    return SarifResultLevel::Warning;
+  case DiagnosticsEngine::Error:
+  case DiagnosticsEngine::Fatal:
+    return SarifResultLevel::Error;
+  }
+  llvm_unreachable("Potentially un-handled DiagnosticsEngine::Level. "
+                   "Is the switch not fully covered?");
+}
+
+SarifRule addDiagnosticLevelToRule(SarifRule Rule,
+                                   DiagnosticsEngine::Level Level) {
+  SarifReportingConfiguration Config =
+      SarifReportingConfiguration::create().setLevel(
+          getSarifResultLevel(Level));
+
+  if (Level == DiagnosticsEngine::Error)
+    Config = Config.setRank(50);
+  else if (Level == DiagnosticsEngine::Fatal)
+    Config = Config.setRank(100);
+
+  return Rule.setDefaultConfiguration(Config);
+}
+
 SARIFDiagnostic::SARIFDiagnostic(raw_ostream &OS, const LangOptions &LangOpts,
                                  DiagnosticOptions &DiagOpts,
                                  SarifDocumentWriter *Writer)
@@ -164,34 +196,6 @@ 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) {

>From 10ff2cbafd31c737660d52f8db32dca5b5e0ed67 Mon Sep 17 00:00:00 2001
From: "Jones, Matthew (DI SW SIM FRWK PLAT SIMFW HPC)"
 <[email protected]>
Date: Fri, 28 Aug 2026 04:09:07 -0700
Subject: [PATCH 2/8] Fixed unchecked optional access and const-correctness

---
 clang-tools-extra/clang-tidy/ClangTidy.cpp | 17 +++++++++--------
 1 file changed, 9 insertions(+), 8 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/ClangTidy.cpp 
b/clang-tools-extra/clang-tidy/ClangTidy.cpp
index 05084b33a92b3..3fce3d42bec8a 100644
--- a/clang-tools-extra/clang-tidy/ClangTidy.cpp
+++ b/clang-tools-extra/clang-tidy/ClangTidy.cpp
@@ -237,8 +237,8 @@ class ErrorReporter {
                                      ? Name.rsplit('-')
                                      : Name.split('-');
     return llvm::formatv(
-        "https://clang.llvm.org/extra/clang-tidy/checks/{0}/{1}.html";,
-        Module, Check);
+        "https://clang.llvm.org/extra/clang-tidy/checks/{0}/{1}.html";, Module,
+        Check);
   }
 
   void exportSarifResult(const ClangTidyError &Error,
@@ -248,8 +248,9 @@ class ErrorReporter {
 
     const std::pair<llvm::StringMap<size_t>::iterator, bool> RuleIndexEntry =
         SarifRuleIdx.try_emplace(Error.DiagnosticName, 0);
-    llvm::StringMap<size_t>::iterator RuleIndexEntryIt = RuleIndexEntry.first;
-    bool Inserted = RuleIndexEntry.second;
+    const llvm::StringMap<size_t>::iterator RuleIndexEntryIt =
+        RuleIndexEntry.first;
+    const bool Inserted = RuleIndexEntry.second;
     size_t &RuleIndex = RuleIndexEntryIt->second;
 
     const DiagnosticsEngine::Level EffectiveLevel =
@@ -267,17 +268,17 @@ class ErrorReporter {
         Rule = Rule.setHelpURI(buildClangTidyHelpURI(Name));
 
       Rule = addDiagnosticLevelToRule(Rule, EffectiveLevel);
-      RuleIndex = SarifWriter->createRule(Rule);
+      RuleIndex = SarifWriter.value().createRule(Rule);
     }
 
-    SarifResult Result =
+    const SarifResult Result =
         SarifResult::create(RuleIndex)
             .setDiagnosticMessage(Error.Message.Message)
             .setDiagnosticLevel(getSarifResultLevel(EffectiveLevel))
             .setThreadFlows(createThreadFlows(Error))
             .addLocations(getResultRanges(Error, Loc));
 
-    SarifWriter->appendResult(Result);
+    SarifWriter.value().appendResult(Result);
   }
 
   SmallVector<CharSourceRange, 4> getResultRanges(const ClangTidyError &Error,
@@ -378,7 +379,7 @@ class ErrorReporter {
     assert(SarifWriter &&
            "SarifWriter must be initialized to export SARIF results");
     assert(SarifOS && "SarifOS must be initialized to export SARIF results");
-    llvm::json::Value Document = SarifWriter->createDocument();
+    llvm::json::Value Document = SarifWriter.value().createDocument();
     *SarifOS << llvm::formatv("{0:2}", Document);
   }
 

>From 1cc22af9be6732100a096427b9349964caad7947 Mon Sep 17 00:00:00 2001
From: "Jones, Matthew (DI SW SIM FRWK PLAT SIMFW HPC)"
 <[email protected]>
Date: Fri, 28 Aug 2026 06:08:54 -0700
Subject: [PATCH 3/8] Textdiagnosticprinter suppressed for stdout

---
 clang-tools-extra/clang-tidy/ClangTidy.cpp    | 36 ++++++++++---------
 clang-tools-extra/clang-tidy/ClangTidy.h      |  3 +-
 .../clang-tidy/tool/ClangTidyMain.cpp         |  3 +-
 3 files changed, 24 insertions(+), 18 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/ClangTidy.cpp 
b/clang-tools-extra/clang-tidy/ClangTidy.cpp
index 3fce3d42bec8a..e8cca7831734f 100644
--- a/clang-tools-extra/clang-tidy/ClangTidy.cpp
+++ b/clang-tools-extra/clang-tidy/ClangTidy.cpp
@@ -105,9 +105,13 @@ class ErrorReporter {
 public:
   ErrorReporter(ClangTidyContext &Context, FixBehaviour ApplyFixes,
                 llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> BaseFS,
-                llvm::raw_ostream *SarifOS = nullptr)
+                llvm::raw_ostream *SarifOS = nullptr,
+                bool ExportSarifToStdout = false)
       : Files(FileSystemOptions(), std::move(BaseFS)),
-        DiagPrinter(new TextDiagnosticPrinter(llvm::outs(), DiagOpts)),
+        DiagPrinter(
+            ExportSarifToStdout
+                ? static_cast<DiagnosticConsumer *>(new IgnoringDiagConsumer())
+                : new TextDiagnosticPrinter(llvm::outs(), DiagOpts)),
         Diags(DiagnosticIDs::create(), DiagOpts, DiagPrinter),
         SourceMgr(Diags, Files), Context(Context), ApplyFixes(ApplyFixes),
         SarifOS(SarifOS) {
@@ -120,7 +124,8 @@ class ErrorReporter {
                                llvm::sys::Process::StandardOutHasColors())
                                ? ShowColorsKind::On
                                : ShowColorsKind::Off);
-    DiagPrinter->BeginSourceFile(LangOpts);
+    if (DiagPrinter)
+      DiagPrinter->BeginSourceFile(LangOpts);
     if (DiagOpts.showColors(llvm::sys::Process::StandardOutHasColors()) &&
         !llvm::sys::Process::StandardOutIsDisplayed())
       llvm::sys::Process::UseANSIEscapeCodes(true);
@@ -246,11 +251,8 @@ class ErrorReporter {
     assert(SarifWriter &&
            "SarifWriter must be initialized to export SARIF results");
 
-    const std::pair<llvm::StringMap<size_t>::iterator, bool> RuleIndexEntry =
+    const auto [RuleIndexEntryIt, Inserted] =
         SarifRuleIdx.try_emplace(Error.DiagnosticName, 0);
-    const llvm::StringMap<size_t>::iterator RuleIndexEntryIt =
-        RuleIndexEntry.first;
-    const bool Inserted = RuleIndexEntry.second;
     size_t &RuleIndex = RuleIndexEntryIt->second;
 
     const DiagnosticsEngine::Level EffectiveLevel =
@@ -268,7 +270,8 @@ class ErrorReporter {
         Rule = Rule.setHelpURI(buildClangTidyHelpURI(Name));
 
       Rule = addDiagnosticLevelToRule(Rule, EffectiveLevel);
-      RuleIndex = SarifWriter.value().createRule(Rule);
+      if(SarifWriter)
+        RuleIndex = SarifWriter->createRule(Rule);
     }
 
     const SarifResult Result =
@@ -278,7 +281,8 @@ class ErrorReporter {
             .setThreadFlows(createThreadFlows(Error))
             .addLocations(getResultRanges(Error, Loc));
 
-    SarifWriter.value().appendResult(Result);
+    if(SarifWriter)
+      SarifWriter->appendResult(Result);
   }
 
   SmallVector<CharSourceRange, 4> getResultRanges(const ClangTidyError &Error,
@@ -376,11 +380,10 @@ class ErrorReporter {
   }
 
   void finalizeSarif() {
-    assert(SarifWriter &&
-           "SarifWriter must be initialized to export SARIF results");
-    assert(SarifOS && "SarifOS must be initialized to export SARIF results");
-    llvm::json::Value Document = SarifWriter.value().createDocument();
-    *SarifOS << llvm::formatv("{0:2}", Document);
+    if (SarifWriter && SarifOS) {
+      llvm::json::Value Document = SarifWriter->createDocument();
+      *SarifOS << llvm::formatv("{0:2}", Document);
+    }
   }
 
   void reportFix(const DiagnosticBuilder &Diag,
@@ -789,8 +792,9 @@ void handleErrors(llvm::ArrayRef<ClangTidyError> Errors,
                   ClangTidyContext &Context, FixBehaviour Fix,
                   unsigned &WarningsAsErrorsCount,
                   llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> BaseFS,
-                  llvm::raw_ostream *SarifOS) {
-  ErrorReporter Reporter(Context, Fix, std::move(BaseFS), SarifOS);
+                  llvm::raw_ostream *SarifOS, bool ExportSarifToStdout) {
+  ErrorReporter Reporter(Context, Fix, std::move(BaseFS), SarifOS,
+                         ExportSarifToStdout);
   llvm::vfs::FileSystem &FileSystem =
       Reporter.getSourceManager().getFileManager().getVirtualFileSystem();
   auto InitialWorkingDir = FileSystem.getCurrentWorkingDirectory();
diff --git a/clang-tools-extra/clang-tidy/ClangTidy.h 
b/clang-tools-extra/clang-tidy/ClangTidy.h
index 5069cb3cca629..6df3d7bcc2c3b 100644
--- a/clang-tools-extra/clang-tidy/ClangTidy.h
+++ b/clang-tools-extra/clang-tidy/ClangTidy.h
@@ -119,7 +119,8 @@ void handleErrors(llvm::ArrayRef<ClangTidyError> Errors,
                   ClangTidyContext &Context, FixBehaviour Fix,
                   unsigned &WarningsAsErrorsCount,
                   llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> BaseFS,
-                  llvm::raw_ostream *SarifOS = nullptr);
+                  llvm::raw_ostream *SarifOS = nullptr,
+                  bool ExportSarifToStdout = false);
 
 /// Serializes replacements into YAML and writes them to the specified
 /// output stream.
diff --git a/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp 
b/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp
index cc39ae2b507bf..442f9bf3f9834 100644
--- a/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp
+++ b/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp
@@ -773,7 +773,8 @@ int clangTidyMain(int argc, const char **argv) {
   unsigned WErrorCount = 0;
 
   handleErrors(Errors, Context, DisableFixes ? FB_NoFix : Behaviour,
-               WErrorCount, BaseFS, SarifOS.get());
+               WErrorCount, BaseFS, SarifOS.get(),
+               SarifOS && ExportSarif == "-");
 
   if (!ExportFixes.empty() && !Errors.empty()) {
     std::error_code EC;

>From 34d46219c4034c606766d3352a34fbc55486264b Mon Sep 17 00:00:00 2001
From: "Jones, Matthew (DI SW SIM FRWK PLAT SIMFW HPC)"
 <[email protected]>
Date: Fri, 28 Aug 2026 06:24:22 -0700
Subject: [PATCH 4/8] fixed formatting

---
 clang-tools-extra/clang-tidy/ClangTidy.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/ClangTidy.cpp 
b/clang-tools-extra/clang-tidy/ClangTidy.cpp
index e8cca7831734f..a86db0fcd37e9 100644
--- a/clang-tools-extra/clang-tidy/ClangTidy.cpp
+++ b/clang-tools-extra/clang-tidy/ClangTidy.cpp
@@ -270,7 +270,7 @@ class ErrorReporter {
         Rule = Rule.setHelpURI(buildClangTidyHelpURI(Name));
 
       Rule = addDiagnosticLevelToRule(Rule, EffectiveLevel);
-      if(SarifWriter)
+      if (SarifWriter)
         RuleIndex = SarifWriter->createRule(Rule);
     }
 
@@ -281,7 +281,7 @@ class ErrorReporter {
             .setThreadFlows(createThreadFlows(Error))
             .addLocations(getResultRanges(Error, Loc));
 
-    if(SarifWriter)
+    if (SarifWriter)
       SarifWriter->appendResult(Result);
   }
 

>From 41d84ca5cc723d34240da2e260b394d064f5eaa9 Mon Sep 17 00:00:00 2001
From: "Jones, Matthew (DI SW SIM FRWK PLAT SIMFW HPC)"
 <[email protected]>
Date: Tue, 1 Sep 2026 06:24:17 -0700
Subject: [PATCH 5/8] fixed invalid informationUri and removed incorrect
 setDescription

---
 clang-tools-extra/clang-tidy/ClangTidy.cpp |  3 +--
 clang/lib/Basic/Sarif.cpp                  | 18 ++++++++++--------
 2 files changed, 11 insertions(+), 10 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/ClangTidy.cpp 
b/clang-tools-extra/clang-tidy/ClangTidy.cpp
index a86db0fcd37e9..d7635346817b2 100644
--- a/clang-tools-extra/clang-tidy/ClangTidy.cpp
+++ b/clang-tools-extra/clang-tidy/ClangTidy.cpp
@@ -263,8 +263,7 @@ class ErrorReporter {
     if (Inserted) {
       const StringRef Name = Error.DiagnosticName;
       SarifRule Rule =
-          SarifRule::create().setRuleId(Name).setName(Name).setDescription(
-              Error.Message.Message);
+          SarifRule::create().setRuleId(Name).setName(Name);
 
       if (!Name.starts_with("clang-diagnostic"))
         Rule = Rule.setHelpURI(buildClangTidyHelpURI(Name));
diff --git a/clang/lib/Basic/Sarif.cpp b/clang/lib/Basic/Sarif.cpp
index e829b9bb47ad9..5536e6a02091f 100644
--- a/clang/lib/Basic/Sarif.cpp
+++ b/clang/lib/Basic/Sarif.cpp
@@ -351,14 +351,16 @@ void SarifDocumentWriter::createRun(StringRef 
ShortToolName,
   // Signify a new run has begun.
   Closed = false;
 
-  json::Object Tool{
-      {"driver",
-       json::Object{{"name", ShortToolName},
-                    {"fullName", LongToolName},
-                    {"language", "en-US"},
-                    {"version", ToolVersion},
-                    {"informationUri",
-                     "https://clang.llvm.org/docs/UsersManual.html"}}}};
+  StringRef InformationUri = "https://clang.llvm.org/docs/UsersManual.html";;
+  if (LongToolName == "clang-tidy")
+    InformationUri = "https://clang.llvm.org/extra/clang-tidy/";;
+
+  json::Object Tool{{"driver", json::Object{{"name", ShortToolName},
+                                            {"fullName", LongToolName},
+                                            {"language", "en-US"},
+                                            {"version", ToolVersion},
+                                            {"informationUri", InformationUri},
+                                            {"rules", json::Array{}}}}};
   json::Object TheRun{{"tool", std::move(Tool)},
                       {"results", {}},
                       {"artifacts", {}},

>From 2a87b7fbde809432c3bdb1adcc7f102dd4d1565e Mon Sep 17 00:00:00 2001
From: "Jones, Matthew (DI SW SIM FRWK PLAT SIMFW HPC)"
 <[email protected]>
Date: Tue, 1 Sep 2026 08:00:57 -0700
Subject: [PATCH 6/8] fixed broken test

---
 clang-tools-extra/clang-tidy/ClangTidy.cpp                    | 4 +---
 .../clang-tidy/infrastructure/export-SARIF-Thread-flows.cpp   | 4 ++--
 2 files changed, 3 insertions(+), 5 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/ClangTidy.cpp 
b/clang-tools-extra/clang-tidy/ClangTidy.cpp
index d7635346817b2..7fa5cff6ffcfd 100644
--- a/clang-tools-extra/clang-tidy/ClangTidy.cpp
+++ b/clang-tools-extra/clang-tidy/ClangTidy.cpp
@@ -262,9 +262,7 @@ class ErrorReporter {
 
     if (Inserted) {
       const StringRef Name = Error.DiagnosticName;
-      SarifRule Rule =
-          SarifRule::create().setRuleId(Name).setName(Name);
-
+      SarifRule Rule = SarifRule::create().setRuleId(Name).setName(Name);
       if (!Name.starts_with("clang-diagnostic"))
         Rule = Rule.setHelpURI(buildClangTidyHelpURI(Name));
 
diff --git 
a/clang-tools-extra/test/clang-tidy/infrastructure/export-SARIF-Thread-flows.cpp
 
b/clang-tools-extra/test/clang-tidy/infrastructure/export-SARIF-Thread-flows.cpp
index 63ff3653cbc3f..23f88e7c5bd18 100644
--- 
a/clang-tools-extra/test/clang-tidy/infrastructure/export-SARIF-Thread-flows.cpp
+++ 
b/clang-tools-extra/test/clang-tidy/infrastructure/export-SARIF-Thread-flows.cpp
@@ -108,7 +108,7 @@ void f() {
 //CHECK-SARIF-NEXT:       "tool": {
 //CHECK-SARIF-NEXT:         "driver": {
 //CHECK-SARIF-NEXT:           "fullName": "clang-tidy",
-//CHECK-SARIF-NEXT:           "informationUri": 
"https://clang.llvm.org/docs/UsersManual.html";,
+//CHECK-SARIF-NEXT:           "informationUri": 
"https://clang.llvm.org/extra/clang-tidy/";,
 //CHECK-SARIF-NEXT:           "language": "en-US",
 //CHECK-SARIF-NEXT:           "name": "clang-tidy",
 //CHECK-SARIF-NEXT:           "rules": [
@@ -119,7 +119,7 @@ void f() {
 //CHECK-SARIF-NEXT:                 "rank": -1
 //CHECK-SARIF-NEXT:               },
 //CHECK-SARIF-NEXT:               "fullDescription": {
-//CHECK-SARIF-NEXT:                 "text": "Dereference of null pointer 
(loaded from variable 'ptr')"
+//CHECK-SARIF-NEXT:                 "text": ""
 //CHECK-SARIF-NEXT:               },
 //CHECK-SARIF-NEXT:               "helpUri": 
"https://clang.llvm.org/extra/clang-tidy/checks/clang-analyzer/core.NullDereference.html";,
 //CHECK-SARIF-NEXT:               "id": "clang-analyzer-core.NullDereference",

>From 962f79f5b70932384b44098040079def81f12a6f Mon Sep 17 00:00:00 2001
From: "Jones, Matthew (DI SW SIM FRWK PLAT SIMFW HPC)"
 <[email protected]>
Date: Tue, 1 Sep 2026 08:35:23 -0700
Subject: [PATCH 7/8] Placeholder for desc

---
 clang-tools-extra/clang-tidy/ClangTidy.cpp                    | 4 +++-
 .../clang-tidy/infrastructure/export-SARIF-Thread-flows.cpp   | 2 +-
 2 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/ClangTidy.cpp 
b/clang-tools-extra/clang-tidy/ClangTidy.cpp
index 7fa5cff6ffcfd..29ca88680a7d9 100644
--- a/clang-tools-extra/clang-tidy/ClangTidy.cpp
+++ b/clang-tools-extra/clang-tidy/ClangTidy.cpp
@@ -262,7 +262,9 @@ class ErrorReporter {
 
     if (Inserted) {
       const StringRef Name = Error.DiagnosticName;
-      SarifRule Rule = SarifRule::create().setRuleId(Name).setName(Name);
+      SarifRule Rule =
+          SarifRule::create().setRuleId(Name).setName(Name).setDescription(
+              Error.Message.Message);
       if (!Name.starts_with("clang-diagnostic"))
         Rule = Rule.setHelpURI(buildClangTidyHelpURI(Name));
 
diff --git 
a/clang-tools-extra/test/clang-tidy/infrastructure/export-SARIF-Thread-flows.cpp
 
b/clang-tools-extra/test/clang-tidy/infrastructure/export-SARIF-Thread-flows.cpp
index 23f88e7c5bd18..9cd4f0d4aa883 100644
--- 
a/clang-tools-extra/test/clang-tidy/infrastructure/export-SARIF-Thread-flows.cpp
+++ 
b/clang-tools-extra/test/clang-tidy/infrastructure/export-SARIF-Thread-flows.cpp
@@ -119,7 +119,7 @@ void f() {
 //CHECK-SARIF-NEXT:                 "rank": -1
 //CHECK-SARIF-NEXT:               },
 //CHECK-SARIF-NEXT:               "fullDescription": {
-//CHECK-SARIF-NEXT:                 "text": ""
+//CHECK-SARIF-NEXT:                 "text": "Dereference of null pointer 
(loaded from variable 'ptr')"
 //CHECK-SARIF-NEXT:               },
 //CHECK-SARIF-NEXT:               "helpUri": 
"https://clang.llvm.org/extra/clang-tidy/checks/clang-analyzer/core.NullDereference.html";,
 //CHECK-SARIF-NEXT:               "id": "clang-analyzer-core.NullDereference",

>From 629ef01af9e070de99a603da7be9dfc5169dcf22 Mon Sep 17 00:00:00 2001
From: "Jones, Matthew (DI SW SIM FRWK PLAT SIMFW HPC)"
 <[email protected]>
Date: Thu, 3 Sep 2026 07:55:56 -0700
Subject: [PATCH 8/8] added more in-depth test cases + for notes, removed
 fullDescription and helpUri

---
 clang-tools-extra/clang-tidy/ClangTidy.cpp    |  53 +++--
 .../clang-tidy/tool/ClangTidyMain.cpp         |   8 +-
 .../export-SARIF-Thread-flows.cpp             |  21 +-
 .../export-SARIF-diagnostics-terminal.cpp     | 191 +++++++++++++++++-
 .../export-SARIF-diagnostics.cpp              | 143 ++++++++++++-
 .../export-SARIF-no-location.cpp              |  98 +++++++++
 clang/include/clang/Basic/Sarif.h             |   9 +-
 clang/lib/Basic/Sarif.cpp                     |  16 +-
 8 files changed, 472 insertions(+), 67 deletions(-)
 create mode 100644 
clang-tools-extra/test/clang-tidy/infrastructure/export-SARIF-no-location.cpp

diff --git a/clang-tools-extra/clang-tidy/ClangTidy.cpp 
b/clang-tools-extra/clang-tidy/ClangTidy.cpp
index 29ca88680a7d9..530c9cfe8d491 100644
--- a/clang-tools-extra/clang-tidy/ClangTidy.cpp
+++ b/clang-tools-extra/clang-tidy/ClangTidy.cpp
@@ -215,6 +215,17 @@ class ErrorReporter {
       exportSarifResult(Error, Loc);
   }
 
+  CharSourceRange getNoteRange(const tooling::DiagnosticMessage &Note) {
+    if (!Note.Ranges.empty())
+      return getRange(Note.Ranges.front());
+
+    tooling::FileByteRange FBR;
+    FBR.FilePath = Note.FilePath;
+    FBR.FileOffset = Note.FileOffset;
+    FBR.Length = 1;
+    return getRange(FBR);
+  }
+
   SmallVector<ThreadFlow, 8> createThreadFlows(const ClangTidyError &Error) {
     SmallVector<ThreadFlow, 8> Flows;
     if (!StringRef(Error.DiagnosticName).starts_with("clang-analyzer-"))
@@ -222,30 +233,13 @@ class ErrorReporter {
 
     Flows.reserve(Error.Notes.size());
     for (const tooling::DiagnosticMessage &Note : Error.Notes) {
-      tooling::FileByteRange FBR;
-      if (Note.Ranges.empty()) {
-        FBR.FilePath = Note.FilePath;
-        FBR.FileOffset = Note.FileOffset;
-        FBR.Length = 1;
-      } else {
-        FBR = Note.Ranges.front();
-      }
-      const CharSourceRange Range = getRange(FBR);
-      Flows.push_back(
-          ThreadFlow::create().setRange(Range).setMessage(Note.Message));
+      Flows.push_back(ThreadFlow::create()
+                          .setRange(getNoteRange(Note))
+                          .setMessage(Note.Message));
     }
     return Flows;
   }
 
-  static std::string buildClangTidyHelpURI(StringRef Name) {
-    const auto [Module, Check] = Name.starts_with("clang-analyzer-")
-                                     ? Name.rsplit('-')
-                                     : Name.split('-');
-    return llvm::formatv(
-        "https://clang.llvm.org/extra/clang-tidy/checks/{0}/{1}.html";, Module,
-        Check);
-  }
-
   void exportSarifResult(const ClangTidyError &Error,
                          const SourceLocation Loc) {
     assert(SarifWriter &&
@@ -262,24 +256,27 @@ class ErrorReporter {
 
     if (Inserted) {
       const StringRef Name = Error.DiagnosticName;
-      SarifRule Rule =
-          SarifRule::create().setRuleId(Name).setName(Name).setDescription(
-              Error.Message.Message);
-      if (!Name.starts_with("clang-diagnostic"))
-        Rule = Rule.setHelpURI(buildClangTidyHelpURI(Name));
-
+      SarifRule Rule = SarifRule::create().setRuleId(Name).setName(Name);
       Rule = addDiagnosticLevelToRule(Rule, EffectiveLevel);
       if (SarifWriter)
         RuleIndex = SarifWriter->createRule(Rule);
     }
 
-    const SarifResult Result =
+    SarifResult Result =
         SarifResult::create(RuleIndex)
             .setDiagnosticMessage(Error.Message.Message)
             .setDiagnosticLevel(getSarifResultLevel(EffectiveLevel))
-            .setThreadFlows(createThreadFlows(Error))
             .addLocations(getResultRanges(Error, Loc));
 
+    if (StringRef(Error.DiagnosticName).starts_with("clang-analyzer-")) {
+      Result = Result.setThreadFlows(createThreadFlows(Error));
+    } else {
+      for (const tooling::DiagnosticMessage &Note : Error.Notes) {
+        const CharSourceRange Range = getNoteRange(Note);
+        if (Range.isValid())
+          Result = Result.addRelatedLocations(Range, Note.Message);
+      }
+    }
     if (SarifWriter)
       SarifWriter->appendResult(Result);
   }
diff --git a/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp 
b/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp
index 442f9bf3f9834..693d1d42345c9 100644
--- a/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp
+++ b/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp
@@ -312,7 +312,7 @@ code with clang-apply-replacements.
                                         cl::value_desc("filename"),
                                         cl::cat(ClangTidyCategory));
 
-static cl::opt<std::string> ExportSarif("export-sarif", desc(R"(
+static cl::opt<std::string> SarifExport("sarif-export", desc(R"(
 File in which to store diagnostics in SARIF format.
 )"),
                                         cl::value_desc("filename"),
@@ -661,9 +661,9 @@ int clangTidyMain(int argc, const char **argv) {
   const SmallString<256> FilePath = makeAbsolute(FileName);
 
   std::unique_ptr<llvm::raw_fd_ostream> SarifOS;
-  if (!ExportSarif.empty()) {
+  if (!SarifExport.empty()) {
     std::error_code EC;
-    SarifOS = std::make_unique<llvm::raw_fd_ostream>(ExportSarif, EC,
+    SarifOS = std::make_unique<llvm::raw_fd_ostream>(SarifExport, EC,
                                                      llvm::sys::fs::OF_Text);
     if (EC) {
       llvm::errs() << "Error opening output file: " << EC.message() << '\n';
@@ -774,7 +774,7 @@ int clangTidyMain(int argc, const char **argv) {
 
   handleErrors(Errors, Context, DisableFixes ? FB_NoFix : Behaviour,
                WErrorCount, BaseFS, SarifOS.get(),
-               SarifOS && ExportSarif == "-");
+               SarifOS && SarifExport == "-");
 
   if (!ExportFixes.empty() && !Errors.empty()) {
     std::error_code EC;
diff --git 
a/clang-tools-extra/test/clang-tidy/infrastructure/export-SARIF-Thread-flows.cpp
 
b/clang-tools-extra/test/clang-tidy/infrastructure/export-SARIF-Thread-flows.cpp
index 9cd4f0d4aa883..0e2fa2d0fc3be 100644
--- 
a/clang-tools-extra/test/clang-tidy/infrastructure/export-SARIF-Thread-flows.cpp
+++ 
b/clang-tools-extra/test/clang-tidy/infrastructure/export-SARIF-Thread-flows.cpp
@@ -1,5 +1,5 @@
 // RUN: grep -Ev "// *[A-Z-]+:" %s > %t-input.cpp
-// RUN: clang-tidy %t-input.cpp -checks='-*,clang-analyzer*' 
-export-sarif=%t.sarif > %t.msg 2>&1
+// RUN: clang-tidy %t-input.cpp -checks='-*,clang-analyzer*' 
-sarif-export=%t.sarif > %t.msg 2>&1
 // RUN: FileCheck -input-file=%t.msg -check-prefix=CHECK-MESSAGES %s 
-implicit-check-not='{{warning|error|note}}:'
 // RUN: FileCheck -input-file=%t.sarif -check-prefix=CHECK-SARIF %s
 void f() {
@@ -20,7 +20,7 @@ void f() {
 //CHECK-SARIF-NEXT:           "length": {{[0-9]+}},
 //CHECK-SARIF-NEXT:           "location": {
 //CHECK-SARIF-NEXT:             "index": 0,
-//CHECK-SARIF-NEXT:             "uri": "{{.*}}-input.cpp"
+//CHECK-SARIF-NEXT:             "uri": "file://{{.*}}-input.cpp"
 //CHECK-SARIF-NEXT:           },
 //CHECK-SARIF-NEXT:           "mimeType": "text/plain",
 //CHECK-SARIF-NEXT:           "roles": [
@@ -45,7 +45,7 @@ void f() {
 //CHECK-SARIF-NEXT:                         "physicalLocation": {
 //CHECK-SARIF-NEXT:                           "artifactLocation": {
 //CHECK-SARIF-NEXT:                             "index": 0,
-//CHECK-SARIF-NEXT:                             "uri": "{{.*}}-input.cpp"
+//CHECK-SARIF-NEXT:                             "uri": 
"file://{{.*}}-input.cpp"
 //CHECK-SARIF-NEXT:                           },
 //CHECK-SARIF-NEXT:                           "region": {
 //CHECK-SARIF-NEXT:                             "endColumn": 11,
@@ -65,7 +65,7 @@ void f() {
 //CHECK-SARIF-NEXT:                         "physicalLocation": {
 //CHECK-SARIF-NEXT:                           "artifactLocation": {
 //CHECK-SARIF-NEXT:                             "index": 0,
-//CHECK-SARIF-NEXT:                              "uri": "{{.*}}-input.cpp"
+//CHECK-SARIF-NEXT:                             "uri": 
"file://{{.*}}-input.cpp"
 //CHECK-SARIF-NEXT:                           },
 //CHECK-SARIF-NEXT:                           "region": {
 //CHECK-SARIF-NEXT:                             "endColumn": 7,
@@ -75,8 +75,8 @@ void f() {
 //CHECK-SARIF-NEXT:                           }
 //CHECK-SARIF-NEXT:                         }
 //CHECK-SARIF-NEXT:                       }
-//CHECK-SARIF-NEXT:                     }                      
-//CHECK-SARIF-NEXT:                   ]        
+//CHECK-SARIF-NEXT:                     }
+//CHECK-SARIF-NEXT:                   ]
 //CHECK-SARIF-NEXT:                 }
 //CHECK-SARIF-NEXT:               ]
 //CHECK-SARIF-NEXT:             }
@@ -87,7 +87,7 @@ void f() {
 //CHECK-SARIF-NEXT:               "physicalLocation": {
 //CHECK-SARIF-NEXT:                 "artifactLocation": {
 //CHECK-SARIF-NEXT:                   "index": 0,
-//CHECK-SARIF-NEXT:                   "uri": "{{.*}}-input.cpp"
+//CHECK-SARIF-NEXT:                   "uri": "file://{{.*}}-input.cpp"
 //CHECK-SARIF-NEXT:                 },
 //CHECK-SARIF-NEXT:                 "region": {
 //CHECK-SARIF-NEXT:                   "endColumn": 7,
@@ -118,10 +118,6 @@ void f() {
 //CHECK-SARIF-NEXT:                 "level": "warning",
 //CHECK-SARIF-NEXT:                 "rank": -1
 //CHECK-SARIF-NEXT:               },
-//CHECK-SARIF-NEXT:               "fullDescription": {
-//CHECK-SARIF-NEXT:                 "text": "Dereference of null pointer 
(loaded from variable 'ptr')"
-//CHECK-SARIF-NEXT:               },
-//CHECK-SARIF-NEXT:               "helpUri": 
"https://clang.llvm.org/extra/clang-tidy/checks/clang-analyzer/core.NullDereference.html";,
 //CHECK-SARIF-NEXT:               "id": "clang-analyzer-core.NullDereference",
 //CHECK-SARIF-NEXT:               "name": "clang-analyzer-core.NullDereference"
 //CHECK-SARIF-NEXT:             }
@@ -132,5 +128,4 @@ void f() {
 //CHECK-SARIF-NEXT:     }
 //CHECK-SARIF-NEXT:   ],
 //CHECK-SARIF-NEXT:   "version": "{{.*}}"
-//CHECK-SARIF-NEXT: }
-
+//CHECK-SARIF-NEXT: }
\ No newline at end of file
diff --git 
a/clang-tools-extra/test/clang-tidy/infrastructure/export-SARIF-diagnostics-terminal.cpp
 
b/clang-tools-extra/test/clang-tidy/infrastructure/export-SARIF-diagnostics-terminal.cpp
index 52fb3fc3a639c..015eace602f2f 100644
--- 
a/clang-tools-extra/test/clang-tidy/infrastructure/export-SARIF-diagnostics-terminal.cpp
+++ 
b/clang-tools-extra/test/clang-tidy/infrastructure/export-SARIF-diagnostics-terminal.cpp
@@ -1,5 +1,5 @@
 // RUN: grep -Ev "// *[A-Z-]+:" %s > %t-input.cpp
-// RUN: not clang-tidy %t-input.cpp 
-checks='-*,google-explicit-constructor,clang-diagnostic-missing-prototypes,clang-diagnostic-zero-length-array'
 
--warnings-as-errors='clang-diagnostic-missing-prototypes,google-explicit-constructor'
 -export-sarif - -- -Wmissing-prototypes -Wzero-length-array 2>/dev/null | 
FileCheck %s
+// RUN: not clang-tidy %t-input.cpp 
-checks='-*,google-explicit-constructor,clang-diagnostic-missing-prototypes,clang-diagnostic-zero-length-array'
 
--warnings-as-errors='clang-diagnostic-missing-prototypes,google-explicit-constructor'
 -sarif-export - -- -Wmissing-prototypes -Wzero-length-array 2>/dev/null | 
FileCheck %s
 #define X(n) void n ## n() {}
 X(f)
 int a[-1];
@@ -51,6 +51,59 @@ struct Foo {
 //CHECK-NEXT:           "message": {
 //CHECK-NEXT:             "text": "no previous prototype for function 'ff'"
 //CHECK-NEXT:           },
+//CHECK-NEXT:           "relatedLocations": [
+//CHECK-NEXT:             {
+//CHECK-NEXT:               "message": {
+//CHECK-NEXT:                 "text": "expanded from macro 'X'"
+//CHECK-NEXT:               },
+//CHECK-NEXT:               "physicalLocation": {
+//CHECK-NEXT:                 "artifactLocation": {
+//CHECK-NEXT:                   "index": 0,
+//CHECK-NEXT:                   "uri": "file://{{.*}}-input.cpp"
+//CHECK-NEXT:                 },
+//CHECK-NEXT:                 "region": {
+//CHECK-NEXT:                   "endColumn": 20,
+//CHECK-NEXT:                   "endLine": 1,
+//CHECK-NEXT:                   "startColumn": 19,
+//CHECK-NEXT:                   "startLine": 1
+//CHECK-NEXT:                 }
+//CHECK-NEXT:               }
+//CHECK-NEXT:             },
+//CHECK-NEXT:             {
+//CHECK-NEXT:               "message": {
+//CHECK-NEXT:                 "text": "declare 'static' if the function is not 
intended to be used outside of this translation unit"
+//CHECK-NEXT:               },
+//CHECK-NEXT:               "physicalLocation": {
+//CHECK-NEXT:                 "artifactLocation": {
+//CHECK-NEXT:                   "index": 0,
+//CHECK-NEXT:                   "uri": "file://{{.*}}-input.cpp"
+//CHECK-NEXT:                 },
+//CHECK-NEXT:                 "region": {
+//CHECK-NEXT:                   "endColumn": 2,
+//CHECK-NEXT:                   "endLine": 2,
+//CHECK-NEXT:                   "startColumn": 1,
+//CHECK-NEXT:                   "startLine": 2
+//CHECK-NEXT:                 }
+//CHECK-NEXT:               }
+//CHECK-NEXT:             },
+//CHECK-NEXT:             {
+//CHECK-NEXT:               "message": {
+//CHECK-NEXT:                 "text": "expanded from macro 'X'"
+//CHECK-NEXT:               },
+//CHECK-NEXT:               "physicalLocation": {
+//CHECK-NEXT:                 "artifactLocation": {
+//CHECK-NEXT:                   "index": 0,
+//CHECK-NEXT:                   "uri": "file://{{.*}}-input.cpp"
+//CHECK-NEXT:                 },
+//CHECK-NEXT:                 "region": {
+//CHECK-NEXT:                   "endColumn": 15,
+//CHECK-NEXT:                   "endLine": 1,
+//CHECK-NEXT:                   "startColumn": 14,
+//CHECK-NEXT:                   "startLine": 1
+//CHECK-NEXT:                 }
+//CHECK-NEXT:               }
+//CHECK-NEXT:             }
+//CHECK-NEXT:           ],
 //CHECK-NEXT:           "ruleId": "clang-diagnostic-missing-prototypes",
 //CHECK-NEXT:           "ruleIndex": 0
 //CHECK-NEXT:         },
@@ -81,11 +134,11 @@ struct Foo {
 //CHECK-NEXT:         {
 //CHECK-NEXT:           "level": "warning",
 //CHECK-NEXT:           "locations": [
-//CHECK-NEXT:              {
+//CHECK-NEXT:             {
 //CHECK-NEXT:               "physicalLocation": {
 //CHECK-NEXT:                 "artifactLocation": {
 //CHECK-NEXT:                   "index": 0,
-//CHECK-NEXT:                    "uri": "file://{{.*}}-input.cpp"
+//CHECK-NEXT:                   "uri": "file://{{.*}}-input.cpp"
 //CHECK-NEXT:                 },
 //CHECK-NEXT:                 "region": {
 //CHECK-NEXT:                   "endColumn": 8,
@@ -95,4 +148,134 @@ struct Foo {
 //CHECK-NEXT:                 }
 //CHECK-NEXT:               }
 //CHECK-NEXT:             }
-//CHECK-NEXT:           ],
\ No newline at end of file
+//CHECK-NEXT:           ],
+//CHECK-NEXT:           "message": {
+//CHECK-NEXT:             "text": "zero size arrays are an extension"
+//CHECK-NEXT:           },
+//CHECK-NEXT:           "ruleId": "clang-diagnostic-zero-length-array",
+//CHECK-NEXT:           "ruleIndex": 2
+//CHECK-NEXT:         },
+//CHECK-NEXT:         {
+//CHECK-NEXT:           "level": "error",
+//CHECK-NEXT:           "locations": [
+//CHECK-NEXT:             {
+//CHECK-NEXT:               "physicalLocation": {
+//CHECK-NEXT:                 "artifactLocation": {
+//CHECK-NEXT:                   "index": 0,
+//CHECK-NEXT:                   "uri": "file://{{.*}}-input.cpp"
+//CHECK-NEXT:                 },
+//CHECK-NEXT:                 "region": {
+//CHECK-NEXT:                   "endColumn": 12,
+//CHECK-NEXT:                   "endLine": 6,
+//CHECK-NEXT:                   "startColumn": 11,
+//CHECK-NEXT:                   "startLine": 6
+//CHECK-NEXT:                 }
+//CHECK-NEXT:               }
+//CHECK-NEXT:             }
+//CHECK-NEXT:           ],
+//CHECK-NEXT:           "message": {
+//CHECK-NEXT:             "text": "unknown type name 'x'"
+//CHECK-NEXT:           },
+//CHECK-NEXT:           "ruleId": "clang-diagnostic-error",
+//CHECK-NEXT:           "ruleIndex": 1
+//CHECK-NEXT:         },
+//CHECK-NEXT:         {
+//CHECK-NEXT:           "level": "error",
+//CHECK-NEXT:           "locations": [
+//CHECK-NEXT:             {
+//CHECK-NEXT:               "physicalLocation": {
+//CHECK-NEXT:                 "artifactLocation": {
+//CHECK-NEXT:                   "index": 0,
+//CHECK-NEXT:                   "uri": "file://{{.*}}-input.cpp"
+//CHECK-NEXT:                 },
+//CHECK-NEXT:                 "region": {
+//CHECK-NEXT:                   "endColumn": 4,
+//CHECK-NEXT:                   "endLine": 8,
+//CHECK-NEXT:                   "startColumn": 3,
+//CHECK-NEXT:                   "startLine": 8
+//CHECK-NEXT:                 }
+//CHECK-NEXT:               }
+//CHECK-NEXT:             }
+//CHECK-NEXT:           ],
+//CHECK-NEXT:           "message": {
+//CHECK-NEXT:             "text": "a type specifier is required for all 
declarations"
+//CHECK-NEXT:           },
+//CHECK-NEXT:           "ruleId": "clang-diagnostic-error",
+//CHECK-NEXT:           "ruleIndex": 1
+//CHECK-NEXT:         },
+//CHECK-NEXT:         {
+//CHECK-NEXT:           "level": "error",
+//CHECK-NEXT:           "locations": [
+//CHECK-NEXT:             {
+//CHECK-NEXT:               "physicalLocation": {
+//CHECK-NEXT:                 "artifactLocation": {
+//CHECK-NEXT:                   "index": 0,
+//CHECK-NEXT:                   "uri": "file://{{.*}}-input.cpp"
+//CHECK-NEXT:                 },
+//CHECK-NEXT:                 "region": {
+//CHECK-NEXT:                   "endColumn": 4,
+//CHECK-NEXT:                   "endLine": 9,
+//CHECK-NEXT:                   "startColumn": 3,
+//CHECK-NEXT:                   "startLine": 9
+//CHECK-NEXT:                 }
+//CHECK-NEXT:               }
+//CHECK-NEXT:             }
+//CHECK-NEXT:           ],
+//CHECK-NEXT:           "message": {
+//CHECK-NEXT:             "text": "single-argument constructors must be marked 
explicit to avoid unintentional implicit conversions"
+//CHECK-NEXT:           },
+//CHECK-NEXT:           "ruleId": "google-explicit-constructor",
+//CHECK-NEXT:           "ruleIndex": 3
+//CHECK-NEXT:         }
+//CHECK-NEXT:       ],
+//CHECK-NEXT:       "tool": {
+//CHECK-NEXT:         "driver": {
+//CHECK-NEXT:           "fullName": "clang-tidy",
+//CHECK-NEXT:           "informationUri": 
"https://clang.llvm.org/extra/clang-tidy/";,
+//CHECK-NEXT:           "language": "en-US",
+//CHECK-NEXT:           "name": "clang-tidy",
+//CHECK-NEXT:           "rules": [
+//CHECK-NEXT:             {
+//CHECK-NEXT:               "defaultConfiguration": {
+//CHECK-NEXT:                 "enabled": true,
+//CHECK-NEXT:                 "level": "error",
+//CHECK-NEXT:                 "rank": 50
+//CHECK-NEXT:               },
+//CHECK-NEXT:               "id": "clang-diagnostic-missing-prototypes",
+//CHECK-NEXT:               "name": "clang-diagnostic-missing-prototypes"
+//CHECK-NEXT:             },
+//CHECK-NEXT:             {
+//CHECK-NEXT:               "defaultConfiguration": {
+//CHECK-NEXT:                 "enabled": true,
+//CHECK-NEXT:                 "level": "error",
+//CHECK-NEXT:                 "rank": 50
+//CHECK-NEXT:               },
+//CHECK-NEXT:               "id": "clang-diagnostic-error",
+//CHECK-NEXT:               "name": "clang-diagnostic-error"
+//CHECK-NEXT:             },
+//CHECK-NEXT:             {
+//CHECK-NEXT:               "defaultConfiguration": {
+//CHECK-NEXT:                 "enabled": true,
+//CHECK-NEXT:                 "level": "warning",
+//CHECK-NEXT:                 "rank": -1
+//CHECK-NEXT:               },
+//CHECK-NEXT:               "id": "clang-diagnostic-zero-length-array",
+//CHECK-NEXT:               "name": "clang-diagnostic-zero-length-array"
+//CHECK-NEXT:             },
+//CHECK-NEXT:             {
+//CHECK-NEXT:               "defaultConfiguration": {
+//CHECK-NEXT:                 "enabled": true,
+//CHECK-NEXT:                 "level": "error",
+//CHECK-NEXT:                 "rank": 50
+//CHECK-NEXT:               },
+//CHECK-NEXT:               "id": "google-explicit-constructor",
+//CHECK-NEXT:               "name": "google-explicit-constructor"
+//CHECK-NEXT:             }
+//CHECK-NEXT:           ],
+//CHECK-NEXT:           "version": "{{.*}}"
+//CHECK-NEXT:         }
+//CHECK-NEXT:       }
+//CHECK-NEXT:     }
+//CHECK-NEXT:   ],
+//CHECK-NEXT:   "version": "{{.*}}"
+//CHECK-NEXT: }
\ No newline at end of file
diff --git 
a/clang-tools-extra/test/clang-tidy/infrastructure/export-SARIF-diagnostics.cpp 
b/clang-tools-extra/test/clang-tidy/infrastructure/export-SARIF-diagnostics.cpp
index 4ba2d3d55a4ed..5ff0c5f9d9454 100644
--- 
a/clang-tools-extra/test/clang-tidy/infrastructure/export-SARIF-diagnostics.cpp
+++ 
b/clang-tools-extra/test/clang-tidy/infrastructure/export-SARIF-diagnostics.cpp
@@ -1,5 +1,5 @@
 // RUN: grep -Ev "// *[A-Z-]+:" %s > %t-input.cpp
-// RUN: not clang-tidy %t-input.cpp 
-checks='-*,google-explicit-constructor,clang-diagnostic-missing-prototypes,clang-diagnostic-zero-length-array'
 
--warnings-as-errors='clang-diagnostic-missing-prototypes,google-explicit-constructor'
 -export-sarif=%t.sarif -- -Wmissing-prototypes -Wzero-length-array > %t.msg 
2>&1
+// RUN: not clang-tidy %t-input.cpp 
-checks='-*,google-explicit-constructor,clang-diagnostic-missing-prototypes,clang-diagnostic-zero-length-array'
 
--warnings-as-errors='clang-diagnostic-missing-prototypes,google-explicit-constructor'
 -sarif-export=%t.sarif -- -Wmissing-prototypes -Wzero-length-array > %t.msg 
2>&1
 // RUN: FileCheck -input-file=%t.msg -check-prefix=CHECK-MESSAGES %s 
-implicit-check-not='{{warning|error|note}}:'
 // RUN: FileCheck -input-file=%t.sarif -check-prefix=CHECK-SARIF %s
 #define X(n) void n ## n() {}
@@ -33,7 +33,7 @@ struct Foo {
 //CHECK-SARIF-NEXT:           "length": {{[0-9]+}},
 //CHECK-SARIF-NEXT:           "location": {
 //CHECK-SARIF-NEXT:             "index": 0,
-//CHECK-SARIF-NEXT:             "uri": "{{.*}}-input.cpp"
+//CHECK-SARIF-NEXT:             "uri": "file://{{.*}}-input.cpp"
 //CHECK-SARIF-NEXT:           },
 //CHECK-SARIF-NEXT:           "mimeType": "text/plain",
 //CHECK-SARIF-NEXT:           "roles": [
@@ -50,7 +50,7 @@ struct Foo {
 //CHECK-SARIF-NEXT:               "physicalLocation": {
 //CHECK-SARIF-NEXT:                 "artifactLocation": {
 //CHECK-SARIF-NEXT:                   "index": 0,
-//CHECK-SARIF-NEXT:                   "uri": "{{.*}}-input.cpp"
+//CHECK-SARIF-NEXT:                   "uri": "file://{{.*}}-input.cpp"
 //CHECK-SARIF-NEXT:                 },
 //CHECK-SARIF-NEXT:                 "region": {
 //CHECK-SARIF-NEXT:                   "endColumn": 2,
@@ -64,6 +64,59 @@ struct Foo {
 //CHECK-SARIF-NEXT:           "message": {
 //CHECK-SARIF-NEXT:             "text": "no previous prototype for function 
'ff'"
 //CHECK-SARIF-NEXT:           },
+//CHECK-SARIF-NEXT:           "relatedLocations": [
+//CHECK-SARIF-NEXT:             {
+//CHECK-SARIF-NEXT:               "message": {
+//CHECK-SARIF-NEXT:                 "text": "expanded from macro 'X'"
+//CHECK-SARIF-NEXT:               },
+//CHECK-SARIF-NEXT:               "physicalLocation": {
+//CHECK-SARIF-NEXT:                 "artifactLocation": {
+//CHECK-SARIF-NEXT:                   "index": 0,
+//CHECK-SARIF-NEXT:                   "uri": "file://{{.*}}-input.cpp"
+//CHECK-SARIF-NEXT:                 },
+//CHECK-SARIF-NEXT:                 "region": {
+//CHECK-SARIF-NEXT:                   "endColumn": 20,
+//CHECK-SARIF-NEXT:                   "endLine": 1,
+//CHECK-SARIF-NEXT:                   "startColumn": 19,
+//CHECK-SARIF-NEXT:                   "startLine": 1
+//CHECK-SARIF-NEXT:                 }
+//CHECK-SARIF-NEXT:               }
+//CHECK-SARIF-NEXT:             },
+//CHECK-SARIF-NEXT:             {
+//CHECK-SARIF-NEXT:               "message": {
+//CHECK-SARIF-NEXT:                 "text": "declare 'static' if the function 
is not intended to be used outside of this translation unit"
+//CHECK-SARIF-NEXT:               },
+//CHECK-SARIF-NEXT:               "physicalLocation": {
+//CHECK-SARIF-NEXT:                 "artifactLocation": {
+//CHECK-SARIF-NEXT:                   "index": 0,
+//CHECK-SARIF-NEXT:                   "uri": "file://{{.*}}-input.cpp"
+//CHECK-SARIF-NEXT:                 },
+//CHECK-SARIF-NEXT:                 "region": {
+//CHECK-SARIF-NEXT:                   "endColumn": 2,
+//CHECK-SARIF-NEXT:                   "endLine": 2,
+//CHECK-SARIF-NEXT:                   "startColumn": 1,
+//CHECK-SARIF-NEXT:                   "startLine": 2
+//CHECK-SARIF-NEXT:                 }
+//CHECK-SARIF-NEXT:               }
+//CHECK-SARIF-NEXT:             },
+//CHECK-SARIF-NEXT:             {
+//CHECK-SARIF-NEXT:               "message": {
+//CHECK-SARIF-NEXT:                 "text": "expanded from macro 'X'"
+//CHECK-SARIF-NEXT:               },
+//CHECK-SARIF-NEXT:               "physicalLocation": {
+//CHECK-SARIF-NEXT:                 "artifactLocation": {
+//CHECK-SARIF-NEXT:                   "index": 0,
+//CHECK-SARIF-NEXT:                   "uri": "file://{{.*}}-input.cpp"
+//CHECK-SARIF-NEXT:                 },
+//CHECK-SARIF-NEXT:                 "region": {
+//CHECK-SARIF-NEXT:                   "endColumn": 15,
+//CHECK-SARIF-NEXT:                   "endLine": 1,
+//CHECK-SARIF-NEXT:                   "startColumn": 14,
+//CHECK-SARIF-NEXT:                   "startLine": 1
+//CHECK-SARIF-NEXT:                 }
+//CHECK-SARIF-NEXT:               }
+//CHECK-SARIF-NEXT:             }
+//CHECK-SARIF-NEXT:           ],
 //CHECK-SARIF-NEXT:           "ruleId": "clang-diagnostic-missing-prototypes",
 //CHECK-SARIF-NEXT:           "ruleIndex": 0
 //CHECK-SARIF-NEXT:         },
@@ -74,7 +127,7 @@ struct Foo {
 //CHECK-SARIF-NEXT:               "physicalLocation": {
 //CHECK-SARIF-NEXT:                 "artifactLocation": {
 //CHECK-SARIF-NEXT:                   "index": 0,
-//CHECK-SARIF-NEXT:                   "uri": "{{.*}}-input.cpp"
+//CHECK-SARIF-NEXT:                   "uri": "file://{{.*}}-input.cpp"
 //CHECK-SARIF-NEXT:                 },
 //CHECK-SARIF-NEXT:                 "region": {
 //CHECK-SARIF-NEXT:                   "endColumn": 9,
@@ -98,7 +151,7 @@ struct Foo {
 //CHECK-SARIF-NEXT:               "physicalLocation": {
 //CHECK-SARIF-NEXT:                 "artifactLocation": {
 //CHECK-SARIF-NEXT:                   "index": 0,
-//CHECK-SARIF-NEXT:                   "uri": "{{.*}}-input.cpp"
+//CHECK-SARIF-NEXT:                   "uri": "file://{{.*}}-input.cpp"
 //CHECK-SARIF-NEXT:                 },
 //CHECK-SARIF-NEXT:                 "region": {
 //CHECK-SARIF-NEXT:                   "endColumn": 8,
@@ -122,7 +175,7 @@ struct Foo {
 //CHECK-SARIF-NEXT:               "physicalLocation": {
 //CHECK-SARIF-NEXT:                 "artifactLocation": {
 //CHECK-SARIF-NEXT:                   "index": 0,
-//CHECK-SARIF-NEXT:                   "uri": "{{.*}}-input.cpp" 
+//CHECK-SARIF-NEXT:                   "uri": "file://{{.*}}-input.cpp"
 //CHECK-SARIF-NEXT:                 },
 //CHECK-SARIF-NEXT:                 "region": {
 //CHECK-SARIF-NEXT:                   "endColumn": 12,
@@ -146,7 +199,7 @@ struct Foo {
 //CHECK-SARIF-NEXT:               "physicalLocation": {
 //CHECK-SARIF-NEXT:                 "artifactLocation": {
 //CHECK-SARIF-NEXT:                   "index": 0,
-//CHECK-SARIF-NEXT:                   "uri": "{{.*}}-input.cpp"
+//CHECK-SARIF-NEXT:                   "uri": "file://{{.*}}-input.cpp"
 //CHECK-SARIF-NEXT:                 },
 //CHECK-SARIF-NEXT:                 "region": {
 //CHECK-SARIF-NEXT:                   "endColumn": 4,
@@ -163,3 +216,79 @@ struct Foo {
 //CHECK-SARIF-NEXT:           "ruleId": "clang-diagnostic-error",
 //CHECK-SARIF-NEXT:           "ruleIndex": 1
 //CHECK-SARIF-NEXT:         },
+//CHECK-SARIF-NEXT:         {
+//CHECK-SARIF-NEXT:           "level": "error",
+//CHECK-SARIF-NEXT:           "locations": [
+//CHECK-SARIF-NEXT:             {
+//CHECK-SARIF-NEXT:               "physicalLocation": {
+//CHECK-SARIF-NEXT:                 "artifactLocation": {
+//CHECK-SARIF-NEXT:                   "index": 0,
+//CHECK-SARIF-NEXT:                   "uri": "file://{{.*}}-input.cpp"
+//CHECK-SARIF-NEXT:                 },
+//CHECK-SARIF-NEXT:                 "region": {
+//CHECK-SARIF-NEXT:                   "endColumn": 4,
+//CHECK-SARIF-NEXT:                   "endLine": 9,
+//CHECK-SARIF-NEXT:                   "startColumn": 3,
+//CHECK-SARIF-NEXT:                   "startLine": 9
+//CHECK-SARIF-NEXT:                 }
+//CHECK-SARIF-NEXT:               }
+//CHECK-SARIF-NEXT:             }
+//CHECK-SARIF-NEXT:           ],
+//CHECK-SARIF-NEXT:           "message": {
+//CHECK-SARIF-NEXT:             "text": "single-argument constructors must be 
marked explicit to avoid unintentional implicit conversions"
+//CHECK-SARIF-NEXT:           },
+//CHECK-SARIF-NEXT:           "ruleId": "google-explicit-constructor",
+//CHECK-SARIF-NEXT:           "ruleIndex": 3
+//CHECK-SARIF-NEXT:         }
+//CHECK-SARIF-NEXT:       ],
+//CHECK-SARIF-NEXT:       "tool": {
+//CHECK-SARIF-NEXT:         "driver": {
+//CHECK-SARIF-NEXT:           "fullName": "clang-tidy",
+//CHECK-SARIF-NEXT:           "informationUri": 
"https://clang.llvm.org/extra/clang-tidy/";,
+//CHECK-SARIF-NEXT:           "language": "en-US",
+//CHECK-SARIF-NEXT:           "name": "clang-tidy",
+//CHECK-SARIF-NEXT:           "rules": [
+//CHECK-SARIF-NEXT:             {
+//CHECK-SARIF-NEXT:               "defaultConfiguration": {
+//CHECK-SARIF-NEXT:                 "enabled": true,
+//CHECK-SARIF-NEXT:                 "level": "error",
+//CHECK-SARIF-NEXT:                 "rank": 50
+//CHECK-SARIF-NEXT:               },
+//CHECK-SARIF-NEXT:               "id": "clang-diagnostic-missing-prototypes",
+//CHECK-SARIF-NEXT:               "name": "clang-diagnostic-missing-prototypes"
+//CHECK-SARIF-NEXT:             },
+//CHECK-SARIF-NEXT:             {
+//CHECK-SARIF-NEXT:               "defaultConfiguration": {
+//CHECK-SARIF-NEXT:                 "enabled": true,
+//CHECK-SARIF-NEXT:                 "level": "error",
+//CHECK-SARIF-NEXT:                 "rank": 50
+//CHECK-SARIF-NEXT:               },
+//CHECK-SARIF-NEXT:               "id": "clang-diagnostic-error",
+//CHECK-SARIF-NEXT:               "name": "clang-diagnostic-error"
+//CHECK-SARIF-NEXT:             },
+//CHECK-SARIF-NEXT:             {
+//CHECK-SARIF-NEXT:               "defaultConfiguration": {
+//CHECK-SARIF-NEXT:                 "enabled": true,
+//CHECK-SARIF-NEXT:                 "level": "warning",
+//CHECK-SARIF-NEXT:                 "rank": -1
+//CHECK-SARIF-NEXT:               },
+//CHECK-SARIF-NEXT:               "id": "clang-diagnostic-zero-length-array",
+//CHECK-SARIF-NEXT:               "name": "clang-diagnostic-zero-length-array"
+//CHECK-SARIF-NEXT:             },
+//CHECK-SARIF-NEXT:             {
+//CHECK-SARIF-NEXT:               "defaultConfiguration": {
+//CHECK-SARIF-NEXT:                 "enabled": true,
+//CHECK-SARIF-NEXT:                 "level": "error",
+//CHECK-SARIF-NEXT:                 "rank": 50
+//CHECK-SARIF-NEXT:               },
+//CHECK-SARIF-NEXT:               "id": "google-explicit-constructor",
+//CHECK-SARIF-NEXT:               "name": "google-explicit-constructor"
+//CHECK-SARIF-NEXT:             }
+//CHECK-SARIF-NEXT:           ],
+//CHECK-SARIF-NEXT:           "version": "{{.*}}"
+//CHECK-SARIF-NEXT:         }
+//CHECK-SARIF-NEXT:       }
+//CHECK-SARIF-NEXT:     }
+//CHECK-SARIF-NEXT:   ],
+//CHECK-SARIF-NEXT:   "version": "{{.*}}"
+//CHECK-SARIF-NEXT: }
\ No newline at end of file
diff --git 
a/clang-tools-extra/test/clang-tidy/infrastructure/export-SARIF-no-location.cpp 
b/clang-tools-extra/test/clang-tidy/infrastructure/export-SARIF-no-location.cpp
new file mode 100644
index 0000000000000..b9855914cca6b
--- /dev/null
+++ 
b/clang-tools-extra/test/clang-tidy/infrastructure/export-SARIF-no-location.cpp
@@ -0,0 +1,98 @@
+// RUN: grep -Ev "// *[A-Z-]+:" %s > %t-input.cpp
+// RUN: not clang-tidy %t-input.cpp 
-checks='-*,clang-diagnostic-*,google-explicit-constructor' 
-sarif-export=%t.sarif -- -fake-command > %t.msg 2>&1
+// RUN: FileCheck -input-file=%t.msg -check-prefix=CHECK-MESSAGES %s 
-implicit-check-not='{{warning|error|note}}:'
+// RUN: FileCheck -input-file=%t.sarif -check-prefix=CHECK-SARIF %s
+class A { A(int) {} };
+
+//NOTE: "-fake-command" is rejected by the driver before a SourceManager is 
created,
+//NOTE: so the diagnostic is stored with an empty FilePath and ranges. 
Therefore, getResultRanges()
+//NOTE: omits locations entirely. 
+
+//CHECK-MESSAGES: error: unknown argument: '-fake-command' 
[clang-diagnostic-error]
+//CHECK-MESSAGES: -input.cpp:1:11: warning: single-argument constructors must 
be marked explicit to avoid unintentional implicit conversions 
[google-explicit-constructor]
+
+//CHECK-SARIF: {
+//CHECK-SARIF-NEXT:   "$schema": 
"https://docs.oasis-open.org/sarif/sarif/v2.1.0/cos02/schemas/sarif-schema-2.1.0.json";,
+//CHECK-SARIF-NEXT:   "runs": [
+//CHECK-SARIF-NEXT:     {
+//CHECK-SARIF-NEXT:       "artifacts": [
+//CHECK-SARIF-NEXT:         {
+//CHECK-SARIF-NEXT:           "length": {{[0-9]+}},
+//CHECK-SARIF-NEXT:           "location": {
+//CHECK-SARIF-NEXT:             "index": 0,
+//CHECK-SARIF-NEXT:             "uri": "file://{{.*}}-input.cpp"
+//CHECK-SARIF-NEXT:           },
+//CHECK-SARIF-NEXT:           "mimeType": "text/plain",
+//CHECK-SARIF-NEXT:           "roles": [
+//CHECK-SARIF-NEXT:             "resultFile"
+//CHECK-SARIF-NEXT:           ]
+//CHECK-SARIF-NEXT:         }
+//CHECK-SARIF-NEXT:       ],
+//CHECK-SARIF-NEXT:       "columnKind": "unicodeCodePoints",
+//CHECK-SARIF-NEXT:       "results": [
+//CHECK-SARIF-NEXT:         {
+//CHECK-SARIF-NEXT:           "level": "error",
+//CHECK-SARIF-NEXT:           "message": {
+//CHECK-SARIF-NEXT:             "text": "unknown argument: '-fake-command'"
+//CHECK-SARIF-NEXT:           },
+//CHECK-SARIF-NEXT:           "ruleId": "clang-diagnostic-error",
+//CHECK-SARIF-NEXT:           "ruleIndex": 0
+//CHECK-SARIF-NEXT:         },
+//CHECK-SARIF-NEXT:         {
+//CHECK-SARIF-NEXT:           "level": "warning",
+//CHECK-SARIF-NEXT:           "locations": [
+//CHECK-SARIF-NEXT:             {
+//CHECK-SARIF-NEXT:               "physicalLocation": {
+//CHECK-SARIF-NEXT:                 "artifactLocation": {
+//CHECK-SARIF-NEXT:                   "index": 0,
+//CHECK-SARIF-NEXT:                   "uri": "file://{{.*}}-input.cpp"
+//CHECK-SARIF-NEXT:                 },
+//CHECK-SARIF-NEXT:                 "region": {
+//CHECK-SARIF-NEXT:                   "endColumn": 12,
+//CHECK-SARIF-NEXT:                   "endLine": 1,
+//CHECK-SARIF-NEXT:                   "startColumn": 11,
+//CHECK-SARIF-NEXT:                   "startLine": 1
+//CHECK-SARIF-NEXT:                 }
+//CHECK-SARIF-NEXT:               }
+//CHECK-SARIF-NEXT:             }
+//CHECK-SARIF-NEXT:           ],
+//CHECK-SARIF-NEXT:           "message": {
+//CHECK-SARIF-NEXT:             "text": "single-argument constructors must be 
marked explicit to avoid unintentional implicit conversions"
+//CHECK-SARIF-NEXT:           },
+//CHECK-SARIF-NEXT:           "ruleId": "google-explicit-constructor",
+//CHECK-SARIF-NEXT:           "ruleIndex": 1
+//CHECK-SARIF-NEXT:         }
+//CHECK-SARIF-NEXT:       ],
+//CHECK-SARIF-NEXT:       "tool": {
+//CHECK-SARIF-NEXT:         "driver": {
+//CHECK-SARIF-NEXT:           "fullName": "clang-tidy",
+//CHECK-SARIF-NEXT:           "informationUri": 
"https://clang.llvm.org/extra/clang-tidy/";,
+//CHECK-SARIF-NEXT:           "language": "en-US",
+//CHECK-SARIF-NEXT:           "name": "clang-tidy",
+//CHECK-SARIF-NEXT:           "rules": [
+//CHECK-SARIF-NEXT:             {
+//CHECK-SARIF-NEXT:               "defaultConfiguration": {
+//CHECK-SARIF-NEXT:                 "enabled": true,
+//CHECK-SARIF-NEXT:                 "level": "error",
+//CHECK-SARIF-NEXT:                 "rank": 50
+//CHECK-SARIF-NEXT:               },
+//CHECK-SARIF-NEXT:               "id": "clang-diagnostic-error",
+//CHECK-SARIF-NEXT:               "name": "clang-diagnostic-error"
+//CHECK-SARIF-NEXT:             },
+//CHECK-SARIF-NEXT:             {
+//CHECK-SARIF-NEXT:               "defaultConfiguration": {
+//CHECK-SARIF-NEXT:                 "enabled": true,
+//CHECK-SARIF-NEXT:                 "level": "warning",
+//CHECK-SARIF-NEXT:                 "rank": -1
+//CHECK-SARIF-NEXT:               },
+//CHECK-SARIF-NEXT:               "id": "google-explicit-constructor",
+//CHECK-SARIF-NEXT:               "name": "google-explicit-constructor"
+//CHECK-SARIF-NEXT:             }
+//CHECK-SARIF-NEXT:           ],
+//CHECK-SARIF-NEXT:           "version": "{{.*}}"
+//CHECK-SARIF-NEXT:         }
+//CHECK-SARIF-NEXT:       }
+//CHECK-SARIF-NEXT:     }
+//CHECK-SARIF-NEXT:   ],
+//CHECK-SARIF-NEXT:   "version": "{{.*}}"
+//CHECK-SARIF-NEXT: }
diff --git a/clang/include/clang/Basic/Sarif.h 
b/clang/include/clang/Basic/Sarif.h
index 7651d2ac7a768..231f28599d785 100644
--- a/clang/include/clang/Basic/Sarif.h
+++ b/clang/include/clang/Basic/Sarif.h
@@ -332,7 +332,8 @@ 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::pair<CharSourceRange, std::string>, 8>
+      RelatedLocations;
   llvm::SmallVector<ThreadFlow, 8> ThreadFlows;
   std::optional<SarifResultLevel> LevelOverride;
 
@@ -373,7 +374,8 @@ class SarifResult {
     return *this;
   }
 
-  SarifResult addRelatedLocations(llvm::ArrayRef<CharSourceRange> DiagLocs) {
+   SarifResult addRelatedLocations(llvm::ArrayRef<CharSourceRange> DiagLocs,
+                                  llvm::StringRef Message = "") {
 #ifndef NDEBUG
     for (const auto &Loc : DiagLocs) {
       assert(
@@ -381,7 +383,8 @@ class SarifResult {
           "SARIF RelatedLocations require character granular source ranges!");
     }
 #endif
-    RelatedLocations.append(DiagLocs.begin(), DiagLocs.end());
+    for (const CharSourceRange &Loc : DiagLocs)
+      RelatedLocations.emplace_back(Loc, Message.str());
     return *this;
   }
 
diff --git a/clang/lib/Basic/Sarif.cpp b/clang/lib/Basic/Sarif.cpp
index 5536e6a02091f..a6e154beb0684 100644
--- a/clang/lib/Basic/Sarif.cpp
+++ b/clang/lib/Basic/Sarif.cpp
@@ -276,11 +276,11 @@ void SarifDocumentWriter::endRun() {
         {"enabled", R.DefaultConfiguration.Enabled},
         {"level", resultLevelToStr(R.DefaultConfiguration.Level)},
         {"rank", R.DefaultConfiguration.Rank}};
-    json::Object Rule{
-        {"name", R.Name},
-        {"id", R.Id},
-        {"fullDescription", json::Object{{"text", R.Description}}},
-        {"defaultConfiguration", std::move(Config)}};
+    json::Object Rule{{"name", R.Name},
+                      {"id", R.Id},
+                      {"defaultConfiguration", std::move(Config)}};
+    if (!(Tool.getObject("driver")->getString("fullName") == "clang-tidy"))
+      Rule["fullDescription"] = json::Object{{"text", R.Description}};
     if (!R.HelpURI.empty())
       Rule["helpUri"] = R.HelpURI;
     if (!R.DeprecatedIds.empty())
@@ -411,9 +411,9 @@ 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 (const auto &[Range, Message] : Result.RelatedLocations)
+      ReLocs.emplace_back(
+          createLocation(createPhysicalLocation(Range), Message));
     Ret["relatedLocations"] = std::move(ReLocs);
   }
 

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

Reply via email to