From f4881fddf7e7c003a709a3ed5fd413270d41d261 Mon Sep 17 00:00:00 2001 From: Daniel Gavin Date: Mon, 13 Dec 2021 21:23:30 +0100 Subject: Improved type completion + add constants type, add deprecrated tag. --- src/analysis/analysis.odin | 30 +++++++++++++++----- src/common/ast.odin | 68 ++++++++++++++++++++++++++++++++++++---------- src/index/collector.odin | 14 ++++++---- src/index/symbol.odin | 28 +++++++++++-------- src/server/completion.odin | 6 +++- src/server/types.odin | 6 ++++ src/testing/testing.odin | 6 ++-- 7 files changed, 116 insertions(+), 42 deletions(-) (limited to 'src') 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 { -- cgit v1.2.3