From 657260eeabf7b933dce952ef31c62a95c933d883 Mon Sep 17 00:00:00 2001 From: Jacob Dufault Date: Sun, 19 Feb 2017 23:06:38 -0800 Subject: [PATCH] add method inheritance support --- main.cpp | 29 ++++++++++++- tests/inheritance/class_inherit.cc | 27 ++++++++++++ tests/inheritance/class_multiple_inherit.cc | 47 ++++++++++++++++++++ tests/inheritance/function_override.cc | 48 +++++++++++++++++++++ tests/inheritance/interface_pure_virtual.cc | 28 ++++++++++++ 5 files changed, 177 insertions(+), 2 deletions(-) create mode 100644 tests/inheritance/class_inherit.cc create mode 100644 tests/inheritance/class_multiple_inherit.cc create mode 100644 tests/inheritance/function_override.cc create mode 100644 tests/inheritance/interface_pure_virtual.cc diff --git a/main.cpp b/main.cpp index e98520a3..aa940a34 100644 --- a/main.cpp +++ b/main.cpp @@ -1354,10 +1354,12 @@ void indexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) { func_def->all_uses.push_back(decl->loc); + bool is_pure_virtual = clang_CXXMethod_isPureVirtual(decl->cursor); + // Add function usage information. We only want to do it once per // definition/declaration. Do it on definition since there should only ever // be one of those in the entire program. - if (decl->isDefinition && IsTypeDefinition(decl->semanticContainer)) { + if ((decl->isDefinition || is_pure_virtual) && IsTypeDefinition(decl->semanticContainer)) { TypeId declaring_type_id = db->ToTypeId(decl->semanticContainer->cursor); TypeDef* declaring_type_def = db->Resolve(declaring_type_id); func_def->declaring_type = declaring_type_id; @@ -1370,7 +1372,7 @@ void indexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) { - if (decl->isDefinition) { + if (decl->isDefinition || is_pure_virtual) { // Mark type usage for parameters as interesting. We handle this here // instead of inside var declaration because clang will not emit a var // declaration for an unnamed parameter, but we still want to mark the @@ -1387,6 +1389,29 @@ void indexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) { break; } } + + + // Process inheritance. + //void clang_getOverriddenCursors(CXCursor cursor, CXCursor **overridden, unsigned *num_overridden); + //void clang_disposeOverriddenCursors(CXCursor *overridden); + if (clang_CXXMethod_isVirtual(decl->cursor)) { + CXCursor* overridden; + unsigned int num_overridden; + clang_getOverriddenCursors(decl->cursor, &overridden, &num_overridden); + + // TODO: How to handle multiple parent overrides?? + for (unsigned int i = 0; i < num_overridden; ++i) { + clang::Cursor parent = overridden[i]; + FuncId parent_id = db->ToFuncId(parent.get_usr()); + FuncDef* parent_def = db->Resolve(parent_id); + func_def = db->Resolve(func_id); // ToFuncId invalidated func_def + + func_def->base = parent_id; + parent_def->derived.push_back(func_id); + } + + clang_disposeOverriddenCursors(overridden); + } } /* diff --git a/tests/inheritance/class_inherit.cc b/tests/inheritance/class_inherit.cc new file mode 100644 index 00000000..c301dfa9 --- /dev/null +++ b/tests/inheritance/class_inherit.cc @@ -0,0 +1,27 @@ +class Parent {}; +class Derived : public Parent {}; + +/* +OUTPUT: +{ + "types": [{ + "id": 0, + "usr": "c:@S@Parent", + "short_name": "Parent", + "qualified_name": "Parent", + "definition": "tests/inheritance/class_inherit.cc:1:7", + "derived": [1], + "all_uses": ["tests/inheritance/class_inherit.cc:1:7", "tests/inheritance/class_inherit.cc:2:24"] + }, { + "id": 1, + "usr": "c:@S@Derived", + "short_name": "Derived", + "qualified_name": "Derived", + "definition": "tests/inheritance/class_inherit.cc:2:7", + "parents": [0], + "all_uses": ["tests/inheritance/class_inherit.cc:2:7"] + }], + "functions": [], + "variables": [] +} +*/ \ No newline at end of file diff --git a/tests/inheritance/class_multiple_inherit.cc b/tests/inheritance/class_multiple_inherit.cc new file mode 100644 index 00000000..8357b60e --- /dev/null +++ b/tests/inheritance/class_multiple_inherit.cc @@ -0,0 +1,47 @@ +class Root {}; +class MiddleA : public Root {}; +class MiddleB : public Root {}; +class Derived : public MiddleA, public MiddleB {}; + +/* +OUTPUT: +{ + "types": [{ + "id": 0, + "usr": "c:@S@Root", + "short_name": "Root", + "qualified_name": "Root", + "definition": "tests/inheritance/class_multiple_inherit.cc:1:7", + "derived": [1, 2], + "all_uses": ["tests/inheritance/class_multiple_inherit.cc:1:7", "tests/inheritance/class_multiple_inherit.cc:2:24", "tests/inheritance/class_multiple_inherit.cc:3:24"] + }, { + "id": 1, + "usr": "c:@S@MiddleA", + "short_name": "MiddleA", + "qualified_name": "MiddleA", + "definition": "tests/inheritance/class_multiple_inherit.cc:2:7", + "parents": [0], + "derived": [3], + "all_uses": ["tests/inheritance/class_multiple_inherit.cc:2:7", "tests/inheritance/class_multiple_inherit.cc:4:24"] + }, { + "id": 2, + "usr": "c:@S@MiddleB", + "short_name": "MiddleB", + "qualified_name": "MiddleB", + "definition": "tests/inheritance/class_multiple_inherit.cc:3:7", + "parents": [0], + "derived": [3], + "all_uses": ["tests/inheritance/class_multiple_inherit.cc:3:7", "tests/inheritance/class_multiple_inherit.cc:4:40"] + }, { + "id": 3, + "usr": "c:@S@Derived", + "short_name": "Derived", + "qualified_name": "Derived", + "definition": "tests/inheritance/class_multiple_inherit.cc:4:7", + "parents": [1, 2], + "all_uses": ["tests/inheritance/class_multiple_inherit.cc:4:7"] + }], + "functions": [], + "variables": [] +} +*/ \ No newline at end of file diff --git a/tests/inheritance/function_override.cc b/tests/inheritance/function_override.cc new file mode 100644 index 00000000..0d228843 --- /dev/null +++ b/tests/inheritance/function_override.cc @@ -0,0 +1,48 @@ +class Root { + virtual void foo(); +}; +class Derived : public Root { + void foo() override {} +}; + +/* +OUTPUT: +{ + "types": [{ + "id": 0, + "usr": "c:@S@Root", + "short_name": "Root", + "qualified_name": "Root", + "definition": "tests/inheritance/function_override.cc:1:7", + "derived": [1], + "all_uses": ["tests/inheritance/function_override.cc:1:7", "tests/inheritance/function_override.cc:4:24"] + }, { + "id": 1, + "usr": "c:@S@Derived", + "short_name": "Derived", + "qualified_name": "Derived", + "definition": "tests/inheritance/function_override.cc:4:7", + "parents": [0], + "funcs": [1], + "all_uses": ["tests/inheritance/function_override.cc:4:7"] + }], + "functions": [{ + "id": 0, + "usr": "c:@S@Root@F@foo#", + "short_name": "foo", + "qualified_name": "Root::foo", + "derived": [1], + "all_uses": ["tests/inheritance/function_override.cc:2:16"] + }, { + "id": 1, + "usr": "c:@S@Derived@F@foo#", + "short_name": "foo", + "qualified_name": "Derived::foo", + "definition": "tests/inheritance/function_override.cc:5:8", + "declaring_type": 1, + "base": 0, + "all_uses": ["tests/inheritance/function_override.cc:5:8"] + }], + "variables": [] +} +*/ \ No newline at end of file diff --git a/tests/inheritance/interface_pure_virtual.cc b/tests/inheritance/interface_pure_virtual.cc new file mode 100644 index 00000000..7d655c6e --- /dev/null +++ b/tests/inheritance/interface_pure_virtual.cc @@ -0,0 +1,28 @@ +class IFoo { + virtual void foo() = 0 {} +}; + +/* +OUTPUT: +{ + "types": [{ + "id": 0, + "usr": "c:@S@IFoo", + "short_name": "IFoo", + "qualified_name": "IFoo", + "definition": "tests/inheritance/interface_pure_virtual.cc:1:7", + "funcs": [0], + "all_uses": ["tests/inheritance/interface_pure_virtual.cc:1:7"] + }], + "functions": [{ + "id": 0, + "usr": "c:@S@IFoo@F@foo#", + "short_name": "foo", + "qualified_name": "IFoo::foo", + "definition": "tests/inheritance/interface_pure_virtual.cc:2:16", + "declaring_type": 0, + "all_uses": ["tests/inheritance/interface_pure_virtual.cc:2:16"] + }], + "variables": [] +} +*/ \ No newline at end of file