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

2024-03-22 Thread Balazs Benics via cfe-commits

https://github.com/steakhal closed 
https://github.com/llvm/llvm-project/pull/84972
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


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

2024-03-22 Thread Balazs Benics via cfe-commits

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

>From f66c62bcf3fd1427ad3f5061ec23110c1c3a5b6e Mon Sep 17 00:00:00 2001
From: Balazs Benics 
Date: Tue, 12 Mar 2024 19:55:29 +0100
Subject: [PATCH] [analyzer] Support C++23 static operator calls

Made by following:
https://github.com/llvm/llvm-project/pull/83585#issuecomment-1980340866

Thanks for the details Tomek!
---
 clang/docs/ReleaseNotes.rst   |  1 +
 .../Core/PathSensitive/CallEvent.h| 72 +++
 clang/lib/StaticAnalyzer/Core/CallEvent.cpp   |  5 +-
 .../Core/ExprEngineCallAndReturn.cpp  |  1 +
 clang/test/Analysis/cxx23-static-operator.cpp | 38 ++
 5 files changed, 116 insertions(+), 1 deletion(-)
 create mode 100644 clang/test/Analysis/cxx23-static-operator.cpp

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index fd12bb41be47a3..45b2e01af997c5 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -576,6 +576,7 @@ Static Analyzer
 - Fixed crashing on loops if the loop variable was declared in switch blocks
   but not under any case blocks if ``unroll-loops=true`` analyzer config is
   set. (#GH68819)
+- Support C++23 static operator calls. (#GH84972)
 
 New features
 
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h 
b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
index 0d36587484bf9c..549c864dc91ef2 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,77 @@ 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) = ::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 CXXOperatorCallExpr *CE, ProgramStateRef St,
+const LocationContext *LCtx,
+CFGBlock::ConstCFGElementRef ElemRef)
+  : SimpleFunctionCall(CE, St, LCtx, ElemRef) {}
+  CXXStaticOperatorCall(const CXXStaticOperatorCall ) = default;
+
+  void cloneTo(void *Dest) const override {
+new (Dest) CXXStaticOperatorCall(*this);
+  }
+
+public:
+  const CXXOperatorCallExpr *getOriginExpr() const override {
+return cast(SimpleFunctionCall::getOriginExpr());
+  }
+
+  unsigned getNumArgs() const override {
+// Ignore the object parameter that is not used for static member 
functions.
+assert(getOriginExpr()->getNumArgs() > 0);
+return getOriginExpr()->getNumArgs() - 1;
+  }
+
+  const Expr *getArgExpr(unsigned Index) const override {
+// Ignore the object parameter that is not used for static member 
functions.
+return getOriginExpr()->getArg(Index + 1);
+  }
+
+  std::optional
+  getAdjustedParameterIndex(unsigned ASTArgumentIndex) const override {
+// Ignore the object parameter that is not used for static member 
functions.
+if (ASTArgumentIndex == 0)
+  return std::nullopt;
+return ASTArgumentIndex - 1;
+  }
+
+  unsigned getASTArgumentIndex(unsigned CallArgumentIndex) const override {
+// Account for the object parameter for the static member function.
+return CallArgumentIndex + 1;
+  }
+
+  OverloadedOperatorKind getOverloadedOperator() const {
+return getOriginExpr()->getOperator();
+  }
+
+  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(CE)) {
 const FunctionDecl *DirectCallee = OpCE->getDirectCallee();
-if (const auto *MD = dyn_cast(DirectCallee))
+if (const auto *MD = dyn_cast(DirectCallee)) {
   if (MD->isImplicitObjectMemberFunction())
 return create(OpCE, State, LCtx, ElemRef);
+  if (MD->isStatic())
+return create(OpCE, 

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

2024-03-13 Thread via cfe-commits

https://github.com/tomasz-kaminski-sonarsource edited 
https://github.com/llvm/llvm-project/pull/84972
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


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

2024-03-13 Thread via cfe-commits


@@ -0,0 +1,36 @@
+// RUN: %clang_analyze_cc1 -std=c++2b -verify %s \
+// RUN:   -analyzer-checker=core,debug.ExprInspection
+
+template  void clang_analyzer_dump(T);
+
+struct Adder {
+  int data;
+  static int operator()(int x, int y) {
+clang_analyzer_dump(x); // expected-warning {{1}}
+clang_analyzer_dump(y); // expected-warning {{2}}
+return x + y;
+  }
+};
+
+void static_operator_call_inlines() {
+  Adder s{10};
+  clang_analyzer_dump(s(1, 2)); // expected-warning {{3}}
+}
+
+struct DataWithCtor {
+  int x;
+  int y;
+  DataWithCtor(int v) : x(v + 10), y(v + 20) {}

tomasz-kaminski-sonarsource wrote:

Could we also dump `this` this to confirm that it is param var regions for 
`operator[]` and we trigger copy elsion?

https://github.com/llvm/llvm-project/pull/84972
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


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

2024-03-13 Thread Balazs Benics via cfe-commits

https://github.com/steakhal edited 
https://github.com/llvm/llvm-project/pull/84972
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


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

2024-03-13 Thread Balazs Benics via cfe-commits

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

>From 9860dad609c8a27dfaa178af5b72285e3ad050fd Mon Sep 17 00:00:00 2001
From: Balazs Benics 
Date: Tue, 12 Mar 2024 19:55:29 +0100
Subject: [PATCH 1/3] [analyzer] Support C++23 static operator calls

Made by following:
https://github.com/llvm/llvm-project/pull/83585#issuecomment-1980340866

Thanks for the details Tomek!
---
 clang/docs/ReleaseNotes.rst   |  2 +
 .../Core/PathSensitive/CallEvent.h| 55 +++
 clang/lib/StaticAnalyzer/Core/CallEvent.cpp   |  5 +-
 .../Core/ExprEngineCallAndReturn.cpp  |  1 +
 clang/test/Analysis/cxx23-static-operator.cpp | 16 ++
 5 files changed, 78 insertions(+), 1 deletion(-)
 create mode 100644 clang/test/Analysis/cxx23-static-operator.cpp

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) = ::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 ) = default;
+
+  void cloneTo(void *Dest) const override {
+new (Dest) CXXStaticOperatorCall(*this);
+  }
+
+public:
+  const CXXOperatorCallExpr *getOriginExpr() const override {
+return cast(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(CE)) {
 const FunctionDecl *DirectCallee = OpCE->getDirectCallee();
-if (const auto *MD = dyn_cast(DirectCallee))
+if (const auto *MD = dyn_cast(DirectCallee)) {
   if (MD->isImplicitObjectMemberFunction())
 return create(OpCE, State, LCtx, ElemRef);
+  if (MD->isStatic())
+return create(OpCE, State, LCtx, ElemRef);
+}
 
   } else if (CE->getCallee()->getType()->isBlockPointerType()) {
 return create(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 , 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 

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

2024-03-13 Thread via cfe-commits

https://github.com/tomasz-kaminski-sonarsource approved this pull request.

Only small change.

https://github.com/llvm/llvm-project/pull/84972
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


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

2024-03-13 Thread via cfe-commits


@@ -709,6 +710,77 @@ 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) = ::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,

tomasz-kaminski-sonarsource wrote:

To guaranteee that cast in `getOriginExpr` is correct.
```suggestion
  CXXStaticOperatorCall(const CXXOperatorCallExpr *CE, ProgramStateRef St,
```

https://github.com/llvm/llvm-project/pull/84972
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


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

2024-03-13 Thread Balazs Benics via cfe-commits

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

>From 9860dad609c8a27dfaa178af5b72285e3ad050fd Mon Sep 17 00:00:00 2001
From: Balazs Benics 
Date: Tue, 12 Mar 2024 19:55:29 +0100
Subject: [PATCH 1/2] [analyzer] Support C++23 static operator calls

Made by following:
https://github.com/llvm/llvm-project/pull/83585#issuecomment-1980340866

Thanks for the details Tomek!
---
 clang/docs/ReleaseNotes.rst   |  2 +
 .../Core/PathSensitive/CallEvent.h| 55 +++
 clang/lib/StaticAnalyzer/Core/CallEvent.cpp   |  5 +-
 .../Core/ExprEngineCallAndReturn.cpp  |  1 +
 clang/test/Analysis/cxx23-static-operator.cpp | 16 ++
 5 files changed, 78 insertions(+), 1 deletion(-)
 create mode 100644 clang/test/Analysis/cxx23-static-operator.cpp

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) = ::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 ) = default;
+
+  void cloneTo(void *Dest) const override {
+new (Dest) CXXStaticOperatorCall(*this);
+  }
+
+public:
+  const CXXOperatorCallExpr *getOriginExpr() const override {
+return cast(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(CE)) {
 const FunctionDecl *DirectCallee = OpCE->getDirectCallee();
-if (const auto *MD = dyn_cast(DirectCallee))
+if (const auto *MD = dyn_cast(DirectCallee)) {
   if (MD->isImplicitObjectMemberFunction())
 return create(OpCE, State, LCtx, ElemRef);
+  if (MD->isStatic())
+return create(OpCE, State, LCtx, ElemRef);
+}
 
   } else if (CE->getCallee()->getType()->isBlockPointerType()) {
 return create(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 , 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 

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

2024-03-13 Thread via cfe-commits


@@ -0,0 +1,16 @@
+// RUN: %clang_analyze_cc1 -std=c++2b -verify %s \
+// RUN:   -analyzer-checker=core,debug.ExprInspection
+
+template  void clang_analyzer_dump(T);

tomasz-kaminski-sonarsource wrote:

To validate the argument indexing is correct (the function I have suggested). 
Could you add example when we construct prvalue of class type as argument:
```c++
struct Clazz {
   int x;
   int y;
   Clazz(int v) : x(v + 10), y(v + 20) {} 
};

struct StaticOp {
static void operator[](Clazz v) {
   clang_analyzer_dump(v.x);
clang_analyzer_dump(v.y);
}
};

StaticOp s;
s[Calzz{10}];
```

https://github.com/llvm/llvm-project/pull/84972
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


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

2024-03-13 Thread via cfe-commits

https://github.com/tomasz-kaminski-sonarsource edited 
https://github.com/llvm/llvm-project/pull/84972
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


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

2024-03-13 Thread via cfe-commits


@@ -0,0 +1,16 @@
+// RUN: %clang_analyze_cc1 -std=c++2b -verify %s \
+// RUN:   -analyzer-checker=core,debug.ExprInspection
+
+template  void clang_analyzer_dump(T);
+
+struct Adder {
+  int data;
+  static int operator()(int x, int y) {
+return x + y;

tomasz-kaminski-sonarsource wrote:

Could you dump values of `x` and `y` from inside the body?

https://github.com/llvm/llvm-project/pull/84972
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


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

2024-03-13 Thread via cfe-commits


@@ -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) = ::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 ) = default;
+
+  void cloneTo(void *Dest) const override {
+new (Dest) CXXStaticOperatorCall(*this);
+  }
+
+public:
+  const CXXOperatorCallExpr *getOriginExpr() const override {
+return cast(SimpleFunctionCall::getOriginExpr());
+  }
+
+  unsigned getNumArgs() const override {
+// Ignore the implicit object parameter.

tomasz-kaminski-sonarsource wrote:

```suggestion
// Ignore the object parameter that is not used for static member functions.
```

https://github.com/llvm/llvm-project/pull/84972
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


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

2024-03-13 Thread via cfe-commits


@@ -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) = ::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 ) = default;
+
+  void cloneTo(void *Dest) const override {
+new (Dest) CXXStaticOperatorCall(*this);
+  }
+
+public:
+  const CXXOperatorCallExpr *getOriginExpr() const override {
+return cast(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
  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(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
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


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

2024-03-12 Thread via cfe-commits

llvmbot wrote:




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

Author: Balazs Benics (steakhal)


Changes

Made by following:
https://github.com/llvm/llvm-project/pull/83585#issuecomment-1980340866

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
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) = ::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 ) = default;
+
+  void cloneTo(void *Dest) const override {
+new (Dest) CXXStaticOperatorCall(*this);
+  }
+
+public:
+  const CXXOperatorCallExpr *getOriginExpr() const override {
+return cast(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(CE)) {
 const FunctionDecl *DirectCallee = OpCE->getDirectCallee();
-if (const auto *MD = dyn_cast(DirectCallee))
+if (const auto *MD = dyn_cast(DirectCallee)) {
   if (MD->isImplicitObjectMemberFunction())
 return create(OpCE, State, LCtx, ElemRef);
+  if (MD->isStatic())
+return create(OpCE, State, LCtx, ElemRef);
+}
 
   } else if (CE->getCallee()->getType()->isBlockPointerType()) {
 return create(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 , 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 00..3c541c336f417a
--- /dev/null
+++ 

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

2024-03-12 Thread Balazs Benics via cfe-commits

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

Made by following:
https://github.com/llvm/llvm-project/pull/83585#issuecomment-1980340866

Thanks for the details Tomek!

>From 9860dad609c8a27dfaa178af5b72285e3ad050fd Mon Sep 17 00:00:00 2001
From: Balazs Benics 
Date: Tue, 12 Mar 2024 19:55:29 +0100
Subject: [PATCH] [analyzer] Support C++23 static operator calls

Made by following:
https://github.com/llvm/llvm-project/pull/83585#issuecomment-1980340866

Thanks for the details Tomek!
---
 clang/docs/ReleaseNotes.rst   |  2 +
 .../Core/PathSensitive/CallEvent.h| 55 +++
 clang/lib/StaticAnalyzer/Core/CallEvent.cpp   |  5 +-
 .../Core/ExprEngineCallAndReturn.cpp  |  1 +
 clang/test/Analysis/cxx23-static-operator.cpp | 16 ++
 5 files changed, 78 insertions(+), 1 deletion(-)
 create mode 100644 clang/test/Analysis/cxx23-static-operator.cpp

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) = ::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 ) = default;
+
+  void cloneTo(void *Dest) const override {
+new (Dest) CXXStaticOperatorCall(*this);
+  }
+
+public:
+  const CXXOperatorCallExpr *getOriginExpr() const override {
+return cast(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(CE)) {
 const FunctionDecl *DirectCallee = OpCE->getDirectCallee();
-if (const auto *MD = dyn_cast(DirectCallee))
+if (const auto *MD = dyn_cast(DirectCallee)) {
   if (MD->isImplicitObjectMemberFunction())
 return create(OpCE, State, LCtx, ElemRef);
+  if (MD->isStatic())
+return create(OpCE, State, LCtx, ElemRef);
+}
 
   } else if (CE->getCallee()->getType()->isBlockPointerType()) {
 return create(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 , const 
ExplodedNode *Pred,
   const StackFrameContext *CallerSFC = CurLC->getStackFrame();
   switch (Call.getKind()) {
   case CE_Function:
+  case CE_CXXStaticOperator:
   case