]> granicus.if.org Git - clang/commitdiff
[libclang] Add support for checking abstractness of records
authorAlex Lorenz <arphaman@gmail.com>
Thu, 14 Dec 2017 22:01:50 +0000 (22:01 +0000)
committerAlex Lorenz <arphaman@gmail.com>
Thu, 14 Dec 2017 22:01:50 +0000 (22:01 +0000)
This patch allows checking whether a C++ record declaration is abstract through
libclang and clang.cindex (Python).

Patch by Johann Klähn!

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

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@320748 91177308-0d34-0410-b5e6-96231b3b80d8

bindings/python/clang/cindex.py
bindings/python/tests/cindex/test_cursor.py
include/clang-c/Index.h
test/Index/load-classes.cpp
tools/c-index-test/c-index-test.c
tools/libclang/CIndex.cpp
tools/libclang/libclang.exports

index d72dd14ef9f30e9e115454f92c365f0e17fbc96f..6cdb10ef081cb139426f7387234c8acab9f30ad6 100644 (file)
@@ -1479,6 +1479,18 @@ 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_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.
         """
@@ -3401,6 +3413,14 @@ functionList = [
    [Cursor],
    bool),
 
+  ("clang_CXXRecord_isAbstract",
+   [Cursor],
+   bool),
+
+  ("clang_CXXRecord_isAbstract",
+   [Cursor],
+   bool),
+
   ("clang_EnumDecl_isScoped",
    [Cursor],
    bool),
index 41ef62757ac34317929ba9ea4bf9bda600f82772..80f023912ac772fcd3c3361fc713fcdb202ea530 100644 (file)
@@ -275,6 +275,28 @@ class TestCursor(unittest.TestCase):
         self.assertTrue(foo.is_virtual_method())
         self.assertFalse(bar.is_virtual_method())
 
+    def test_is_abstract_record(self):
+        """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')
+        self.assertTrue(cls.is_abstract_record())
+
+        cls = get_cursor(tu, 'Y')
+        self.assertFalse(cls.is_abstract_record())
+
+    def test_is_abstract_record(self):
+        """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')
+        self.assertTrue(cls.is_abstract_record())
+
+        cls = get_cursor(tu, 'Y')
+        self.assertFalse(cls.is_abstract_record())
+
     def test_is_scoped_enum(self):
         """Ensure Cursor.is_scoped_enum works."""
         source = 'class X {}; enum RegularEnum {}; enum class ScopedEnum {};'
index 1204d6a5d88e33ae07385bc99c3d96d6ab8a6de1..587008a7210b1b95a5adfdc76fb689eaedddaa19 100644 (file)
@@ -32,7 +32,7 @@
  * compatible, thus CINDEX_VERSION_MAJOR is expected to remain stable.
  */
 #define CINDEX_VERSION_MAJOR 0
-#define CINDEX_VERSION_MINOR 44
+#define CINDEX_VERSION_MINOR 45
 
 #define CINDEX_VERSION_ENCODE(major, minor) ( \
       ((major) * 10000)                       \
@@ -4466,6 +4466,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.
  */
index 8b1ed317e3be409f83c31d4c58ad2b39fad92112..b6c25b4f7517de1db7c889bcd0ce75ba710560d6 100644 (file)
@@ -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]
index 91afbe219acc880789633abb7a55fb1228444cd6..99f05669b64c748fe88e0cca09ce73efb64db73b 100644 (file)
@@ -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))
index 656df9b09b05f8e5eb1a7d366c44cc28bd454081..f4d347108c9ff92768ee44b465b50e1cba7ea1c7 100644 (file)
@@ -7919,6 +7919,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;
index bd262ee1a04ec73e674cc37b65b6370ddcb8b1e0..4d3a029567d4898d2de5c7ba462f309b61e34391 100644 (file)
@@ -13,6 +13,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