24 #include "llvm/ADT/Statistic.h" 25 #include "llvm/ADT/SmallVector.h" 26 #include "llvm/Support/Casting.h" 27 using namespace clang;
33 const std::string OutputFile;
35 const bool SupportsCrossFileDiagnostics;
36 const bool SerializeStatistics;
39 const std::string& prefix,
41 bool supportsMultipleFiles);
43 ~PlistDiagnostics()
override {}
45 void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags,
46 FilesMade *filesMade)
override;
48 StringRef
getName()
const override {
49 return "PlistDiagnostics";
52 PathGenerationScheme getGenerationScheme()
const override {
55 bool supportsLogicalOpControlFlow()
const override {
return true; }
56 bool supportsCrossFileDiagnostics()
const override {
57 return SupportsCrossFileDiagnostics;
63 const std::string& output,
65 bool supportsMultipleFiles)
68 SupportsCrossFileDiagnostics(supportsMultipleFiles),
69 SerializeStatistics(AnalyzerOpts.shouldSerializeStats()) {}
75 C.push_back(
new PlistDiagnostics(AnalyzerOpts, s,
79 void ento::createPlistMultiFileDiagnosticConsumer(
AnalyzerOptions &AnalyzerOpts,
83 C.push_back(
new PlistDiagnostics(AnalyzerOpts, s,
97 Indent(o, indent) <<
"<key>ranges</key>\n";
98 Indent(o, indent) <<
"<array>\n";
100 for (
auto &R : Ranges)
105 Indent(o, indent) <<
"</array>\n";
108 static void EmitMessage(raw_ostream &o, StringRef Message,
unsigned indent) {
110 assert(!Message.empty());
111 Indent(o, indent) <<
"<key>extended_message</key>\n";
117 Indent(o, indent) <<
"<key>message</key>\n";
129 Indent(o, indent) <<
"<dict>\n";
132 Indent(o, indent) <<
"<key>kind</key><string>control</string>\n";
135 Indent(o, indent) <<
"<key>edges</key>\n";
137 Indent(o, indent) <<
"<array>\n";
141 Indent(o, indent) <<
"<dict>\n";
147 Indent(o, indent) <<
"<key>start</key>\n";
153 Indent(o, indent) <<
"<key>end</key>\n";
159 Indent(o, indent) <<
"</dict>\n";
162 Indent(o, indent) <<
"</array>\n";
168 Indent(o, indent) <<
"<key>alternate</key>";
173 Indent(o, indent) <<
"</dict>\n";
182 bool isKeyEvent =
false) {
184 Indent(o, indent) <<
"<dict>\n";
187 Indent(o, indent) <<
"<key>kind</key><string>event</string>\n";
190 Indent(o, indent) <<
"<key>key_event</key><true/>\n";
196 Indent(o, indent) <<
"<key>location</key>\n";
201 EmitRanges(o, Ranges, FM, SM, LangOpts, indent);
204 Indent(o, indent) <<
"<key>depth</key>";
212 Indent(o, indent); o <<
"</dict>\n";
221 bool includeControlFlow,
222 bool isKeyEvent =
false);
232 ReportPiece(o, *callEnter, FM, SM, LangOpts, indent, depth,
true,
239 ReportPiece(o, *callEnterWithinCaller, FM, SM, LangOpts,
240 indent, depth,
true);
242 for (PathPieces::const_iterator I = P.
path.begin(), E = P.
path.end();I!=E;++I)
243 ReportPiece(o, **I, FM, SM, LangOpts, indent, depth,
true);
248 ReportPiece(o, *callExit, FM, SM, LangOpts, indent, depth,
true);
260 ReportPiece(o, **I, FM, SM, LangOpts, indent, depth,
false);
271 Indent(o, indent) <<
"<dict>\n";
277 Indent(o, indent) <<
"<key>location</key>\n";
282 EmitRanges(o, Ranges, FM, SM, LangOpts, indent);
289 Indent(o, indent); o <<
"</dict>\n";
304 bool includeControlFlow,
308 if (includeControlFlow)
313 ReportCall(o, cast<PathDiagnosticCallPiece>(P), FM, SM, LangOpts,
317 ReportEvent(o, cast<PathDiagnosticEventPiece>(P), FM, SM, LangOpts,
318 indent, depth, isKeyEvent);
321 ReportMacro(o, cast<PathDiagnosticMacroPiece>(P), FM, SM, LangOpts,
325 ReportNote(o, cast<PathDiagnosticNotePiece>(P), FM, SM, LangOpts,
331 void PlistDiagnostics::FlushDiagnosticsImpl(
332 std::vector<const PathDiagnostic *> &Diags,
333 FilesMade *filesMade) {
341 SM = &Diags.front()->path.front()->getLocation().getManager();
344 AddFID(FM, Fids, *SM, Piece.getLocation().asLocation());
355 WorkList.push_back(&D->path);
357 while (!WorkList.empty()) {
358 const PathPieces &Path = *WorkList.pop_back_val();
360 for (
const auto &Iter : Path) {
365 dyn_cast<PathDiagnosticCallPiece>(&Piece)) {
366 if (
auto CallEnterWithin = Call->getCallEnterWithinCallerEvent())
367 AddPieceFID(*CallEnterWithin);
369 if (
auto CallEnterEvent = Call->getCallEnterEvent())
370 AddPieceFID(*CallEnterEvent);
372 WorkList.push_back(&Call->path);
374 dyn_cast<PathDiagnosticMacroPiece>(&Piece)) {
375 WorkList.push_back(&Macro->subPieces);
383 llvm::raw_fd_ostream o(OutputFile, EC, llvm::sys::fs::F_Text);
385 llvm::errs() <<
"warning: could not create file: " << EC.message() <<
'\n';
396 " <key>clang_version</key>\n";
398 o <<
" <key>files</key>\n" 405 " <key>diagnostics</key>\n" 408 for (std::vector<const PathDiagnostic*>::iterator DI=Diags.begin(),
409 DE = Diags.end(); DI!=DE; ++DI) {
416 assert(std::is_partitioned(
417 PP.begin(), PP.end(),
418 [](
const std::shared_ptr<PathDiagnosticPiece> &E)
420 "PathDiagnostic is not partitioned so that notes precede the rest");
422 PathPieces::const_iterator FirstNonNote = std::partition_point(
423 PP.begin(), PP.end(),
424 [](
const std::shared_ptr<PathDiagnosticPiece> &E)
427 PathPieces::const_iterator I = PP.begin();
429 if (FirstNonNote != PP.begin()) {
430 o <<
" <key>notes</key>\n" 433 for (; I != FirstNonNote; ++I)
439 o <<
" <key>path</key>\n";
443 for (PathPieces::const_iterator E = PP.end(); I != E; ++I)
449 o <<
" <key>description</key>";
451 o <<
" <key>category</key>";
453 o <<
" <key>type</key>";
455 o <<
" <key>check_name</key>";
458 o <<
" <!-- This hash is experimental and going to change! -->\n";
459 o <<
" <key>issue_hash_content_of_line_in_context</key>";
467 DeclWithIssue, LangOpts))
474 if (
const NamedDecl *ND = dyn_cast<NamedDecl>(DeclWithIssue)) {
476 switch (ND->getKind()) {
477 case Decl::CXXRecord:
478 declKind =
"C++ class";
480 case Decl::CXXMethod:
481 declKind =
"C++ method";
483 case Decl::ObjCMethod:
484 declKind =
"Objective-C method";
487 declKind =
"function";
492 if (!declKind.empty()) {
493 const std::string &declName = ND->getDeclName().getAsString();
494 o <<
" <key>issue_context_kind</key>";
496 o <<
" <key>issue_context</key>";
512 o <<
" <key>issue_hash_function_offset</key><string>" 519 o <<
" <key>issue_hash_function_offset</key><string>" 529 o <<
" <key>location</key>\n";
533 if (!filesMade->empty()) {
535 PDFileEntry::ConsumerFiles *files = filesMade->getFiles(*D);
537 for (PDFileEntry::ConsumerFiles::const_iterator CI = files->begin(),
538 CE = files->end(); CI != CE; ++CI) {
539 StringRef newName = CI->first;
540 if (newName != lastName) {
541 if (!lastName.empty()) {
545 o <<
" <key>" << lastName <<
"_files</key>\n";
548 o <<
" <string>" << CI->second <<
"</string>\n";
560 if (llvm::AreStatisticsEnabled() && SerializeStatistics) {
561 o <<
" <key>statistics</key>\n";
563 llvm::raw_string_ostream os(stats);
564 llvm::PrintStatisticsJSON(os);
570 o <<
"</dict>\n</plist>";
static void ReportPiece(raw_ostream &o, const PathDiagnosticPiece &P, const FIDMap &FM, const SourceManager &SM, const LangOptions &LangOpts, unsigned indent, unsigned depth, bool includeControlFlow, bool isKeyEvent=false)
bool isLastInMainSourceFile() const
void AddFID(FIDMap &FIDs, SmallVectorImpl< FileID > &V, const SourceManager &SM, SourceLocation L)
void EmitLocation(raw_ostream &o, const SourceManager &SM, SourceLocation L, const FIDMap &FM, unsigned indent)
Defines the clang::FileManager interface and associated types.
std::string getClangFullVersion()
Retrieves a string representing the complete clang version, which includes the clang version number...
virtual Stmt * getBody() const
getBody - If this Decl represents a declaration for a body of code, such as a function or method defi...
Stmt - This represents one statement.
Defines the SourceManager interface.
Decl - This represents one declaration (or definition), e.g.
std::shared_ptr< PathDiagnosticEventPiece > getCallEnterWithinCallerEvent() const
A Range represents the closed range [from, to].
llvm::SmallString< 32 > GetIssueHash(const SourceManager &SM, FullSourceLoc &IssueLoc, llvm::StringRef CheckerName, llvm::StringRef BugType, const Decl *D, const LangOptions &LangOpts)
Get an MD5 hash to help identify bugs.
constexpr XRayInstrMask Function
static void ReportEvent(raw_ostream &o, const PathDiagnosticEventPiece &P, const FIDMap &FM, const SourceManager &SM, const LangOptions &LangOpts, unsigned indent, unsigned depth, bool isKeyEvent=false)
raw_ostream & EmitInteger(raw_ostream &o, int64_t value)
std::string getName(ArrayRef< StringRef > Parts) const
Get the platform-specific name separator.
PathDiagnosticLocation getLocation() const
PathDiagnostic - PathDiagnostic objects represent a single path-sensitive diagnostic.
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
const LangOptions & getLangOpts() const
static void ReportNote(raw_ostream &o, const PathDiagnosticNotePiece &P, const FIDMap &FM, const SourceManager &SM, const LangOptions &LangOpts, unsigned indent, unsigned depth)
SourceLocation getExpansionLoc(SourceLocation Loc) const
Given a SourceLocation object Loc, return the expansion location referenced by the ID...
StringRef getBugType() const
StringRef getCheckName() const
std::vector< PathDiagnosticLocationPair >::const_iterator const_iterator
static void ReportCall(raw_ostream &o, const PathDiagnosticCallPiece &P, const FIDMap &FM, const SourceManager &SM, const LangOptions &LangOpts, unsigned indent, unsigned depth)
const FileEntry * getFileEntryForID(FileID FID) const
Returns the FileEntry record for the provided FileID.
Defines version macros and version-related utility functions for Clang.
Defines the clang::Preprocessor interface.
PathDiagnosticLocation getUniqueingLoc() const
Get the location on which the report should be uniqued.
static void EmitRanges(raw_ostream &o, const ArrayRef< SourceRange > Ranges, const FIDMap &FM, const SourceManager &SM, const LangOptions &LangOpts, unsigned indent)
static void ReportDiag(raw_ostream &o, const PathDiagnosticPiece &P, const FIDMap &FM, const SourceManager &SM, const LangOptions &LangOpts)
StringRef getCategory() const
llvm::DenseMap< FileID, unsigned > FIDMap
std::shared_ptr< PathDiagnosticEventPiece > getCallEnterEvent() const
StringRef getName() const
std::shared_ptr< PathDiagnosticEventPiece > getCallExitEvent() const
std::vector< PathDiagnosticConsumer * > PathDiagnosticConsumers
void EscapeText(Rewriter &R, FileID FID, bool EscapeSpaces=false, bool ReplaceTabs=false)
EscapeText - HTMLize a specified file so that special characters are are translated so that they are ...
SourceLocation getLocStart() const LLVM_READONLY
FullSourceLoc asLocation() const
PathDiagnosticLocation getLocation() const override
raw_ostream & EmitPlistHeader(raw_ostream &o)
An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...
ArrayRef< SourceRange > getRanges() const
Return the SourceRanges associated with this PathDiagnosticPiece.
Dataflow Directional Tag Classes.
void EmitRange(raw_ostream &o, const SourceManager &SM, CharSourceRange R, const FIDMap &FM, unsigned indent)
unsigned getExpansionLineNumber(bool *Invalid=nullptr) const
static CharSourceRange getAsCharRange(SourceRange Range, const SourceManager &SM, const LangOptions &LangOpts)
Given a token range, produce a corresponding CharSourceRange that is not a token range.
CharSourceRange getExpansionRange(SourceLocation Loc) const
Given a SourceLocation object, return the range of tokens covered by the expansion in the ultimate fi...
raw_ostream & EmitString(raw_ostream &o, StringRef s)
static void ReportControlFlow(raw_ostream &o, const PathDiagnosticControlFlowPiece &P, const FIDMap &FM, const SourceManager &SM, const LangOptions &LangOpts, unsigned indent)
static void ReportMacro(raw_ostream &o, const PathDiagnosticMacroPiece &P, const FIDMap &FM, const SourceManager &SM, const LangOptions &LangOpts, unsigned indent, unsigned depth)
static void EmitMessage(raw_ostream &o, StringRef Message, unsigned indent)
A SourceLocation and its associated SourceManager.
const Decl * getUniqueingDecl() const
Get the declaration containing the uniqueing location.
A trivial tuple used to represent a source range.
This represents a decl that may have a name.
StringRef getString() const
This class handles loading and caching of source files into memory.
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
StringRef getShortDescription() const
const Decl * getDeclWithIssue() const
Return the semantic context where an issue occurred.