[clang] 476a497 - Add clang_CXXMethod_isCopyAssignmentOperator to libclang

Luca Di Sera via cfe-commits cfe-commits at lists.llvm.org
Wed Oct 26 21:55:30 PDT 2022


Author: Luca Di Sera
Date: 2022-10-27T06:55:11+02:00
New Revision: 476a497f729a408ba436f75fc50a41254ce65bc8

URL: https://github.com/llvm/llvm-project/commit/476a497f729a408ba436f75fc50a41254ce65bc8
DIFF: https://github.com/llvm/llvm-project/commit/476a497f729a408ba436f75fc50a41254ce65bc8.diff

LOG: Add clang_CXXMethod_isCopyAssignmentOperator to libclang

The new method is a wrapper of `CXXMethodDecl::isCopyAssignmentOperator` and
can be used to recognized copy-assignment operators in libclang.

An export for the method, together with its documentation, was added to
"clang/include/clang-c/Index.h" with an implementation provided in
"clang/tools/libclang/CIndex.cpp". The implementation was based on
similar `clang_CXXMethod.*` implementations, following the same
structure but calling `CXXMethodDecl::isCopyAssignmentOperator` for its
main logic.

The new symbol was further added to "clang/tools/libclang/libclang.map"
to be exported, under the LLVM16 tag.

"clang/tools/c-index-test/c-index-test.c" was modified to print a
specific tag, "(copy-assignment operator)", for cursors that are
recognized by `clang_CXXMethod_isCopyAssignmentOperator`.
A new regression test file,
"clang/test/Index/copy-assignment-operator.cpp", was added to ensure
that the correct constructs were recognized or not by the new function.

The "clang/test/Index/get-cursor.cpp" regression test file was updated
as it was affected by the new "(copy-assignment operator)" tag.

A binding for the new function was added to libclang's python's
bindings, in "clang/bindings/python/clang/cindex.py", adding a new
method for `Cursor`, `is_copy_assignment_operator_method`.

The current release note, `clang/docs/ReleaseNotes.rst`, was modified to
report the new addition under the "libclang" section.

Reviewed By: aaron.ballman

Differential Revision: https://reviews.llvm.org/D136604

Added: 
    clang/test/Index/copy-assignment-operator.cpp

Modified: 
    clang/bindings/python/clang/cindex.py
    clang/docs/ReleaseNotes.rst
    clang/include/clang-c/Index.h
    clang/test/Index/get-cursor.cpp
    clang/tools/c-index-test/c-index-test.c
    clang/tools/libclang/CIndex.cpp
    clang/tools/libclang/libclang.map

Removed: 
    


################################################################################
diff  --git a/clang/bindings/python/clang/cindex.py b/clang/bindings/python/clang/cindex.py
index a8fe6e3e7ed56..99dcbb341dfe1 100644
--- a/clang/bindings/python/clang/cindex.py
+++ b/clang/bindings/python/clang/cindex.py
@@ -1479,6 +1479,31 @@ def is_deleted_method(self):
         """
         return conf.lib.clang_CXXMethod_isDeleted(self)
 
+    def is_copy_assignment_operator_method(self):
+        """Returnrs True if the cursor refers to a copy-assignment operator.
+
+        A copy-assignment operator `X::operator=` is a non-static,
+        non-template member function of _class_ `X` with exactly one
+        parameter of type `X`, `X&`, `const X&`, `volatile X&` or `const
+        volatile X&`.
+
+
+        That is, for example, the `operator=` in:
+
+           class Foo {
+               bool operator=(const volatile Foo&);
+           };
+
+        Is a copy-assignment operator, while the `operator=` in:
+
+           class Bar {
+               bool operator=(const int&);
+           };
+
+        Is not.
+        """
+        return conf.lib.clang_CXXMethod_isCopyAssignmentOperator(self)
+
     def is_mutable_field(self):
         """Returns True if the cursor refers to a C++ field that is declared
         'mutable'.
@@ -3436,6 +3461,10 @@ def cursor(self):
    [Cursor],
    bool),
 
