From 44153f94e8511b60afe84e893aee52b01d74ab34 Mon Sep 17 00:00:00 2001 From: Jacob Dufault Date: Sat, 20 May 2017 17:19:32 -0700 Subject: [PATCH] Fix auto variable type deduction when auto is a pointer. --- src/indexer.cc | 3 +- src/libclangmm/Cursor.cc | 16 ++++++++ src/libclangmm/Cursor.h | 2 + tests/vars/deduce_auto_type.cc | 48 ++++++++++++++++++++++ tests/vars/type_instance_on_using_type.cc | 50 +++++++++++++++++++++++ 5 files changed, 117 insertions(+), 2 deletions(-) create mode 100644 tests/vars/deduce_auto_type.cc create mode 100644 tests/vars/type_instance_on_using_type.cc diff --git a/src/indexer.cc b/src/indexer.cc index 1e23e13a..dddb65e7 100644 --- a/src/indexer.cc +++ b/src/indexer.cc @@ -481,8 +481,7 @@ clang::VisiterResult VisitDeclForTypeUsageVisitor( // (ie, Foo => Foo<*,*>). optional ResolveToDeclarationType(IndexFile* db, clang::Cursor cursor) { - clang::Cursor declaration = - cursor.get_type().strip_qualifiers().get_declaration(); + clang::Cursor declaration = cursor.get_declaration(); declaration = declaration.template_specialization_to_template_definition(); std::string usr = declaration.get_usr(); if (usr != "") diff --git a/src/libclangmm/Cursor.cc b/src/libclangmm/Cursor.cc index 7af78e9e..79f2ab99 100644 --- a/src/libclangmm/Cursor.cc +++ b/src/libclangmm/Cursor.cc @@ -34,6 +34,10 @@ std::string Type::get_usr() const { return clang::Cursor(clang_getTypeDeclaration(cx_type)).get_usr(); } +Type Type::get_canonical() const { + return clang_getCanonicalType(cx_type); +} + Type Type::strip_qualifiers() const { // CXRefQualifierKind qualifiers = clang_Type_getCXXRefQualifier(cx_type) switch (cx_type.kind) { @@ -112,6 +116,18 @@ CXCursorKind Cursor::get_kind() const { return cx_cursor.kind; } +Cursor Cursor::get_declaration() const { + Type type = get_type(); + + // auto x = new Foo() will not be deduced to |Foo| if we do not use the + // canonical type. However, a canonical type will look past typedefs so we + // will not accurately report variables on typedefs if we always do this. + if (type.cx_type.kind == CXType_Auto) + type = type.get_canonical(); + + return type.strip_qualifiers().get_declaration(); +} + Type Cursor::get_type() const { return Type(clang_getCursorType(cx_cursor)); } diff --git a/src/libclangmm/Cursor.h b/src/libclangmm/Cursor.h index e504280a..de27bcd1 100644 --- a/src/libclangmm/Cursor.h +++ b/src/libclangmm/Cursor.h @@ -23,6 +23,7 @@ class Type { CXCursor get_declaration() const; std::string get_usr() const; std::string get_spelling() const; + Type get_canonical() const; // Try to resolve this type and remove qualifies, ie, Foo* will become Foo Type strip_qualifiers() const; @@ -46,6 +47,7 @@ class Cursor { bool operator!=(const Cursor& rhs) const; CXCursorKind get_kind() const; + Cursor get_declaration() const; Type get_type() const; std::string get_spelling() const; std::string get_display_name() const; diff --git a/tests/vars/deduce_auto_type.cc b/tests/vars/deduce_auto_type.cc new file mode 100644 index 00000000..f6df559c --- /dev/null +++ b/tests/vars/deduce_auto_type.cc @@ -0,0 +1,48 @@ +class Foo {}; +void f() { + auto x = new Foo(); + auto* y = new Foo(); +} + +/* +OUTPUT: +{ + "types": [{ + "id": 0, + "usr": "c:@S@Foo", + "short_name": "Foo", + "detailed_name": "Foo", + "definition_spelling": "1:7-1:10", + "definition_extent": "1:1-1:13", + "instances": [0, 1], + "uses": ["1:7-1:10", "3:16-3:19", "4:17-4:20"] + }], + "funcs": [{ + "id": 0, + "usr": "c:@F@f#", + "short_name": "f", + "detailed_name": "void f()", + "definition_spelling": "2:6-2:7", + "definition_extent": "2:1-5:2" + }], + "vars": [{ + "id": 0, + "usr": "c:deduce_auto_type.cc@29@F@f#@x", + "short_name": "x", + "detailed_name": "Foo * x", + "definition_spelling": "3:8-3:9", + "definition_extent": "3:3-3:21", + "variable_type": 0, + "uses": ["3:8-3:9"] + }, { + "id": 1, + "usr": "c:deduce_auto_type.cc@52@F@f#@y", + "short_name": "y", + "detailed_name": "Foo * y", + "definition_spelling": "4:9-4:10", + "definition_extent": "4:3-4:22", + "variable_type": 0, + "uses": ["4:9-4:10"] + }] +} +*/ diff --git a/tests/vars/type_instance_on_using_type.cc b/tests/vars/type_instance_on_using_type.cc new file mode 100644 index 00000000..3f87c118 --- /dev/null +++ b/tests/vars/type_instance_on_using_type.cc @@ -0,0 +1,50 @@ +struct S {}; +using F = S; +void Foo() { + F a; +} + +// TODO: Should we also add a usage to |S|? + +/* +OUTPUT: +{ + "types": [{ + "id": 0, + "usr": "c:@S@S", + "short_name": "S", + "detailed_name": "S", + "definition_spelling": "1:8-1:9", + "definition_extent": "1:1-1:12", + "uses": ["1:8-1:9", "2:11-2:12"] + }, { + "id": 1, + "usr": "c:@F", + "short_name": "F", + "detailed_name": "F", + "definition_spelling": "2:7-2:8", + "definition_extent": "2:1-2:12", + "alias_of": 0, + "instances": [0], + "uses": ["2:7-2:8", "4:3-4:4"] + }], + "funcs": [{ + "id": 0, + "usr": "c:@F@Foo#", + "short_name": "Foo", + "detailed_name": "void Foo()", + "definition_spelling": "3:6-3:9", + "definition_extent": "3:1-5:2" + }], + "vars": [{ + "id": 0, + "usr": "c:type_instance_on_using_type.cc@44@F@Foo#@a", + "short_name": "a", + "detailed_name": "F a", + "definition_spelling": "4:5-4:6", + "definition_extent": "4:3-4:6", + "variable_type": 1, + "uses": ["4:5-4:6"] + }] +} +*/