Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions lua/hopcsharp/database/utils.lua
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ M.types = {
ENUM = 5,
METHOD = 6,
CONSTRUCTOR = 7,
FIELD = 8,
PROPERTY = 9,
}

M.reference_types = {
Expand All @@ -39,6 +41,7 @@ M.reference_types = {
TYPE_ARGUMENT = 5,
TYPEOF_EXPRESSION = 6,
PARAMETER = 7,
MEMBER_ACCESS = 8,
}

M.get_type_name = function(type)
Expand Down Expand Up @@ -69,6 +72,14 @@ M.get_type_name = function(type)
if type == M.types.CONSTRUCTOR then
return 'constructor'
end

if type == M.types.FIELD then
return 'field'
end

if type == M.types.PROPERTY then
return 'property'
end
end

M.get_reference_type_name = function(type)
Expand Down Expand Up @@ -99,6 +110,10 @@ M.get_reference_type_name = function(type)
if type == M.reference_types.PARAMETER then
return 'parameter'
end

if type == M.reference_types.MEMBER_ACCESS then
return 'member'
end
end

return M
5 changes: 5 additions & 0 deletions lua/hopcsharp/parse/definition.lua
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ M.__parse_definitions = function(tree, path_id, namespace_id, file_content, writ
type = dbutils.types.INTERFACE
elseif parent_node_type == 'constructor_declaration' then
type = dbutils.types.CONSTRUCTOR
elseif parent_node_type == 'variable_declarator' then
-- see query for field_declaration
type = dbutils.types.FIELD
elseif parent_node_type == 'property_declaration' then
type = dbutils.types.PROPERTY
end

local row, column, _, _ = node:range()
Expand Down
7 changes: 5 additions & 2 deletions lua/hopcsharp/parse/query.lua
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ M.declaration_identifier = utils.__get_query([[
(method_declaration name: (identifier) @name)
(interface_declaration name: (identifier) @name)
(constructor_declaration name: (identifier) @name)
(property_declaration name: (identifier) @name)
(field_declaration (variable_declaration (variable_declarator name: (identifier) @name)))
]
]])

Expand All @@ -28,10 +30,11 @@ M.reference = utils.__get_query([[
(invocation_expression function: [
(identifier) @name
(generic_name (identifier) @name)
(member_access_expression name: (identifier) @name)
(member_access_expression name: (generic_name (identifier) @name))
])

(member_access_expression name: (identifier) @name)
(member_access_expression name: (generic_name (identifier) @name))

(variable_declaration type: [
(identifier) @name
(generic_name (identifier) @name)
Expand Down
6 changes: 2 additions & 4 deletions lua/hopcsharp/parse/reference.lua
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ M.__parse_reference = function(tree, path_id, namespace_id, file_content, writer

-- should not be a problem with nulls
-- those nodes are always inside other nodes
if parent_node_type == 'generic_name' or parent_node_type == 'member_access_expression' then
if parent_node_type == 'generic_name' then
parent_node_type = node:parent():parent():type()
end

Expand All @@ -28,9 +28,7 @@ M.__parse_reference = function(tree, path_id, namespace_id, file_content, writer
elseif parent_node_type == 'invocation_expression' then
type = dbutils.reference_types.METHOD_INVOCATION
elseif parent_node_type == 'member_access_expression' then
-- in context of a query that is being used,
-- it must be a method invocation
type = dbutils.reference_types.METHOD_INVOCATION
type = dbutils.reference_types.MEMBER_ACCESS
elseif parent_node_type == 'attribute' then
type = dbutils.reference_types.ATTRIBUTE
elseif parent_node_type == 'variable_declaration' then
Expand Down
73 changes: 73 additions & 0 deletions test/parse/definition_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -84,4 +84,77 @@ describe('parse.definition', function()
assert(rows[1].namespace == 'This.Is.Namespace.One')
end, writer)
end)

it('__parse_definitions populates database correctly (fields and properties)', function()
database.__drop_db()
local path = vim.fn.getcwd() .. '/test/sources/ClassWithPropertiesAndFields.cs'
local writer = BufferedWriter:new(database.__get_db(), 1)
local db = database.__get_db()

parse.__parse_tree(path, function(tree, path_id, file_content, wr)
local namespace_id = namespace.__parse_namespaces(tree:root(), path_id, file_content)
definition.__parse_definitions(tree:root(), path_id, namespace_id, file_content, wr)

local rows = db:eval(query.get_definition_by_name_and_type('m_Field1', utils.types.FIELD))
-- one for class, one for record and one for struct
assert(#rows == 3)
assert(rows[1].name == 'm_Field1')
assert(rows[1].path:match('test/sources/ClassWithPropertiesAndFields.cs$'))
assert(rows[1].type == utils.types.FIELD)
assert(rows[1].namespace == 'This.Is.Namespace.One')
assert(rows[2].name == 'm_Field1')
assert(rows[2].path:match('test/sources/ClassWithPropertiesAndFields.cs$'))
assert(rows[2].type == utils.types.FIELD)
assert(rows[2].namespace == 'This.Is.Namespace.One')
assert(rows[3].name == 'm_Field1')
assert(rows[3].path:match('test/sources/ClassWithPropertiesAndFields.cs$'))
assert(rows[3].type == utils.types.FIELD)
assert(rows[3].namespace == 'This.Is.Namespace.One')

rows = db:eval(query.get_definition_by_name_and_type('m_Field2', utils.types.FIELD))
assert(#rows == 3)
assert(rows[1].name == 'm_Field2')
assert(rows[1].path:match('test/sources/ClassWithPropertiesAndFields.cs$'))
assert(rows[1].type == utils.types.FIELD)
assert(rows[1].namespace == 'This.Is.Namespace.One')
assert(rows[2].name == 'm_Field2')
assert(rows[2].path:match('test/sources/ClassWithPropertiesAndFields.cs$'))
assert(rows[2].type == utils.types.FIELD)
assert(rows[2].namespace == 'This.Is.Namespace.One')
assert(rows[3].name == 'm_Field2')
assert(rows[3].path:match('test/sources/ClassWithPropertiesAndFields.cs$'))
assert(rows[3].type == utils.types.FIELD)
assert(rows[3].namespace == 'This.Is.Namespace.One')

rows = db:eval(query.get_definition_by_name_and_type('Property1', utils.types.PROPERTY))
assert(#rows == 3)
assert(rows[1].name == 'Property1')
assert(rows[1].path:match('test/sources/ClassWithPropertiesAndFields.cs$'))
assert(rows[1].type == utils.types.PROPERTY)
assert(rows[1].namespace == 'This.Is.Namespace.One')
assert(rows[2].name == 'Property1')
assert(rows[2].path:match('test/sources/ClassWithPropertiesAndFields.cs$'))
assert(rows[2].type == utils.types.PROPERTY)
assert(rows[2].namespace == 'This.Is.Namespace.One')
assert(rows[3].name == 'Property1')
assert(rows[3].path:match('test/sources/ClassWithPropertiesAndFields.cs$'))
assert(rows[3].type == utils.types.PROPERTY)
assert(rows[3].namespace == 'This.Is.Namespace.One')

rows = db:eval(query.get_definition_by_name_and_type('Property2', utils.types.PROPERTY))
assert(#rows == 3)
assert(rows[1].name == 'Property2')
assert(rows[1].path:match('test/sources/ClassWithPropertiesAndFields.cs$'))
assert(rows[1].type == utils.types.PROPERTY)
assert(rows[1].namespace == 'This.Is.Namespace.One')
assert(rows[2].name == 'Property2')
assert(rows[2].path:match('test/sources/ClassWithPropertiesAndFields.cs$'))
assert(rows[2].type == utils.types.PROPERTY)
assert(rows[2].namespace == 'This.Is.Namespace.One')
assert(rows[3].name == 'Property2')
assert(rows[3].path:match('test/sources/ClassWithPropertiesAndFields.cs$'))
assert(rows[3].type == utils.types.PROPERTY)
assert(rows[3].namespace == 'This.Is.Namespace.One')
end, writer)
end)
end)
52 changes: 52 additions & 0 deletions test/parse/query_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,58 @@ describe('parse.query', function()
assert(visited_count == 2)
end)

it('declaration identifier - property', function()
local content = [[
namespace My.Test.Namespace;
public class Class1 {
public int Property { get; set; }
}
]]

local visited = false
local parser = assert(vim.treesitter.get_string_parser(content, 'c_sharp', { error = false }))
parser:parse(false, function(_, trees)
assert(trees)
parser:for_each_tree(function(tree, _)
assert(tree)
for _, node, _, _ in query.declaration_identifier:iter_captures(tree:root(), content, 0, -1) do
if node:parent():type() == 'property_declaration' then
local name = vim.treesitter.get_node_text(node, content, nil)
visited = true
assert(name == 'Property')
end
end
end)
end)
assert(visited)
end)

it('declaration identifier - field', function()
local content = [[
namespace My.Test.Namespace;
public class Class1 {
private int m_DeclaredField;
}
]]

local visited = false
local parser = assert(vim.treesitter.get_string_parser(content, 'c_sharp', { error = false }))
parser:parse(false, function(_, trees)
assert(trees)
parser:for_each_tree(function(tree, _)
assert(tree)
for _, node, _, _ in query.declaration_identifier:iter_captures(tree:root(), content, 0, -1) do
if node:parent():type() == 'variable_declarator' then
local name = vim.treesitter.get_node_text(node, content, nil)
visited = true
assert(name == 'm_DeclaredField')
end
end
end)
end)
assert(visited)
end)

it('base identifier', function()
local content = [[
namespace My.Test.Namespace;
Expand Down
6 changes: 3 additions & 3 deletions test/parse/reference_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -69,14 +69,14 @@ describe('parse.reference', function()
assert(row.namespace == 'This.Is.Reference.Namespace')
end

-- method Run
rows = db:eval(query.get_reference_by_name_and_type('Run', utils.reference_types.METHOD_INVOCATION))
-- method Run (member accessed)
rows = db:eval(query.get_reference_by_name_and_type('Run', utils.reference_types.MEMBER_ACCESS))

assert(#rows == 2)
for _, row in ipairs(rows) do
assert(row.name == 'Run')
assert(row.path:match('test/sources/hop_to_reference.cs$'))
assert(row.type == utils.reference_types.METHOD_INVOCATION)
assert(row.type == utils.reference_types.MEMBER_ACCESS)
assert(row.namespace == 'This.Is.Reference.Namespace')
end

Expand Down
24 changes: 24 additions & 0 deletions test/sources/ClassWithPropertiesAndFields.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@

namespace This.Is.Namespace.One;

public class ClassWithPropertiesAndFields {
private bool m_Field1;
private bool m_Field2;
public bool Property1 { get; set; }
public bool Property2 { get; set; }
}

public record RecordWithPropertiesAndFields {
private bool m_Field1;
private bool m_Field2;
public bool Property1 { get; set; }
public bool Property2 { get; set; }
}

public struct StructWithPropertiesAndFields {
private bool m_Field1;
private bool m_Field2;
public bool Property1 { get; set; }
public bool Property2 { get; set; }
}

Loading