Newer
Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
From 85f611be67af9f9b5677917b4fee5bd15b5dc394 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johann=20Kl=C3=A4hn?= <dev@jklaehn.de>
Date: Mon, 31 Jul 2017 14:09:08 +0200
Subject: [PATCH 01/12] [libclang] Add support for checking abstractness of
records
---
bindings/python/clang/cindex.py | 10 ++++++++++
bindings/python/tests/cindex/test_cursor.py | 11 +++++++++++
include/clang-c/Index.h | 6 ++++++
test/Index/load-classes.cpp | 2 +-
tools/c-index-test/c-index-test.c | 2 ++
tools/libclang/CIndex.cpp | 11 +++++++++++
tools/libclang/libclang.exports | 1 +
7 files changed, 42 insertions(+), 1 deletion(-)
diff --git a/tools/clang/bindings/python/clang/cindex.py b/tools/clang/bindings/python/clang/cindex.py
index 236803a9ab..0f01d171ad 100644
--- a/tools/clang/bindings/python/clang/cindex.py
+++ b/tools/clang/bindings/python/clang/cindex.py
@@ -1478,6 +1478,12 @@ class Cursor(Structure):
"""
return conf.lib.clang_CXXMethod_isVirtual(self)
+ def is_abstract_record(self):
+ """Returns True if the cursor refers to a C++ record declaration
+ that has pure virtual member functions.
+ """
+ return conf.lib.clang_CXXRecord_isAbstract(self)
+
def is_scoped_enum(self):
"""Returns True if the cursor refers to a scoped enum declaration.
"""
@@ -3319,6 +3325,10 @@ functionList = [
[Cursor],
bool),
+ ("clang_CXXRecord_isAbstract",
+ [Cursor],
+ bool),
+
("clang_EnumDecl_isScoped",
[Cursor],
bool),
diff --git a/tools/clang/bindings/python/tests/cindex/test_cursor.py b/tools/clang/bindings/python/tests/cindex/test_cursor.py
index 4787ea931e..85c455fd73 100644
--- a/tools/clang/bindings/python/tests/cindex/test_cursor.py
+++ b/tools/clang/bindings/python/tests/cindex/test_cursor.py
@@ -255,6 +255,17 @@ def test_is_virtual_method():
assert foo.is_virtual_method()
assert not bar.is_virtual_method()
+def test_is_abstract_record():
+ """Ensure Cursor.is_abstract_record works."""
+ source = 'struct X { virtual void x() = 0; }; struct Y : X { void x(); };'
+ tu = get_tu(source, lang='cpp')
+
+ cls = get_cursor(tu, 'X')
+ assert cls.is_abstract_record()
+
+ cls = get_cursor(tu, 'Y')
+ assert not cls.is_abstract_record()
+
def test_is_scoped_enum():
"""Ensure Cursor.is_scoped_enum works."""
source = 'class X {}; enum RegularEnum {}; enum class ScopedEnum {};'
diff --git a/tools/clang/include/clang-c/Index.h b/tools/clang/include/clang-c/Index.h
index 3b5ea9fa53..89957e8526 100644
--- a/tools/clang/include/clang-c/Index.h
+++ b/tools/clang/include/clang-c/Index.h
@@ -4419,6 +4419,12 @@ CINDEX_LINKAGE unsigned clang_CXXMethod_isStatic(CXCursor C);
CINDEX_LINKAGE unsigned clang_CXXMethod_isVirtual(CXCursor C);
/**
+ * \brief Determine if a C++ record is abstract, i.e. whether a class or struct
+ * has a pure virtual member function.
+ */
+CINDEX_LINKAGE unsigned clang_CXXRecord_isAbstract(CXCursor C);
+
+/**
* \brief Determine if an enum declaration refers to a scoped enum.
*/
CINDEX_LINKAGE unsigned clang_EnumDecl_isScoped(CXCursor C);
diff --git a/tools/clang/test/Index/load-classes.cpp b/tools/clang/test/Index/load-classes.cpp
index 8b1ed317e3..b6c25b4f75 100644
--- a/tools/clang/test/Index/load-classes.cpp
+++ b/tools/clang/test/Index/load-classes.cpp
@@ -29,7 +29,7 @@ X::X(int value) {
}
// RUN: c-index-test -test-load-source all %s | FileCheck %s
-// CHECK: load-classes.cpp:3:8: StructDecl=X:3:8 (Definition) Extent=[3:1 - 26:2]
+// CHECK: load-classes.cpp:3:8: StructDecl=X:3:8 (Definition) (abstract) Extent=[3:1 - 26:2]
// CHECK: load-classes.cpp:4:3: CXXConstructor=X:4:3 (converting constructor) Extent=[4:3 - 4:15] [access=public]
// FIXME: missing TypeRef in the constructor name
// CHECK: load-classes.cpp:4:9: ParmDecl=value:4:9 (Definition) Extent=[4:5 - 4:14]
diff --git a/tools/clang/tools/c-index-test/c-index-test.c b/tools/clang/tools/c-index-test/c-index-test.c
index cf3581e259..08a187ffdd 100644
--- a/tools/clang/tools/c-index-test/c-index-test.c
+++ b/tools/clang/tools/c-index-test/c-index-test.c
@@ -804,6 +804,8 @@ static void PrintCursor(CXCursor Cursor, const char *CommentSchemaFile) {
printf(" (const)");
if (clang_CXXMethod_isPureVirtual(Cursor))
printf(" (pure)");
+ if (clang_CXXRecord_isAbstract(Cursor))
+ printf(" (abstract)");
if (clang_EnumDecl_isScoped(Cursor))
printf(" (scoped)");
if (clang_Cursor_isVariadic(Cursor))
diff --git a/tools/clang/tools/libclang/CIndex.cpp b/tools/clang/tools/libclang/CIndex.cpp
index ca21b6c6f6..621bc42076 100644
--- a/tools/clang/tools/libclang/CIndex.cpp
+++ b/tools/clang/tools/libclang/CIndex.cpp
@@ -7846,6 +7846,17 @@ unsigned clang_CXXMethod_isVirtual(CXCursor C) {
return (Method && Method->isVirtual()) ? 1 : 0;
}
+unsigned clang_CXXRecord_isAbstract(CXCursor C) {
+ if (!clang_isDeclaration(C.kind))
+ return 0;
+
+ const auto *D = cxcursor::getCursorDecl(C);
+ const auto *RD = dyn_cast_or_null<CXXRecordDecl>(D);
+ if (RD)
+ RD = RD->getDefinition();
+ return (RD && RD->isAbstract()) ? 1 : 0;
+}
+
unsigned clang_EnumDecl_isScoped(CXCursor C) {
if (!clang_isDeclaration(C.kind))
return 0;
diff --git a/tools/clang/tools/libclang/libclang.exports b/tools/clang/tools/libclang/libclang.exports
index e0d178a529..9ddc055125 100644
--- a/tools/clang/tools/libclang/libclang.exports
+++ b/tools/clang/tools/libclang/libclang.exports
@@ -12,6 +12,7 @@ clang_CXXMethod_isConst
clang_CXXMethod_isPureVirtual
clang_CXXMethod_isStatic
clang_CXXMethod_isVirtual
+clang_CXXRecord_isAbstract
clang_EnumDecl_isScoped
clang_Cursor_getArgument
clang_Cursor_getNumTemplateArguments
--
2.13.0