Skip to content
Snippets Groups Projects
llvm5-0001-libclang-Add-support-for-checking-abstractness-of-re.patch 5.69 KiB
Newer Older
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