+  ("clang_CXXMethod_isCopyAssignmentOperator",
+   [Cursor],
+   bool),
+
   ("clang_CXXMethod_isPureVirtual",
    [Cursor],
    bool),

diff  --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index cb438b596c90c..d73e58acbccd1 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -673,8 +673,11 @@ libclang
   the behavior of ``QualType::getNonReferenceType`` for ``CXType``.
 - Introduced the new function ``clang_CXXMethod_isDeleted``, which queries
   whether the method is declared ``= delete``.
-- ``clang_Cursor_getNumTemplateArguments``, ``clang_Cursor_getTemplateArgumentKind``,
-  ``clang_Cursor_getTemplateArgumentType``, ``clang_Cursor_getTemplateArgumentValue`` and
+- Introduced the new function ``clang_CXXMethod_isCopyAssignmentOperator``,
+  which identifies whether a method cursor is a copy-assignment
+  operator.
+- ``clang_Cursor_getNumTemplateArguments``, ``clang_Cursor_getTemplateArgumentKind``, 
+  ``clang_Cursor_getTemplateArgumentType``, ``clang_Cursor_getTemplateArgumentValue`` and 
   ``clang_Cursor_getTemplateArgumentUnsignedValue`` now work on struct, class,
   and partial template specialization cursors in addition to function cursors.
 

diff  --git a/clang/include/clang-c/Index.h b/clang/include/clang-c/Index.h
index 4e6fe060f2518..2cd2d499ab53d 100644
--- a/clang/include/clang-c/Index.h
+++ b/clang/include/clang-c/Index.h
@@ -4283,6 +4283,31 @@ CINDEX_LINKAGE unsigned clang_CXXMethod_isStatic(CXCursor C);
  */
 CINDEX_LINKAGE unsigned clang_CXXMethod_isVirtual(CXCursor C);
 
