mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-02-27 05:50:12 +00:00
Add clang_CXXMethod_isMoveAssignmentOperator to libclang
The new method is a wrapper of `CXXMethodDecl::isMoveAssignmentOperator` and can be used to recognized move-assignment operators in libclang. An export for the function, 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::isMoveAssignmentOperator` 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, "(move-assignment operator)", for cursors that are recognized by `clang_CXXMethod_isMoveAssignmentOperator`. A new regression test file, "clang/test/Index/move-assignment-operator.cpp", was added to ensure whether 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 "(move-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_move_assignment_operator_method`. An accompanying test was added to `clang/bindings/python/tests/cindex/test_cursor.py`, testing the new function with the same methodology as the corresponding libclang test. 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/D137246
This commit is contained in:
parent
47eddbbf33
commit
5c67cf0a7f
@ -1504,6 +1504,31 @@ class Cursor(Structure):
|
||||
"""
|
||||
return conf.lib.clang_CXXMethod_isCopyAssignmentOperator(self)
|
||||
|
||||
def is_move_assignment_operator_method(self):
|
||||
"""Returnrs True if the cursor refers to a move-assignment operator.
|
||||
|
||||
A move-assignment operator `X::operator=` is a non-static,
|
||||
non-template member function of _class_ `X` with exactly one
|
||||
parameter of type `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 move-assignment operator, while the `operator=` in:
|
||||
|
||||
class Bar {
|
||||
bool operator=(const int&&);
|
||||
};
|
||||
|
||||
Is not.
|
||||
"""
|
||||
return conf.lib.clang_CXXMethod_isMoveAssignmentOperator(self)
|
||||
|
||||
def is_mutable_field(self):
|
||||
"""Returns True if the cursor refers to a C++ field that is declared
|
||||
'mutable'.
|
||||
@ -3465,6 +3490,10 @@ functionList = [
|
||||
[Cursor],
|
||||
bool),
|
||||
|
||||
("clang_CXXMethod_isMoveAssignmentOperator",
|
||||
[Cursor],
|
||||
bool),
|
||||
|
||||
("clang_CXXMethod_isPureVirtual",
|
||||
[Cursor],
|
||||
bool),
|
||||
|
@ -219,6 +219,64 @@ class TestCursor(unittest.TestCase):
|
||||
self.assertTrue(xc.is_default_method())
|
||||
self.assertFalse(yc.is_default_method())
|
||||
|
||||
def test_is_move_assignment_operator_method(self):
|
||||
"""Ensure Cursor.is_move_assignment_operator_method works."""
|
||||
source_with_move_assignment_operators = """
|
||||
struct Foo {
|
||||
// Those are move-assignment operators
|
||||
bool operator=(const Foo&&);
|
||||
bool operator=(Foo&&);
|
||||
bool operator=(volatile Foo&&);
|
||||
bool operator=(const volatile Foo&&);
|
||||
|
||||
// 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>&&);
|
||||
};
|
||||
"""
|
||||
source_without_move_assignment_operators = """
|
||||
struct Foo {
|
||||
// Those are not move-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);
|
||||
bool operator=(Foo);
|
||||
};
|
||||
"""
|
||||
tu_with_move_assignment_operators = get_tu(
|
||||
source_with_move_assignment_operators, lang="cpp"
|
||||
)
|
||||
tu_without_move_assignment_operators = get_tu(
|
||||
source_without_move_assignment_operators, lang="cpp"
|
||||
)
|
||||
|
||||
move_assignment_operators_cursors = get_cursors(
|
||||
tu_with_move_assignment_operators, "operator="
|
||||
)
|
||||
non_move_assignment_operators_cursors = get_cursors(
|
||||
tu_without_move_assignment_operators, "operator="
|
||||
)
|
||||
|
||||
self.assertEqual(len(move_assignment_operators_cursors), 8)
|
||||
self.assertTrue(len(non_move_assignment_operators_cursors), 7)
|
||||
|
||||
self.assertTrue(all([
|
||||
cursor.is_move_assignment_operator_method()
|
||||
for cursor in move_assignment_operators_cursors
|
||||
]))
|
||||
self.assertFalse(any([
|
||||
cursor.is_move_assignment_operator_method()
|
||||
for cursor in non_move_assignment_operators_cursors
|
||||
]))
|
||||
|
||||
def test_is_mutable_field(self):
|
||||
"""Ensure Cursor.is_mutable_field works."""
|
||||
source = 'class X { int x_; mutable int y_; };'
|
||||
|
@ -792,6 +792,9 @@ libclang
|
||||
- Introduced the new function ``clang_CXXMethod_isCopyAssignmentOperator``,
|
||||
which identifies whether a method cursor is a copy-assignment
|
||||
operator.
|
||||
- Introduced the new function ``clang_CXXMethod_isMoveAssignmentOperator``,
|
||||
which identifies whether a method cursor is a move-assignment
|
||||
operator.
|
||||
- ``clang_Cursor_getNumTemplateArguments``, ``clang_Cursor_getTemplateArgumentKind``,
|
||||
``clang_Cursor_getTemplateArgumentType``, ``clang_Cursor_getTemplateArgumentValue`` and
|
||||
``clang_Cursor_getTemplateArgumentUnsignedValue`` now work on struct, class,
|
||||
|
@ -4312,6 +4312,31 @@ CINDEX_LINKAGE unsigned clang_CXXMethod_isVirtual(CXCursor C);
|
||||
*/
|
||||
CINDEX_LINKAGE unsigned clang_CXXMethod_isCopyAssignmentOperator(CXCursor C);
|
||||
|
||||
/**
|
||||
* Determine if a C++ member function is a move-assignment operator,
|
||||
* returning 1 if such is the case and 0 otherwise.
|
||||
*
|
||||
* > A move-assignment operator `X::operator=` is a non-static,
|
||||
* > non-template member function of _class_ `X` with exactly one
|
||||
* > parameter of type `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 move-assignment operator, while the `operator=` in:
|
||||
*
|
||||
* class Bar {
|
||||
* bool operator=(const int&&);
|
||||
* };
|
||||
*
|
||||
* Is not.
|
||||
*/
|
||||
CINDEX_LINKAGE unsigned clang_CXXMethod_isMoveAssignmentOperator(CXCursor C);
|
||||
|
||||
/**
|
||||
* Determine if a C++ record is abstract, i.e. whether a class or struct
|
||||
* has a pure virtual member function.
|
||||
|
@ -227,7 +227,7 @@ struct Z {
|
||||
// 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 (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: 74:6 CXXMethod=operator=:74:6 (move-assignment operator) (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])
|
||||
// CHECK-SPELLING: 79:8 CXXMethod=operator~:79:8 (const) Extent=[79:3 - 79:25] Spelling=operator~ ([79:8 - 79:17])
|
||||
|
45
clang/test/Index/move-assignment-operator.cpp
Normal file
45
clang/test/Index/move-assignment-operator.cpp
Normal file
@ -0,0 +1,45 @@
|
||||
struct Foo {
|
||||
// Those are move-assignment operators
|
||||
bool operator=(const Foo&&);
|
||||
bool operator=(Foo&&);
|
||||
bool operator=(volatile Foo&&);
|
||||
bool operator=(const volatile Foo&&);
|
||||
|
||||
// Those are not move-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);
|
||||
bool operator=(Foo);
|
||||
};
|
||||
|
||||
// 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>&&);
|
||||
};
|
||||
|
||||
// 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 (move-assignment operator) [type=bool (const Foo &&)] [typekind=FunctionProto] [canonicaltype=bool (const Foo &&)] [canonicaltypekind=FunctionProto] [resulttype=bool] [resulttypekind=Bool] [args= [const Foo &&] [RValueReference]] [isPOD=0] [isAnonRecDecl=0]
|
||||
// CHECK: CXXMethod=operator=:4:10 (move-assignment operator) [type=bool (Foo &&)] [typekind=FunctionProto] [canonicaltype=bool (Foo &&)] [canonicaltypekind=FunctionProto] [resulttype=bool] [resulttypekind=Bool] [args= [Foo &&] [RValueReference]] [isPOD=0] [isAnonRecDecl=0]
|
||||
// CHECK: CXXMethod=operator=:5:10 (move-assignment operator) [type=bool (volatile Foo &&)] [typekind=FunctionProto] [canonicaltype=bool (volatile Foo &&)] [canonicaltypekind=FunctionProto] [resulttype=bool] [resulttypekind=Bool] [args= [volatile Foo &&] [RValueReference]] [isPOD=0] [isAnonRecDecl=0]
|
||||
// CHECK: CXXMethod=operator=:6:10 (move-assignment operator) [type=bool (const volatile Foo &&)] [typekind=FunctionProto] [canonicaltype=bool (const volatile Foo &&)] [canonicaltypekind=FunctionProto] [resulttype=bool] [resulttypekind=Bool] [args= [const volatile Foo &&] [RValueReference]] [isPOD=0] [isAnonRecDecl=0]
|
||||
// CHECK: FunctionTemplate=operator=:10: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=:11:10 [type=bool (const bool &&)] [typekind=FunctionProto] [resulttype=bool] [resulttypekind=Bool] [args= [const bool &&] [RValueReference]] [isPOD=0] [isAnonRecDecl=0]
|
||||
// CHECK: CXXMethod=operator=:12:10 [type=bool (char &&)] [typekind=FunctionProto] [resulttype=bool] [resulttypekind=Bool] [args= [char &&] [RValueReference]] [isPOD=0] [isAnonRecDecl=0]
|
||||
// CHECK: CXXMethod=operator=:13:10 [type=bool (volatile unsigned int &&)] [typekind=FunctionProto] [resulttype=bool] [resulttypekind=Bool] [args= [volatile unsigned int &&] [RValueReference]] [isPOD=0] [isAnonRecDecl=0]
|
||||
// CHECK: CXXMethod=operator=:14:10 [type=bool (const volatile unsigned char &&)] [typekind=FunctionProto] [resulttype=bool] [resulttypekind=Bool] [args= [const volatile unsigned char &&] [RValueReference]] [isPOD=0] [isAnonRecDecl=0]
|
||||
// CHECK: CXXMethod=operator=:15:10 [type=bool (int)] [typekind=FunctionProto] [resulttype=bool] [resulttypekind=Bool] [args= [int] [Int]] [isPOD=0] [isAnonRecDecl=0]
|
||||
// CHECK: CXXMethod=operator=:16: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: ClassTemplate=Bar:21:7 (Definition) [type=] [typekind=Invalid] [isPOD=0] [isAnonRecDecl=0]
|
||||
// CHECK: CXXMethod=operator=:22:10 (move-assignment operator) [type=bool (const Bar<T> &&)] [typekind=FunctionProto] [canonicaltype=bool (const Bar<T> &&)] [canonicaltypekind=FunctionProto] [resulttype=bool] [resulttypekind=Bool] [args= [const Bar<T> &&] [RValueReference]] [isPOD=0] [isAnonRecDecl=0]
|
||||
// CHECK: CXXMethod=operator=:23:10 (move-assignment operator) [type=bool (Bar<T> &&)] [typekind=FunctionProto] [canonicaltype=bool (Bar<T> &&)] [canonicaltypekind=FunctionProto] [resulttype=bool] [resulttypekind=Bool] [args= [Bar<T> &&] [RValueReference]] [isPOD=0] [isAnonRecDecl=0]
|
||||
// CHECK: CXXMethod=operator=:24:10 (move-assignment operator) [type=bool (volatile Bar<T> &&)] [typekind=FunctionProto] [canonicaltype=bool (volatile Bar<T> &&)] [canonicaltypekind=FunctionProto] [resulttype=bool] [resulttypekind=Bool] [args= [volatile Bar<T> &&] [RValueReference]] [isPOD=0] [isAnonRecDecl=0]
|
||||
// CHECK: CXXMethod=operator=:25:10 (move-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> &&] [RValueReference]] [isPOD=0] [isAnonRecDecl=0]
|
@ -912,6 +912,8 @@ static void PrintCursor(CXCursor Cursor, const char *CommentSchemaFile) {
|
||||
printf(" (pure)");
|
||||
if (clang_CXXMethod_isCopyAssignmentOperator(Cursor))
|
||||
printf(" (copy-assignment operator)");
|
||||
if (clang_CXXMethod_isMoveAssignmentOperator(Cursor))
|
||||
printf(" (move-assignment operator)");
|
||||
if (clang_CXXRecord_isAbstract(Cursor))
|
||||
printf(" (abstract)");
|
||||
if (clang_EnumDecl_isScoped(Cursor))
|
||||
|
@ -8917,6 +8917,17 @@ unsigned clang_CXXMethod_isCopyAssignmentOperator(CXCursor C) {
|
||||
return (Method && Method->isCopyAssignmentOperator()) ? 1 : 0;
|
||||
}
|
||||
|
||||
unsigned clang_CXXMethod_isMoveAssignmentOperator(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->isMoveAssignmentOperator()) ? 1 : 0;
|
||||
}
|
||||
|
||||
unsigned clang_CXXRecord_isAbstract(CXCursor C) {
|
||||
if (!clang_isDeclaration(C.kind))
|
||||
return 0;
|
||||
|
@ -411,6 +411,7 @@ LLVM_16 {
|
||||
clang_getNonReferenceType;
|
||||
clang_CXXMethod_isDeleted;
|
||||
clang_CXXMethod_isCopyAssignmentOperator;
|
||||
clang_CXXMethod_isMoveAssignmentOperator;
|
||||
};
|
||||
|
||||
# Example of how to add a new symbol version entry. If you do add a new symbol
|
||||
|
Loading…
x
Reference in New Issue
Block a user