22 #include "llvm/ADT/DenseMap.h"
23 #include "llvm/ADT/SmallVector.h"
24 #include "llvm/Support/Casting.h"
25 using namespace clang;
27 using namespace markup;
31 const std::string OutputFile;
33 const bool SupportsCrossFileDiagnostics;
36 const std::string& prefix,
38 bool supportsMultipleFiles);
40 ~PlistDiagnostics()
override {}
42 void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags,
43 FilesMade *filesMade)
override;
45 StringRef getName()
const override {
46 return "PlistDiagnostics";
49 PathGenerationScheme getGenerationScheme()
const override {
52 bool supportsLogicalOpControlFlow()
const override {
return true; }
53 bool supportsCrossFileDiagnostics()
const override {
54 return SupportsCrossFileDiagnostics;
60 const std::string& output,
62 bool supportsMultipleFiles)
65 SupportsCrossFileDiagnostics(supportsMultipleFiles) {}
71 C.push_back(
new PlistDiagnostics(AnalyzerOpts, s,
75 void ento::createPlistMultiFileDiagnosticConsumer(
AnalyzerOptions &AnalyzerOpts,
79 C.push_back(
new PlistDiagnostics(AnalyzerOpts, s,
90 Indent(o, indent) <<
"<dict>\n";
93 Indent(o, indent) <<
"<key>kind</key><string>control</string>\n";
96 Indent(o, indent) <<
"<key>edges</key>\n";
98 Indent(o, indent) <<
"<array>\n";
102 Indent(o, indent) <<
"<dict>\n";
108 Indent(o, indent) <<
"<key>start</key>\n";
111 EmitRange(o, SM, Lexer::getAsCharRange(StartEdge, SM, LangOpts), FM,
114 Indent(o, indent) <<
"<key>end</key>\n";
116 EmitRange(o, SM, Lexer::getAsCharRange(EndEdge, SM, LangOpts), FM,
120 Indent(o, indent) <<
"</dict>\n";
123 Indent(o, indent) <<
"</array>\n";
129 Indent(o, indent) <<
"<key>alternate</key>";
134 Indent(o, indent) <<
"</dict>\n";
143 bool isKeyEvent =
false) {
145 Indent(o, indent) <<
"<dict>\n";
148 Indent(o, indent) <<
"<key>kind</key><string>event</string>\n";
151 Indent(o, indent) <<
"<key>key_event</key><true/>\n";
157 Indent(o, indent) <<
"<key>location</key>\n";
163 if (!Ranges.empty()) {
164 Indent(o, indent) <<
"<key>ranges</key>\n";
165 Indent(o, indent) <<
"<array>\n";
167 for (
auto &R : Ranges)
172 Indent(o, indent) <<
"</array>\n";
176 Indent(o, indent) <<
"<key>depth</key>";
181 Indent(o, indent) <<
"<key>extended_message</key>\n";
187 Indent(o, indent) <<
"<key>message</key>\n";
193 Indent(o, indent); o <<
"</dict>\n";
202 bool includeControlFlow,
203 bool isKeyEvent =
false);
216 ReportPiece(o, *callEnter, FM, SM, LangOpts, indent, depth,
true,
224 if (callEnterWithinCaller)
225 ReportPiece(o, *callEnterWithinCaller, FM, SM, LangOpts,
226 indent, depth,
true);
228 for (PathPieces::const_iterator
I = P.
path.begin(),
E = P.
path.end();
I!=
E;++
I)
229 ReportPiece(o, **
I, FM, SM, LangOpts, indent, depth,
true);
237 ReportPiece(o, *callExit, FM, SM, LangOpts, indent, depth,
true);
249 ReportPiece(o, **
I, FM, SM, LangOpts, indent, depth,
false);
265 bool includeControlFlow,
268 case PathDiagnosticPiece::ControlFlow:
269 if (includeControlFlow)
273 case PathDiagnosticPiece::Call:
274 ReportCall(o, cast<PathDiagnosticCallPiece>(P), FM, SM, LangOpts,
277 case PathDiagnosticPiece::Event:
278 ReportEvent(o, cast<PathDiagnosticSpotPiece>(P), FM, SM, LangOpts,
279 indent, depth, isKeyEvent);
281 case PathDiagnosticPiece::Macro:
282 ReportMacro(o, cast<PathDiagnosticMacroPiece>(P), FM, SM, LangOpts,
288 void PlistDiagnostics::FlushDiagnosticsImpl(
289 std::vector<const PathDiagnostic *> &Diags,
290 FilesMade *filesMade) {
298 SM = &Diags.front()->path.front()->getLocation().getManager();
302 DE = Diags.end(); DI != DE; ++DI) {
307 WorkList.push_back(&D->
path);
309 while (!WorkList.empty()) {
310 const PathPieces &path = *WorkList.pop_back_val();
312 for (PathPieces::const_iterator
I = path.begin(),
E = path.end();
I !=
E;
318 E = Ranges.end();
I !=
E; ++
I) {
319 AddFID(FM, Fids, *SM,
I->getBegin());
320 AddFID(FM, Fids, *SM,
I->getEnd());
324 dyn_cast<PathDiagnosticCallPiece>(piece)) {
326 callEnterWithin = call->getCallEnterWithinCallerEvent();
328 AddFID(FM, Fids, *SM, callEnterWithin->getLocation().asLocation());
330 WorkList.push_back(&call->path);
333 dyn_cast<PathDiagnosticMacroPiece>(piece)) {
334 WorkList.push_back(¯o->subPieces);
342 llvm::raw_fd_ostream o(OutputFile, EC, llvm::sys::fs::F_Text);
344 llvm::errs() <<
"warning: could not create file: " << EC.message() <<
'\n';
355 " <key>clang_version</key>\n";
357 o <<
" <key>files</key>\n"
364 " <key>diagnostics</key>\n"
368 DE = Diags.end(); DI!=DE; ++DI) {
371 " <key>path</key>\n";
377 for (PathPieces::const_iterator
I = D->
path.begin(),
E = D->
path.end();
384 o <<
" <key>description</key>";
386 o <<
" <key>category</key>";
388 o <<
" <key>type</key>";
390 o <<
" <key>check_name</key>";
393 o <<
" <!-- This hash is experimental and going to change! -->\n";
394 o <<
" <key>issue_hash_content_of_line_in_context</key>";
402 DeclWithIssue, LangOpts))
409 if (
const NamedDecl *ND = dyn_cast<NamedDecl>(DeclWithIssue)) {
411 switch (ND->getKind()) {
412 case Decl::CXXRecord:
413 declKind =
"C++ class";
415 case Decl::CXXMethod:
416 declKind =
"C++ method";
418 case Decl::ObjCMethod:
419 declKind =
"Objective-C method";
422 declKind =
"function";
427 if (!declKind.empty()) {
428 const std::string &declName = ND->getDeclName().getAsString();
429 o <<
" <key>issue_context_kind</key>";
431 o <<
" <key>issue_context</key>";
437 if (
const Stmt *Body = DeclWithIssue->getBody()) {
447 o <<
" <key>issue_hash_function_offset</key><string>"
448 << L.getExpansionLineNumber() - UFunL.getExpansionLineNumber()
454 o <<
" <key>issue_hash_function_offset</key><string>"
455 << L.getExpansionLineNumber() - FunL.getExpansionLineNumber()
464 o <<
" <key>location</key>\n";
468 if (!filesMade->empty()) {
470 PDFileEntry::ConsumerFiles *files = filesMade->getFiles(*D);
472 for (PDFileEntry::ConsumerFiles::const_iterator CI = files->begin(),
473 CE = files->end(); CI != CE; ++CI) {
474 StringRef newName = CI->first;
475 if (newName != lastName) {
476 if (!lastName.empty()) {
480 o <<
" <key>" << lastName <<
"_files</key>\n";
483 o <<
" <string>" << CI->second <<
"</string>\n";
496 o <<
"</dict>\n</plist>";
PathDiagnosticLocation getUniqueingLoc() const
Get the location on which the report should be uniqued.
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)
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...
Defines the SourceManager interface.
StringRef getCategory() const
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.
ArrayRef< SourceRange > getRanges() const
Return the SourceRanges associated with this PathDiagnosticPiece.
PathDiagnosticLocation getLocation() const
static void ReportEvent(raw_ostream &o, const PathDiagnosticPiece &P, const FIDMap &FM, const SourceManager &SM, const LangOptions &LangOpts, unsigned indent, unsigned depth, bool isKeyEvent=false)
const Decl * getDeclWithIssue() const
Return the semantic context where an issue occurred.
raw_ostream & EmitInteger(raw_ostream &o, int64_t value)
FullSourceLoc asLocation() const
PathDiagnostic - PathDiagnostic objects represent a single path-sensitive diagnostic.
std::pair< SourceLocation, SourceLocation > getExpansionRange(SourceLocation Loc) const
Given a SourceLocation object, return the range of tokens covered by the expansion in the ultimate fi...
StringRef getString() const
const LangOptions & getLangOpts() const
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
std::vector< PathDiagnosticLocationPair >::const_iterator const_iterator
IntrusiveRefCntPtr< PathDiagnosticEventPiece > getCallExitEvent() const
detail::InMemoryDirectory::const_iterator I
virtual PathDiagnosticLocation getLocation() const =0
const FileEntry * getFileEntryForID(FileID FID) const
Returns the FileEntry record for the provided FileID.
IntrusiveRefCntPtr< PathDiagnosticEventPiece > getCallEnterWithinCallerEvent() const
static void ReportCall(raw_ostream &o, const PathDiagnosticCallPiece &P, const FIDMap &FM, const SourceManager &SM, const LangOptions &LangOpts, unsigned indent, unsigned depth)
StringRef getShortDescription() const
Defines version macros and version-related utility functions for Clang.
Defines the clang::Preprocessor interface.
IntrusiveRefCntPtr< PathDiagnosticEventPiece > getCallEnterEvent() const
static void ReportDiag(raw_ostream &o, const PathDiagnosticPiece &P, const FIDMap &FM, const SourceManager &SM, const LangOptions &LangOpts)
const char * getName() const
const TemplateArgument * iterator
std::vector< PathDiagnosticConsumer * > PathDiagnosticConsumers
const Decl * getUniqueingDecl() const
Get the declaration containing the uniqueing location.
llvm::DenseMap< FileID, unsigned > FIDMap
raw_ostream & EmitPlistHeader(raw_ostream &o)
An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...
bool isLastInMainSourceFile() const
detail::InMemoryDirectory::const_iterator E
void EmitRange(raw_ostream &o, const SourceManager &SM, CharSourceRange R, const FIDMap &FM, unsigned indent)
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)
A SourceLocation and its associated SourceManager.
StringRef getBugType() const
A trivial tuple used to represent a source range.
NamedDecl - This represents a decl with a name.
SourceLocation getExpansionLoc(SourceLocation Loc) const
Given a SourceLocation object Loc, return the expansion location referenced by the ID...
StringRef getCheckName() 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.