Revert "Revert "[analyzer] NFC: Separate PathDiagnosticConsumer options from AnalyzerOptions.""

This reverts commit 10f1ca99b4.

(cherry picked from commit c599fc738a70e482976c6cc0ea31bef561641279)
This commit is contained in:
Artem Dergachev 2020-11-10 14:03:57 -08:00
parent fa5cb4b936
commit 499bce3aba
8 changed files with 164 additions and 116 deletions

View File

@ -58,6 +58,47 @@ namespace ento {
class PathDiagnostic; class PathDiagnostic;
/// These options tweak the behavior of path diangostic consumers.
/// Most of these options are currently supported by very few consumers.
struct PathDiagnosticConsumerOptions {
/// Run-line of the tool that produced the diagnostic.
/// It can be included with the diagnostic for debugging purposes.
std::string ToolInvocation;
/// Whether to include additional information about macro expansions
/// with the diagnostics, because otherwise they can be hard to obtain
/// without re-compiling the program under analysis.
bool ShouldDisplayMacroExpansions;
/// Whether to include LLVM statistics of the process in the diagnostic.
/// Useful for profiling the tool on large real-world codebases.
bool ShouldSerializeStats;
/// If the consumer intends to produce multiple output files, should it
/// use randomly generated file names for these files (with the tiny risk of
/// having random collisions) or deterministic human-readable file names
/// (with a larger risk of deterministic collisions or invalid characters
/// in the file name). We should not really give this choice to the users
/// because deterministic mode is always superior when done right, but
/// for some consumers this mode is experimental and needs to be
/// off by default.
bool ShouldWriteStableReportFilename;
/// Whether the consumer should treat consumed diagnostics as hard errors.
/// Useful for breaking your build when issues are found.
bool ShouldDisplayWarningsAsErrors;
/// Whether the consumer should attempt to rewrite the source file
/// with fix-it hints attached to the diagnostics it consumes.
bool ShouldApplyFixIts;
/// Whether the consumer should present the name of the entity that emitted
/// the diagnostic (eg., a checker) so that the user knew how to disable it.
bool ShouldDisplayDiagnosticName;
PathDiagnosticConsumerOptions() = delete;
};
class PathDiagnosticConsumer { class PathDiagnosticConsumer {
public: public:
class PDFileEntry : public llvm::FoldingSetNode { class PDFileEntry : public llvm::FoldingSetNode {

View File

@ -14,6 +14,7 @@
#ifndef LLVM_CLANG_STATICANALYZER_CORE_ANALYZEROPTIONS_H #ifndef LLVM_CLANG_STATICANALYZER_CORE_ANALYZEROPTIONS_H
#define LLVM_CLANG_STATICANALYZER_CORE_ANALYZEROPTIONS_H #define LLVM_CLANG_STATICANALYZER_CORE_ANALYZEROPTIONS_H
#include "clang/Analysis/PathDiagnostic.h"
#include "clang/Basic/LLVM.h" #include "clang/Basic/LLVM.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h" #include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/Optional.h" #include "llvm/ADT/Optional.h"
@ -255,7 +256,7 @@ public:
unsigned NoRetryExhausted : 1; unsigned NoRetryExhausted : 1;
/// Emit analyzer warnings as errors. /// Emit analyzer warnings as errors.
unsigned AnalyzerWerror : 1; bool AnalyzerWerror : 1;
/// The inlining stack depth limit. /// The inlining stack depth limit.
// Cap the stack depth at 4 calls (5 stack frames, base + 4 calls). // Cap the stack depth at 4 calls (5 stack frames, base + 4 calls).
@ -390,6 +391,16 @@ public:
/// ///
/// \sa CXXMemberInliningMode /// \sa CXXMemberInliningMode
bool mayInlineCXXMemberFunction(CXXInlineableMemberKind K) const; bool mayInlineCXXMemberFunction(CXXInlineableMemberKind K) const;
ento::PathDiagnosticConsumerOptions getDiagOpts() const {
return {FullCompilerInvocation,
ShouldDisplayMacroExpansions,
ShouldSerializeStats,
ShouldWriteStableReportFilename,
AnalyzerWerror,
ShouldApplyFixIts,
ShouldDisplayCheckerNameForText};
}
}; };
using AnalyzerOptionsRef = IntrusiveRefCntPtr<AnalyzerOptions>; using AnalyzerOptionsRef = IntrusiveRefCntPtr<AnalyzerOptions>;

View File

@ -13,6 +13,8 @@
#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHDIAGNOSTICCONSUMERS_H #ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHDIAGNOSTICCONSUMERS_H
#define LLVM_CLANG_STATICANALYZER_CORE_PATHDIAGNOSTICCONSUMERS_H #define LLVM_CLANG_STATICANALYZER_CORE_PATHDIAGNOSTICCONSUMERS_H
#include "clang/Analysis/PathDiagnostic.h"
#include <string> #include <string>
#include <vector> #include <vector>
@ -30,8 +32,9 @@ class PathDiagnosticConsumer;
typedef std::vector<PathDiagnosticConsumer*> PathDiagnosticConsumers; typedef std::vector<PathDiagnosticConsumer*> PathDiagnosticConsumers;
#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN) \ #define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN) \
void CREATEFN(AnalyzerOptions &AnalyzerOpts, PathDiagnosticConsumers &C, \ void CREATEFN(PathDiagnosticConsumerOptions Diagopts, \
const std::string &Prefix, const Preprocessor &PP, \ PathDiagnosticConsumers &C, const std::string &Prefix, \
const Preprocessor &PP, \
const cross_tu::CrossTranslationUnitContext &CTU); const cross_tu::CrossTranslationUnitContext &CTU);
#include "clang/StaticAnalyzer/Core/Analyses.def" #include "clang/StaticAnalyzer/Core/Analyses.def"

View File

@ -23,7 +23,6 @@
#include "clang/Lex/Token.h" #include "clang/Lex/Token.h"
#include "clang/Rewrite/Core/HTMLRewrite.h" #include "clang/Rewrite/Core/HTMLRewrite.h"
#include "clang/Rewrite/Core/Rewriter.h" #include "clang/Rewrite/Core/Rewriter.h"
#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
#include "clang/StaticAnalyzer/Core/IssueHash.h" #include "clang/StaticAnalyzer/Core/IssueHash.h"
#include "clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h" #include "clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h"
#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/ArrayRef.h"
@ -58,17 +57,18 @@ using namespace ento;
namespace { namespace {
class HTMLDiagnostics : public PathDiagnosticConsumer { class HTMLDiagnostics : public PathDiagnosticConsumer {
PathDiagnosticConsumerOptions DiagOpts;
std::string Directory; std::string Directory;
bool createdDir = false; bool createdDir = false;
bool noDir = false; bool noDir = false;
const Preprocessor &PP; const Preprocessor &PP;
AnalyzerOptions &AnalyzerOpts;
const bool SupportsCrossFileDiagnostics; const bool SupportsCrossFileDiagnostics;
public: public:
HTMLDiagnostics(AnalyzerOptions &AnalyzerOpts, const std::string &OutputDir, HTMLDiagnostics(PathDiagnosticConsumerOptions DiagOpts,
const Preprocessor &pp, bool supportsMultipleFiles) const std::string &OutputDir, const Preprocessor &pp,
: Directory(OutputDir), PP(pp), AnalyzerOpts(AnalyzerOpts), bool supportsMultipleFiles)
: DiagOpts(std::move(DiagOpts)), Directory(OutputDir), PP(pp),
SupportsCrossFileDiagnostics(supportsMultipleFiles) {} SupportsCrossFileDiagnostics(supportsMultipleFiles) {}
~HTMLDiagnostics() override { FlushDiagnostics(nullptr); } ~HTMLDiagnostics() override { FlushDiagnostics(nullptr); }
@ -133,7 +133,7 @@ private:
} // namespace } // namespace
void ento::createHTMLDiagnosticConsumer( void ento::createHTMLDiagnosticConsumer(
AnalyzerOptions &AnalyzerOpts, PathDiagnosticConsumers &C, PathDiagnosticConsumerOptions DiagOpts, PathDiagnosticConsumers &C,
const std::string &OutputDir, const Preprocessor &PP, const std::string &OutputDir, const Preprocessor &PP,
const cross_tu::CrossTranslationUnitContext &CTU) { const cross_tu::CrossTranslationUnitContext &CTU) {
@ -142,37 +142,38 @@ void ento::createHTMLDiagnosticConsumer(
// output mode. This doesn't make much sense, we should have the minimal text // output mode. This doesn't make much sense, we should have the minimal text
// as our default. In the case of backward compatibility concerns, this could // as our default. In the case of backward compatibility concerns, this could
// be preserved with -analyzer-config-compatibility-mode=true. // be preserved with -analyzer-config-compatibility-mode=true.
createTextMinimalPathDiagnosticConsumer(AnalyzerOpts, C, OutputDir, PP, CTU); createTextMinimalPathDiagnosticConsumer(DiagOpts, C, OutputDir, PP, CTU);
// TODO: Emit an error here. // TODO: Emit an error here.
if (OutputDir.empty()) if (OutputDir.empty())
return; return;
C.push_back(new HTMLDiagnostics(AnalyzerOpts, OutputDir, PP, true)); C.push_back(new HTMLDiagnostics(std::move(DiagOpts), OutputDir, PP, true));
} }
void ento::createHTMLSingleFileDiagnosticConsumer( void ento::createHTMLSingleFileDiagnosticConsumer(
AnalyzerOptions &AnalyzerOpts, PathDiagnosticConsumers &C, PathDiagnosticConsumerOptions DiagOpts, PathDiagnosticConsumers &C,
const std::string &OutputDir, const Preprocessor &PP, const std::string &OutputDir, const Preprocessor &PP,
const cross_tu::CrossTranslationUnitContext &CTU) { const cross_tu::CrossTranslationUnitContext &CTU) {
createTextMinimalPathDiagnosticConsumer(DiagOpts, C, OutputDir, PP, CTU);
// TODO: Emit an error here. // TODO: Emit an error here.
if (OutputDir.empty()) if (OutputDir.empty())
return; return;
C.push_back(new HTMLDiagnostics(AnalyzerOpts, OutputDir, PP, false)); C.push_back(new HTMLDiagnostics(std::move(DiagOpts), OutputDir, PP, false));
createTextMinimalPathDiagnosticConsumer(AnalyzerOpts, C, OutputDir, PP, CTU);
} }
void ento::createPlistHTMLDiagnosticConsumer( void ento::createPlistHTMLDiagnosticConsumer(
AnalyzerOptions &AnalyzerOpts, PathDiagnosticConsumers &C, PathDiagnosticConsumerOptions DiagOpts, PathDiagnosticConsumers &C,
const std::string &prefix, const Preprocessor &PP, const std::string &prefix, const Preprocessor &PP,
const cross_tu::CrossTranslationUnitContext &CTU) { const cross_tu::CrossTranslationUnitContext &CTU) {
createHTMLDiagnosticConsumer( createHTMLDiagnosticConsumer(
AnalyzerOpts, C, std::string(llvm::sys::path::parent_path(prefix)), PP, DiagOpts, C, std::string(llvm::sys::path::parent_path(prefix)), PP,
CTU); CTU);
createPlistMultiFileDiagnosticConsumer(AnalyzerOpts, C, prefix, PP, CTU); createPlistMultiFileDiagnosticConsumer(DiagOpts, C, prefix, PP, CTU);
createTextMinimalPathDiagnosticConsumer(AnalyzerOpts, C, prefix, PP, CTU); createTextMinimalPathDiagnosticConsumer(std::move(DiagOpts), C, prefix, PP,
CTU);
} }
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
@ -245,7 +246,7 @@ void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D,
int FD; int FD;
SmallString<128> Model, ResultPath; SmallString<128> Model, ResultPath;
if (!AnalyzerOpts.ShouldWriteStableReportFilename) { if (!DiagOpts.ShouldWriteStableReportFilename) {
llvm::sys::path::append(Model, Directory, "report-%%%%%%.html"); llvm::sys::path::append(Model, Directory, "report-%%%%%%.html");
if (std::error_code EC = if (std::error_code EC =
llvm::sys::fs::make_absolute(Model)) { llvm::sys::fs::make_absolute(Model)) {
@ -535,7 +536,7 @@ void HTMLDiagnostics::FinalizeHTML(const PathDiagnostic& D, Rewriter &R,
<input type="checkbox" class="spoilerhider" id="showinvocation" /> <input type="checkbox" class="spoilerhider" id="showinvocation" />
<label for="showinvocation" >Show analyzer invocation</label> <label for="showinvocation" >Show analyzer invocation</label>
<div class="spoiler">clang -cc1 )<<<"; <div class="spoiler">clang -cc1 )<<<";
os << html::EscapeText(AnalyzerOpts.FullCompilerInvocation); os << html::EscapeText(DiagOpts.ToolInvocation);
os << R"<<<( os << R"<<<(
</div> </div>
<div id='tooltiphint' hidden="true"> <div id='tooltiphint' hidden="true">

View File

@ -20,7 +20,6 @@
#include "clang/Lex/Preprocessor.h" #include "clang/Lex/Preprocessor.h"
#include "clang/Lex/TokenConcatenation.h" #include "clang/Lex/TokenConcatenation.h"
#include "clang/Rewrite/Core/HTMLRewrite.h" #include "clang/Rewrite/Core/HTMLRewrite.h"
#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
#include "clang/StaticAnalyzer/Core/IssueHash.h" #include "clang/StaticAnalyzer/Core/IssueHash.h"
#include "clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h" #include "clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h"
#include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallPtrSet.h"
@ -40,13 +39,17 @@ using namespace markup;
namespace { namespace {
class PlistDiagnostics : public PathDiagnosticConsumer { class PlistDiagnostics : public PathDiagnosticConsumer {
PathDiagnosticConsumerOptions DiagOpts;
const std::string OutputFile; const std::string OutputFile;
const Preprocessor &PP; const Preprocessor &PP;
const cross_tu::CrossTranslationUnitContext &CTU; const cross_tu::CrossTranslationUnitContext &CTU;
AnalyzerOptions &AnOpts;
const bool SupportsCrossFileDiagnostics; const bool SupportsCrossFileDiagnostics;
void printBugPath(llvm::raw_ostream &o, const FIDMap &FM,
const PathPieces &Path);
public: public:
PlistDiagnostics(AnalyzerOptions &AnalyzerOpts, PlistDiagnostics(PathDiagnosticConsumerOptions DiagOpts,
const std::string &OutputFile, const Preprocessor &PP, const std::string &OutputFile, const Preprocessor &PP,
const cross_tu::CrossTranslationUnitContext &CTU, const cross_tu::CrossTranslationUnitContext &CTU,
bool supportsMultipleFiles); bool supportsMultipleFiles);
@ -75,23 +78,19 @@ namespace {
/// A helper class for emitting a single report. /// A helper class for emitting a single report.
class PlistPrinter { class PlistPrinter {
const FIDMap& FM; const FIDMap& FM;
AnalyzerOptions &AnOpts;
const Preprocessor &PP; const Preprocessor &PP;
const cross_tu::CrossTranslationUnitContext &CTU; const cross_tu::CrossTranslationUnitContext &CTU;
llvm::SmallVector<const PathDiagnosticMacroPiece *, 0> MacroPieces; llvm::SmallVector<const PathDiagnosticMacroPiece *, 0> MacroPieces;
public: public:
PlistPrinter(const FIDMap& FM, AnalyzerOptions &AnOpts, PlistPrinter(const FIDMap& FM,
const Preprocessor &PP, const Preprocessor &PP,
const cross_tu::CrossTranslationUnitContext &CTU) const cross_tu::CrossTranslationUnitContext &CTU)
: FM(FM), AnOpts(AnOpts), PP(PP), CTU(CTU) { : FM(FM), PP(PP), CTU(CTU) {
} }
void ReportDiag(raw_ostream &o, const PathDiagnosticPiece& P) { void ReportDiag(raw_ostream &o, const PathDiagnosticPiece& P) {
ReportPiece(o, P, /*indent*/ 4, /*depth*/ 0, /*includeControlFlow*/ true); ReportPiece(o, P, /*indent*/ 4, /*depth*/ 0, /*includeControlFlow*/ true);
// Don't emit a warning about an unused private field.
(void)AnOpts;
} }
/// Print the expansions of the collected macro pieces. /// Print the expansions of the collected macro pieces.
@ -166,11 +165,6 @@ struct ExpansionInfo {
} // end of anonymous namespace } // end of anonymous namespace
static void printBugPath(llvm::raw_ostream &o, const FIDMap& FM,
AnalyzerOptions &AnOpts, const Preprocessor &PP,
const cross_tu::CrossTranslationUnitContext &CTU,
const PathPieces &Path);
/// Print coverage information to output stream {@code o}. /// Print coverage information to output stream {@code o}.
/// May modify the used list of files {@code Fids} by inserting new ones. /// May modify the used list of files {@code Fids} by inserting new ones.
static void printCoverage(const PathDiagnostic *D, static void printCoverage(const PathDiagnostic *D,
@ -521,11 +515,53 @@ static void printCoverage(const PathDiagnostic *D,
assert(IndentLevel == InputIndentLevel); assert(IndentLevel == InputIndentLevel);
} }
static void printBugPath(llvm::raw_ostream &o, const FIDMap& FM, //===----------------------------------------------------------------------===//
AnalyzerOptions &AnOpts, const Preprocessor &PP, // Methods of PlistDiagnostics.
const cross_tu::CrossTranslationUnitContext &CTU, //===----------------------------------------------------------------------===//
const PathPieces &Path) {
PlistPrinter Printer(FM, AnOpts, PP, CTU); PlistDiagnostics::PlistDiagnostics(
PathDiagnosticConsumerOptions DiagOpts, const std::string &output,
const Preprocessor &PP, const cross_tu::CrossTranslationUnitContext &CTU,
bool supportsMultipleFiles)
: DiagOpts(std::move(DiagOpts)), OutputFile(output), PP(PP), CTU(CTU),
SupportsCrossFileDiagnostics(supportsMultipleFiles) {
// FIXME: Will be used by a later planned change.
(void)this->CTU;
}
void ento::createPlistDiagnosticConsumer(
PathDiagnosticConsumerOptions DiagOpts, PathDiagnosticConsumers &C,
const std::string &OutputFile, const Preprocessor &PP,
const cross_tu::CrossTranslationUnitContext &CTU) {
// TODO: Emit an error here.
if (OutputFile.empty())
return;
C.push_back(new PlistDiagnostics(DiagOpts, OutputFile, PP, CTU,
/*supportsMultipleFiles=*/false));
createTextMinimalPathDiagnosticConsumer(std::move(DiagOpts), C, OutputFile,
PP, CTU);
}
void ento::createPlistMultiFileDiagnosticConsumer(
PathDiagnosticConsumerOptions DiagOpts, PathDiagnosticConsumers &C,
const std::string &OutputFile, const Preprocessor &PP,
const cross_tu::CrossTranslationUnitContext &CTU) {
// TODO: Emit an error here.
if (OutputFile.empty())
return;
C.push_back(new PlistDiagnostics(DiagOpts, OutputFile, PP, CTU,
/*supportsMultipleFiles=*/true));
createTextMinimalPathDiagnosticConsumer(std::move(DiagOpts), C, OutputFile,
PP, CTU);
}
void PlistDiagnostics::printBugPath(llvm::raw_ostream &o, const FIDMap &FM,
const PathPieces &Path) {
PlistPrinter Printer(FM, PP, CTU);
assert(std::is_partitioned(Path.begin(), Path.end(), assert(std::is_partitioned(Path.begin(), Path.end(),
[](const PathDiagnosticPieceRef &E) { [](const PathDiagnosticPieceRef &E) {
return E->getKind() == PathDiagnosticPiece::Note; return E->getKind() == PathDiagnosticPiece::Note;
@ -558,7 +594,7 @@ static void printBugPath(llvm::raw_ostream &o, const FIDMap& FM,
o << " </array>\n"; o << " </array>\n";
if (!AnOpts.ShouldDisplayMacroExpansions) if (!DiagOpts.ShouldDisplayMacroExpansions)
return; return;
o << " <key>macro_expansions</key>\n" o << " <key>macro_expansions</key>\n"
@ -567,48 +603,6 @@ static void printBugPath(llvm::raw_ostream &o, const FIDMap& FM,
o << " </array>\n"; o << " </array>\n";
} }
//===----------------------------------------------------------------------===//
// Methods of PlistDiagnostics.
//===----------------------------------------------------------------------===//
PlistDiagnostics::PlistDiagnostics(
AnalyzerOptions &AnalyzerOpts, const std::string &output,
const Preprocessor &PP, const cross_tu::CrossTranslationUnitContext &CTU,
bool supportsMultipleFiles)
: OutputFile(output), PP(PP), CTU(CTU), AnOpts(AnalyzerOpts),
SupportsCrossFileDiagnostics(supportsMultipleFiles) {
// FIXME: Will be used by a later planned change.
(void)this->CTU;
}
void ento::createPlistDiagnosticConsumer(
AnalyzerOptions &AnalyzerOpts, PathDiagnosticConsumers &C,
const std::string &OutputFile, const Preprocessor &PP,
const cross_tu::CrossTranslationUnitContext &CTU) {
// TODO: Emit an error here.
if (OutputFile.empty())
return;
C.push_back(new PlistDiagnostics(AnalyzerOpts, OutputFile, PP, CTU,
/*supportsMultipleFiles*/ false));
createTextMinimalPathDiagnosticConsumer(AnalyzerOpts, C, OutputFile, PP, CTU);
}
void ento::createPlistMultiFileDiagnosticConsumer(
AnalyzerOptions &AnalyzerOpts, PathDiagnosticConsumers &C,
const std::string &OutputFile, const Preprocessor &PP,
const cross_tu::CrossTranslationUnitContext &CTU) {
// TODO: Emit an error here.
if (OutputFile.empty())
return;
C.push_back(new PlistDiagnostics(AnalyzerOpts, OutputFile, PP, CTU,
/*supportsMultipleFiles*/ true));
createTextMinimalPathDiagnosticConsumer(AnalyzerOpts, C, OutputFile, PP, CTU);
}
void PlistDiagnostics::FlushDiagnosticsImpl( void PlistDiagnostics::FlushDiagnosticsImpl(
std::vector<const PathDiagnostic *> &Diags, std::vector<const PathDiagnostic *> &Diags,
FilesMade *filesMade) { FilesMade *filesMade) {
@ -683,7 +677,7 @@ void PlistDiagnostics::FlushDiagnosticsImpl(
o << " <dict>\n"; o << " <dict>\n";
const PathDiagnostic *D = *DI; const PathDiagnostic *D = *DI;
printBugPath(o, FM, AnOpts, PP, CTU, D->path); printBugPath(o, FM, D->path);
// Output the bug type and bug category. // Output the bug type and bug category.
o << " <key>description</key>"; o << " <key>description</key>";
@ -807,7 +801,7 @@ void PlistDiagnostics::FlushDiagnosticsImpl(
EmitString(o << " ", SM.getFileEntryForID(FID)->getName()) << '\n'; EmitString(o << " ", SM.getFileEntryForID(FID)->getName()) << '\n';
o << " </array>\n"; o << " </array>\n";
if (llvm::AreStatisticsEnabled() && AnOpts.ShouldSerializeStats) { if (llvm::AreStatisticsEnabled() && DiagOpts.ShouldSerializeStats) {
o << " <key>statistics</key>\n"; o << " <key>statistics</key>\n";
std::string stats; std::string stats;
llvm::raw_string_ostream os(stats); llvm::raw_string_ostream os(stats);

View File

@ -14,7 +14,6 @@
#include "clang/Basic/FileManager.h" #include "clang/Basic/FileManager.h"
#include "clang/Basic/Version.h" #include "clang/Basic/Version.h"
#include "clang/Lex/Preprocessor.h" #include "clang/Lex/Preprocessor.h"
#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
#include "clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h" #include "clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h"
#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringMap.h"
@ -32,8 +31,7 @@ class SarifDiagnostics : public PathDiagnosticConsumer {
const LangOptions &LO; const LangOptions &LO;
public: public:
SarifDiagnostics(AnalyzerOptions &, const std::string &Output, SarifDiagnostics(const std::string &Output, const LangOptions &LO)
const LangOptions &LO)
: OutputFile(Output), LO(LO) {} : OutputFile(Output), LO(LO) {}
~SarifDiagnostics() override = default; ~SarifDiagnostics() override = default;
@ -48,7 +46,7 @@ public:
} // end anonymous namespace } // end anonymous namespace
void ento::createSarifDiagnosticConsumer( void ento::createSarifDiagnosticConsumer(
AnalyzerOptions &AnalyzerOpts, PathDiagnosticConsumers &C, PathDiagnosticConsumerOptions DiagOpts, PathDiagnosticConsumers &C,
const std::string &Output, const Preprocessor &PP, const std::string &Output, const Preprocessor &PP,
const cross_tu::CrossTranslationUnitContext &CTU) { const cross_tu::CrossTranslationUnitContext &CTU) {
@ -56,8 +54,9 @@ void ento::createSarifDiagnosticConsumer(
if (Output.empty()) if (Output.empty())
return; return;
C.push_back(new SarifDiagnostics(AnalyzerOpts, Output, PP.getLangOpts())); C.push_back(new SarifDiagnostics(Output, PP.getLangOpts()));
createTextMinimalPathDiagnosticConsumer(AnalyzerOpts, C, Output, PP, CTU); createTextMinimalPathDiagnosticConsumer(std::move(DiagOpts), C, Output, PP,
CTU);
} }
static StringRef getFileName(const FileEntry &FE) { static StringRef getFileName(const FileEntry &FE) {

View File

@ -34,20 +34,17 @@ namespace {
/// type to the standard error, or to to compliment many others. Emits detailed /// type to the standard error, or to to compliment many others. Emits detailed
/// diagnostics in textual format for the 'text' output type. /// diagnostics in textual format for the 'text' output type.
class TextDiagnostics : public PathDiagnosticConsumer { class TextDiagnostics : public PathDiagnosticConsumer {
PathDiagnosticConsumerOptions DiagOpts;
DiagnosticsEngine &DiagEng; DiagnosticsEngine &DiagEng;
const LangOptions &LO; const LangOptions &LO;
const bool IncludePath = false; bool ShouldDisplayPathNotes;
const bool ShouldEmitAsError = false;
const bool ApplyFixIts = false;
const bool ShouldDisplayCheckerName = false;
public: public:
TextDiagnostics(DiagnosticsEngine &DiagEng, const LangOptions &LO, TextDiagnostics(PathDiagnosticConsumerOptions DiagOpts,
bool ShouldIncludePath, const AnalyzerOptions &AnOpts) DiagnosticsEngine &DiagEng, const LangOptions &LO,
: DiagEng(DiagEng), LO(LO), IncludePath(ShouldIncludePath), bool ShouldDisplayPathNotes)
ShouldEmitAsError(AnOpts.AnalyzerWerror), : DiagOpts(std::move(DiagOpts)), DiagEng(DiagEng), LO(LO),
ApplyFixIts(AnOpts.ShouldApplyFixIts), ShouldDisplayPathNotes(ShouldDisplayPathNotes) {}
ShouldDisplayCheckerName(AnOpts.ShouldDisplayCheckerNameForText) {}
~TextDiagnostics() override {} ~TextDiagnostics() override {}
StringRef getName() const override { return "TextDiagnostics"; } StringRef getName() const override { return "TextDiagnostics"; }
@ -56,13 +53,13 @@ public:
bool supportsCrossFileDiagnostics() const override { return true; } bool supportsCrossFileDiagnostics() const override { return true; }
PathGenerationScheme getGenerationScheme() const override { PathGenerationScheme getGenerationScheme() const override {
return IncludePath ? Minimal : None; return ShouldDisplayPathNotes ? Minimal : None;
} }
void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags, void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags,
FilesMade *filesMade) override { FilesMade *filesMade) override {
unsigned WarnID = unsigned WarnID =
ShouldEmitAsError DiagOpts.ShouldDisplayWarningsAsErrors
? DiagEng.getCustomDiagID(DiagnosticsEngine::Error, "%0") ? DiagEng.getCustomDiagID(DiagnosticsEngine::Error, "%0")
: DiagEng.getCustomDiagID(DiagnosticsEngine::Warning, "%0"); : DiagEng.getCustomDiagID(DiagnosticsEngine::Warning, "%0");
unsigned NoteID = DiagEng.getCustomDiagID(DiagnosticsEngine::Note, "%0"); unsigned NoteID = DiagEng.getCustomDiagID(DiagnosticsEngine::Note, "%0");
@ -72,7 +69,7 @@ public:
auto reportPiece = [&](unsigned ID, FullSourceLoc Loc, StringRef String, auto reportPiece = [&](unsigned ID, FullSourceLoc Loc, StringRef String,
ArrayRef<SourceRange> Ranges, ArrayRef<SourceRange> Ranges,
ArrayRef<FixItHint> Fixits) { ArrayRef<FixItHint> Fixits) {
if (!ApplyFixIts) { if (!DiagOpts.ShouldApplyFixIts) {
DiagEng.Report(Loc, ID) << String << Ranges << Fixits; DiagEng.Report(Loc, ID) << String << Ranges << Fixits;
return; return;
} }
@ -92,9 +89,10 @@ public:
E = Diags.end(); E = Diags.end();
I != E; ++I) { I != E; ++I) {
const PathDiagnostic *PD = *I; const PathDiagnostic *PD = *I;
std::string WarningMsg = std::string WarningMsg = (DiagOpts.ShouldDisplayDiagnosticName
(ShouldDisplayCheckerName ? " [" + PD->getCheckerName() + "]" : "") ? " [" + PD->getCheckerName() + "]"
.str(); : "")
.str();
reportPiece(WarnID, PD->getLocation().asLocation(), reportPiece(WarnID, PD->getLocation().asLocation(),
(PD->getShortDescription() + WarningMsg).str(), (PD->getShortDescription() + WarningMsg).str(),
@ -110,7 +108,7 @@ public:
Piece->getFixits()); Piece->getFixits());
} }
if (!IncludePath) if (!ShouldDisplayPathNotes)
continue; continue;
// Then, add the path notes if necessary. // Then, add the path notes if necessary.
@ -125,7 +123,7 @@ public:
} }
} }
if (!ApplyFixIts || Repls.empty()) if (Repls.empty())
return; return;
Rewriter Rewrite(SM, LO); Rewriter Rewrite(SM, LO);
@ -139,18 +137,19 @@ public:
} // end anonymous namespace } // end anonymous namespace
void ento::createTextPathDiagnosticConsumer( void ento::createTextPathDiagnosticConsumer(
AnalyzerOptions &AnalyzerOpts, PathDiagnosticConsumers &C, PathDiagnosticConsumerOptions DiagOpts, PathDiagnosticConsumers &C,
const std::string &Prefix, const clang::Preprocessor &PP, const std::string &Prefix, const clang::Preprocessor &PP,
const cross_tu::CrossTranslationUnitContext &CTU) { const cross_tu::CrossTranslationUnitContext &CTU) {
C.emplace_back(new TextDiagnostics(PP.getDiagnostics(), PP.getLangOpts(), C.emplace_back(new TextDiagnostics(std::move(DiagOpts), PP.getDiagnostics(),
/*ShouldIncludePath*/ true, AnalyzerOpts)); PP.getLangOpts(),
/*ShouldDisplayPathNotes=*/true));
} }
void ento::createTextMinimalPathDiagnosticConsumer( void ento::createTextMinimalPathDiagnosticConsumer(
AnalyzerOptions &AnalyzerOpts, PathDiagnosticConsumers &C, PathDiagnosticConsumerOptions DiagOpts, PathDiagnosticConsumers &C,
const std::string &Prefix, const clang::Preprocessor &PP, const std::string &Prefix, const clang::Preprocessor &PP,
const cross_tu::CrossTranslationUnitContext &CTU) { const cross_tu::CrossTranslationUnitContext &CTU) {
C.emplace_back(new TextDiagnostics(PP.getDiagnostics(), PP.getLangOpts(), C.emplace_back(new TextDiagnostics(std::move(DiagOpts), PP.getDiagnostics(),
/*ShouldIncludePath*/ false, PP.getLangOpts(),
AnalyzerOpts)); /*ShouldDisplayPathNotes=*/false));
} }

View File

@ -150,7 +150,7 @@ public:
break; break;
#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN) \ #define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN) \
case PD_##NAME: \ case PD_##NAME: \
CREATEFN(*Opts.get(), PathConsumers, OutDir, PP, CTU); \ CREATEFN(Opts->getDiagOpts(), PathConsumers, OutDir, PP, CTU); \
break; break;
#include "clang/StaticAnalyzer/Core/Analyses.def" #include "clang/StaticAnalyzer/Core/Analyses.def"
default: default: