aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Gavin <danielgavin5@hotmail.com>2021-12-13 21:23:30 +0100
committerDaniel Gavin <danielgavin5@hotmail.com>2021-12-13 21:23:30 +0100
commitf4881fddf7e7c003a709a3ed5fd413270d41d261 (patch)
treeab4cf3008856cdebfa032bb833957c607f2735e0
parentc67ba465cbee1c450f75785905ba5d74d03cb3c8 (diff)
Improved type completion + add constants type, add deprecrated tag.
-rw-r--r--src/analysis/analysis.odin30
-rw-r--r--src/common/ast.odin68
-rw-r--r--src/index/collector.odin14
-rw-r--r--src/index/symbol.odin28
-rw-r--r--src/server/completion.odin6
-rw-r--r--src/server/types.odin6
-rw-r--r--src/testing/testing.odin6
-rw-r--r--tests/completions_test.odin51
8 files changed, 166 insertions, 43 deletions
diff --git a/src/analysis/analysis.odin b/src/analysis/analysis.odin
index d2cf071..4d4fd75 100644
--- a/src/analysis/analysis.odin
+++ b/src/analysis/analysis.odin
@@ -766,7 +766,7 @@ resolve_function_overload :: proc(ast_context: ^AstContext, group: ast.Proc_Grou
resolve_basic_lit :: proc(ast_context: ^AstContext, basic_lit: ast.Basic_Lit) -> (index.Symbol, bool) {
symbol := index.Symbol {
- type = .Keyword,
+ type = .Constant,
};
value: index.SymbolUntypedValue;
@@ -1084,6 +1084,10 @@ resolve_type_identifier :: proc(ast_context: ^AstContext, node: ast.Ident) -> (i
return_symbol, ok = make_symbol_dynamic_array_from_ast(ast_context, v), true;
case Map_Type:
return_symbol, ok = make_symbol_map_from_ast(ast_context, v), true;
+ case Basic_Lit:
+ return_symbol, ok = resolve_basic_lit(ast_context, v);
+ return_symbol.name = node.name;
+ return_symbol.type = ast_context.variables[node.name] ? .Variable : .Constant;
case:
return_symbol, ok = resolve_type_expression(ast_context, local);
}
@@ -1138,6 +1142,10 @@ resolve_type_identifier :: proc(ast_context: ^AstContext, node: ast.Ident) -> (i
return_symbol, ok = make_symbol_array_from_ast(ast_context, v), true;
case Dynamic_Array_Type:
return_symbol, ok = make_symbol_dynamic_array_from_ast(ast_context, v), true;
+ case Basic_Lit:
+ return_symbol, ok = resolve_basic_lit(ast_context, v);
+ return_symbol.name = node.name;
+ return_symbol.type = global.mutable ? .Variable : .Constant;
case:
return_symbol, ok = resolve_type_expression(ast_context, global.expr);
}
@@ -1320,7 +1328,6 @@ expand_struct_usings :: proc(ast_context: ^AstContext, symbol: index.Symbol, val
}
resolve_symbol_return :: proc(ast_context: ^AstContext, symbol: index.Symbol, ok := true) -> (index.Symbol, bool) {
-
if !ok {
return symbol, ok;
}
@@ -1328,7 +1335,7 @@ resolve_symbol_return :: proc(ast_context: ^AstContext, symbol: index.Symbol, ok
symbol := symbol;
if symbol.type == .Unresolved {
- fix_symbol_unresolved_type(&symbol);
+ resolve_unresolved_symbol(ast_context, &symbol);
}
#partial switch v in symbol.value {
@@ -1358,14 +1365,14 @@ resolve_symbol_return :: proc(ast_context: ^AstContext, symbol: index.Symbol, ok
return symbol, true;
}
case index.SymbolGenericValue:
- return resolve_type_expression(ast_context, v.expr);
+ ret, ok := resolve_type_expression(ast_context, v.expr);
+ return ret, ok;
}
return symbol, true;
}
-fix_symbol_unresolved_type :: proc(symbol: ^index.Symbol) {
-
+resolve_unresolved_symbol :: proc(ast_context: ^AstContext, symbol: ^index.Symbol) {
using index;
#partial switch v in symbol.value {
@@ -1381,8 +1388,13 @@ fix_symbol_unresolved_type :: proc(symbol: ^index.Symbol) {
symbol.type = .Enum;
case SymbolBitSetValue:
symbol.type = .Enum;
+ case index.SymbolGenericValue:
+ ast_context.current_package = symbol.pkg;
+ if ret, ok := resolve_type_expression(ast_context, v.expr); ok {
+ symbol.type = ret.type;
+ symbol.signature = ret.signature;
+ }
}
-
}
resolve_location_identifier :: proc(ast_context: ^AstContext, node: ast.Ident) -> (index.Symbol, bool) {
@@ -1541,6 +1553,10 @@ make_symbol_procedure_from_ast :: proc(ast_context: ^AstContext, n: ^ast.Node, v
}
}
+ if expr, ok := ast_context.globals[name]; ok {
+ symbol.is_deprecated = expr.deprecated;
+ }
+
symbol.value = index.SymbolProcedureValue {
return_types = return_types[:],
arg_types = arg_types[:],
diff --git a/src/common/ast.odin b/src/common/ast.odin
index 2b53053..62ae7e9 100644
--- a/src/common/ast.odin
+++ b/src/common/ast.odin
@@ -65,32 +65,76 @@ keyword_map: map[string]bool = {
};
GlobalExpr :: struct {
- name: string,
- expr: ^ast.Expr,
- mutable: bool,
- docs: ^ast.Comment_Group,
- attributes: []^ast.Attribute,
+ name: string,
+ expr: ^ast.Expr,
+ mutable: bool,
+ docs: ^ast.Comment_Group,
+ attributes: []^ast.Attribute,
+ deprecated: bool,
+ file_private: bool,
+ package_private: bool,
}
collect_value_decl :: proc(exprs: ^[dynamic]GlobalExpr, file: ast.File, stmt: ^ast.Node, skip_private: bool) {
if value_decl, ok := stmt.derived.(ast.Value_Decl); ok {
+ is_deprecated := false;
+ is_private_file := false;
+ is_package_file := false;
+
for attribute in value_decl.attributes {
for elem in attribute.elems {
- if ident, ok := elem.derived.(ast.Ident); ok && ident.name == "private" && skip_private {
- return;
+ if value, ok := elem.derived.(ast.Field_Value); ok {
+ if ident, ok := value.field.derived.(ast.Ident); ok {
+ switch ident.name {
+ case "private":
+ if val, ok := value.value.derived.(ast.Basic_Lit); ok {
+ switch val.tok.text {
+ case "\"file\"":
+ is_private_file = true;
+ case "package":
+ is_package_file = true;
+ }
+ }
+ case "deprecated":
+ is_deprecated = true;
+ }
+ }
+ } else if ident, ok := elem.derived.(ast.Ident); ok {
+ switch ident.name {
+ case "deprecated":
+ is_deprecated = true;
+ }
}
}
}
+ if is_private_file && skip_private {
+ return;
+ }
+
for name, i in value_decl.names {
str := get_ast_node_string(name, file.src);
if value_decl.type != nil {
- append(exprs, GlobalExpr {name = str, expr = value_decl.type, mutable = value_decl.is_mutable, docs = value_decl.docs, attributes = value_decl.attributes[:]});
+ append(exprs, GlobalExpr {
+ name = str,
+ expr = value_decl.type,
+ mutable = value_decl.is_mutable,
+ docs = value_decl.docs,
+ attributes = value_decl.attributes[:],
+ deprecated = is_deprecated,
+ });
} else {
if len(value_decl.values) > i {
- append(exprs, GlobalExpr {name = str, expr = value_decl.values[i], mutable = value_decl.is_mutable, docs = value_decl.docs, attributes = value_decl.attributes[:]});
+ append(exprs, GlobalExpr {
+ name = str,
+ expr = value_decl.values[i],
+ mutable = value_decl.is_mutable,
+ docs = value_decl.docs,
+ attributes = value_decl.attributes[:],
+ deprecated = is_deprecated,
+ });
}
}
}
@@ -98,15 +142,12 @@ collect_value_decl :: proc(exprs: ^[dynamic]GlobalExpr, file: ast.File, stmt: ^a
}
collect_globals :: proc(file: ast.File, skip_private := false) -> []GlobalExpr {
-
exprs := make([dynamic]GlobalExpr, context.temp_allocator);
for decl in file.decls {
-
if value_decl, ok := decl.derived.(ast.Value_Decl); ok {
collect_value_decl(&exprs, file, decl, skip_private);
} else if when_decl, ok := decl.derived.(ast.When_Stmt); ok {
-
if when_decl.cond == nil {
continue;
}
@@ -116,7 +157,6 @@ collect_globals :: proc(file: ast.File, skip_private := false) -> []GlobalExpr {
}
if binary, ok := when_decl.cond.derived.(ast.Binary_Expr); ok {
-
if binary.left == nil || binary.right == nil {
continue;
}
@@ -138,7 +178,6 @@ collect_globals :: proc(file: ast.File, skip_private := false) -> []GlobalExpr {
if ident != nil && basic_lit != nil {
if ident.name == "ODIN_OS" && basic_lit.tok.text[1:len(basic_lit.tok.text)-1] == ODIN_OS {
-
if block, ok := when_decl.body.derived.(ast.Block_Stmt); ok {
for stmt in block.stmts {
collect_value_decl(&exprs, file, stmt, skip_private);
@@ -160,7 +199,6 @@ collect_globals :: proc(file: ast.File, skip_private := false) -> []GlobalExpr {
}
}
} else if foreign_decl, ok := decl.derived.(ast.Foreign_Block_Decl); ok {
-
if foreign_decl.body == nil {
continue;
}
diff --git a/src/index/collector.odin b/src/index/collector.odin
index c9c7848..74c47e1 100644
--- a/src/index/collector.odin
+++ b/src/index/collector.odin
@@ -347,21 +347,22 @@ collect_symbols :: proc(collection: ^SymbolCollection, file: ast.File, uri: stri
case ast.Basic_Lit:
token = v;
symbol.value = collect_generic(collection, col_expr, package_map);
- case ast.Ident:
- token = v;
- symbol.value = collect_generic(collection, col_expr, package_map);
if expr.mutable {
token_type = .Variable;
} else {
- token_type = .Unresolved;
+ token_type = .Constant;
}
- case: // default
+ case ast.Ident:
+ token = v;
symbol.value = collect_generic(collection, col_expr, package_map);
if expr.mutable {
token_type = .Variable;
} else {
token_type = .Unresolved;
}
+ case: // default
+ symbol.value = collect_generic(collection, col_expr, package_map);
+ token_type = .Unresolved;
token = expr.expr;
}
@@ -370,6 +371,9 @@ collect_symbols :: proc(collection: ^SymbolCollection, file: ast.File, uri: stri
symbol.pkg = get_index_unique_string(collection, directory);
symbol.type = token_type;
symbol.doc = common.get_doc(expr.docs, collection.allocator);
+ symbol.is_deprecated = expr.deprecated;
+ symbol.is_private_file = expr.file_private;
+ symbol.is_private_package = expr.package_private;
when ODIN_OS == "windows" {
symbol.uri = get_index_unique_string(collection, strings.to_lower(uri, context.temp_allocator));
diff --git a/src/index/symbol.odin b/src/index/symbol.odin
index a429a17..8e13786 100644
--- a/src/index/symbol.odin
+++ b/src/index/symbol.odin
@@ -103,18 +103,21 @@ SymbolValue :: union {
}
Symbol :: struct {
- range: common.Range,
- uri: string,
- pkg: string,
- name: string,
- doc: string,
- signature: string,
- returns: string,
- type: SymbolType,
- value: SymbolValue,
- references: []common.Location,
- pointers: int,
- is_distinct: bool,
+ range: common.Range,
+ uri: string,
+ pkg: string,
+ name: string,
+ doc: string,
+ signature: string,
+ returns: string,
+ type: SymbolType,
+ value: SymbolValue,
+ references: []common.Location,
+ pointers: int,
+ is_distinct: bool,
+ is_deprecated: bool,
+ is_private_file: bool,
+ is_private_package: bool,
}
SymbolType :: enum {
@@ -125,6 +128,7 @@ SymbolType :: enum {
Enum = 13,
Keyword = 14,
EnumMember = 20,
+ Constant = 21,
Struct = 22,
Unresolved = 9999,
}
diff --git a/src/server/completion.odin b/src/server/completion.odin
index 26d6ba2..0aa202e 100644
--- a/src/server/completion.odin
+++ b/src/server/completion.odin
@@ -448,6 +448,7 @@ get_selector_completion :: proc(ast_context: ^analysis.AstContext, position_cont
for search in searched {
symbol := search.symbol;
+ resolve_unresolved_symbol(ast_context, &symbol);
build_symbol_return(&symbol);
build_symbol_signature(&symbol);
@@ -462,6 +463,7 @@ get_selector_completion :: proc(ast_context: ^analysis.AstContext, position_cont
item.insertText = fmt.tprintf("%v($0)", item.label);
item.insertTextFormat = .Snippet;
item.command.command = "editor.action.triggerParameterHints";
+ item.deprecated = symbol.is_deprecated;
}
append(&items, item);
@@ -843,6 +845,7 @@ get_identifier_completion :: proc(ast_context: ^analysis.AstContext, position_co
if results, ok := index.fuzzy_search(lookup, pkgs[:]); ok {
for r in results {
r := r;
+ resolve_unresolved_symbol(ast_context, &r.symbol);
build_symbol_return(&r.symbol);
build_symbol_signature(&r.symbol);
if r.symbol.uri != ast_context.uri {
@@ -1010,9 +1013,10 @@ get_identifier_completion :: proc(ast_context: ^analysis.AstContext, position_co
if result.symbol.type == .Function {
item.insertText = fmt.tprintf("%v($0)", item.label);
item.insertTextFormat = .Snippet;
+ item.deprecated = result.symbol.is_deprecated;
item.command.command = "editor.action.triggerParameterHints";
}
-
+
item.detail = concatenate_symbols_information(ast_context, result.symbol, true);
append(&items, item);
diff --git a/src/server/types.odin b/src/server/types.odin
index f5aa2b3..9f3c866 100644
--- a/src/server/types.odin
+++ b/src/server/types.odin
@@ -267,9 +267,15 @@ CompletionItem :: struct {
insertTextFormat: InsertTextFormat,
insertText: string,
additionalTextEdits: []TextEdit,
+ tags: []CompletionItemTag,
+ deprecated: bool,
command: Command,
}
+CompletionItemTag :: enum {
+ Deprecated = 1,
+}
+
CompletionList :: struct {
isIncomplete: bool,
items: []CompletionItem,
diff --git a/src/testing/testing.odin b/src/testing/testing.odin
index 540bb4c..0703708 100644
--- a/src/testing/testing.odin
+++ b/src/testing/testing.odin
@@ -84,6 +84,7 @@ setup :: proc(src: ^Source) {
fullpath := uri.path;
p := parser.Parser {
+ //err = parser.default_error_handler,
err = index.log_error_handler,
warn = index.log_warning_handler,
};
@@ -107,8 +108,9 @@ setup :: proc(src: ^Source) {
ok := parser.parse_file(&p, &file);
- if !ok {
- return;
+
+ if !ok || file.syntax_error_count > 0 {
+ panic("Parser error in test package source");
}
if ret := index.collect_symbols(&index.indexer.static_index.collection, file, uri.uri); ret != .None {
diff --git a/tests/completions_test.odin b/tests/completions_test.odin
index ef28802..1ea7efa 100644
--- a/tests/completions_test.odin
+++ b/tests/completions_test.odin
@@ -789,7 +789,6 @@ ast_overload_with_any_int_index_completion :: proc(t: ^testing.T) {
@(test)
ast_package_procedure_completion :: proc(t: ^testing.T) {
-
packages := make([dynamic]test.Package);
append(&packages, test.Package {
@@ -906,6 +905,56 @@ ast_basic_value_binary_completion :: proc(t: ^testing.T) {
test.expect_completion_details(t, &source, "", {"test.xb2: int"});
}
+@(test)
+ast_file_private_completion :: proc(t: ^testing.T) {
+ packages := make([dynamic]test.Package);
+
+ append(&packages, test.Package {
+ pkg = "my_package",
+ source = `package my_package
+
+ @(private="file") my_proc :: proc() -> bool {
+ }
+ `,
+ });
+
+ source := test.Source {
+ main = `package main
+ import "my_package"
+ main :: proc() {
+ my_package.*
+ }
+ `,
+ packages = packages[:],
+ };
+
+ test.expect_completion_details(t, &source, ".", {});
+}
+
+@(test)
+ast_non_mutable_variable_struct_completion :: proc(t: ^testing.T) {
+ packages := make([dynamic]test.Package);
+
+ append(&packages, test.Package {
+ pkg = "my_package",
+ source = `package my_package
+ My_Struct :: struct { a: int }
+ Im :: My_Struct;
+ `,
+ });
+
+ source := test.Source {
+ main = `package main
+ import "my_package"
+ main :: proc() {
+ my_package.*
+ }
+ `,
+ packages = packages[:],
+ };
+
+ test.expect_completion_details(t, &source, ".", {"my_package.Im: struct"});
+}
/*
Looks like a bug in for each on w.*