-
Notifications
You must be signed in to change notification settings - Fork 14.3k
Reapply "[analyzer] Delay the checker constructions after parsing" #128369
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Reapply "[analyzer] Delay the checker constructions after parsing" #128369
Conversation
@llvm/pr-subscribers-clang @llvm/pr-subscribers-clang-static-analyzer-1 Author: Balazs Benics (steakhal) ChangesReapply "[analyzer] Delay the checker constructions after parsing" (#128350) This reverts commit db836ed, as-is. Depends on #128368 Patch is 27.75 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/128369.diff 16 Files Affected:
diff --git a/clang/include/clang/Analysis/AnalysisDeclContext.h b/clang/include/clang/Analysis/AnalysisDeclContext.h
index a517a4e757c9f..ced4bb8595bea 100644
--- a/clang/include/clang/Analysis/AnalysisDeclContext.h
+++ b/clang/include/clang/Analysis/AnalysisDeclContext.h
@@ -451,7 +451,7 @@ class AnalysisDeclContextManager {
bool synthesizeBodies = false, bool addStaticInitBranches = false,
bool addCXXNewAllocator = true, bool addRichCXXConstructors = true,
bool markElidedCXXConstructors = true, bool addVirtualBaseBranches = true,
- CodeInjector *injector = nullptr);
+ std::unique_ptr<CodeInjector> injector = nullptr);
AnalysisDeclContext *getContext(const Decl *D);
diff --git a/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h b/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h
index 7563d8bbd1d27..8e1d25b3eefa1 100644
--- a/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h
+++ b/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h
@@ -570,7 +570,8 @@ class BugReporterData {
public:
virtual ~BugReporterData() = default;
- virtual ArrayRef<PathDiagnosticConsumer*> getPathDiagnosticConsumers() = 0;
+ virtual ArrayRef<std::unique_ptr<PathDiagnosticConsumer>>
+ getPathDiagnosticConsumers() = 0;
virtual ASTContext &getASTContext() = 0;
virtual SourceManager &getSourceManager() = 0;
virtual AnalyzerOptions &getAnalyzerOptions() = 0;
@@ -608,7 +609,8 @@ class BugReporter {
/// Generate and flush diagnostics for all bug reports.
void FlushReports();
- ArrayRef<PathDiagnosticConsumer*> getPathDiagnosticConsumers() {
+ ArrayRef<std::unique_ptr<PathDiagnosticConsumer>>
+ getPathDiagnosticConsumers() {
return D.getPathDiagnosticConsumers();
}
@@ -670,9 +672,10 @@ class BugReporter {
protected:
/// Generate the diagnostics for the given bug report.
virtual std::unique_ptr<DiagnosticForConsumerMapTy>
- generateDiagnosticForConsumerMap(BugReport *exampleReport,
- ArrayRef<PathDiagnosticConsumer *> consumers,
- ArrayRef<BugReport *> bugReports);
+ generateDiagnosticForConsumerMap(
+ BugReport *exampleReport,
+ ArrayRef<std::unique_ptr<PathDiagnosticConsumer>> consumers,
+ ArrayRef<BugReport *> bugReports);
};
/// GRBugReporter is used for generating path-sensitive reports.
@@ -684,10 +687,11 @@ class PathSensitiveBugReporter final : public BugReporter {
SmallVectorImpl<BugReport *> &bugReports) override;
/// Generate the diagnostics for the given bug report.
- std::unique_ptr<DiagnosticForConsumerMapTy>
- generateDiagnosticForConsumerMap(BugReport *exampleReport,
- ArrayRef<PathDiagnosticConsumer *> consumers,
- ArrayRef<BugReport *> bugReports) override;
+ std::unique_ptr<DiagnosticForConsumerMapTy> generateDiagnosticForConsumerMap(
+ BugReport *exampleReport,
+ ArrayRef<std::unique_ptr<PathDiagnosticConsumer>> consumers,
+ ArrayRef<BugReport *> bugReports) override;
+
public:
PathSensitiveBugReporter(BugReporterData& d, ExprEngine& eng)
: BugReporter(d), Eng(eng) {}
@@ -706,7 +710,7 @@ class PathSensitiveBugReporter final : public BugReporter {
/// Iterates through the bug reports within a single equivalence class,
/// stops at a first non-invalidated report.
std::unique_ptr<DiagnosticForConsumerMapTy> generatePathDiagnostics(
- ArrayRef<PathDiagnosticConsumer *> consumers,
+ ArrayRef<std::unique_ptr<PathDiagnosticConsumer>> consumers,
ArrayRef<PathSensitiveBugReport *> &bugReports);
void emitReport(std::unique_ptr<BugReport> R) override;
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h b/clang/include/clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h
index 88a9d76f24887..9fafd6acaa2ac 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h
@@ -30,7 +30,8 @@ class CrossTranslationUnitContext;
namespace ento {
class PathDiagnosticConsumer;
-typedef std::vector<PathDiagnosticConsumer*> PathDiagnosticConsumers;
+using PathDiagnosticConsumers =
+ std::vector<std::unique_ptr<PathDiagnosticConsumer>>;
#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN) \
void CREATEFN(PathDiagnosticConsumerOptions Diagopts, \
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h
index c76e9c0326afe..e3cf1bac83ad0 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h
@@ -47,11 +47,11 @@ class AnalysisManager : public BugReporterData {
AnalyzerOptions &options;
AnalysisManager(ASTContext &ctx, Preprocessor &PP,
- const PathDiagnosticConsumers &Consumers,
+ PathDiagnosticConsumers Consumers,
StoreManagerCreator storemgr,
ConstraintManagerCreator constraintmgr,
CheckerManager *checkerMgr, AnalyzerOptions &Options,
- CodeInjector *injector = nullptr);
+ std::unique_ptr<CodeInjector> injector = nullptr);
~AnalysisManager() override;
@@ -91,7 +91,8 @@ class AnalysisManager : public BugReporterData {
return LangOpts;
}
- ArrayRef<PathDiagnosticConsumer*> getPathDiagnosticConsumers() override {
+ ArrayRef<std::unique_ptr<PathDiagnosticConsumer>>
+ getPathDiagnosticConsumers() override {
return PathConsumers;
}
diff --git a/clang/include/clang/StaticAnalyzer/Frontend/AnalysisConsumer.h b/clang/include/clang/StaticAnalyzer/Frontend/AnalysisConsumer.h
index f3b1c1f206459..2163d66466c1c 100644
--- a/clang/include/clang/StaticAnalyzer/Frontend/AnalysisConsumer.h
+++ b/clang/include/clang/StaticAnalyzer/Frontend/AnalysisConsumer.h
@@ -29,7 +29,8 @@ class CheckerRegistry;
class AnalysisASTConsumer : public ASTConsumer {
public:
- virtual void AddDiagnosticConsumer(PathDiagnosticConsumer *Consumer) = 0;
+ virtual void
+ AddDiagnosticConsumer(std::unique_ptr<PathDiagnosticConsumer> Consumer) = 0;
/// This method allows registering statically linked custom checkers that are
/// not a part of the Clang tree. It employs the same mechanism that is used
diff --git a/clang/lib/Analysis/AnalysisDeclContext.cpp b/clang/lib/Analysis/AnalysisDeclContext.cpp
index d3a1a993711fb..d0b663bd94580 100644
--- a/clang/lib/Analysis/AnalysisDeclContext.cpp
+++ b/clang/lib/Analysis/AnalysisDeclContext.cpp
@@ -71,8 +71,8 @@ AnalysisDeclContextManager::AnalysisDeclContextManager(
bool addLoopExit, bool addScopes, bool synthesizeBodies,
bool addStaticInitBranch, bool addCXXNewAllocator,
bool addRichCXXConstructors, bool markElidedCXXConstructors,
- bool addVirtualBaseBranches, CodeInjector *injector)
- : Injector(injector), FunctionBodyFarm(ASTCtx, injector),
+ bool addVirtualBaseBranches, std::unique_ptr<CodeInjector> injector)
+ : Injector(std::move(injector)), FunctionBodyFarm(ASTCtx, Injector.get()),
SynthesizeBodies(synthesizeBodies) {
cfgBuildOptions.PruneTriviallyFalseEdges = !useUnoptimizedCFG;
cfgBuildOptions.AddImplicitDtors = addImplicitDtors;
diff --git a/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
index da2d16ca9b5dd..10dfa73cc522d 100644
--- a/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
@@ -40,17 +40,28 @@ enum class OpenVariant {
OpenAt
};
+static std::optional<int> getCreateFlagValue(const ASTContext &Ctx,
+ const Preprocessor &PP) {
+ std::optional<int> MacroVal = tryExpandAsInteger("O_CREAT", PP);
+ if (MacroVal.has_value())
+ return MacroVal;
+
+ // If we failed, fall-back to known values.
+ if (Ctx.getTargetInfo().getTriple().getVendor() == llvm::Triple::Apple)
+ return {0x0200};
+ return MacroVal;
+}
+
namespace {
-class UnixAPIMisuseChecker
- : public Checker<check::PreCall, check::ASTDecl<TranslationUnitDecl>> {
+class UnixAPIMisuseChecker : public Checker<check::PreCall> {
const BugType BT_open{this, "Improper use of 'open'", categories::UnixAPI};
const BugType BT_getline{this, "Improper use of getdelim",
categories::UnixAPI};
const BugType BT_pthreadOnce{this, "Improper use of 'pthread_once'",
categories::UnixAPI};
const BugType BT_ArgumentNull{this, "NULL pointer", categories::UnixAPI};
- mutable std::optional<uint64_t> Val_O_CREAT;
+ const std::optional<int> Val_O_CREAT;
ProgramStateRef
EnsurePtrNotNull(SVal PtrVal, const Expr *PtrExpr, CheckerContext &C,
@@ -63,6 +74,9 @@ class UnixAPIMisuseChecker
const Expr *SizePtrExpr, CheckerContext &C, ProgramStateRef State) const;
public:
+ UnixAPIMisuseChecker(const ASTContext &Ctx, const Preprocessor &PP)
+ : Val_O_CREAT(getCreateFlagValue(Ctx, PP)) {}
+
void checkASTDecl(const TranslationUnitDecl *TU, AnalysisManager &Mgr,
BugReporter &BR) const;
@@ -134,20 +148,6 @@ ProgramStateRef UnixAPIMisuseChecker::EnsurePtrNotNull(
return PtrNotNull;
}
-void UnixAPIMisuseChecker::checkASTDecl(const TranslationUnitDecl *TU,
- AnalysisManager &Mgr,
- BugReporter &) const {
- // The definition of O_CREAT is platform specific.
- // Try to get the macro value from the preprocessor.
- Val_O_CREAT = tryExpandAsInteger("O_CREAT", Mgr.getPreprocessor());
- // If we failed, fall-back to known values.
- if (!Val_O_CREAT) {
- if (TU->getASTContext().getTargetInfo().getTriple().getVendor() ==
- llvm::Triple::Apple)
- Val_O_CREAT = 0x0200;
- }
-}
-
//===----------------------------------------------------------------------===//
// "open" (man 2 open)
//===----------------------------------------------------------------------===/
@@ -262,7 +262,7 @@ void UnixAPIMisuseChecker::CheckOpenVariant(CheckerContext &C,
return;
}
- if (!Val_O_CREAT) {
+ if (!Val_O_CREAT.has_value()) {
return;
}
@@ -276,7 +276,7 @@ void UnixAPIMisuseChecker::CheckOpenVariant(CheckerContext &C,
}
NonLoc oflags = V.castAs<NonLoc>();
NonLoc ocreateFlag = C.getSValBuilder()
- .makeIntVal(*Val_O_CREAT, oflagsEx->getType())
+ .makeIntVal(Val_O_CREAT.value(), oflagsEx->getType())
.castAs<NonLoc>();
SVal maskedFlagsUC = C.getSValBuilder().evalBinOpNN(state, BO_And,
oflags, ocreateFlag,
@@ -621,14 +621,17 @@ void UnixAPIPortabilityChecker::checkPreStmt(const CallExpr *CE,
// Registration.
//===----------------------------------------------------------------------===//
-#define REGISTER_CHECKER(CHECKERNAME) \
- void ento::register##CHECKERNAME(CheckerManager &mgr) { \
- mgr.registerChecker<CHECKERNAME>(); \
- } \
- \
- bool ento::shouldRegister##CHECKERNAME(const CheckerManager &mgr) { \
- return true; \
- }
+void ento::registerUnixAPIMisuseChecker(CheckerManager &Mgr) {
+ Mgr.registerChecker<UnixAPIMisuseChecker>(Mgr.getASTContext(),
+ Mgr.getPreprocessor());
+}
+bool ento::shouldRegisterUnixAPIMisuseChecker(const CheckerManager &Mgr) {
+ return true;
+}
-REGISTER_CHECKER(UnixAPIMisuseChecker)
-REGISTER_CHECKER(UnixAPIPortabilityChecker)
+void ento::registerUnixAPIPortabilityChecker(CheckerManager &Mgr) {
+ Mgr.registerChecker<UnixAPIPortabilityChecker>();
+}
+bool ento::shouldRegisterUnixAPIPortabilityChecker(const CheckerManager &Mgr) {
+ return true;
+}
diff --git a/clang/lib/StaticAnalyzer/Core/AnalysisManager.cpp b/clang/lib/StaticAnalyzer/Core/AnalysisManager.cpp
index f9750db7b5017..8a16716f951b8 100644
--- a/clang/lib/StaticAnalyzer/Core/AnalysisManager.cpp
+++ b/clang/lib/StaticAnalyzer/Core/AnalysisManager.cpp
@@ -14,32 +14,28 @@ using namespace ento;
void AnalysisManager::anchor() { }
AnalysisManager::AnalysisManager(ASTContext &ASTCtx, Preprocessor &PP,
- const PathDiagnosticConsumers &PDC,
+ PathDiagnosticConsumers PDC,
StoreManagerCreator storemgr,
ConstraintManagerCreator constraintmgr,
CheckerManager *checkerMgr,
AnalyzerOptions &Options,
- CodeInjector *injector)
+ std::unique_ptr<CodeInjector> injector)
: AnaCtxMgr(
ASTCtx, Options.UnoptimizedCFG,
Options.ShouldIncludeImplicitDtorsInCFG,
- /*addInitializers=*/true,
- Options.ShouldIncludeTemporaryDtorsInCFG,
+ /*addInitializers=*/true, Options.ShouldIncludeTemporaryDtorsInCFG,
Options.ShouldIncludeLifetimeInCFG,
// Adding LoopExit elements to the CFG is a requirement for loop
// unrolling.
- Options.ShouldIncludeLoopExitInCFG ||
- Options.ShouldUnrollLoops,
- Options.ShouldIncludeScopesInCFG,
- Options.ShouldSynthesizeBodies,
+ Options.ShouldIncludeLoopExitInCFG || Options.ShouldUnrollLoops,
+ Options.ShouldIncludeScopesInCFG, Options.ShouldSynthesizeBodies,
Options.ShouldConditionalizeStaticInitializers,
/*addCXXNewAllocator=*/true,
Options.ShouldIncludeRichConstructorsInCFG,
Options.ShouldElideConstructors,
- /*addVirtualBaseBranches=*/true,
- injector),
+ /*addVirtualBaseBranches=*/true, std::move(injector)),
Ctx(ASTCtx), PP(PP), LangOpts(ASTCtx.getLangOpts()),
- PathConsumers(PDC), CreateStoreMgr(storemgr),
+ PathConsumers(std::move(PDC)), CreateStoreMgr(storemgr),
CreateConstraintMgr(constraintmgr), CheckerMgr(checkerMgr),
options(Options) {
AnaCtxMgr.getCFGBuildOptions().setAllAlwaysAdd();
@@ -50,14 +46,11 @@ AnalysisManager::AnalysisManager(ASTContext &ASTCtx, Preprocessor &PP,
AnalysisManager::~AnalysisManager() {
FlushDiagnostics();
- for (PathDiagnosticConsumer *Consumer : PathConsumers) {
- delete Consumer;
- }
}
void AnalysisManager::FlushDiagnostics() {
PathDiagnosticConsumer::FilesMade filesMade;
- for (PathDiagnosticConsumer *Consumer : PathConsumers) {
+ for (const auto &Consumer : PathConsumers) {
Consumer->FlushDiagnostics(&filesMade);
}
}
diff --git a/clang/lib/StaticAnalyzer/Core/BugReporter.cpp b/clang/lib/StaticAnalyzer/Core/BugReporter.cpp
index 13677ed341d0c..7101b1eb2c7f5 100644
--- a/clang/lib/StaticAnalyzer/Core/BugReporter.cpp
+++ b/clang/lib/StaticAnalyzer/Core/BugReporter.cpp
@@ -2958,7 +2958,7 @@ std::optional<PathDiagnosticBuilder> PathDiagnosticBuilder::findValidReport(
std::unique_ptr<DiagnosticForConsumerMapTy>
PathSensitiveBugReporter::generatePathDiagnostics(
- ArrayRef<PathDiagnosticConsumer *> consumers,
+ ArrayRef<std::unique_ptr<PathDiagnosticConsumer>> consumers,
ArrayRef<PathSensitiveBugReport *> &bugReports) {
assert(!bugReports.empty());
@@ -2968,9 +2968,9 @@ PathSensitiveBugReporter::generatePathDiagnostics(
PathDiagnosticBuilder::findValidReport(bugReports, *this);
if (PDB) {
- for (PathDiagnosticConsumer *PC : consumers) {
- if (std::unique_ptr<PathDiagnostic> PD = PDB->generate(PC)) {
- (*Out)[PC] = std::move(PD);
+ for (const auto &PC : consumers) {
+ if (std::unique_ptr<PathDiagnostic> PD = PDB->generate(PC.get())) {
+ (*Out)[PC.get()] = std::move(PD);
}
}
}
@@ -3164,7 +3164,7 @@ void BugReporter::FlushReport(BugReportEquivClass &EQ) {
return;
}
- ArrayRef<PathDiagnosticConsumer*> Consumers = getPathDiagnosticConsumers();
+ ArrayRef Consumers = getPathDiagnosticConsumers();
std::unique_ptr<DiagnosticForConsumerMapTy> Diagnostics =
generateDiagnosticForConsumerMap(report, Consumers, bugReports);
@@ -3298,12 +3298,13 @@ findExecutedLines(const SourceManager &SM, const ExplodedNode *N) {
std::unique_ptr<DiagnosticForConsumerMapTy>
BugReporter::generateDiagnosticForConsumerMap(
- BugReport *exampleReport, ArrayRef<PathDiagnosticConsumer *> consumers,
+ BugReport *exampleReport,
+ ArrayRef<std::unique_ptr<PathDiagnosticConsumer>> consumers,
ArrayRef<BugReport *> bugReports) {
auto *basicReport = cast<BasicBugReport>(exampleReport);
auto Out = std::make_unique<DiagnosticForConsumerMapTy>();
- for (auto *Consumer : consumers)
- (*Out)[Consumer] =
+ for (const auto &Consumer : consumers)
+ (*Out)[Consumer.get()] =
generateDiagnosticForBasicReport(basicReport, AnalysisEntryPoint);
return Out;
}
@@ -3371,11 +3372,10 @@ static void resetDiagnosticLocationToMainFile(PathDiagnostic &PD) {
}
}
-
-
std::unique_ptr<DiagnosticForConsumerMapTy>
PathSensitiveBugReporter::generateDiagnosticForConsumerMap(
- BugReport *exampleReport, ArrayRef<PathDiagnosticConsumer *> consumers,
+ BugReport *exampleReport,
+ ArrayRef<std::unique_ptr<PathDiagnosticConsumer>> consumers,
ArrayRef<BugReport *> bugReports) {
std::vector<BasicBugReport *> BasicBugReports;
std::vector<PathSensitiveBugReport *> PathSensitiveBugReports;
diff --git a/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp b/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp
index 5c0df8808c272..21d99a359ca80 100644
--- a/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp
+++ b/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp
@@ -193,7 +193,8 @@ void ento::createHTMLDiagnosticConsumer(
if (OutputDir.empty())
return;
- C.push_back(new HTMLDiagnostics(std::move(DiagOpts), OutputDir, PP, true));
+ C.emplace_back(std::make_unique<HTMLDiagnostics>(std::move(DiagOpts),
+ OutputDir, PP, true));
}
void ento::createHTMLSingleFileDiagnosticConsumer(
@@ -208,7 +209,8 @@ void ento::createHTMLSingleFileDiagnosticConsumer(
if (OutputDir.empty())
return;
- C.push_back(new HTMLDiagnostics(std::move(DiagOpts), OutputDir, PP, false));
+ C.emplace_back(std::make_unique<HTMLDiagnostics>(std::move(DiagOpts),
+ OutputDir, PP, false));
}
void ento::createPlistHTMLDiagnosticConsumer(
diff --git a/clang/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp b/clang/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp
index d806d970acf8d..2ab248f9aa6d9 100644
--- a/clang/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp
+++ b/clang/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp
@@ -541,9 +541,9 @@ void ento::createPlistDiagnosticConsumer(
if (OutputFile.empty())
return;
- C.push_back(new PlistDiagnostics(DiagOpts, OutputFile, PP, CTU,
- MacroExpansions,
- /*supportsMultipleFiles=*/false));
+ C.push_back(std::make_unique<PlistDiagnostics>(
+ DiagOpts, OutputFile, PP, CTU, MacroExpansions,
+ /*supportsMultipleFiles=*/false));
createTextMinimalPathDiagnosticConsumer(std::move(DiagOpts), C, OutputFile,
PP, CTU, MacroExpansions);
}
@@ -558,9 +558,9 @@ void ento::createPlistMultiFileDiagnosticConsumer(
if (OutputFile.empty())
return;
- C.push_back(new PlistDiagnostics(DiagOpts, OutputFile, PP, CTU,
- MacroExpansions,
- /*supportsMultipleFiles=*/true));
+ C.push_back(std::make_unique<PlistDiagnostics>(
+ DiagOpts, OutputFile, PP, CTU, MacroExpansions,
+ /*supportsMultipleFiles=*/true));
createTextMinimalPathDiagnosticConsumer(std::move(DiagOpts), C, Ou...
[truncated]
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
…lvm#128350) This reverts commit db836ed.
ea932d9
to
ca3c1fb
Compare
Ping @Xazax-hun @NagyDonat |
Thank you for the review! |
Reapply "[analyzer] Delay the checker constructions after parsing" (#128350)
This reverts commit db836ed, as-is.
Depends on #128368