Skip to content

[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

Merged
merged 1 commit into from
Mar 22, 2024
Merged

[analyzer] Support C++23 static operator calls #84972

merged 1 commit into from
Mar 22, 2024

Conversation

steakhal
Copy link
Contributor

@steakhal steakhal commented Mar 12, 2024

Made by following:
#83585 (comment)

Thanks for the details Tomek!

CPP-5080

@llvmbot llvmbot added the clang Clang issues not falling into any other category label Mar 12, 2024
@llvmbot
Copy link
Member

llvmbot commented Mar 12, 2024

@llvm/pr-subscribers-clang

@llvm/pr-subscribers-clang-static-analyzer-1

Author: Balazs Benics (steakhal)

Changes

Made by following:
#83585 (comment)

Thanks for the details Tomek!


Full diff: https://github.com/llvm/llvm-project/pull/84972.diff

5 Files Affected:

  • (modified) clang/docs/ReleaseNotes.rst (+2)
  • (modified) clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h (+55)
  • (modified) clang/lib/StaticAnalyzer/Core/CallEvent.cpp (+4-1)
  • (modified) clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp (+1)
  • (added) clang/test/Analysis/cxx23-static-operator.cpp (+16)
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}}
+}

Copy link
Contributor

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!
@steakhal steakhal merged commit e925968 into llvm:main Mar 22, 2024
@steakhal steakhal deleted the bb/csa-support-cxx23-static-operators branch March 22, 2024 11:04
chencha3 pushed a commit to chencha3/llvm-project that referenced this pull request Mar 23, 2024
Made by following:
llvm#83585 (comment)

Thanks for the details Tomek!

CPP-5080
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:static analyzer clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants