Skip to content

Commit

Permalink
resolve parameterized types (#115)
Browse files Browse the repository at this point in the history
- moved symbol display and other related items to Vls.CodeHelp
  • Loading branch information
Prince781 committed May 6, 2020
1 parent 68241b4 commit a46e192
Show file tree
Hide file tree
Showing 8 changed files with 897 additions and 723 deletions.
540 changes: 540 additions & 0 deletions src/codehelp/codehelp.vala

Large diffs are not rendered by default.

492 changes: 228 additions & 264 deletions src/codehelp/completionengine.vala

Large diffs are not rendered by default.

82 changes: 35 additions & 47 deletions src/codehelp/signaturehelpengine.vala
Original file line number Diff line number Diff line change
Expand Up @@ -6,27 +6,27 @@ namespace Vls.SignatureHelpEngine {
Jsonrpc.Client client, Variant id, string method,
Vala.SourceFile doc, Compilation compilation,
Position pos) {
long idx = (long) Util.get_string_pos (doc.content, pos.line, pos.character);
// long idx = (long) Util.get_string_pos (doc.content, pos.line, pos.character);

if (idx >= 2 && doc.content[idx-1:idx] == "(") {
debug ("[textDocument/signatureHelp] possible argument list");
} else if (idx >= 1 && doc.content[idx-1:idx] == ",") {
debug ("[textDocument/signatureHelp] possible ith argument in list");
}
// if (idx >= 2 && doc.content[idx-1:idx] == "(") {
// debug ("[textDocument/signatureHelp] possible argument list");
// } else if (idx >= 1 && doc.content[idx-1:idx] == ",") {
// debug ("[textDocument/signatureHelp] possible ith argument in list");
// }

var signatures = new ArrayList<SignatureInformation> ();
int active_param = -1;

Vala.CodeContext.push (compilation.code_context);
debug ("[%s] extracting expression ...", method);
// debug ("[%s] extracting expression ...", method);
var se = new SymbolExtractor (pos, doc, compilation.code_context);
if (se.extracted_expression != null) {
#if !VALA_FEATURE_INITIAL_ARGUMENT_COUNT
active_param = se.method_arguments - 1;
#endif
show_help (lang_serv, project, method, se.extracted_expression, signatures, ref active_param);
show_help (lang_serv, project, method, se.extracted_expression, se.block.scope, signatures, ref active_param);
} else {
debug ("[%s] could not get extracted expression", method);
// debug ("[%s] could not get extracted expression", method);
}

if (signatures.is_empty) {
Expand Down Expand Up @@ -55,7 +55,7 @@ namespace Vls.SignatureHelpEngine {
}

void show_help (Server lang_serv, Project project,
string method, Vala.CodeNode result,
string method, Vala.CodeNode result, Vala.Scope scope,
Collection<SignatureInformation> signatures,
ref int active_param) {
if (result is Vala.ExpressionStatement) {
Expand All @@ -70,10 +70,9 @@ namespace Vls.SignatureHelpEngine {
// or a method. Could be null if we invoke an array element,
// for example.
Vala.Symbol? explicit_sym = null;
// The symbol referenced indirectly
Vala.Symbol? type_sym = null;
// The parent symbol (useful for creation methods)
Vala.Symbol? parent_sym = null;
// The data type of the expression
Vala.DataType? data_type = null;
Vala.List<Vala.DataType>? method_type_arguments = null;
// either "begin" or "end" or null
string? coroutine_name = null;

Expand All @@ -91,19 +90,17 @@ namespace Vls.SignatureHelpEngine {
// }

// get the method type from the expression
Vala.DataType data_type = mc.call.value_type;
data_type = mc.call.value_type;
explicit_sym = mc.call.symbol_reference;
if (mc.call is Vala.MemberAccess)
method_type_arguments = ((Vala.MemberAccess)mc.call).get_type_arguments ();

if (data_type is Vala.CallableType) {
var ct = data_type as Vala.CallableType;
var ct = (Vala.CallableType) data_type;
param_list = ct.get_parameters ();

if (ct is Vala.DelegateType) {
var dt = ct as Vala.DelegateType;
type_sym = dt.delegate_symbol;
} else if (ct is Vala.MethodType) {
if (ct is Vala.MethodType) {
var mt = ct as Vala.MethodType;
type_sym = mt.method_symbol;

// handle special cases for .begin() and .end() in coroutines (async methods)
if (mc.call is Vala.MemberAccess && mt.method_symbol.coroutine &&
Expand All @@ -115,17 +112,19 @@ namespace Vls.SignatureHelpEngine {
param_list = mt.method_symbol.get_async_begin_parameters ();
else if (coroutine_name == "end") {
param_list = mt.method_symbol.get_async_end_parameters ();
type_sym = mt.method_symbol.get_end_method ();
explicit_sym = mt.method_symbol.get_end_method ();
coroutine_name = null; // .end() is its own method
} else if (coroutine_name != null) {
debug (@"[$method] coroutine name `$coroutine_name' not handled");
}
}
} else if (ct is Vala.SignalType) {
var st = ct as Vala.SignalType;
type_sym = st.signal_symbol;
}
}

// now make data_type refer to the parent expression's type (if it exists)
data_type = null;
if (mc.call is Vala.MemberAccess && ((Vala.MemberAccess)mc.call).inner != null)
data_type = ((Vala.MemberAccess)mc.call).inner.value_type;
} else if (result is Vala.ObjectCreationExpression
#if VALA_FEATURE_INITIAL_ARGUMENT_COUNT
&& ((Vala.ObjectCreationExpression)result).initial_argument_count != -1
Expand All @@ -144,6 +143,9 @@ namespace Vls.SignatureHelpEngine {
// }

explicit_sym = oce.symbol_reference;
data_type = oce.value_type;
if (oce.member_name != null)
method_type_arguments = oce.member_name.get_type_arguments ();

if (explicit_sym == null && oce.member_name != null) {
explicit_sym = oce.member_name.symbol_reference;
Expand All @@ -154,39 +156,24 @@ namespace Vls.SignatureHelpEngine {
var callable_sym = explicit_sym as Vala.Callable;
param_list = callable_sym.get_parameters ();
}

parent_sym = explicit_sym.parent_symbol;
} else {
// debug (@"[$method] %s neither a method call nor (complete) object creation expr", result.to_string ());
return; // early exit
}

if (explicit_sym == null && type_sym == null) {
// debug (@"[$method] could not get explicit_sym and type_sym from $(result.type_name)");
if (explicit_sym == null && data_type == null) {
// debug (@"[$method] could not get explicit_sym and data_type from $(result.type_name)");
return; // early exit
}

if (explicit_sym == null) {
si.label = Server.get_symbol_data_type (type_sym, false, null, true);
si.documentation = lang_serv.get_symbol_documentation (project, type_sym);
} else {
// TODO: need a function to display symbol names correctly given context
if (type_sym != null) {
si.label = Server.get_symbol_data_type (type_sym, false, null, true, coroutine_name);
si.documentation = lang_serv.get_symbol_documentation (project, type_sym);
} else {
si.label = Server.get_symbol_data_type (explicit_sym, false, parent_sym, true, coroutine_name);
}
// try getting the documentation for the explicit symbol
// if the type does not have any documentation
if (si.documentation == null)
si.documentation = lang_serv.get_symbol_documentation (project, explicit_sym);
}
si.label = CodeHelp.get_symbol_representation (data_type, explicit_sym, scope, method_type_arguments);
if (explicit_sym != null)
si.documentation = lang_serv.get_symbol_documentation (project, explicit_sym);

if (param_list != null) {
foreach (var parameter in param_list) {
si.parameters.add (new ParameterInformation () {
label = Server.get_symbol_data_type (parameter, false, null, true),
label = CodeHelp.get_symbol_representation (data_type, parameter, scope, method_type_arguments),
documentation = lang_serv.get_symbol_documentation (project, parameter)
});
// debug (@"found parameter $parameter (name = $(parameter.ellipsis ? "..." :parameter.name))");
Expand Down Expand Up @@ -233,9 +220,10 @@ namespace Vls.SignatureHelpEngine {
}

Vala.CodeNode result = Server.get_best (fs, doc);
Vala.Scope scope = CodeHelp.get_scope_containing_node (result);
// debug (@"[$method] got best: $(result.type_name) @ $(result.source_reference)");

show_help (lang_serv, project, method, result, signatures, ref active_param);
show_help (lang_serv, project, method, result, scope, signatures, ref active_param);
}

void finish (Jsonrpc.Client client, Variant id, Collection<SignatureInformation> signatures, int active_param) {
Expand Down
17 changes: 17 additions & 0 deletions src/codehelp/symbolextractor.vala
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,12 @@ class Vls.SymbolExtractor : Object {
return expr;
} else {
Vala.Expression inner = resolve_typed_expression (fake_ma.inner);
Vala.List<Vala.DataType>? method_type_arguments = null;
Vala.Symbol? symbol;

if (inner is Vala.MemberAccess)
method_type_arguments = ((Vala.MemberAccess)inner).get_type_arguments ();

if (inner.value_type != null) {
symbol = Vala.SemanticAnalyzer.get_symbol_for_data_type (inner.value_type);
if (symbol == null)
Expand All @@ -310,11 +315,16 @@ class Vls.SymbolExtractor : Object {
expr.value_type = ((Vala.Property)member).property_type;
else if (member is Vala.Callable)
expr.value_type = get_callable_type_for_callable ((Vala.Callable)member);
if (expr.value_type != null)
expr.value_type = expr.value_type.get_actual_type (inner.value_type, method_type_arguments, expr);
return expr;
}
} else if (fake_expr is FakeMethodCall) {
var fake_mc = (FakeMethodCall) fake_expr;
Vala.Expression call = resolve_typed_expression (fake_mc.inner);
Vala.List<Vala.DataType>? method_type_arguments = null;
if (call is Vala.MemberAccess)
method_type_arguments = ((Vala.MemberAccess)call).get_type_arguments ();
var expr = new Vala.MethodCall (call);
Vala.Callable? callable;
if (call.value_type != null) {
Expand All @@ -327,6 +337,11 @@ class Vls.SymbolExtractor : Object {
}
if (callable != null)
expr.value_type = callable.return_type;
if (call is Vala.MemberAccess && ((Vala.MemberAccess)call).inner != null) {
var call_inner = ((Vala.MemberAccess)call).inner;
if (call_inner.value_type != null)
expr.value_type = expr.value_type.get_actual_type (call_inner.value_type, method_type_arguments, expr);
}
#if VALA_FEATURE_INITIAL_ARGUMENT_COUNT
expr.initial_argument_count = fake_mc.arguments_count;
#endif
Expand All @@ -349,6 +364,8 @@ class Vls.SymbolExtractor : Object {
} else {
throw new TypeResolutionError.NTH_EXPRESSION ("OCE: inner expr neither Class nor method");
}
if (expr.member_name != null && expr.value_type != null)
expr.value_type = expr.value_type.get_actual_type (expr.member_name.value_type, expr.member_name.get_type_arguments (), expr);
#if VALA_FEATURE_INITIAL_ARGUMENT_COUNT
expr.initial_argument_count = ((FakeMethodCall)fake_oce.inner).arguments_count;
#endif
Expand Down
2 changes: 1 addition & 1 deletion src/list_symbols.vala
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ class Vls.ListSymbols : Vala.CodeVisitor {
dsym = ns_name_to_dsym [sym_full_name];
unique = false;
} else {
dsym = new DocumentSymbol.from_vala_symbol (sym, kind);
dsym = new DocumentSymbol.from_vala_symbol (null, sym, kind);
}

// handle conflicts
Expand Down
1 change: 1 addition & 0 deletions src/meson.build
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
vls_src = files([
'list_symbols.vala',
'codehelp/codehelp.vala',
'codehelp/completionengine.vala',
'codehelp/find_scope.vala',
'codehelp/find_symbol.vala',
Expand Down
36 changes: 23 additions & 13 deletions src/protocol.vala
Original file line number Diff line number Diff line change
Expand Up @@ -238,9 +238,13 @@ namespace LanguageServer {
public Range selectionRange { get; set; }
public Gee.List<DocumentSymbol> children { get; private set; default = new Gee.LinkedList<DocumentSymbol> (); }

public DocumentSymbol.from_vala_symbol (Vala.Symbol sym, SymbolKind kind) {
/**
* @param type the data type containing this symbol, if there was one (not available for Namespaces, for example)
* @param sym the symbol
*/
public DocumentSymbol.from_vala_symbol (Vala.DataType? type, Vala.Symbol sym, SymbolKind kind) {
this.name = sym.name;
this.detail = Vls.Server.get_symbol_data_type (sym, true, null, true);
this.detail = Vls.CodeHelp.get_symbol_representation (type, sym, null);
this.kind = kind;
this.range = Vls.Server.get_best_range (sym);
this.selectionRange = new Range.from_sourceref (sym.source_reference);
Expand Down Expand Up @@ -424,7 +428,6 @@ namespace LanguageServer {
public string? insertText { get; set; }
public InsertTextFormat insertTextFormat { get; set; }
private uint _hash;
protected string _hash_string;

private CompletionItem () {}

Expand All @@ -436,18 +439,26 @@ namespace LanguageServer {
this.insertTextFormat = InsertTextFormat.Snippet;
if (documentation != null)
this.documentation = new MarkupContent.plaintext(documentation);
this._hash_string = @"$label $kind";
this._hash = _hash_string.hash ();
this._hash = this.label.hash ();
}

public CompletionItem.from_symbol (Vala.Symbol sym, CompletionItemKind kind,
MarkupContent? documentation, string? label_override = null) {
/**
* A completion suggestion.
*
* @param instance_type the parent data type of data type of the expression where this symbol appears, or null
* @param sym the symbol itself
* @param scope the scope to display this in
* @param kind the kind of completion to display
* @param documentation the documentation to display
* @param label_override if non-null, override the displayed symbol name with this
*/
public CompletionItem.from_symbol (Vala.DataType? instance_type, Vala.Symbol sym, Vala.Scope? scope,
CompletionItemKind kind, MarkupContent? documentation, string? label_override = null) {
this.label = label_override ?? sym.name;
this.kind = kind;
this.detail = Vls.Server.get_symbol_data_type (sym, false, null, false, label_override);
this.detail = Vls.CodeHelp.get_symbol_representation (instance_type, sym, scope, null, null, false);
this.documentation = documentation;
this._hash_string = @"$label $(Vls.Server.get_symbol_data_type (sym, true)) $kind";
this._hash = _hash_string.hash ();
this._hash = this.label.hash ();

var version = sym.get_attribute ("Version");
if (version != null && (version.get_bool ("deprecated") || version.get_string ("deprecated_since") != null)) {
Expand All @@ -466,16 +477,15 @@ namespace LanguageServer {
if (insert_text.contains ("$0") || insert_text.contains ("${0"))
this.insertTextFormat = InsertTextFormat.Snippet;
this.documentation = documentation;
this._hash_string = @"$label $insert_text $kind";
this._hash = _hash_string.hash ();
this._hash = this.label.hash ();
}

public uint hash () {
return this._hash;
}

public bool equal_to (CompletionItem other) {
return other._hash_string == this._hash_string;
return other.label == this.label && other.kind == this.kind;
}

public new void Json.Serializable.set_property (ParamSpec pspec, Value value) {
Expand Down
Loading

0 comments on commit a46e192

Please sign in to comment.