22 #include "llvm/ADT/SmallVector.h" 23 #include "llvm/Support/Casting.h" 24 using namespace clang;
30 const std::string OutputFile;
32 const bool SupportsCrossFileDiagnostics;
35 const std::string& prefix,
37 bool supportsMultipleFiles);
39 ~PlistDiagnostics()
override {}
41 void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags,
42 FilesMade *filesMade)
override;
44 StringRef getName()
const override {
45 return "PlistDiagnostics";
48 PathGenerationScheme getGenerationScheme()
const override {
51 bool supportsLogicalOpControlFlow()
const override {
return true; }
52 bool supportsCrossFileDiagnostics()
const override {
53 return SupportsCrossFileDiagnostics;
59 const std::string& output,
61 bool supportsMultipleFiles)
64 SupportsCrossFileDiagnostics(supportsMultipleFiles) {}
70 C.push_back(
new PlistDiagnostics(AnalyzerOpts, s,
74 void ento::createPlistMultiFileDiagnosticConsumer(
AnalyzerOptions &AnalyzerOpts,
78 C.push_back(
new PlistDiagnostics(AnalyzerOpts, s,
89 Indent(o, indent) <<
"<dict>\n";
92 Indent(o, indent) <<
"<key>kind</key><string>control</string>\n";
95 Indent(o, indent) <<
"<key>edges</key>\n";
97 Indent(o, indent) <<
"<array>\n";
101 Indent(o, indent) <<
"<dict>\n";
107 Indent(o, indent) <<
"<key>start</key>\n";
113 Indent(o, indent) <<
"<key>end</key>\n";
119 Indent(o, indent) <<
"</dict>\n";
122 Indent(o, indent) <<
"</array>\n";
128 Indent(o, indent) <<
"<key>alternate</key>";
133 Indent(o, indent) <<
"</dict>\n";
142 bool isKeyEvent =
false) {
144 Indent(o, indent) <<
"<dict>\n";
147 Indent(o, indent) <<
"<key>kind</key><string>event</string>\n";
150 Indent(o, indent) <<
"<key>key_event</key><true/>\n";
156 Indent(o, indent) <<
"<key>location</key>\n";
162 if (!Ranges.empty()) {
163 Indent(o, indent) <<
"<key>ranges</key>\n";
164 Indent(o, indent) <<
"<array>\n";
166 for (
auto &R : Ranges)
171 Indent(o, indent) <<
"</array>\n";
175 Indent(o, indent) <<
"<key>depth</key>";
180 Indent(o, indent) <<
"<key>extended_message</key>\n";
186 Indent(o, indent) <<
"<key>message</key>\n";
192 Indent(o, indent); o <<
"</dict>\n";
201 bool includeControlFlow,
202 bool isKeyEvent =
false);
212 ReportPiece(o, *callEnter, FM, SM, LangOpts, indent, depth,
true,
219 ReportPiece(o, *callEnterWithinCaller, FM, SM, LangOpts,
220 indent, depth,
true);
222 for (PathPieces::const_iterator I = P.
path.begin(), E = P.
path.end();I!=E;++I)
223 ReportPiece(o, **I, FM, SM, LangOpts, indent, depth,
true);
228 ReportPiece(o, *callExit, FM, SM, LangOpts, indent, depth,
true);
240 ReportPiece(o, **I, FM, SM, LangOpts, indent, depth,
false);
256 bool includeControlFlow,
260 if (includeControlFlow)
265 ReportCall(o, cast<PathDiagnosticCallPiece>(P), FM, SM, LangOpts,
269 ReportEvent(o, cast<PathDiagnosticSpotPiece>(P), FM, SM, LangOpts,
270 indent, depth, isKeyEvent);
273 ReportMacro(o, cast<PathDiagnosticMacroPiece>(P), FM, SM, LangOpts,
282 void PlistDiagnostics::FlushDiagnosticsImpl(
283 std::vector<const PathDiagnostic *> &Diags,
284 FilesMade *filesMade) {
292 SM = &Diags.front()->path.front()->getLocation().getManager();
295 AddFID(FM, Fids, *SM, Piece.getLocation().asLocation());
298 AddFID(FM, Fids, *SM, Range.getBegin());
299 AddFID(FM, Fids, *SM, Range.getEnd());
306 WorkList.push_back(&D->path);
308 while (!WorkList.empty()) {
309 const PathPieces &Path = *WorkList.pop_back_val();
311 for (
const auto &Iter : Path) {
316 dyn_cast<PathDiagnosticCallPiece>(&Piece)) {
317 if (
auto CallEnterWithin = Call->getCallEnterWithinCallerEvent())
318 AddPieceFID(*CallEnterWithin);
320 if (
auto CallEnterEvent = Call->getCallEnterEvent())
321 AddPieceFID(*CallEnterEvent);
323 WorkList.push_back(&Call->path);
325 dyn_cast<PathDiagnosticMacroPiece>(&Piece)) {
326 WorkList.push_back(&Macro->subPieces);
334 llvm::raw_fd_ostream o(OutputFile, EC, llvm::sys::fs::F_Text);
336 llvm::errs() <<
"warning: could not create file: " << EC.message() <<
'\n';
347 " <key>clang_version</key>\n";
349 o <<
" <key>files</key>\n" 356 " <key>diagnostics</key>\n" 359 for (std::vector<const PathDiagnostic*>::iterator DI=Diags.begin(),
360 DE = Diags.end(); DI!=DE; ++DI) {
363 " <key>path</key>\n";
369 for (PathPieces::const_iterator I = D->
path.begin(), E = D->
path.end();
376 o <<
" <key>description</key>";
378 o <<
" <key>category</key>";
380 o <<
" <key>type</key>";
382 o <<
" <key>check_name</key>";
385 o <<
" <!-- This hash is experimental and going to change! -->\n";
386 o <<
" <key>issue_hash_content_of_line_in_context</key>";
394 DeclWithIssue, LangOpts))
401 if (
const NamedDecl *ND = dyn_cast<NamedDecl>(DeclWithIssue)) {
403 switch (ND->getKind()) {
404 case Decl::CXXRecord:
405 declKind =
"C++ class";
407 case Decl::CXXMethod:
408 declKind =
"C++ method";
410 case Decl::ObjCMethod:
411 declKind =
"Objective-C method";
414 declKind =
"function";
419 if (!declKind.empty()) {
420 const std::string &declName = ND->getDeclName().getAsString();
421 o <<
" <key>issue_context_kind</key>";
423 o <<
" <key>issue_context</key>";
439 o <<
" <key>issue_hash_function_offset</key><string>" 446 o <<
" <key>issue_hash_function_offset</key><string>" 456 o <<
" <key>location</key>\n";
460 if (!filesMade->empty()) {
462 PDFileEntry::ConsumerFiles *files = filesMade->getFiles(*D);
464 for (PDFileEntry::ConsumerFiles::const_iterator CI = files->begin(),
465 CE = files->end(); CI != CE; ++CI) {
466 StringRef newName = CI->first;
467 if (newName != lastName) {
468 if (!lastName.empty()) {
472 o <<
" <key>" << lastName <<
"_files</key>\n";
475 o <<
" <string>" << CI->second <<
"</string>\n";
488 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
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.
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)
raw_ostream & EmitInteger(raw_ostream &o, int64_t value)
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
std::vector< PathDiagnosticLocationPair >::const_iterator const_iterator
SourceLocation getExpansionLoc(SourceLocation Loc) const
Given a SourceLocation object Loc, return the expansion location referenced by the ID...
StringRef getBugType() const
StringRef getCheckName() const
virtual PathDiagnosticLocation getLocation() const =0
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 ReportDiag(raw_ostream &o, const PathDiagnosticPiece &P, const FIDMap &FM, const SourceManager &SM, const LangOptions &LangOpts)
StringRef getCategory() const
std::shared_ptr< PathDiagnosticEventPiece > getCallEnterEvent() const
StringRef getName() const
std::shared_ptr< PathDiagnosticEventPiece > getCallExitEvent() const
std::vector< PathDiagnosticConsumer * > PathDiagnosticConsumers
FullSourceLoc asLocation() const
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...
ArrayRef< SourceRange > getRanges() const
Return the SourceRanges associated with this PathDiagnosticPiece.
Dataflow Directional Tag Classes.
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...
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.
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.
const Decl * getUniqueingDecl() const
Get the declaration containing the uniqueing location.
A trivial tuple used to represent a source range.
NamedDecl - This represents a decl with a name.
StringRef getString() const
SourceLocation getLocStart() const LLVM_READONLY
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.