diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp index 977deb3182debf..19c85352a6144c 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -2057,11 +2057,17 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, llvm_unreachable("Support for MatrixSubscriptExpr is not implemented."); break; - case Stmt::GCCAsmStmtClass: + case Stmt::GCCAsmStmtClass: { Bldr.takeNodes(Pred); - VisitGCCAsmStmt(cast(S), Pred, Dst); + ExplodedNodeSet PreVisit; + getCheckerManager().runCheckersForPreStmt(PreVisit, Pred, S, *this); + ExplodedNodeSet PostVisit; + for (ExplodedNode *const N : PreVisit) + VisitGCCAsmStmt(cast(S), N, PostVisit); + getCheckerManager().runCheckersForPostStmt(Dst, PostVisit, S, *this); Bldr.addNodes(Dst); break; + } case Stmt::MSAsmStmtClass: Bldr.takeNodes(Pred); diff --git a/clang/unittests/StaticAnalyzer/CMakeLists.txt b/clang/unittests/StaticAnalyzer/CMakeLists.txt index dcc557b44fb315..5ef72cfaea4011 100644 --- a/clang/unittests/StaticAnalyzer/CMakeLists.txt +++ b/clang/unittests/StaticAnalyzer/CMakeLists.txt @@ -10,6 +10,7 @@ add_clang_unittest(StaticAnalysisTests CallDescriptionTest.cpp CallEventTest.cpp ConflictingEvalCallsTest.cpp + ExprEngineVisitTest.cpp FalsePositiveRefutationBRVisitorTest.cpp IsCLibraryFunctionTest.cpp MemRegionDescriptiveNameTest.cpp diff --git a/clang/unittests/StaticAnalyzer/ExprEngineVisitTest.cpp b/clang/unittests/StaticAnalyzer/ExprEngineVisitTest.cpp new file mode 100644 index 00000000000000..a8579f9d0f90cc --- /dev/null +++ b/clang/unittests/StaticAnalyzer/ExprEngineVisitTest.cpp @@ -0,0 +1,87 @@ +//===- ExprEngineVisitTest.cpp --------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "CheckerRegistration.h" +#include "clang/AST/Stmt.h" +#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" +#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" +#include "clang/StaticAnalyzer/Core/Checker.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" +#include "gtest/gtest.h" + +using namespace clang; +using namespace ento; + +namespace { + +void emitErrorReport(CheckerContext &C, const BugType &Bug, + const std::string &Desc) { + if (ExplodedNode *Node = C.generateNonFatalErrorNode(C.getState())) { + auto Report = std::make_unique(Bug, Desc, Node); + C.emitReport(std::move(Report)); + } +} + +#define CREATE_EXPR_ENGINE_CHECKER(CHECKER_NAME, CALLBACK, STMT_TYPE, \ + BUG_NAME) \ + class CHECKER_NAME : public Checker> { \ + public: \ + void check##CALLBACK(const STMT_TYPE *ASM, CheckerContext &C) const { \ + emitErrorReport(C, Bug, "check" #CALLBACK "<" #STMT_TYPE ">"); \ + } \ + \ + private: \ + const BugType Bug{this, BUG_NAME}; \ + }; + +CREATE_EXPR_ENGINE_CHECKER(ExprEngineVisitPreChecker, PreStmt, GCCAsmStmt, + "GCCAsmStmtBug") +CREATE_EXPR_ENGINE_CHECKER(ExprEngineVisitPostChecker, PostStmt, GCCAsmStmt, + "GCCAsmStmtBug") + +void addExprEngineVisitPreChecker(AnalysisASTConsumer &AnalysisConsumer, + AnalyzerOptions &AnOpts) { + AnOpts.CheckersAndPackages = {{"ExprEngineVisitPreChecker", true}}; + AnalysisConsumer.AddCheckerRegistrationFn([](CheckerRegistry &Registry) { + Registry.addChecker("ExprEngineVisitPreChecker", + "Desc", "DocsURI"); + }); +} + +void addExprEngineVisitPostChecker(AnalysisASTConsumer &AnalysisConsumer, + AnalyzerOptions &AnOpts) { + AnOpts.CheckersAndPackages = {{"ExprEngineVisitPostChecker", true}}; + AnalysisConsumer.AddCheckerRegistrationFn([](CheckerRegistry &Registry) { + Registry.addChecker( + "ExprEngineVisitPostChecker", "Desc", "DocsURI"); + }); +} + +TEST(ExprEngineVisitTest, checkPreStmtGCCAsmStmt) { + std::string Diags; + EXPECT_TRUE(runCheckerOnCode(R"( + void top() { + asm(""); + } + )", + Diags)); + EXPECT_EQ(Diags, "ExprEngineVisitPreChecker: checkPreStmt\n"); +} + +TEST(ExprEngineVisitTest, checkPostStmtGCCAsmStmt) { + std::string Diags; + EXPECT_TRUE(runCheckerOnCode(R"( + void top() { + asm(""); + } + )", + Diags)); + EXPECT_EQ(Diags, "ExprEngineVisitPostChecker: checkPostStmt\n"); +} + +} // namespace