Author: Dave Bartolomeo Date: 2025-09-25T10:47:51-07:00 New Revision: 30402c7dea57d35ead80387c061cda6977ba98ef
URL: https://github.com/llvm/llvm-project/commit/30402c7dea57d35ead80387c061cda6977ba98ef DIFF: https://github.com/llvm/llvm-project/commit/30402c7dea57d35ead80387c061cda6977ba98ef.diff LOG: [analyzer] Emit IssueHash in SARIF (#159445) This change adds two new properties to each `result` object in the SARIF log: `partialFingerprints`: Contains the "issue hash" that the analyzer already generates for each result, which can help identify a result across runs even if surrounding code changes. `hostedViewUri`: If running with `-analyzer-format=sarif-html`, this property will now be emitted with the `file:` URL of the generated HTML report for that result. Along the way, I discovered an existing bug where the HTML diagnostic consumer does not record the path to the generated report if another compilation already created that report. This caused both the SARIF and Plist consumers to be missing the link to the file in all but one of the compilations in case of a warning in a header file. I added a new test to ensure that the generated SARIF for each compilation contains the property. Finally, I made a few changes to the `normalize_sarif` processing in the tests. I switched to `sed` to allow substitutions. The normalization now removes directory components from `file:` URLs, replaces the `length` property of the source file with a constant `-1`, and puts placeholders in the values of the `version` properties rather than just deleting them. The URL transformation in particular lets us verify that the right filename is generated for each HTML report. Fixes #158159 rdar://160410408 Added: clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.h clang/test/Analysis/diagnostics/Inputs/expected-sarif/sarif-multi-file-diagnostics.c.sarif clang/test/Analysis/diagnostics/sarif-multi-file-diagnostics.c Modified: clang/include/clang/Analysis/PathDiagnostic.h clang/include/clang/Basic/Sarif.h clang/lib/Analysis/PathDiagnostic.cpp clang/lib/Basic/Sarif.cpp clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp clang/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp clang/lib/StaticAnalyzer/Core/SarifDiagnostics.cpp clang/test/Analysis/diagnostics/Inputs/expected-sarif/sarif-diagnostics-taint-test.c.sarif clang/test/Analysis/diagnostics/Inputs/expected-sarif/sarif-multi-diagnostic-test.c.sarif clang/test/Analysis/lit.local.cfg Removed: ################################################################################ diff --git a/clang/include/clang/Analysis/PathDiagnostic.h b/clang/include/clang/Analysis/PathDiagnostic.h index 5907df022e449..197920d4cd100 100644 --- a/clang/include/clang/Analysis/PathDiagnostic.h +++ b/clang/include/clang/Analysis/PathDiagnostic.h @@ -885,6 +885,10 @@ class PathDiagnostic : public llvm::FoldingSetNode { return UniqueingDecl; } + /// Get a hash that identifies the issue. + SmallString<32> getIssueHash(const SourceManager &SrcMgr, + const LangOptions &LangOpts) const; + void flattenLocations() { Loc.flatten(); for (const auto &I : pathImpl) diff --git a/clang/include/clang/Basic/Sarif.h b/clang/include/clang/Basic/Sarif.h index e6c46224b316d..a88d1ee2965a9 100644 --- a/clang/include/clang/Basic/Sarif.h +++ b/clang/include/clang/Basic/Sarif.h @@ -322,6 +322,8 @@ class SarifResult { uint32_t RuleIdx; std::string RuleId; std::string DiagnosticMessage; + std::string HostedViewerURI; + llvm::SmallDenseMap<StringRef, std::string, 4> PartialFingerprints; llvm::SmallVector<CharSourceRange, 8> Locations; llvm::SmallVector<ThreadFlow, 8> ThreadFlows; std::optional<SarifResultLevel> LevelOverride; @@ -347,6 +349,11 @@ class SarifResult { return *this; } + SarifResult setHostedViewerURI(llvm::StringRef URI) { + HostedViewerURI = URI.str(); + return *this; + } + SarifResult setLocations(llvm::ArrayRef<CharSourceRange> DiagLocs) { #ifndef NDEBUG for (const auto &Loc : DiagLocs) { @@ -366,6 +373,12 @@ class SarifResult { LevelOverride = TheLevel; return *this; } + + SarifResult addPartialFingerprint(llvm::StringRef key, + llvm::StringRef value) { + PartialFingerprints[key] = value; + return *this; + } }; /// This class handles creating a valid SARIF document given various input @@ -475,6 +488,8 @@ class SarifDocumentWriter { /// reported diagnostics, resulting in an expensive call. llvm::json::Object createDocument(); + static std::string fileNameToURI(llvm::StringRef Filename); + private: /// Source Manager to use for the current SARIF document. const SourceManager &SourceMgr; diff --git a/clang/lib/Analysis/PathDiagnostic.cpp b/clang/lib/Analysis/PathDiagnostic.cpp index ef24efd3c4bd0..e42731b93bfb2 100644 --- a/clang/lib/Analysis/PathDiagnostic.cpp +++ b/clang/lib/Analysis/PathDiagnostic.cpp @@ -24,6 +24,7 @@ #include "clang/AST/Type.h" #include "clang/Analysis/AnalysisDeclContext.h" #include "clang/Analysis/CFG.h" +#include "clang/Analysis/IssueHash.h" #include "clang/Analysis/ProgramPoint.h" #include "clang/Basic/LLVM.h" #include "clang/Basic/SourceLocation.h" @@ -1075,6 +1076,19 @@ unsigned PathDiagnostic::full_size() { return size; } +SmallString<32> +PathDiagnostic::getIssueHash(const SourceManager &SrcMgr, + const LangOptions &LangOpts) const { + PathDiagnosticLocation UPDLoc = getUniqueingLoc(); + FullSourceLoc FullLoc( + SrcMgr.getExpansionLoc(UPDLoc.isValid() ? UPDLoc.asLocation() + : getLocation().asLocation()), + SrcMgr); + + return clang::getIssueHash(FullLoc, getCheckerName(), getBugType(), + getDeclWithIssue(), LangOpts); +} + //===----------------------------------------------------------------------===// // FoldingSet profiling methods. //===----------------------------------------------------------------------===// diff --git a/clang/lib/Basic/Sarif.cpp b/clang/lib/Basic/Sarif.cpp index 69862b73febd7..b3fb9a21249e9 100644 --- a/clang/lib/Basic/Sarif.cpp +++ b/clang/lib/Basic/Sarif.cpp @@ -67,7 +67,7 @@ static std::string percentEncodeURICharacter(char C) { /// \param Filename The filename to be represented as URI. /// /// \return RFC3986 URI representing the input file name. -static std::string fileNameToURI(StringRef Filename) { +std::string SarifDocumentWriter::fileNameToURI(StringRef Filename) { SmallString<32> Ret = StringRef("file://"); // Get the root name to see if it has a URI authority. @@ -391,6 +391,11 @@ void SarifDocumentWriter::appendResult(const SarifResult &Result) { json::Object Ret{{"message", createMessage(Result.DiagnosticMessage)}, {"ruleIndex", static_cast<int64_t>(RuleIdx)}, {"ruleId", Rule.Id}}; + + if (!Result.HostedViewerURI.empty()) { + Ret["hostedViewerUri"] = Result.HostedViewerURI; + } + if (!Result.Locations.empty()) { json::Array Locs; for (auto &Range : Result.Locations) { @@ -398,6 +403,15 @@ void SarifDocumentWriter::appendResult(const SarifResult &Result) { } Ret["locations"] = std::move(Locs); } + + if (!Result.PartialFingerprints.empty()) { + json::Object fingerprints = {}; + for (auto &pair : Result.PartialFingerprints) { + fingerprints[pair.first] = pair.second; + } + Ret["partialFingerprints"] = std::move(fingerprints); + } + if (!Result.ThreadFlows.empty()) Ret["codeFlows"] = json::Array{createCodeFlow(Result.ThreadFlows)}; diff --git a/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp b/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp index 4c9c619f2487a..217b853305ed1 100644 --- a/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp +++ b/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp @@ -10,6 +10,7 @@ // //===----------------------------------------------------------------------===// +#include "HTMLDiagnostics.h" #include "PlistDiagnostics.h" #include "SarifDiagnostics.h" #include "clang/AST/Decl.h" @@ -82,7 +83,7 @@ class HTMLDiagnostics : public PathDiagnosticConsumer { void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags, FilesMade *filesMade) override; - StringRef getName() const override { return "HTMLDiagnostics"; } + StringRef getName() const override { return HTML_DIAGNOSTICS_NAME; } bool supportsCrossFileDiagnostics() const override { return SupportsCrossFileDiagnostics; @@ -254,18 +255,6 @@ void HTMLDiagnostics::FlushDiagnosticsImpl( ReportDiag(*Diag, filesMade); } -static llvm::SmallString<32> getIssueHash(const PathDiagnostic &D, - const Preprocessor &PP) { - SourceManager &SMgr = PP.getSourceManager(); - PathDiagnosticLocation UPDLoc = D.getUniqueingLoc(); - FullSourceLoc L(SMgr.getExpansionLoc(UPDLoc.isValid() - ? UPDLoc.asLocation() - : D.getLocation().asLocation()), - SMgr); - return getIssueHash(L, D.getCheckerName(), D.getBugType(), - D.getDeclWithIssue(), PP.getLangOpts()); -} - void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D, FilesMade *filesMade) { // Create the HTML directory if it is missing. @@ -310,7 +299,8 @@ void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D, } } - SmallString<32> IssueHash = getIssueHash(D, PP); + SmallString<32> IssueHash = + D.getIssueHash(PP.getSourceManager(), PP.getLangOpts()); auto [It, IsNew] = EmittedHashes.insert(IssueHash); if (!IsNew) { // We've already emitted a duplicate issue. It'll get overwritten anyway. @@ -369,6 +359,12 @@ void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D, if (EC != llvm::errc::file_exists) { llvm::errs() << "warning: could not create file in '" << Directory << "': " << EC.message() << '\n'; + } else if (filesMade) { + // Record that we created the file so that it gets referenced in the + // plist and SARIF reports for every translation unit that found the + // issue. + filesMade->addDiagnostic(D, getName(), + llvm::sys::path::filename(ResultPath)); } return; } @@ -679,8 +675,8 @@ void HTMLDiagnostics::FinalizeHTML(const PathDiagnostic &D, Rewriter &R, os << "\n<!-- FUNCTIONNAME " << declName << " -->\n"; - os << "\n<!-- ISSUEHASHCONTENTOFLINEINCONTEXT " << getIssueHash(D, PP) - << " -->\n"; + os << "\n<!-- ISSUEHASHCONTENTOFLINEINCONTEXT " + << D.getIssueHash(PP.getSourceManager(), PP.getLangOpts()) << " -->\n"; os << "\n<!-- BUGLINE " << LineNumber diff --git a/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.h b/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.h new file mode 100644 index 0000000000000..d6e4d6b344ddb --- /dev/null +++ b/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.h @@ -0,0 +1,14 @@ +//==- HTMLDiagnostics.h - HTML Diagnostics for Paths ---------------*- C++ -*-// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_STATICANALYZER_CORE_HTMLDIAGNOSTICS_H +#define LLVM_CLANG_LIB_STATICANALYZER_CORE_HTMLDIAGNOSTICS_H + +#define HTML_DIAGNOSTICS_NAME "HTMLDiagnostics" + +#endif diff --git a/clang/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp b/clang/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp index f4b08e265f9e7..3e3fff900cde8 100644 --- a/clang/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp +++ b/clang/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp @@ -706,13 +706,11 @@ void PlistDiagnostics::FlushDiagnosticsImpl( o << " <key>issue_hash_content_of_line_in_context</key>"; PathDiagnosticLocation UPDLoc = D->getUniqueingLoc(); FullSourceLoc L(SM.getExpansionLoc(UPDLoc.isValid() - ? UPDLoc.asLocation() - : D->getLocation().asLocation()), + ? UPDLoc.asLocation() + : D->getLocation().asLocation()), SM); - const Decl *DeclWithIssue = D->getDeclWithIssue(); - EmitString(o, getIssueHash(L, D->getCheckerName(), D->getBugType(), - DeclWithIssue, LangOpts)) - << '\n'; + + EmitString(o, D->getIssueHash(SM, LangOpts)) << '\n'; // Output information about the semantic context where // the issue occurred. diff --git a/clang/lib/StaticAnalyzer/Core/SarifDiagnostics.cpp b/clang/lib/StaticAnalyzer/Core/SarifDiagnostics.cpp index d2c46cf00ac80..6673f2f319c0e 100644 --- a/clang/lib/StaticAnalyzer/Core/SarifDiagnostics.cpp +++ b/clang/lib/StaticAnalyzer/Core/SarifDiagnostics.cpp @@ -11,6 +11,8 @@ //===----------------------------------------------------------------------===// #include "SarifDiagnostics.h" +#include "HTMLDiagnostics.h" +#include "clang/Analysis/IssueHash.h" #include "clang/Analysis/MacroExpansionContext.h" #include "clang/Analysis/PathDiagnostic.h" #include "clang/Basic/Sarif.h" @@ -31,12 +33,13 @@ namespace { class SarifDiagnostics : public PathDiagnosticConsumer { std::string OutputFile; const LangOptions &LO; + const SourceManager &SM; SarifDocumentWriter SarifWriter; public: SarifDiagnostics(const std::string &Output, const LangOptions &LO, const SourceManager &SM) - : OutputFile(Output), LO(LO), SarifWriter(SM) {} + : OutputFile(Output), LO(LO), SM(SM), SarifWriter(SM) {} ~SarifDiagnostics() override = default; void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags, @@ -46,6 +49,11 @@ class SarifDiagnostics : public PathDiagnosticConsumer { PathGenerationScheme getGenerationScheme() const override { return Minimal; } bool supportsLogicalOpControlFlow() const override { return true; } bool supportsCrossFileDiagnostics() const override { return true; } + +private: + SarifResult createResult(const PathDiagnostic *Diag, + const StringMap<uint32_t> &RuleMapping, + const LangOptions &LO, FilesMade *FM); }; } // end anonymous namespace @@ -173,9 +181,12 @@ createRuleMapping(const std::vector<const PathDiagnostic *> &Diags, return RuleMapping; } -static SarifResult createResult(const PathDiagnostic *Diag, - const StringMap<uint32_t> &RuleMapping, - const LangOptions &LO) { +static const llvm::StringRef IssueHashKey = "clang/issueHash/v1"; + +SarifResult +SarifDiagnostics::createResult(const PathDiagnostic *Diag, + const StringMap<uint32_t> &RuleMapping, + const LangOptions &LO, FilesMade *FM) { StringRef CheckName = Diag->getCheckerName(); uint32_t RuleIdx = RuleMapping.lookup(CheckName); @@ -183,17 +194,40 @@ static SarifResult createResult(const PathDiagnostic *Diag, Diag->getLocation().asRange(), Diag->getLocation().getManager(), LO); SmallVector<ThreadFlow, 8> Flows = createThreadFlows(Diag, LO); + + auto IssueHash = Diag->getIssueHash(SM, LO); + + std::string HtmlReportURL; + if (FM && !FM->empty()) { + // Find the HTML report that was generated for this issue, if one exists. + PDFileEntry::ConsumerFiles *Files = FM->getFiles(*Diag); + if (Files) { + auto HtmlFile = + std::find_if(Files->cbegin(), Files->cend(), [](auto &File) { + return File.first == HTML_DIAGNOSTICS_NAME; + }); + if (HtmlFile != Files->cend()) { + SmallString<128> HtmlReportPath = + llvm::sys::path::parent_path(OutputFile); + llvm::sys::path::append(HtmlReportPath, HtmlFile->second); + HtmlReportURL = SarifDocumentWriter::fileNameToURI(HtmlReportPath); + } + } + } + auto Result = SarifResult::create(RuleIdx) .setRuleId(CheckName) .setDiagnosticMessage(Diag->getVerboseDescription()) .setDiagnosticLevel(SarifResultLevel::Warning) .setLocations({Range}) + .addPartialFingerprint(IssueHashKey, IssueHash) + .setHostedViewerURI(HtmlReportURL) .setThreadFlows(Flows); return Result; } void SarifDiagnostics::FlushDiagnosticsImpl( - std::vector<const PathDiagnostic *> &Diags, FilesMade *) { + std::vector<const PathDiagnostic *> &Diags, FilesMade *FM) { // We currently overwrite the file if it already exists. However, it may be // useful to add a feature someday that allows the user to append a run to an // existing SARIF file. One danger from that approach is that the size of the @@ -210,7 +244,7 @@ void SarifDiagnostics::FlushDiagnosticsImpl( SarifWriter.createRun("clang", "clang static analyzer", ToolVersion); StringMap<uint32_t> RuleMapping = createRuleMapping(Diags, SarifWriter); for (const PathDiagnostic *D : Diags) { - SarifResult Result = createResult(D, RuleMapping, LO); + SarifResult Result = createResult(D, RuleMapping, LO, FM); SarifWriter.appendResult(Result); } auto Document = SarifWriter.createDocument(); diff --git a/clang/test/Analysis/diagnostics/Inputs/expected-sarif/sarif-diagnostics-taint-test.c.sarif b/clang/test/Analysis/diagnostics/Inputs/expected-sarif/sarif-diagnostics-taint-test.c.sarif index 0bded6f0925d1..76f25475e3b21 100644 --- a/clang/test/Analysis/diagnostics/Inputs/expected-sarif/sarif-diagnostics-taint-test.c.sarif +++ b/clang/test/Analysis/diagnostics/Inputs/expected-sarif/sarif-diagnostics-taint-test.c.sarif @@ -4,9 +4,10 @@ { "artifacts": [ { - "length": 425, + "length": -1, "location": { "index": 0, + "uri": "file:///[...]/sarif-diagnostics-taint-test.c" }, "mimeType": "text/plain", "roles": [ @@ -31,6 +32,7 @@ "physicalLocation": { "artifactLocation": { "index": 0, + "uri": "file:///[...]/sarif-diagnostics-taint-test.c" }, "region": { "endColumn": 6, @@ -50,6 +52,7 @@ "physicalLocation": { "artifactLocation": { "index": 0, + "uri": "file:///[...]/sarif-diagnostics-taint-test.c" }, "region": { "endColumn": 18, @@ -71,6 +74,7 @@ "physicalLocation": { "artifactLocation": { "index": 0, + "uri": "file:///[...]/sarif-diagnostics-taint-test.c" }, "region": { "endColumn": 18, @@ -84,6 +88,9 @@ "message": { "text": "tainted" }, + "partialFingerprints": { + "clang/issueHash/v1": "5c964815b8d6db3989bacdd308e657d0" + }, "ruleId": "debug.TaintTest", "ruleIndex": 0 } @@ -108,8 +115,10 @@ "name": "debug.TaintTest" } ], + "version": "[clang version]" } } } ], + "version": "[SARIF version]" } diff --git a/clang/test/Analysis/diagnostics/Inputs/expected-sarif/sarif-multi-diagnostic-test.c.sarif b/clang/test/Analysis/diagnostics/Inputs/expected-sarif/sarif-multi-diagnostic-test.c.sarif index e35ab695bb38e..4aa6239f6312d 100644 --- a/clang/test/Analysis/diagnostics/Inputs/expected-sarif/sarif-multi-diagnostic-test.c.sarif +++ b/clang/test/Analysis/diagnostics/Inputs/expected-sarif/sarif-multi-diagnostic-test.c.sarif @@ -4,9 +4,10 @@ { "artifacts": [ { - "length": 1152, + "length": -1, "location": { "index": 0, + "uri": "file:///[...]/sarif-multi-diagnostic-test.c" }, "mimeType": "text/plain", "roles": [ @@ -31,6 +32,7 @@ "physicalLocation": { "artifactLocation": { "index": 0, + "uri": "file:///[...]/sarif-multi-diagnostic-test.c" }, "region": { "endColumn": 6, @@ -50,6 +52,7 @@ "physicalLocation": { "artifactLocation": { "index": 0, + "uri": "file:///[...]/sarif-multi-diagnostic-test.c" }, "region": { "endColumn": 18, @@ -65,12 +68,14 @@ ] } ], + "hostedViewerUri": "file:///[...]/report-5c9648.html", "level": "warning", "locations": [ { "physicalLocation": { "artifactLocation": { "index": 0, + "uri": "file:///[...]/sarif-multi-diagnostic-test.c" }, "region": { "endColumn": 18, @@ -84,6 +89,9 @@ "message": { "text": "tainted" }, + "partialFingerprints": { + "clang/issueHash/v1": "5c964815b8d6db3989bacdd308e657d0" + }, "ruleId": "debug.TaintTest", "ruleIndex": 0 }, @@ -102,6 +110,7 @@ "physicalLocation": { "artifactLocation": { "index": 0, + "uri": "file:///[...]/sarif-multi-diagnostic-test.c" }, "region": { "endColumn": 6, @@ -121,6 +130,7 @@ "physicalLocation": { "artifactLocation": { "index": 0, + "uri": "file:///[...]/sarif-multi-diagnostic-test.c" }, "region": { "endColumn": 12, @@ -140,6 +150,7 @@ "physicalLocation": { "artifactLocation": { "index": 0, + "uri": "file:///[...]/sarif-multi-diagnostic-test.c" }, "region": { "endColumn": 9, @@ -155,12 +166,14 @@ ] } ], + "hostedViewerUri": "file:///[...]/report-256f65.html", "level": "warning", "locations": [ { "physicalLocation": { "artifactLocation": { "index": 0, + "uri": "file:///[...]/sarif-multi-diagnostic-test.c" }, "region": { "endColumn": 9, @@ -174,6 +187,9 @@ "message": { "text": "Called function pointer is an uninitialized pointer value" }, + "partialFingerprints": { + "clang/issueHash/v1": "256f6502719de88bece09a676d4102c6" + }, "ruleId": "core.CallAndMessage", "ruleIndex": 1 }, @@ -192,6 +208,7 @@ "physicalLocation": { "artifactLocation": { "index": 0, + "uri": "file:///[...]/sarif-multi-diagnostic-test.c" }, "region": { "endColumn": 13, @@ -211,6 +228,7 @@ "physicalLocation": { "artifactLocation": { "index": 0, + "uri": "file:///[...]/sarif-multi-diagnostic-test.c" }, "region": { "endColumn": 3, @@ -229,6 +247,7 @@ "physicalLocation": { "artifactLocation": { "index": 0, + "uri": "file:///[...]/sarif-multi-diagnostic-test.c" }, "region": { "endColumn": 14, @@ -243,12 +262,14 @@ ] } ], + "hostedViewerUri": "file:///[...]/report-91023b.html", "level": "warning", "locations": [ { "physicalLocation": { "artifactLocation": { "index": 0, + "uri": "file:///[...]/sarif-multi-diagnostic-test.c" }, "region": { "endColumn": 14, @@ -261,6 +282,9 @@ "message": { "text": "Division by zero" }, + "partialFingerprints": { + "clang/issueHash/v1": "91023b85b7e0ff79f11ab603e63cfa58" + }, "ruleId": "core.DivideZero", "ruleIndex": 2 }, @@ -279,6 +303,7 @@ "physicalLocation": { "artifactLocation": { "index": 0, + "uri": "file:///[...]/sarif-multi-diagnostic-test.c" }, "region": { "endColumn": 24, @@ -298,6 +323,7 @@ "physicalLocation": { "artifactLocation": { "index": 0, + "uri": "file:///[...]/sarif-multi-diagnostic-test.c" }, "region": { "endColumn": 12, @@ -317,6 +343,7 @@ "physicalLocation": { "artifactLocation": { "index": 0, + "uri": "file:///[...]/sarif-multi-diagnostic-test.c" }, "region": { "endColumn": 3, @@ -335,6 +362,7 @@ "physicalLocation": { "artifactLocation": { "index": 0, + "uri": "file:///[...]/sarif-multi-diagnostic-test.c" }, "region": { "endColumn": 12, @@ -349,12 +377,14 @@ ] } ], + "hostedViewerUri": "file:///[...]/report-b18daa.html", "level": "warning", "locations": [ { "physicalLocation": { "artifactLocation": { "index": 0, + "uri": "file:///[...]/sarif-multi-diagnostic-test.c" }, "region": { "endColumn": 12, @@ -367,6 +397,9 @@ "message": { "text": "Potential leak of memory pointed to by 'mem'" }, + "partialFingerprints": { + "clang/issueHash/v1": "b18daabce2816b9efb6afffaa64ca9f9" + }, "ruleId": "unix.Malloc", "ruleIndex": 3 }, @@ -385,6 +418,7 @@ "physicalLocation": { "artifactLocation": { "index": 0, + "uri": "file:///[...]/sarif-multi-diagnostic-test.c" }, "region": { "endColumn": 12, @@ -404,6 +438,7 @@ "physicalLocation": { "artifactLocation": { "index": 0, + "uri": "file:///[...]/sarif-multi-diagnostic-test.c" }, "region": { "endColumn": 20, @@ -418,12 +453,14 @@ ] } ], + "hostedViewerUri": "file:///[...]/report-4e5361.html", "level": "warning", "locations": [ { "physicalLocation": { "artifactLocation": { "index": 0, + "uri": "file:///[...]/sarif-multi-diagnostic-test.c" }, "region": { "endColumn": 20, @@ -436,6 +473,9 @@ "message": { "text": "Division by zero" }, + "partialFingerprints": { + "clang/issueHash/v1": "4e53611783411e0dae06a4084b00281c" + }, "ruleId": "core.DivideZero", "ruleIndex": 2 } @@ -499,8 +539,10 @@ "name": "unix.Malloc" } ], + "version": "[clang version]" } } } ], + "version": "[SARIF version]" } diff --git a/clang/test/Analysis/diagnostics/Inputs/expected-sarif/sarif-multi-file-diagnostics.c.sarif b/clang/test/Analysis/diagnostics/Inputs/expected-sarif/sarif-multi-file-diagnostics.c.sarif new file mode 100644 index 0000000000000..85e710fc7bac3 --- /dev/null +++ b/clang/test/Analysis/diagnostics/Inputs/expected-sarif/sarif-multi-file-diagnostics.c.sarif @@ -0,0 +1,144 @@ +{ + "$schema": "https://docs.oasis-open.org/sarif/sarif/v2.1.0/cos02/schemas/sarif-schema-2.1.0.json", + "runs": [ + { + "artifacts": [ + { + "length": -1, + "location": { + "index": 0, + "uri": "file:///[...]/sarif-multi-file-diagnostics.c" + }, + "mimeType": "text/plain", + "roles": [ + "resultFile" + ] + } + ], + "columnKind": "unicodeCodePoints", + "results": [ + { + "codeFlows": [ + { + "threadFlows": [ + { + "locations": [ + { + "importance": "important", + "location": { + "message": { + "text": "Assuming 'p' is null" + }, + "physicalLocation": { + "artifactLocation": { + "index": 0, + "uri": "file:///[...]/sarif-multi-file-diagnostics.c" + }, + "region": { + "endColumn": 7, + "startColumn": 7, + "startLine": 8 + } + } + } + }, + { + "importance": "unimportant", + "location": { + "message": { + "text": "Taking false branch" + }, + "physicalLocation": { + "artifactLocation": { + "index": 0, + "uri": "file:///[...]/sarif-multi-file-diagnostics.c" + }, + "region": { + "endColumn": 3, + "startColumn": 3, + "startLine": 8 + } + } + } + }, + { + "importance": "essential", + "location": { + "message": { + "text": "Dereference of null pointer (loaded from variable 'p')" + }, + "physicalLocation": { + "artifactLocation": { + "index": 0, + "uri": "file:///[...]/sarif-multi-file-diagnostics.c" + }, + "region": { + "endColumn": 14, + "endLine": 11, + "startColumn": 12, + "startLine": 11 + } + } + } + } + ] + } + ] + } + ], + "hostedViewerUri": "file:///[...]/report-d03238.html", + "level": "warning", + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "index": 0, + "uri": "file:///[...]/sarif-multi-file-diagnostics.c" + }, + "region": { + "endColumn": 14, + "endLine": 11, + "startColumn": 12, + "startLine": 11 + } + } + } + ], + "message": { + "text": "Dereference of null pointer (loaded from variable 'p')" + }, + "partialFingerprints": { + "clang/issueHash/v1": "d0323824ffaf9fee78b866e18d300fda" + }, + "ruleId": "core.NullDereference", + "ruleIndex": 0 + } + ], + "tool": { + "driver": { + "fullName": "clang static analyzer", + "informationUri": "https://clang.llvm.org/docs/UsersManual.html", + "language": "en-US", + "name": "clang", + "rules": [ + { + "defaultConfiguration": { + "enabled": true, + "level": "warning", + "rank": -1 + }, + "fullDescription": { + "text": "Check for dereferences of null pointers" + }, + "helpUri": "https://clang.llvm.org/docs/analyzer/checkers.html#core-nulldereference", + "id": "core.NullDereference", + "name": "core.NullDereference" + } + ], + "version": "[clang version]" + } + } + } + ], + "version": "[SARIF version]" +} \ No newline at end of file diff --git a/clang/test/Analysis/diagnostics/sarif-multi-file-diagnostics.c b/clang/test/Analysis/diagnostics/sarif-multi-file-diagnostics.c new file mode 100644 index 0000000000000..48880b592f261 --- /dev/null +++ b/clang/test/Analysis/diagnostics/sarif-multi-file-diagnostics.c @@ -0,0 +1,12 @@ +// RUN: rm -rf %t && mkdir %t +// RUN: %clang_analyze_cc1 -analyzer-checker=core %s -verify -analyzer-output=sarif-html -o %t%{fs-sep}out1.sarif +// RUN: %clang_analyze_cc1 -analyzer-checker=core %s -verify -analyzer-output=sarif-html -o %t%{fs-sep}out2.sarif +// RUN: cat %t%{fs-sep}out1.sarif | %normalize_sarif | diff -U1 -b %S/Inputs/expected-sarif/sarif-multi-file-diagnostics.c.sarif - +// RUN: cat %t%{fs-sep}out2.sarif | %normalize_sarif | diff -U1 -b %S/Inputs/expected-sarif/sarif-multi-file-diagnostics.c.sarif - + +int test(int *p) { + if (p) + return 0; + else + return *p; // expected-warning {{Dereference of null pointer (loaded from variable 'p')}} +} diff --git a/clang/test/Analysis/lit.local.cfg b/clang/test/Analysis/lit.local.cfg index f08ff8d6cce63..3d60a16405ea6 100644 --- a/clang/test/Analysis/lit.local.cfg +++ b/clang/test/Analysis/lit.local.cfg @@ -21,11 +21,15 @@ config.substitutions.append( config.substitutions.append( ( "%normalize_sarif", - "grep -Ev '^[[:space:]]*(%s|%s|%s)[[:space:]]*$'" + "sed -r '%s;%s;%s;%s'" % ( - '"uri": "file:.*%basename_t"', - '"version": ".* version .*"', - '"version": "2.1.0"', + # Replace version strings that are likely to change. + r's/"version": ".* version .*"/"version": "[clang version]"/', + r's/"version": "2.1.0"/"version": "[SARIF version]"/', + # Strip directories from file URIs + r's/"file:(\/+)([^"\/]+\/)*([^"]+)"/"file:\1[...]\/\3"/', + # Set "length" to -1 + r's/"length": [[:digit:]]+/"length": -1/' ), ) ) _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
