Skip to content

Commit 57607e2

Browse files
authored
[Clang][Diagnose] Minimal support on emit-include-location in sarif mode (#170415)
Currently, invoking `clang++` with `-fdiagnostics-format=sarif` causes a crash, with stack traces indicating that `SARIFDiagnostic::emitIncludeLocation` is unimplemented. This PR adds minimal support for converting `In file included from ...` and `In module ...` into `SARIF.result.relatedLocations`. With this change, `clang++ -fdiagnostics-format=sarif` no longer crashes and now provides a minimal amount of useful information. Thank you.
1 parent c7f62d2 commit 57607e2

File tree

7 files changed

+84
-20
lines changed

7 files changed

+84
-20
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -465,6 +465,10 @@ Improvements to Clang's diagnostics
465465
Objective-C method and block declarations when calling format functions. It is part
466466
of the format-nonliteral diagnostic (#GH60718)
467467

468+
- Fixed a crash when enabling ``-fdiagnostics-format=sarif`` and the output
469+
carries messages like 'In file included from ...' or 'In module ...'.
470+
Now the include/import locations are written into `sarif.run.result.relatedLocations`.
471+
468472
Improvements to Clang's time-trace
469473
----------------------------------
470474

clang/include/clang/Basic/Sarif.h

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,7 @@ class SarifResult {
325325
std::string HostedViewerURI;
326326
llvm::SmallDenseMap<StringRef, std::string, 4> PartialFingerprints;
327327
llvm::SmallVector<CharSourceRange, 8> Locations;
328+
llvm::SmallVector<CharSourceRange, 8> RelatedLocations;
328329
llvm::SmallVector<ThreadFlow, 8> ThreadFlows;
329330
std::optional<SarifResultLevel> LevelOverride;
330331

@@ -354,16 +355,29 @@ class SarifResult {
354355
return *this;
355356
}
356357

357-
SarifResult setLocations(llvm::ArrayRef<CharSourceRange> DiagLocs) {
358+
SarifResult addLocations(llvm::ArrayRef<CharSourceRange> DiagLocs) {
358359
#ifndef NDEBUG
359360
for (const auto &Loc : DiagLocs) {
360361
assert(Loc.isCharRange() &&
361362
"SARIF Results require character granular source ranges!");
362363
}
363364
#endif
364-
Locations.assign(DiagLocs.begin(), DiagLocs.end());
365+
Locations.append(DiagLocs.begin(), DiagLocs.end());
365366
return *this;
366367
}
368+
369+
SarifResult addRelatedLocations(llvm::ArrayRef<CharSourceRange> DiagLocs) {
370+
#ifndef NDEBUG
371+
for (const auto &Loc : DiagLocs) {
372+
assert(
373+
Loc.isCharRange() &&
374+
"SARIF RelatedLocations require character granular source ranges!");
375+
}
376+
#endif
377+
RelatedLocations.append(DiagLocs.begin(), DiagLocs.end());
378+
return *this;
379+
}
380+
367381
SarifResult setThreadFlows(llvm::ArrayRef<ThreadFlow> ThreadFlowResults) {
368382
ThreadFlows.assign(ThreadFlowResults.begin(), ThreadFlowResults.end());
369383
return *this;

clang/include/clang/Frontend/SARIFDiagnostic.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,10 +63,20 @@ class SARIFDiagnostic : public DiagnosticRenderer {
6363
ArrayRef<CharSourceRange> Ranges,
6464
const Diagnostic &Diag);
6565

66+
SarifResult addRelatedLocationToResult(SarifResult Result, FullSourceLoc Loc,
67+
PresumedLoc PLoc);
68+
69+
llvm::SmallVector<CharSourceRange>
70+
getSarifLocation(FullSourceLoc Loc, PresumedLoc PLoc,
71+
ArrayRef<CharSourceRange> Ranges);
72+
6673
SarifRule addDiagnosticLevelToRule(SarifRule Rule,
6774
DiagnosticsEngine::Level Level);
6875

6976
llvm::StringRef emitFilename(StringRef Filename, const SourceManager &SM);
77+
78+
llvm::SmallVector<std::pair<FullSourceLoc, PresumedLoc>>
79+
RelatedLocationsCache;
7080
};
7181

7282
} // end namespace clang

clang/lib/Basic/Sarif.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,14 @@ void SarifDocumentWriter::appendResult(const SarifResult &Result) {
404404
Ret["locations"] = std::move(Locs);
405405
}
406406

407+
if (!Result.RelatedLocations.empty()) {
408+
json::Array ReLocs;
409+
for (auto &Range : Result.RelatedLocations) {
410+
ReLocs.emplace_back(createLocation(createPhysicalLocation(Range)));
411+
}
412+
Ret["relatedLocations"] = std::move(ReLocs);
413+
}
414+
407415
if (!Result.PartialFingerprints.empty()) {
408416
json::Object fingerprints = {};
409417
for (auto &pair : Result.PartialFingerprints) {

clang/lib/Frontend/SARIFDiagnostic.cpp

Lines changed: 41 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -58,12 +58,48 @@ void SARIFDiagnostic::emitDiagnosticMessage(
5858
if (Loc.isValid())
5959
Result = addLocationToResult(Result, Loc, PLoc, Ranges, *Diag);
6060

61+
for (auto &[RelLoc, RelPLoc] : RelatedLocationsCache)
62+
Result = addRelatedLocationToResult(Result, RelLoc, RelPLoc);
63+
RelatedLocationsCache.clear();
64+
6165
Writer->appendResult(Result);
6266
}
6367

68+
void SARIFDiagnostic::emitIncludeLocation(FullSourceLoc Loc, PresumedLoc PLoc) {
69+
// We always emit include location before results, for example:
70+
//
71+
// In file included from ...
72+
// In file included from ...
73+
// error: ...
74+
//
75+
// At this time We cannot peek the SarifRule. But what we
76+
// do is to push it into a cache and wait for next time
77+
// \ref SARIFDiagnostic::emitDiagnosticMessage to pick it up.
78+
RelatedLocationsCache.push_back({Loc, PLoc});
79+
}
80+
81+
void SARIFDiagnostic::emitImportLocation(FullSourceLoc Loc, PresumedLoc PLoc,
82+
StringRef ModuleName) {
83+
RelatedLocationsCache.push_back({Loc, PLoc});
84+
}
85+
6486
SarifResult SARIFDiagnostic::addLocationToResult(
6587
SarifResult Result, FullSourceLoc Loc, PresumedLoc PLoc,
6688
ArrayRef<CharSourceRange> Ranges, const Diagnostic &Diag) {
89+
auto Locations = getSarifLocation(Loc, PLoc, Ranges);
90+
return Result.addLocations(Locations);
91+
}
92+
93+
SarifResult SARIFDiagnostic::addRelatedLocationToResult(SarifResult Result,
94+
FullSourceLoc Loc,
95+
PresumedLoc PLoc) {
96+
auto Locations = getSarifLocation(Loc, PLoc, {});
97+
return Result.addRelatedLocations(Locations);
98+
}
99+
100+
llvm::SmallVector<CharSourceRange>
101+
SARIFDiagnostic::getSarifLocation(FullSourceLoc Loc, PresumedLoc PLoc,
102+
ArrayRef<CharSourceRange> Ranges) {
67103
SmallVector<CharSourceRange> Locations = {};
68104

69105
if (PLoc.isInvalid()) {
@@ -75,7 +111,7 @@ SarifResult SARIFDiagnostic::addLocationToResult(
75111
// FIXME(llvm-project/issues/57366): File-only locations
76112
}
77113
}
78-
return Result;
114+
return {};
79115
}
80116

81117
FileID CaretFileID = Loc.getExpansionLoc().getFileID();
@@ -127,10 +163,11 @@ SarifResult SARIFDiagnostic::addLocationToResult(
127163
SourceLocation DiagLoc = SM.translateLineCol(FID, PLoc.getLine(), ColNo);
128164

129165
// FIXME(llvm-project/issues/57366): Properly process #line directives.
130-
Locations.push_back(
131-
CharSourceRange{SourceRange{DiagLoc, DiagLoc}, /* ITR = */ false});
166+
CharSourceRange Range = {SourceRange{DiagLoc, DiagLoc}, /* ITR = */ false};
167+
if (Range.isValid())
168+
Locations.push_back(std::move(Range));
132169

133-
return Result.setLocations(Locations);
170+
return Locations;
134171
}
135172

136173
SarifRule
@@ -207,15 +244,6 @@ void SARIFDiagnostic::emitDiagnosticLoc(FullSourceLoc Loc, PresumedLoc PLoc,
207244
assert(false && "Not implemented in SARIF mode");
208245
}
209246

210-
void SARIFDiagnostic::emitIncludeLocation(FullSourceLoc Loc, PresumedLoc PLoc) {
211-
assert(false && "Not implemented in SARIF mode");
212-
}
213-
214-
void SARIFDiagnostic::emitImportLocation(FullSourceLoc Loc, PresumedLoc PLoc,
215-
StringRef ModuleName) {
216-
assert(false && "Not implemented in SARIF mode");
217-
}
218-
219247
void SARIFDiagnostic::emitBuildingModuleLocation(FullSourceLoc Loc,
220248
PresumedLoc PLoc,
221249
StringRef ModuleName) {

clang/lib/StaticAnalyzer/Core/SarifDiagnostics.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ SarifDiagnostics::createResult(const PathDiagnostic *Diag,
218218
.setRuleId(CheckName)
219219
.setDiagnosticMessage(Diag->getVerboseDescription())
220220
.setDiagnosticLevel(SarifResultLevel::Warning)
221-
.setLocations({Range})
221+
.addLocations({Range})
222222
.addPartialFingerprint(IssueHashKey, IssueHash)
223223
.setHostedViewerURI(HtmlReportURL)
224224
.setThreadFlows(Flows);

clang/unittests/Basic/SarifTest.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,7 @@ TEST_F(SarifDocumentWriterTest, checkSerializingResultsWithCustomRuleConfig) {
290290
TEST_F(SarifDocumentWriterTest, checkSerializingArtifacts) {
291291
// GIVEN:
292292
const std::string ExpectedOutput =
293-
R"({"$schema":"https://docs.oasis-open.org/sarif/sarif/v2.1.0/cos02/schemas/sarif-schema-2.1.0.json","runs":[{"artifacts":[{"length":40,"location":{"index":0,"uri":"file:///main.cpp"},"mimeType":"text/plain","roles":["resultFile"]}],"columnKind":"unicodeCodePoints","results":[{"level":"error","locations":[{"physicalLocation":{"artifactLocation":{"index":0,"uri":"file:///main.cpp"},"region":{"endColumn":14,"startColumn":14,"startLine":3}}}],"message":{"text":"expected ';' after top level declarator"},"ruleId":"clang.unittest","ruleIndex":0}],"tool":{"driver":{"fullName":"sarif test runner","informationUri":"https://clang.llvm.org/docs/UsersManual.html","language":"en-US","name":"sarif test","rules":[{"defaultConfiguration":{"enabled":true,"level":"warning","rank":-1},"fullDescription":{"text":"Example rule created during unit tests"},"id":"clang.unittest","name":"clang unit test"}],"version":"1.0.0"}}}],"version":"2.1.0"})";
293+
R"({"$schema":"https://docs.oasis-open.org/sarif/sarif/v2.1.0/cos02/schemas/sarif-schema-2.1.0.json","runs":[{"artifacts":[{"length":40,"location":{"index":0,"uri":"file:///main.cpp"},"mimeType":"text/plain","roles":["resultFile"]}],"columnKind":"unicodeCodePoints","results":[{"level":"error","locations":[{"physicalLocation":{"artifactLocation":{"index":0,"uri":"file:///main.cpp"},"region":{"endColumn":14,"startColumn":14,"startLine":3}}}],"message":{"text":"expected ';' after top level declarator"},"relatedLocations":[{"physicalLocation":{"artifactLocation":{"index":0,"uri":"file:///main.cpp"},"region":{"endColumn":14,"startColumn":14,"startLine":3}}}],"ruleId":"clang.unittest","ruleIndex":0}],"tool":{"driver":{"fullName":"sarif test runner","informationUri":"https://clang.llvm.org/docs/UsersManual.html","language":"en-US","name":"sarif test","rules":[{"defaultConfiguration":{"enabled":true,"level":"warning","rank":-1},"fullDescription":{"text":"Example rule created during unit tests"},"id":"clang.unittest","name":"clang unit test"}],"version":"1.0.0"}}}],"version":"2.1.0"})";
294294

295295
SarifDocumentWriter Writer{SourceMgr};
296296
const SarifRule &Rule =
@@ -312,12 +312,12 @@ TEST_F(SarifDocumentWriterTest, checkSerializingArtifacts) {
312312
registerSource("/main.cpp", SourceText, /* IsMainFile = */ true);
313313
CharSourceRange SourceCSR =
314314
getFakeCharSourceRange(MainFileID, {3, 14}, {3, 14});
315-
316315
DiagLocs.push_back(SourceCSR);
317316

318317
const SarifResult &Result =
319318
SarifResult::create(RuleIdx)
320-
.setLocations(DiagLocs)
319+
.addLocations(DiagLocs)
320+
.addRelatedLocations(DiagLocs)
321321
.setDiagnosticMessage("expected ';' after top level declarator")
322322
.setDiagnosticLevel(SarifResultLevel::Error);
323323
Writer.appendResult(Result);
@@ -377,7 +377,7 @@ TEST_F(SarifDocumentWriterTest, checkSerializingCodeflows) {
377377
unsigned RuleIdx = Writer.createRule(Rule);
378378
const SarifResult &Result =
379379
SarifResult::create(RuleIdx)
380-
.setLocations({DiagLoc})
380+
.addLocations({DiagLoc})
381381
.setDiagnosticMessage("Redefinition of 'foo'")
382382
.setThreadFlows(Threadflows)
383383
.setDiagnosticLevel(SarifResultLevel::Warning);

0 commit comments

Comments
 (0)