-
Notifications
You must be signed in to change notification settings - Fork 14.2k
[analyzer] Support C++23 static operator calls #84972
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
Conversation
@llvm/pr-subscribers-clang @llvm/pr-subscribers-clang-static-analyzer-1 Author: Balazs Benics (steakhal) ChangesMade by following: Thanks for the details Tomek! Full diff: https://github.com/llvm/llvm-project/pull/84972.diff 5 Files Affected:
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index e14c92eae0afe1..7629707c122470 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -473,6 +473,8 @@ libclang
Static Analyzer
---------------
+- Support C++23 static operator calls.
+
New features
^^^^^^^^^^^^
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
index 0d36587484bf9c..be6d713f9f55fb 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
@@ -59,6 +59,7 @@ namespace ento {
enum CallEventKind {
CE_Function,
+ CE_CXXStaticOperator,
CE_CXXMember,
CE_CXXMemberOperator,
CE_CXXDestructor,
@@ -709,6 +710,60 @@ class CXXInstanceCall : public AnyFunctionCall {
}
};
+/// Represents a static C++ operator call.
+///
+/// "A" in this example.
+/// However, "B" and "C" are represented by SimpleFunctionCall.
+/// \code
+/// struct S {
+/// int pad;
+/// static void operator()(int x, int y);
+/// };
+/// S s{10};
+/// void (*fptr)(int, int) = &S::operator();
+///
+/// s(1, 2); // A
+/// S::operator()(1, 2); // B
+/// fptr(1, 2); // C
+/// \endcode
+class CXXStaticOperatorCall : public SimpleFunctionCall {
+ friend class CallEventManager;
+
+protected:
+ CXXStaticOperatorCall(const CallExpr *CE, ProgramStateRef St,
+ const LocationContext *LCtx,
+ CFGBlock::ConstCFGElementRef ElemRef)
+ : SimpleFunctionCall(CE, St, LCtx, ElemRef) {}
+ CXXStaticOperatorCall(const CXXStaticOperatorCall &Other) = default;
+
+ void cloneTo(void *Dest) const override {
+ new (Dest) CXXStaticOperatorCall(*this);
+ }
+
+public:
+ const CXXOperatorCallExpr *getOriginExpr() const override {
+ return cast<CXXOperatorCallExpr>(SimpleFunctionCall::getOriginExpr());
+ }
+
+ unsigned getNumArgs() const override {
+ // Ignore the implicit object parameter.
+ assert(getOriginExpr()->getNumArgs() > 0);
+ return getOriginExpr()->getNumArgs() - 1;
+ }
+
+ const Expr *getArgExpr(unsigned Index) const override {
+ // Ignore the implicit object parameter.
+ return getOriginExpr()->getArg(Index + 1);
+ }
+
+ Kind getKind() const override { return CE_CXXStaticOperator; }
+ StringRef getKindAsString() const override { return "CXXStaticOperatorCall"; }
+
+ static bool classof(const CallEvent *CA) {
+ return CA->getKind() == CE_CXXStaticOperator;
+ }
+};
+
/// Represents a non-static C++ member function call.
///
/// Example: \c obj.fun()
diff --git a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
index bc14aea27f6736..0e317ec765ec09 100644
--- a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
+++ b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
@@ -1408,9 +1408,12 @@ CallEventManager::getSimpleCall(const CallExpr *CE, ProgramStateRef State,
if (const auto *OpCE = dyn_cast<CXXOperatorCallExpr>(CE)) {
const FunctionDecl *DirectCallee = OpCE->getDirectCallee();
- if (const auto *MD = dyn_cast<CXXMethodDecl>(DirectCallee))
+ if (const auto *MD = dyn_cast<CXXMethodDecl>(DirectCallee)) {
if (MD->isImplicitObjectMemberFunction())
return create<CXXMemberOperatorCall>(OpCE, State, LCtx, ElemRef);
+ if (MD->isStatic())
+ return create<CXXStaticOperatorCall>(OpCE, State, LCtx, ElemRef);
+ }
} else if (CE->getCallee()->getType()->isBlockPointerType()) {
return create<BlockCall>(CE, State, LCtx, ElemRef);
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
index 4755b6bfa6dc0a..9d3e4fc944fb7b 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
@@ -846,6 +846,7 @@ ExprEngine::mayInlineCallKind(const CallEvent &Call, const ExplodedNode *Pred,
const StackFrameContext *CallerSFC = CurLC->getStackFrame();
switch (Call.getKind()) {
case CE_Function:
+ case CE_CXXStaticOperator:
case CE_Block:
break;
case CE_CXXMember:
diff --git a/clang/test/Analysis/cxx23-static-operator.cpp b/clang/test/Analysis/cxx23-static-operator.cpp
new file mode 100644
index 00000000000000..3c541c336f417a
--- /dev/null
+++ b/clang/test/Analysis/cxx23-static-operator.cpp
@@ -0,0 +1,16 @@
+// RUN: %clang_analyze_cc1 -std=c++2b -verify %s \
+// RUN: -analyzer-checker=core,debug.ExprInspection
+
+template <typename T> void clang_analyzer_dump(T);
+
+struct Adder {
+ int data;
+ static int operator()(int x, int y) {
+ return x + y;
+ }
+};
+
+void static_operator_call_inlines() {
+ Adder s{10};
+ clang_analyzer_dump(s(1, 2)); // expected-warning {{3 S32b}}
+}
|
clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
Outdated
Show resolved
Hide resolved
clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Only small change.
Made by following: #83585 (comment) Thanks for the details Tomek!
Made by following: llvm#83585 (comment) Thanks for the details Tomek! CPP-5080
Made by following:
#83585 (comment)
Thanks for the details Tomek!
CPP-5080