clang: lib/StaticAnalyzer/Core/SarifDiagnostics.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
9
10
11
12
23#include "llvm/ADT/StringMap.h"
24#include "llvm/Support/ConvertUTF.h"
25#include "llvm/Support/JSON.h"
26#include
27
28using namespace llvm;
29using namespace clang;
30using namespace ento;
31
32namespace {
34 std::string OutputFile;
35 const LangOptions &LO;
36 const SourceManager &SM;
37 SarifDocumentWriter SarifWriter;
38
39public:
40 SarifDiagnostics(const std::string &Output, const LangOptions &LO,
41 const SourceManager &SM)
42 : OutputFile(Output), LO(LO), SM(SM), SarifWriter(SM) {}
43 ~SarifDiagnostics() override = default;
44
45 void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags,
46 FilesMade *FM) override;
47
48 StringRef getName() const override { return "SarifDiagnostics"; }
49 PathGenerationScheme getGenerationScheme() const override { return Minimal; }
50 bool supportsLogicalOpControlFlow() const override { return true; }
51 bool supportsCrossFileDiagnostics() const override { return true; }
52
53private:
54 SarifResult createResult(const PathDiagnostic *Diag,
55 const StringMap<uint32_t> &RuleMapping,
56 const LangOptions &LO, FilesMade *FM);
57};
58}
59
60void ento::createSarifDiagnosticConsumer(
62 const std::string &Output, const Preprocessor &PP,
65
67
68 createTextMinimalPathDiagnosticConsumer(std::move(DiagOpts), C, Output, PP,
69 CTU, MacroExpansions);
70}
71
72
73
76 const std::string &Output, const Preprocessor &PP) {
77
78
79 if (Output.empty())
80 return;
81
82 C.push_back(std::make_unique(Output, PP.getLangOpts(),
84}
85
87 return llvm::StringSwitch(CheckName)
88#define GET_CHECKERS
89#define CHECKER(FULLNAME, CLASS, HELPTEXT, DOC_URI, IS_HIDDEN) \
90 .Case(FULLNAME, HELPTEXT)
91#include "clang/StaticAnalyzer/Checkers/Checkers.inc"
92#undef CHECKER
93#undef GET_CHECKERS
94 ;
95}
96
98 return llvm::StringSwitch(CheckName)
99#define GET_CHECKERS
100#define CHECKER(FULLNAME, CLASS, HELPTEXT, DOC_URI, IS_HIDDEN) \
101 .Case(FULLNAME, DOC_URI)
102#include "clang/StaticAnalyzer/Checkers/Checkers.inc"
103#undef CHECKER
104#undef GET_CHECKERS
105 ;
106}
107
110 switch (Piece.getKind()) {
115
116 break;
118 return Piece.getTagStr() == "ConditionBRVisitor"
123 }
125}
126
127
128
132
133
136
138
139
140
144}
145
149 const PathPieces &Pieces = Diag->path.flatten(false);
150 for (const auto &Piece : Pieces) {
152 Piece->getLocation().asRange(), Piece->getLocation().getManager(), LO);
157 Flows.push_back(Flow);
158 }
159 return Flows;
160}
161
162static StringMap<uint32_t>
165 StringMap<uint32_t> RuleMapping;
166 llvm::StringSet<> Seen;
167
169 StringRef CheckName = D->getCheckerName();
170 std::pair<llvm::StringSet<>::iterator, bool> P = Seen.insert(CheckName);
171 if (P.second) {
177 size_t RuleIdx = SarifWriter.createRule(Rule);
178 RuleMapping[CheckName] = RuleIdx;
179 }
180 }
181 return RuleMapping;
182}
183
184static const llvm::StringRef IssueHashKey = "clang/issueHash/v1";
185
188 const StringMap<uint32_t> &RuleMapping,
190
191 StringRef CheckName = Diag->getCheckerName();
192 uint32_t RuleIdx = RuleMapping.lookup(CheckName);
194 Diag->getLocation().asRange(), Diag->getLocation().getManager(), LO);
195
197
198 auto IssueHash = Diag->getIssueHash(SM, LO);
199
200 std::string HtmlReportURL;
201 if (FM && !FM->empty()) {
202
203 PDFileEntry::ConsumerFiles *Files = FM->getFiles(*Diag);
204 if (Files) {
205 auto HtmlFile = llvm::find_if(*Files, [](const auto &File) {
207 });
208 if (HtmlFile != Files->end()) {
210 llvm::sys::path::parent_path(OutputFile);
211 llvm::sys::path::append(HtmlReportPath, HtmlFile->second);
213 }
214 }
215 }
216
222 .addPartialFingerprint(IssueHashKey, IssueHash)
225 return Result;
226}
227
228void SarifDiagnostics::FlushDiagnosticsImpl(
229 std::vector<const PathDiagnostic *> &Diags, FilesMade *FM) {
230
231
232
233
234
235 std::error_code EC;
236 llvm::raw_fd_ostream OS(OutputFile, EC, llvm::sys::fs::OF_TextWithCRLF);
237 if (EC) {
238 llvm::errs() << "warning: could not create file: " << EC.message() << '\n';
239 return;
240 }
241
243 SarifWriter.createRun("clang", "clang static analyzer", ToolVersion);
244 StringMap<uint32_t> RuleMapping = createRuleMapping(Diags, SarifWriter);
245 for (const PathDiagnostic *D : Diags) {
246 SarifResult Result = createResult(D, RuleMapping, LO, FM);
248 }
250 OS << llvm::formatv("{0:2}\n", json::Value(std::move(Document)));
251}
#define HTML_DIAGNOSTICS_NAME
static DiagnosticBuilder Diag(DiagnosticsEngine *Diags, const LangOptions &Features, FullSourceLoc TokLoc, const char *TokBegin, const char *TokRangeBegin, const char *TokRangeEnd, unsigned DiagID)
Produce a diagnostic highlighting some portion of a literal.
Defines the clang::Preprocessor interface.
static StringRef getRuleHelpURIStr(StringRef CheckName)
Definition SarifDiagnostics.cpp:97
static CharSourceRange convertTokenRangeToCharRange(const SourceRange &R, const SourceManager &SM, const LangOptions &LO)
Accepts a SourceRange corresponding to a pair of the first and last tokens and converts to a Characte...
Definition SarifDiagnostics.cpp:129
static StringRef getRuleDescription(StringRef CheckName)
Definition SarifDiagnostics.cpp:86
static StringMap< uint32_t > createRuleMapping(const std::vector< const PathDiagnostic * > &Diags, SarifDocumentWriter &SarifWriter)
Definition SarifDiagnostics.cpp:163
static const llvm::StringRef IssueHashKey
Definition SarifDiagnostics.cpp:184
static ThreadFlowImportance calculateImportance(const PathDiagnosticPiece &Piece)
Definition SarifDiagnostics.cpp:109
static SmallVector< ThreadFlow, 8 > createThreadFlows(const PathDiagnostic *Diag, const LangOptions &LO)
Definition SarifDiagnostics.cpp:146
Defines clang::SarifDocumentWriter, clang::SarifRule, clang::SarifResult.
Defines the SourceManager interface.
Defines version macros and version-related utility functions for Clang.
Represents a character-granular source range.
static CharSourceRange getCharRange(SourceRange R)
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
static SourceLocation getLocForEndOfToken(SourceLocation Loc, unsigned Offset, const SourceManager &SM, const LangOptions &LangOpts)
Computes the source location just past the end of the token at this source location.
MacroExpansionContext tracks the macro expansions processed by the Preprocessor.
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
SourceManager & getSourceManager() const
const LangOptions & getLangOpts() const
This class handles creating a valid SARIF document given various input attributes.
void createRun(const llvm::StringRef ShortToolName, const llvm::StringRef LongToolName, const llvm::StringRef ToolVersion=CLANG_VERSION_STRING)
Create a new run with which any upcoming analysis will be associated.
size_t createRule(const SarifRule &Rule)
Associate the given rule with the current run.
static std::string fileNameToURI(llvm::StringRef Filename)
llvm::json::Object createDocument()
Return the SARIF document in its current state.
void appendResult(const SarifResult &SarifResult)
Append a new result to the currently in-flight run.
A SARIF result (also called a "reporting item") is a unit of output produced when one of the tool's r...
SarifResult setHostedViewerURI(llvm::StringRef URI)
SarifResult setThreadFlows(llvm::ArrayRef< ThreadFlow > ThreadFlowResults)
SarifResult setDiagnosticMessage(llvm::StringRef Message)
SarifResult setRuleId(llvm::StringRef Id)
SarifResult addLocations(llvm::ArrayRef< CharSourceRange > DiagLocs)
SarifResult setDiagnosticLevel(const SarifResultLevel &TheLevel)
static SarifResult create(uint32_t RuleIdx)
SarifRule setDescription(llvm::StringRef RuleDesc)
SarifRule setHelpURI(llvm::StringRef RuleHelpURI)
SarifRule setRuleId(llvm::StringRef RuleId)
static SarifRule create()
SarifRule setName(llvm::StringRef RuleName)
Encodes a location in the source.
This class handles loading and caching of source files into memory.
A trivial tuple used to represent a source range.
SourceLocation getEnd() const
SourceLocation getBegin() const
ThreadFlow setImportance(const ThreadFlowImportance &ItemImportance)
ThreadFlow setRange(const CharSourceRange &ItemRange)
static ThreadFlow create()
ThreadFlow setMessage(llvm::StringRef ItemMessage)
This class is used for tools that requires cross translation unit capability.
StringRef getTagStr() const
Return the string representation of the tag.
PathDiagnostic - PathDiagnostic objects represent a single path-sensitive diagnostic.
A Range represents the closed range [from, to].
std::vector< std::unique_ptr< PathDiagnosticConsumer > > PathDiagnosticConsumers
@ OS
Indicates that the tracking object is a descendant of a referenced-counted OSObject,...
void createSarifDiagnosticConsumerImpl(PathDiagnosticConsumerOptions DiagOpts, PathDiagnosticConsumers &C, const std::string &Output, const Preprocessor &PP)
Creates and registers a SARIF diagnostic consumer, without any additional text consumer.
Definition SarifDiagnostics.cpp:74
StringRef getName(const HeaderType T)
The JSON file list parser is used to communicate input to InstallAPI.
@ Result
The result type of a method or function.
std::string getClangFullVersion()
Retrieves a string representing the complete clang version, which includes the clang version number,...
Diagnostic wrappers for TextAPI types for error reporting.
These options tweak the behavior of path diangostic consumers.