+/**
+ * Determine if a C++ member function is a copy-assignment operator,
+ * returning 1 if such is the case and 0 otherwise.
+ *
+ * > A copy-assignment operator `X::operator=` is a non-static,
+ * > non-template member function of _class_ `X` with exactly one
+ * > parameter of type `X`, `X&`, `const X&`, `volatile X&` or `const
+ * > volatile X&`.
+ *
+ * That is, for example, the `operator=` in:
+ *
+ *    class Foo {
+ *        bool operator=(const volatile Foo&);
+ *    };
+ *
+ * Is a copy-assignment operator, while the `operator=` in:
+ *
+ *    class Bar {
+ *        bool operator=(const int&);
+ *    };
+ *
+ * Is not.
+ */
+CINDEX_LINKAGE unsigned clang_CXXMethod_isCopyAssignmentOperator(CXCursor C);
+
 /**
  * Determine if a C++ record is abstract, i.e. whether a class or struct
  * has a pure virtual member function.

diff  --git a/clang/test/Index/copy-assignment-operator.cpp b/clang/test/Index/copy-assignment-operator.cpp
new file mode 100644
index 0000000000000..7f741931f9cef
--- /dev/null
+++ b/clang/test/Index/copy-assignment-operator.cpp
@@ -0,0 +1,47 @@
+struct Foo {
+    // Those are copy-assignment operators
+    bool operator=(const Foo&);
+    bool operator=(Foo&);
+    bool operator=(volatile Foo&);
+    bool operator=(const volatile Foo&);
+    bool operator=(Foo);
+
+    // Those are not copy-assignment operators
+    template<typename T>
+    bool operator=(const T&);
+    bool operator=(const bool&);
+    bool operator=(char&);
+    bool operator=(volatile unsigned int&);
+    bool operator=(const volatile unsigned char&);
+    bool operator=(int);
+};
+
+// Positive-check that the recognition works for templated classes too
+template <typename T>
+class Bar {
+    bool operator=(const Bar&);
+    bool operator=(Bar<T>&);
+    bool operator=(volatile Bar&);
+    bool operator=(const volatile Bar<T>&);
+    bool operator=(Bar);
+};
+
+// RUN: c-index-test -test-print-type --std=c++11 %s | FileCheck %s
+// CHECK: StructDecl=Foo:1:8 (Definition) [type=Foo] [typekind=Record] [isPOD=0]
+// CHECK: CXXMethod=operator=:3:10 (copy-assignment operator) [type=bool (const Foo &)] [typekind=FunctionProto] [canonicaltype=bool (const Foo &)] [canonicaltypekind=FunctionProto] [resulttype=bool] [resulttypekind=Bool] [args= [const Foo &] [LValueReference]] [isPOD=0] [isAnonRecDecl=0]
+// CHECK: CXXMethod=operator=:4:10 (copy-assignment operator) [type=bool (Foo &)] [typekind=FunctionProto] [canonicaltype=bool (Foo &)] [canonicaltypekind=FunctionProto] [resulttype=bool] [resulttypekind=Bool] [args= [Foo &] [LValueReference]] [isPOD=0] [isAnonRecDecl=0]
+// CHECK: CXXMethod=operator=:5:10 (copy-assignment operator) [type=bool (volatile Foo &)] [typekind=FunctionProto] [canonicaltype=bool (volatile Foo &)] [canonicaltypekind=FunctionProto] [resulttype=bool] [resulttypekind=Bool] [args= [volatile Foo &] [LValueReference]] [isPOD=0] [isAnonRecDecl=0]
+// CHECK: CXXMethod=operator=:6:10 (copy-assignment operator) [type=bool (const volatile Foo &)] [typekind=FunctionProto] [canonicaltype=bool (const volatile Foo &)] [canonicaltypekind=FunctionProto] [resulttype=bool] [resulttypekind=Bool] [args= [const volatile Foo &] [LValueReference]] [isPOD=0] [isAnonRecDecl=0]
+// CHECK: CXXMethod=operator=:7:10 (copy-assignment operator) [type=bool (Foo)] [typekind=FunctionProto] [canonicaltype=bool (Foo)] [canonicaltypekind=FunctionProto] [resulttype=bool] [resulttypekind=Bool] [args= [Foo] [Elaborated]] [isPOD=0] [isAnonRecDecl=0]
+// CHECK: FunctionTemplate=operator=:11:10 [type=bool (const T &)] [typekind=FunctionProto] [canonicaltype=bool (const type-parameter-0-0 &)] [canonicaltypekind=FunctionProto] [resulttype=bool] [resulttypekind=Bool] [isPOD=0] [isAnonRecDecl=0]
+// CHECK: CXXMethod=operator=:12:10 [type=bool (const bool &)] [typekind=FunctionProto] [resulttype=bool] [resulttypekind=Bool] [args= [const bool &] [LValueReference]] [isPOD=0] [isAnonRecDecl=0]
+// CHECK: CXXMethod=operator=:13:10 [type=bool (char &)] [typekind=FunctionProto] [resulttype=bool] [resulttypekind=Bool] [args= [char &] [LValueReference]] [isPOD=0] [isAnonRecDecl=0]
+// CHECK: CXXMethod=operator=:14:10 [type=bool (volatile unsigned int &)] [typekind=FunctionProto] [resulttype=bool] [resulttypekind=Bool] [args= [volatile unsigned int &] [LValueReference]] [isPOD=0] [isAnonRecDecl=0]
+// CHECK: CXXMethod=operator=:15:10 [type=bool (const volatile unsigned char &)] [typekind=FunctionProto] [resulttype=bool] [resulttypekind=Bool] [args= [const volatile unsigned char &] [LValueReference]] [isPOD=0] [isAnonRecDecl=0]
+// CHECK: CXXMethod=operator=:16:10 [type=bool (int)] [typekind=FunctionProto] [resulttype=bool] [resulttypekind=Bool] [args= [int] [Int]] [isPOD=0] [isAnonRecDecl=0]
+// CHECK: ClassTemplate=Bar:21:7 (Definition) [type=] [typekind=Invalid] [isPOD=0] [isAnonRecDecl=0]
+// CHECK: CXXMethod=operator=:22:10 (copy-assignment operator) [type=bool (const Bar<T> &)] [typekind=FunctionProto] [canonicaltype=bool (const Bar<T> &)] [canonicaltypekind=FunctionProto] [resulttype=bool] [resulttypekind=Bool] [args= [const Bar<T> &] [LValueReference]] [isPOD=0] [isAnonRecDecl=0]
+// CHECK: CXXMethod=operator=:23:10 (copy-assignment operator) [type=bool (Bar<T> &)] [typekind=FunctionProto] [canonicaltype=bool (Bar<T> &)] [canonicaltypekind=FunctionProto] [resulttype=bool] [resulttypekind=Bool] [args= [Bar<T> &] [LValueReference]] [isPOD=0] [isAnonRecDecl=0]
+// CHECK: CXXMethod=operator=:24:10 (copy-assignment operator) [type=bool (volatile Bar<T> &)] [typekind=FunctionProto] [canonicaltype=bool (volatile Bar<T> &)] [canonicaltypekind=FunctionProto] [resulttype=bool] [resulttypekind=Bool] [args= [volatile Bar<T> &] [LValueReference]] [isPOD=0] [isAnonRecDecl=0]
+// CHECK: CXXMethod=operator=:25:10 (copy-assignment operator) [type=bool (const volatile Bar<T> &)] [typekind=FunctionProto] [canonicaltype=bool (const volatile Bar<T> &)] [canonicaltypekind=FunctionProto] [resulttype=bool] [resulttypekind=Bool] [args= [const volatile Bar<T> &] [LValueReference]] [isPOD=0] [isAnonRecDecl=0]
+// CHECK: CXXMethod=operator=:26:10 (copy-assignment operator) [type=bool (Bar<T>)] [typekind=FunctionProto] [canonicaltype=bool (Bar<T>)] [canonicaltypekind=FunctionProto] [resulttype=bool] [resulttypekind=Bool] [args= [Bar<T>] [Elaborated]] [isPOD=0] [isAnonRecDecl=0]

diff  --git a/clang/test/Index/get-cursor.cpp b/clang/test/Index/get-cursor.cpp
index 85e22212ea503..b9d47dc6532b0 100644
--- a/clang/test/Index/get-cursor.cpp
+++ b/clang/test/Index/get-cursor.cpp
@@ -226,7 +226,7 @@ struct Z {
 // RUN: c-index-test -cursor-at=%s:69:3 -cursor-at=%s:70:11 -cursor-at=%s:73:6 -cursor-at=%s:74:6 -cursor-at=%s:77:8 -cursor-at=%s:78:8 -cursor-at=%s:79:8 -cursor-at=%s:80:8 -cursor-at=%s:81:8 -cursor-at=%s:82:8 -cursor-at=%s:85:6 -cursor-at=%s:86:6 -cursor-at=%s:87:6 -cursor-at=%s:88:6 -cursor-at=%s:91:5 -cursor-at=%s:92:5 -cursor-at=%s:93:5 -cursor-at=%s:94:5 -cursor-at=%s:95:5 -cursor-at=%s:96:5 -cursor-at=%s:97:5 -cursor-at=%s:98:5 -cursor-at=%s:100:5 -cursor-at=%s:101:5 -cursor-at=%s:104:6 -cursor-at=%s:105:6 -cursor-at=%s:106:6 -cursor-at=%s:107:6 -cursor-at=%s:108:6 -cursor-at=%s:109:6 -cursor-at=%s:110:6 -cursor-at=%s:111:6 -cursor-at=%s:113:6 -cursor-at=%s:114:6 -cursor-at=%s:117:8 -cursor-at=%s:118:8 -cursor-at=%s:120:8 -cursor-at=%s:121:8 -cursor-at=%s:122:8 -cursor-at=%s:123:8 -cursor-at=%s:124:8 -cursor-at=%s:125:8 -cursor-at=%s:128:6 -cursor-at=%s:129:6 -cursor-at=%s:130:6 -cursor-at=%s:132:3 -cursor-at=%s:146:15 -cursor-at=%s:149:6 -cursor-at=%s:150:25 -cursor-at=%s:151:6 -cursor-at=%s:152:6 -cursor-at=%s:153:6 -cursor-at=%s:154:6 -cursor-at=%s:155:6 -std=c++11 %s | FileCheck -check-prefix=CHECK-SPELLING %s
 // CHECK-SPELLING: 69:3 CXXConstructor=A:69:3 (default constructor) Extent=[69:3 - 69:6] Spelling=A ([69:3 - 69:4])
 // CHECK-SPELLING: 70:11 CXXDestructor=~A:70:11 (virtual) Extent=[70:3 - 70:15] Spelling=~A ([70:11 - 70:13])
-// CHECK-SPELLING: 73:6 CXXMethod=operator=:73:6 Extent=[73:3 - 73:25] Spelling=operator= ([73:6 - 73:15])
+// CHECK-SPELLING: 73:6 CXXMethod=operator=:73:6 (copy-assignment operator) Extent=[73:3 - 73:25] Spelling=operator= ([73:6 - 73:15])
 // CHECK-SPELLING: 74:6 CXXMethod=operator=:74:6 (noexcept) Extent=[74:3 - 74:29] Spelling=operator= ([74:6 - 74:15])
 // CHECK-SPELLING: 77:8 CXXMethod=operator+:77:8 (const) Extent=[77:3 - 77:25] Spelling=operator+ ([77:8 - 77:17])
 // CHECK-SPELLING: 78:8 CXXMethod=operator-:78:8 (const) Extent=[78:3 - 78:25] Spelling=operator- ([78:8 - 78:17])

diff  --git a/clang/tools/c-index-test/c-index-test.c b/clang/tools/c-index-test/c-index-test.c
index 805f790023ab0..108b44524cc8a 100644
--- a/clang/tools/c-index-test/c-index-test.c
+++ b/clang/tools/c-index-test/c-index-test.c
@@ -910,6 +910,8 @@ static void PrintCursor(CXCursor Cursor, const char *CommentSchemaFile) {
       printf(" (const)");
     if (clang_CXXMethod_isPureVirtual(Cursor))
       printf(" (pure)");
+    if (clang_CXXMethod_isCopyAssignmentOperator(Cursor))
+      printf(" (copy-assignment operator)");
     if (clang_CXXRecord_isAbstract(Cursor))
       printf(" (abstract)");
     if (clang_EnumDecl_isScoped(Cursor))

diff  --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp
index 9cdbddd82f76c..728625ceb023f 100644
--- a/clang/tools/libclang/CIndex.cpp
+++ b/clang/tools/libclang/CIndex.cpp
@@ -8899,6 +8899,17 @@ unsigned clang_CXXMethod_isVirtual(CXCursor C) {
   return (Method && Method->isVirtual()) ? 1 : 0;
 }
 
+unsigned clang_CXXMethod_isCopyAssignmentOperator(CXCursor C) {
+  if (!clang_isDeclaration(C.kind))
+    return 0;
+
+  const Decl *D = cxcursor::getCursorDecl(C);
+  const CXXMethodDecl *Method =
+      D ? dyn_cast_or_null<CXXMethodDecl>(D->getAsFunction()) : nullptr;
+
+  return (Method && Method->isCopyAssignmentOperator()) ? 1 : 0;
+}
+
 unsigned clang_CXXRecord_isAbstract(CXCursor C) {
   if (!clang_isDeclaration(C.kind))
     return 0;

diff  --git a/clang/tools/libclang/libclang.map b/clang/tools/libclang/libclang.map
index 2d7c2e2c8da62..331ad5760d12e 100644
--- a/clang/tools/libclang/libclang.map
+++ b/clang/tools/libclang/libclang.map
@@ -410,6 +410,7 @@ LLVM_16 {
     clang_getUnqualifiedType;
     clang_getNonReferenceType;
     clang_CXXMethod_isDeleted;
+    clang_CXXMethod_isCopyAssignmentOperator;
 };
 
 # Example of how to add a new symbol version entry.  If you do add a new symbol


        


More information about the cfe-commits mailing list