================
@@ -195,6 +210,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 auto [RuleIndexEntryIt, Inserted] =
+ SarifRuleIdx.try_emplace(Error.DiagnosticName, 0);
+ 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);
+ if (SarifWriter)
+ RuleIndex = SarifWriter->createRule(Rule);
+ }
+
+ const SarifResult Result =
+ SarifResult::create(RuleIndex)
+ .setDiagnosticMessage(Error.Message.Message)
+ .setDiagnosticLevel(getSarifResultLevel(EffectiveLevel))
+ .setThreadFlows(createThreadFlows(Error))
+ .addLocations(getResultRanges(Error, Loc));
+
+ if (SarifWriter)
+ 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;
----------------
matthew-j-code wrote:
I believe and empty locations is valid here, from SARIF §3.27.12 : A result
object SHOULD contain a property named locations whose value is an array of
zero or more location objects (§3.28) each of which specifies a location where
the result occurred.
Inside SarifDocumentWriter::appendResult there is a check for empty locations,
and omits it:
```
if (!Result.Locations.empty()) {
json::Array Locs;
for (auto &Range : Result.Locations) {
Locs.emplace_back(createLocation(createPhysicalLocation(Range)));
}
Ret["locations"] = std::move(Locs);
}
```
https://github.com/llvm/llvm-project/pull/219182
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits