26#include "llvm/ADT/SmallVector.h"
27#include "llvm/ADT/Statistic.h"
42 PathDiagnosticConsumerOptions DiagOpts;
43 const std::string OutputFile;
44 const Preprocessor &PP;
45 const cross_tu::CrossTranslationUnitContext &CTU;
46 const MacroExpansionContext &MacroExpansions;
47 const bool SupportsCrossFileDiagnostics;
49 void printBugPath(llvm::raw_ostream &o,
const FIDMap &FM,
50 const PathPieces &Path);
53 PlistDiagnostics(PathDiagnosticConsumerOptions DiagOpts,
54 const std::string &OutputFile,
const Preprocessor &PP,
55 const cross_tu::CrossTranslationUnitContext &CTU,
56 const MacroExpansionContext &MacroExpansions,
57 bool supportsMultipleFiles);
59 ~PlistDiagnostics()
override {}
61 void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags,
62 FilesMade *filesMade)
override;
64 StringRef
getName()
const override {
65 return "PlistDiagnostics";
68 PathGenerationScheme getGenerationScheme()
const override {
71 bool supportsLogicalOpControlFlow()
const override {
return true; }
72 bool supportsCrossFileDiagnostics()
const override {
73 return SupportsCrossFileDiagnostics;
83 const Preprocessor &PP;
84 const cross_tu::CrossTranslationUnitContext &CTU;
85 const MacroExpansionContext &MacroExpansions;
86 llvm::SmallVector<const PathDiagnosticMacroPiece *, 0> MacroPieces;
89 PlistPrinter(
const FIDMap &FM,
const Preprocessor &PP,
90 const cross_tu::CrossTranslationUnitContext &CTU,
91 const MacroExpansionContext &MacroExpansions)
92 : FM(FM), PP(PP), CTU(CTU), MacroExpansions(MacroExpansions) {}
94 void ReportDiag(raw_ostream &o,
const PathDiagnosticPiece& P) {
95 ReportPiece(o, P, 4, 0,
true);
104 void ReportMacroExpansions(raw_ostream &o,
unsigned indent);
107 void ReportPiece(raw_ostream &o,
const PathDiagnosticPiece &P,
108 unsigned indent,
unsigned depth,
bool includeControlFlow,
109 bool isKeyEvent =
false) {
112 if (includeControlFlow)
136 void EmitRanges(raw_ostream &o,
const ArrayRef<SourceRange> Ranges,
138 void EmitMessage(raw_ostream &o, StringRef Message,
unsigned indent);
139 void EmitFixits(raw_ostream &o, ArrayRef<FixItHint> fixits,
unsigned indent);
141 void ReportControlFlow(raw_ostream &o,
142 const PathDiagnosticControlFlowPiece& P,
144 void ReportEvent(raw_ostream &o,
const PathDiagnosticEventPiece& P,
145 unsigned indent,
unsigned depth,
bool isKeyEvent =
false);
146 void ReportCall(raw_ostream &o,
const PathDiagnosticCallPiece &P,
147 unsigned indent,
unsigned depth);
148 void ReportMacroSubPieces(raw_ostream &o,
const PathDiagnosticMacroPiece& P,
149 unsigned indent,
unsigned depth);
150 void ReportNote(raw_ostream &o,
const PathDiagnosticNotePiece& P,
153 void ReportPopUp(raw_ostream &o,
const PathDiagnosticPopUpPiece &P,
162 unsigned InputIndentLevel,
165 llvm::raw_fd_ostream &o);
175void PlistPrinter::EmitRanges(raw_ostream &o,
182 Indent(o, indent) <<
"<key>ranges</key>\n";
183 Indent(o, indent) <<
"<array>\n";
189 for (
auto &R : Ranges)
194 Indent(o, indent) <<
"</array>\n";
197void PlistPrinter::EmitMessage(raw_ostream &o, StringRef Message,
201 Indent(o, indent) <<
"<key>extended_message</key>\n";
207 Indent(o, indent) <<
"<key>message</key>\n";
212void PlistPrinter::EmitFixits(raw_ostream &o, ArrayRef<FixItHint> fixits,
214 if (fixits.size() == 0)
220 Indent(o, indent) <<
"<key>fixits</key>\n";
221 Indent(o, indent) <<
"<array>\n";
222 for (
const auto &fixit : fixits) {
223 assert(!fixit.isNull());
225 assert(!fixit.InsertFromRange.isValid() &&
"Not implemented yet!");
226 assert(!fixit.BeforePreviousInsertions &&
"Not implemented yet!");
227 Indent(o, indent) <<
" <dict>\n";
228 Indent(o, indent) <<
" <key>remove_range</key>\n";
231 Indent(o, indent) <<
" <key>insert_string</key>";
234 Indent(o, indent) <<
" </dict>\n";
236 Indent(o, indent) <<
"</array>\n";
239void PlistPrinter::ReportControlFlow(raw_ostream &o,
240 const PathDiagnosticControlFlowPiece& P,
246 Indent(o, indent) <<
"<dict>\n";
249 Indent(o, indent) <<
"<key>kind</key><string>control</string>\n";
252 Indent(o, indent) <<
"<key>edges</key>\n";
254 Indent(o, indent) <<
"<array>\n";
258 Indent(o, indent) <<
"<dict>\n";
264 Indent(o, indent) <<
"<key>start</key>\n";
265 SourceRange StartEdge(
266 SM.getExpansionLoc(I->getStart().asRange().getBegin()));
270 Indent(o, indent) <<
"<key>end</key>\n";
271 SourceRange EndEdge(
SM.getExpansionLoc(I->getEnd().asRange().getBegin()));
276 Indent(o, indent) <<
"</dict>\n";
279 Indent(o, indent) <<
"</array>\n";
285 Indent(o, indent) <<
"<key>alternate</key>";
290 "Fixits on constrol flow pieces are not implemented yet!");
293 Indent(o, indent) <<
"</dict>\n";
296void PlistPrinter::ReportEvent(raw_ostream &o,
const PathDiagnosticEventPiece& P,
297 unsigned indent,
unsigned depth,
302 Indent(o, indent) <<
"<dict>\n";
305 Indent(o, indent) <<
"<key>kind</key><string>event</string>\n";
308 Indent(o, indent) <<
"<key>key_event</key><true/>\n";
314 Indent(o, indent) <<
"<key>location</key>\n";
318 ArrayRef<SourceRange> Ranges = P.
getRanges();
319 EmitRanges(o, Ranges, indent);
322 Indent(o, indent) <<
"<key>depth</key>";
333 Indent(o, indent); o <<
"</dict>\n";
336void PlistPrinter::ReportCall(raw_ostream &o,
const PathDiagnosticCallPiece &P,
341 ReportPiece(o, *callEnter, indent, depth,
true,
348 ReportPiece(o, *callEnterWithinCaller, indent, depth,
351 for (PathPieces::const_iterator I = P.
path.begin(), E = P.
path.end();I!=E;++I)
352 ReportPiece(o, **I, indent, depth,
true);
357 ReportPiece(o, *callExit, indent, depth,
true);
360 "Fixits on call pieces are not implemented yet!");
363void PlistPrinter::ReportMacroSubPieces(raw_ostream &o,
364 const PathDiagnosticMacroPiece& P,
365 unsigned indent,
unsigned depth) {
366 MacroPieces.push_back(&P);
368 for (
const auto &SubPiece : P.
subPieces) {
369 ReportPiece(o, *SubPiece, indent, depth,
false);
373 "Fixits on constrol flow pieces are not implemented yet!");
376void PlistPrinter::ReportMacroExpansions(raw_ostream &o,
unsigned indent) {
378 for (
const PathDiagnosticMacroPiece *P : MacroPieces) {
381 SourceLocation MacroExpansionLoc =
384 const std::optional<StringRef> MacroName =
386 const std::optional<StringRef> ExpansionText =
389 if (!MacroName || !ExpansionText)
392 Indent(o, indent) <<
"<dict>\n";
398 Indent(o, indent) <<
"<key>location</key>\n";
402 ArrayRef<SourceRange> Ranges = P->
getRanges();
403 EmitRanges(o, Ranges, indent);
406 Indent(o, indent) <<
"<key>name</key>";
410 Indent(o, indent) <<
"<key>expansion</key>";
420void PlistPrinter::ReportNote(raw_ostream &o,
const PathDiagnosticNotePiece& P,
425 Indent(o, indent) <<
"<dict>\n";
431 Indent(o, indent) <<
"<key>location</key>\n";
435 ArrayRef<SourceRange> Ranges = P.
getRanges();
436 EmitRanges(o, Ranges, indent);
446 Indent(o, indent); o <<
"</dict>\n";
449void PlistPrinter::ReportPopUp(raw_ostream &o,
450 const PathDiagnosticPopUpPiece &P,
454 Indent(o, indent) <<
"<dict>\n";
457 Indent(o, indent) <<
"<key>kind</key><string>pop-up</string>\n";
462 Indent(o, indent) <<
"<key>location</key>\n";
466 ArrayRef<SourceRange> Ranges = P.
getRanges();
467 EmitRanges(o, Ranges, indent);
473 "Fixits on pop-up pieces are not implemented yet!");
477 Indent(o, indent) <<
"</dict>\n";
487 unsigned InputIndentLevel,
490 llvm::raw_fd_ostream &o) {
499 for (
const auto &[FID, Lines] : ExecutedLines) {
500 unsigned FileKey =
AddFID(FM, Fids, FID);
504 for (
unsigned LineNo : Lines) {
521PlistDiagnostics::PlistDiagnostics(
522 PathDiagnosticConsumerOptions DiagOpts,
const std::string &output,
523 const Preprocessor &PP,
const cross_tu::CrossTranslationUnitContext &CTU,
524 const MacroExpansionContext &MacroExpansions,
bool supportsMultipleFiles)
525 : DiagOpts(std::move(DiagOpts)), OutputFile(output), PP(PP), CTU(CTU),
526 MacroExpansions(MacroExpansions),
527 SupportsCrossFileDiagnostics(supportsMultipleFiles) {
541 if (OutputFile.empty())
544 C.push_back(std::make_unique<PlistDiagnostics>(
545 DiagOpts, OutputFile, PP, CTU, MacroExpansions, SupportsMultipleFiles));
548void ento::createPlistDiagnosticConsumer(
557 createTextMinimalPathDiagnosticConsumer(std::move(DiagOpts),
C, OutputFile,
558 PP, CTU, MacroExpansions);
561void ento::createPlistMultiFileDiagnosticConsumer(
571 createTextMinimalPathDiagnosticConsumer(std::move(DiagOpts),
C, OutputFile,
572 PP, CTU, MacroExpansions);
575void PlistDiagnostics::printBugPath(llvm::raw_ostream &o,
const FIDMap &FM,
577 PlistPrinter Printer(FM, PP, CTU, MacroExpansions);
578 assert(std::is_partitioned(Path.begin(), Path.end(),
580 return E->getKind() == PathDiagnosticPiece::Note;
582 "PathDiagnostic is not partitioned so that notes precede the rest");
584 PathPieces::const_iterator FirstNonNote =
589 PathPieces::const_iterator I = Path.begin();
591 if (FirstNonNote != Path.begin()) {
592 o <<
" <key>notes</key>\n"
595 for (; I != FirstNonNote; ++I)
596 Printer.ReportDiag(o, **I);
601 o <<
" <key>path</key>\n";
605 for (
const auto &Piece : llvm::make_range(I, Path.end()))
606 Printer.ReportDiag(o, *Piece);
613 o <<
" <key>macro_expansions</key>\n"
615 Printer.ReportMacroExpansions(o, 4);
619void PlistDiagnostics::FlushDiagnosticsImpl(
620 std::vector<const PathDiagnostic *> &Diags,
621 FilesMade *filesMade) {
625 SmallVector<FileID, 10> Fids;
629 auto AddPieceFID = [&FM, &Fids, &
SM](
const PathDiagnosticPiece &Piece) {
630 AddFID(FM, Fids,
SM, Piece.getLocation().asLocation());
631 ArrayRef<SourceRange> Ranges = Piece.getRanges();
632 for (
const SourceRange &Range : Ranges) {
638 for (
const PathDiagnostic *D : Diags) {
640 SmallVector<const PathPieces *, 5> WorkList;
641 WorkList.push_back(&D->path);
643 while (!WorkList.empty()) {
644 const PathPieces &Path = *WorkList.pop_back_val();
646 for (
const auto &Iter : Path) {
647 const PathDiagnosticPiece &Piece = *Iter;
650 if (
const PathDiagnosticCallPiece *
Call =
651 dyn_cast<PathDiagnosticCallPiece>(&Piece)) {
652 if (
auto CallEnterWithin =
Call->getCallEnterWithinCallerEvent())
653 AddPieceFID(*CallEnterWithin);
655 if (
auto CallEnterEvent =
Call->getCallEnterEvent())
656 AddPieceFID(*CallEnterEvent);
658 WorkList.push_back(&
Call->path);
659 }
else if (
const PathDiagnosticMacroPiece *
Macro =
660 dyn_cast<PathDiagnosticMacroPiece>(&Piece)) {
661 WorkList.push_back(&
Macro->subPieces);
669 llvm::raw_fd_ostream o(OutputFile, EC, llvm::sys::fs::OF_TextWithCRLF);
671 llvm::errs() <<
"warning: could not create file: " << EC.message() <<
'\n';
682 " <key>clang_version</key>\n";
684 o <<
" <key>diagnostics</key>\n"
687 for (std::vector<const PathDiagnostic*>::iterator DI=Diags.begin(),
688 DE = Diags.end(); DI!=DE; ++DI) {
692 const PathDiagnostic *D = *DI;
693 printBugPath(o, FM, D->
path);
696 o <<
" <key>description</key>";
698 o <<
" <key>category</key>";
700 o <<
" <key>type</key>";
702 o <<
" <key>check_name</key>";
705 o <<
" <!-- This hash is experimental and going to change! -->\n";
706 o <<
" <key>issue_hash_content_of_line_in_context</key>";
708 FullSourceLoc L(
SM.getExpansionLoc(UPDLoc.
isValid()
714 DeclWithIssue, LangOpts))
721 if (
const NamedDecl *ND = dyn_cast<NamedDecl>(DeclWithIssue)) {
723 switch (ND->getKind()) {
724 case Decl::CXXRecord:
725 declKind =
"C++ class";
727 case Decl::CXXMethod:
728 declKind =
"C++ method";
730 case Decl::ObjCMethod:
731 declKind =
"Objective-C method";
734 declKind =
"function";
739 if (!declKind.empty()) {
740 const std::string &declName = ND->getDeclName().getAsString();
741 o <<
" <key>issue_context_kind</key>";
743 o <<
" <key>issue_context</key>";
749 if (
const Stmt *Body = DeclWithIssue->
getBody()) {
761 o <<
" <key>issue_hash_function_offset</key><string>"
767 FullSourceLoc FunL(
SM.getExpansionLoc(Body->getBeginLoc()),
SM);
768 o <<
" <key>issue_hash_function_offset</key><string>"
778 o <<
" <key>location</key>\n";
782 if (!filesMade->empty()) {
784 PDFileEntry::ConsumerFiles *files = filesMade->getFiles(*D);
786 for (PDFileEntry::ConsumerFiles::const_iterator CI = files->begin(),
787 CE = files->end(); CI != CE; ++CI) {
788 StringRef newName = CI->first;
789 if (newName != lastName) {
790 if (!lastName.empty()) {
794 o <<
" <key>" << lastName <<
"_files</key>\n";
797 o <<
" <string>" << CI->second <<
"</string>\n";
811 o <<
" <key>files</key>\n"
813 for (FileID FID : Fids)
814 EmitString(o <<
" ",
SM.getFileEntryRefForID(FID)->getName()) <<
'\n';
818 o <<
" <key>statistics</key>\n";
820 llvm::raw_string_ostream os(stats);
821 llvm::PrintStatisticsJSON(os);
826 o <<
"</dict>\n</plist>\n";
833static std::optional<StringRef>
838 if (
auto CTUMacroExpCtx =
840 return CTUMacroExpCtx->getExpandedText(MacroExpansionLoc);
static void printCoverage(const PathDiagnostic *D, unsigned InputIndentLevel, SmallVectorImpl< FileID > &Fids, FIDMap &FM, llvm::raw_fd_ostream &o)
Print coverage information to output stream o.
static std::optional< StringRef > getExpandedMacro(SourceLocation MacroLoc, const cross_tu::CrossTranslationUnitContext &CTU, const MacroExpansionContext &MacroExpansions, const SourceManager &SM)
Defines the clang::Preprocessor interface.
Defines the SourceManager interface.
Defines version macros and version-related utility functions for Clang.
__device__ __2f16 float __ockl_bool s
virtual Stmt * getBody() const
getBody - If this Decl represents a declaration for a body of code, such as a function or method defi...
FullSourceLoc getExpansionLoc() const
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.
MacroExpansionContext tracks the macro expansions processed by the Preprocessor.
std::optional< StringRef > getExpandedText(SourceLocation MacroExpansionLoc) const
std::optional< StringRef > getOriginalText(SourceLocation MacroExpansionLoc) const
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
SourceManager & getSourceManager() const
const LangOptions & getLangOpts() const
Encodes a location in the source.
This class handles loading and caching of source files into memory.
SourceLocation getBeginLoc() const LLVM_READONLY
This class is used for tools that requires cross translation unit capability.
std::optional< clang::MacroExpansionContext > getMacroExpansionContextForSourceLocation(const clang::SourceLocation &ToLoc) const
Returns the MacroExpansionContext for the imported TU to which the given source-location corresponds.
std::shared_ptr< PathDiagnosticEventPiece > getCallExitEvent() const
std::shared_ptr< PathDiagnosticEventPiece > getCallEnterWithinCallerEvent() const
std::shared_ptr< PathDiagnosticEventPiece > getCallEnterEvent() const
std::vector< PathDiagnosticLocationPair >::const_iterator const_iterator
FullSourceLoc asLocation() const
ArrayRef< SourceRange > getRanges() const
Return the SourceRanges associated with this PathDiagnosticPiece.
bool isLastInMainSourceFile() const
StringRef getString() const
ArrayRef< FixItHint > getFixits() const
Return the fix-it hints associated with this PathDiagnosticPiece.
PathDiagnosticLocation getLocation() const override
PathDiagnostic - PathDiagnostic objects represent a single path-sensitive diagnostic.
StringRef getCheckerName() const
PathDiagnosticLocation getUniqueingLoc() const
Get the location on which the report should be uniqued.
const Decl * getDeclWithIssue() const
Return the semantic context where an issue occurred.
const FilesToLineNumsMap & getExecutedLines() const
StringRef getBugType() const
const Decl * getUniqueingDecl() const
Get the declaration containing the uniqueing location.
StringRef getCategory() const
StringRef getShortDescription() const
PathDiagnosticLocation getLocation() const
std::vector< std::unique_ptr< PathDiagnosticConsumer > > PathDiagnosticConsumers
void createPlistDiagnosticConsumerImpl(PathDiagnosticConsumerOptions DiagOpts, PathDiagnosticConsumers &C, const std::string &Output, const Preprocessor &PP, const cross_tu::CrossTranslationUnitContext &CTU, const MacroExpansionContext &MacroExpansions, bool SupportsMultipleFiles)
Creates and registers a Plist diagnostic consumer, without any additional text consumer.
std::shared_ptr< PathDiagnosticPiece > PathDiagnosticPieceRef
std::map< FileID, std::set< unsigned > > FilesToLineNumsMap
File IDs mapped to sets of line numbers.
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 ...
StringRef getName(const HeaderType T)
void EmitRange(raw_ostream &o, const SourceManager &SM, CharSourceRange R, const FIDMap &FM, unsigned indent)
raw_ostream & EmitString(raw_ostream &o, StringRef s)
llvm::DenseMap< FileID, unsigned > FIDMap
unsigned AddFID(FIDMap &FIDs, SmallVectorImpl< FileID > &V, FileID FID)
raw_ostream & EmitInteger(raw_ostream &o, int64_t value)
raw_ostream & EmitPlistHeader(raw_ostream &o)
void EmitLocation(raw_ostream &o, const SourceManager &SM, SourceLocation L, const FIDMap &FM, unsigned indent)
std::variant< struct RequiresDecl, struct HeaderDecl, struct UmbrellaDirDecl, struct ModuleDecl, struct ExcludeDecl, struct ExportDecl, struct ExportAsDecl, struct ExternModuleDecl, struct UseDecl, struct LinkDecl, struct ConfigMacrosDecl, struct ConflictDecl > Decl
All declarations that can appear in a module declaration.
The JSON file list parser is used to communicate input to InstallAPI.
raw_ostream & Indent(raw_ostream &Out, const unsigned int Space, bool IsDot)
llvm::SmallString< 32 > getIssueHash(const FullSourceLoc &IssueLoc, llvm::StringRef CheckerName, llvm::StringRef WarningMessage, const Decl *IssueDecl, const LangOptions &LangOpts)
Returns an opaque identifier for a diagnostic.
U cast(CodeGen::Address addr)
std::string getClangFullVersion()
Retrieves a string representing the complete clang version, which includes the clang version number,...
These options tweak the behavior of path diangostic consumers.
bool ShouldDisplayMacroExpansions
Whether to include additional information about macro expansions with the diagnostics,...
bool ShouldSerializeStats
Whether to include LLVM statistics of the process in the diagnostic.