[clang] [analyzer] Support C++23 static operator calls (PR #84972)

via cfe-commits cfe-commits at lists.llvm.org
Tue Mar 12 23:45:20 PDT 2024


================
@@ -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;
+  }
+};
----------------
tomasz-kaminski-sonarsource wrote:

Could you please add the following function.
I believe we should override first two to match the semantic described in `CallEvent`, because arguments include object argument, that do not have corresponding parameter.
Last is just for consistency.
```
 std::optional<unsigned>
  getAdjustedParameterIndex(unsigned ASTArgumentIndex) const override {
    // For member operator calls argument 0 on the expression corresponds
    // to implicit this-parameter on the declaration.
    return (ASTArgumentIndex > 0)
               ? std::optional<unsigned>(ASTArgumentIndex - 1)
               : std::nullopt;
  }

  unsigned getASTArgumentIndex(unsigned CallArgumentIndex) const override {
    // For member operator calls argument 0 on the expression corresponds
    // to implicit this-parameter on the declaration.
    return CallArgumentIndex + 1;
  }

  OverloadedOperatorKind getOverloadedOperator() const {
    return getOriginExpr()->getOperator();
  }
```

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


More information about the cfe-commits mailing list