diff options
| author | Daniel Gavin <danielgavin5@hotmail.com> | 2021-12-31 14:51:12 +0100 |
|---|---|---|
| committer | Daniel Gavin <danielgavin5@hotmail.com> | 2021-12-31 14:51:12 +0100 |
| commit | d28b0ac8400136d0ccc6942c907e6fb3f034488f (patch) | |
| tree | 2bfe679da112da226db2cd95c9c3d145bd1ca0d5 /src | |
| parent | bb1379a911f43134b8dc5ed9ec2eebb889b800fb (diff) | |
| parent | e587db0c06c0972a67867282eb9f16448101f34b (diff) | |
Merge branch 'master' into refractor-analysis
Diffstat (limited to 'src')
| -rw-r--r-- | src/analysis/analysis.odin | 303 | ||||
| -rw-r--r-- | src/common/ast.odin | 7 | ||||
| -rw-r--r-- | src/common/config.odin | 1 | ||||
| -rw-r--r-- | src/index/collector.odin | 32 | ||||
| -rw-r--r-- | src/index/symbol.odin | 21 | ||||
| -rw-r--r-- | src/odin/printer/visit.odin | 10 | ||||
| -rw-r--r-- | src/server/check.odin | 280 | ||||
| -rw-r--r-- | src/server/completion.odin | 174 | ||||
| -rw-r--r-- | src/server/hover.odin | 12 | ||||
| -rw-r--r-- | src/server/requests.odin | 7 | ||||
| -rw-r--r-- | src/server/signature.odin | 12 | ||||
| -rw-r--r-- | src/server/types.odin | 1 | ||||
| -rw-r--r-- | src/testing/testing.odin | 35 |
13 files changed, 605 insertions, 290 deletions
diff --git a/src/analysis/analysis.odin b/src/analysis/analysis.odin index c16bdf9..1330796 100644 --- a/src/analysis/analysis.odin +++ b/src/analysis/analysis.odin @@ -44,6 +44,7 @@ DocumentPositionContext :: struct { returns: ^ast.Return_Stmt, //used for completion comp_lit: ^ast.Comp_Lit, //used for completion parent_comp_lit: ^ast.Comp_Lit, //used for completion + field_value: ^ast.Field_Value, implicit: bool, //used for completion arrow: bool, binary: ^ast.Binary_Expr, //used for completion @@ -292,10 +293,18 @@ resolve_poly_spec_node :: proc(ast_context: ^AstContext, call_node: ^ast.Node, s } } -resolve_type_comp_literal :: proc(ast_context: ^AstContext, position_context: ^DocumentPositionContext, current_symbol: index.Symbol, current_comp_lit: ^ast.Comp_Lit) -> (index.Symbol, bool) { +resolve_type_comp_literal :: proc(ast_context: ^AstContext, position_context: ^DocumentPositionContext, current_symbol: index.Symbol, current_comp_lit: ^ast.Comp_Lit) -> (index.Symbol, ^ast.Comp_Lit, bool) { if position_context.comp_lit == current_comp_lit { - return current_symbol, true; + return current_symbol, current_comp_lit, true; + } + + element_index := 0; + + for elem, i in current_comp_lit.elems { + if position_in_node(elem, position_context.position) { + element_index = i; + } } for elem in current_comp_lit.elems { @@ -303,28 +312,42 @@ resolve_type_comp_literal :: proc(ast_context: ^AstContext, position_context: ^D if !position_in_node(elem, position_context.position) { continue; } - - if field_value, ok := elem.derived.(ast.Field_Value); ok { - + + if field_value, ok := elem.derived.(ast.Field_Value); ok { //named if comp_lit, ok := field_value.value.derived.(ast.Comp_Lit); ok { - if s, ok := current_symbol.value.(index.SymbolStructValue); ok { - for name, i in s.names { - if name == field_value.field.derived.(ast.Ident).name { - if symbol, ok := resolve_type_expression(ast_context, s.types[i]); ok { + //Stop at bitset, because we don't want to enter a comp_lit of a bitset + if _, ok := symbol.value.(index.SymbolBitSetValue); ok { + return current_symbol, current_comp_lit, true; + } return resolve_type_comp_literal(ast_context, position_context, symbol, cast(^ast.Comp_Lit)field_value.value); } } } } } + } else { //indexed + if s, ok := current_symbol.value.(index.SymbolStructValue); ok { + + if len(s.types) <= element_index { + return {}, {}, false; + } + + if symbol, ok := resolve_type_expression(ast_context, s.types[element_index]); ok { + //Stop at bitset, because we don't want to enter a comp_lit of a bitset + if _, ok := symbol.value.(index.SymbolBitSetValue); ok { + return current_symbol, current_comp_lit, true; + } + return resolve_type_comp_literal(ast_context, position_context, symbol, cast(^ast.Comp_Lit)field_value.value); + } + } } } - return current_symbol, true; + return current_symbol, current_comp_lit, true; } resolve_generic_function :: proc { @@ -411,7 +434,6 @@ resolve_generic_function_symbol :: proc(ast_context: ^AstContext, params: []^ast argument_types := make([dynamic]^ast.Field, context.temp_allocator); for result in results { - if result.type == nil { continue; } @@ -430,7 +452,6 @@ resolve_generic_function_symbol :: proc(ast_context: ^AstContext, params: []^ast } for param in params { - if len(param.names) == 0 { continue; } @@ -515,12 +536,12 @@ is_symbol_same_typed :: proc(ast_context: ^AstContext, a, b: index.Symbol, flags return false; } - if a.is_distinct != b.is_distinct { + if .Distinct in a.flags != .Distinct in b.flags { return false; } - if a.is_distinct == b.is_distinct && - a.is_distinct == true && + if .Distinct in a.flags == .Distinct in b.flags && + .Distinct in a.flags && a.name == b.name && a.pkg == b.pkg { return true; @@ -806,6 +827,14 @@ resolve_type_expression :: proc(ast_context: ^AstContext, node: ^ast.Expr) -> (i using ast; switch v in &node.derived { + case Union_Type: + return make_symbol_union_from_ast(ast_context, v, ast_context.field_name, true), true; + case Enum_Type: + return make_symbol_enum_from_ast(ast_context, v, ast_context.field_name, true), true; + case Struct_Type: + return make_symbol_struct_from_ast(ast_context, v, ast_context.field_name, true), true; + case Bit_Set_Type: + return make_symbol_bitset_from_ast(ast_context, v, ast_context.field_name, true), true; case Array_Type: return make_symbol_array_from_ast(ast_context, v), true; case Dynamic_Array_Type: @@ -823,7 +852,7 @@ resolve_type_expression :: proc(ast_context: ^AstContext, node: ^ast.Expr) -> (i case Basic_Lit: return resolve_basic_lit(ast_context, v); case Type_Cast: - return resolve_type_expression(ast_context, v.type); + return resolve_type_expression(ast_context, v.type); case Auto_Cast: return resolve_type_expression(ast_context, v.expr); case Comp_Lit: @@ -855,7 +884,20 @@ resolve_type_expression :: proc(ast_context: ^AstContext, node: ^ast.Expr) -> (i ident.name = v.tok.text; return resolve_type_identifier(ast_context, ident^); case Type_Assertion: - return resolve_type_expression(ast_context, v.type); + if unary, ok := v.type.derived.(ast.Unary_Expr); ok { + if unary.op.kind == .Question { + if symbol, ok := resolve_type_expression(ast_context, v.expr); ok { + if union_value, ok := symbol.value.(index.SymbolUnionValue); ok { + if len(union_value.types) != 1 { + return {}, false; + } + return resolve_type_expression(ast_context, union_value.types[0]); + } + } + } + } else { + return resolve_type_expression(ast_context, v.type); + } case Proc_Lit: if v.type.results != nil { if len(v.type.results.list) == 1 { @@ -1090,7 +1132,7 @@ resolve_type_identifier :: proc(ast_context: ^AstContext, node: ast.Ident) -> (i if is_distinct { return_symbol.name = node.name; - return_symbol.is_distinct = is_distinct; + return_symbol.flags |= {.Distinct}; } return return_symbol, ok; @@ -1148,7 +1190,7 @@ resolve_type_identifier :: proc(ast_context: ^AstContext, node: ast.Ident) -> (i if is_distinct { return_symbol.name = node.name; - return_symbol.is_distinct = is_distinct; + return_symbol.flags |= {.Distinct}; } return_symbol.doc = common.get_doc(global.docs, context.temp_allocator); @@ -1335,8 +1377,8 @@ resolve_symbol_return :: proc(ast_context: ^AstContext, symbol: index.Symbol, ok if symbol.type == .Unresolved { resolve_unresolved_symbol(ast_context, &symbol); } - - #partial switch v in symbol.value { + + #partial switch v in &symbol.value { case index.SymbolProcedureGroupValue: if symbol, ok := resolve_function_overload(ast_context, v.group.derived.(ast.Proc_Group)); ok { return symbol, true; @@ -1353,14 +1395,33 @@ resolve_symbol_return :: proc(ast_context: ^AstContext, symbol: index.Symbol, ok } else { return symbol, true; } + case index.SymbolUnionValue: + if v.poly != nil { + //Todo(daniel): Maybe change the function to return a new symbol instead of referencing it. + //resolving the poly union means changing the type, so we do a copy of it. + types := make([dynamic]^ast.Expr, context.temp_allocator); + append_elems(&types, ..v.types); + v.types = types[:]; + resolve_poly_union(ast_context, v.poly, &symbol); + } + return symbol, ok; case index.SymbolStructValue: + if v.poly != nil { + //Todo(daniel): Maybe change the function to return a new symbol instead of referencing it. + //resolving the struct union means changing the type, so we do a copy of it. + types := make([dynamic]^ast.Expr, context.temp_allocator); + append_elems(&types, ..v.types); + v.types = types[:]; + resolve_poly_struct(ast_context, v.poly, &symbol); + } + //expand the types and names from the using - can't be done while indexing without complicating everything(this also saves memory) if len(v.usings) > 0 { expanded := symbol; expanded.value = expand_struct_usings(ast_context, symbol, v); return expanded, true; } else { - return symbol, true; + return symbol, true; } case index.SymbolGenericValue: ret, ok := resolve_type_expression(ast_context, v.expr); @@ -1556,7 +1617,9 @@ 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; + if expr.deprecated { + symbol.flags |= {.Distinct}; + } } symbol.value = index.SymbolProcedureValue { @@ -1635,14 +1698,19 @@ make_symbol_basic_type_from_ast :: proc(ast_context: ^AstContext, n: ^ast.Node, return symbol; } -make_symbol_union_from_ast :: proc(ast_context: ^AstContext, v: ast.Union_Type, ident: string) -> index.Symbol { +make_symbol_union_from_ast :: proc(ast_context: ^AstContext, v: ast.Union_Type, ident: string, inlined := false) -> index.Symbol { symbol := index.Symbol { range = common.get_token_range(v, ast_context.file.src), - type = .Enum, + type = .Union, pkg = get_package_from_node(v.node), }; + if inlined { + symbol.flags |= {.Anonymous}; + symbol.name = "union"; + } + names := make([dynamic]string, context.temp_allocator); for variant in v.variants { @@ -1658,22 +1726,30 @@ make_symbol_union_from_ast :: proc(ast_context: ^AstContext, v: ast.Union_Type, } symbol.value = index.SymbolUnionValue { - names = names[:], types = v.variants, union_name = ident, }; + if v.poly_params != nil { + resolve_poly_union(ast_context, v.poly_params, &symbol); + } + return symbol; } -make_symbol_enum_from_ast :: proc(ast_context: ^AstContext, v: ast.Enum_Type, ident: string) -> index.Symbol { - +make_symbol_enum_from_ast :: proc(ast_context: ^AstContext, v: ast.Enum_Type, ident: string, inlined := false) -> index.Symbol { symbol := index.Symbol { range = common.get_token_range(v, ast_context.file.src), type = .Enum, pkg = get_package_from_node(v.node), }; + if inlined { + symbol.flags |= {.Anonymous}; + symbol.name = "enum"; + } + + names := make([dynamic]string, context.temp_allocator); for n in v.fields { @@ -1696,7 +1772,7 @@ make_symbol_enum_from_ast :: proc(ast_context: ^AstContext, v: ast.Enum_Type, id return symbol; } -make_symbol_bitset_from_ast :: proc(ast_context: ^AstContext, v: ast.Bit_Set_Type, ident: string) -> index.Symbol { +make_symbol_bitset_from_ast :: proc(ast_context: ^AstContext, v: ast.Bit_Set_Type, ident: string, inlined := false) -> index.Symbol { symbol := index.Symbol { range = common.get_token_range(v, ast_context.file.src), @@ -1704,6 +1780,11 @@ make_symbol_bitset_from_ast :: proc(ast_context: ^AstContext, v: ast.Bit_Set_Typ pkg = get_package_from_node(v.node), }; + if inlined { + symbol.flags |= {.Anonymous}; + symbol.name = "bitset"; + } + symbol.value = index.SymbolBitSetValue { expr = v.elem, bitset_name = ident, @@ -1712,7 +1793,7 @@ make_symbol_bitset_from_ast :: proc(ast_context: ^AstContext, v: ast.Bit_Set_Typ return symbol; } -make_symbol_struct_from_ast :: proc(ast_context: ^AstContext, v: ast.Struct_Type, ident: string) -> index.Symbol { +make_symbol_struct_from_ast :: proc(ast_context: ^AstContext, v: ast.Struct_Type, ident: string, inlined := false) -> index.Symbol { symbol := index.Symbol { range = common.get_token_range(v, ast_context.file.src), @@ -1720,12 +1801,16 @@ make_symbol_struct_from_ast :: proc(ast_context: ^AstContext, v: ast.Struct_Type pkg = get_package_from_node(v.node), }; + if inlined { + symbol.flags |= {.Anonymous}; + symbol.name = "struct"; + } + names := make([dynamic]string, context.temp_allocator); types := make([dynamic]^ast.Expr, context.temp_allocator); usings := make(map[string]bool, 0, context.temp_allocator); for field in v.fields.list { - for n in field.names { if identifier, ok := n.derived.(ast.Ident); ok { append(&names, identifier.name); @@ -1746,7 +1831,7 @@ make_symbol_struct_from_ast :: proc(ast_context: ^AstContext, v: ast.Struct_Type }; if v.poly_params != nil { - resolve_poly_struct(ast_context, v, &symbol); + resolve_poly_struct(ast_context, v.poly_params, &symbol); } //TODO change the expand to not double copy the array, but just pass the dynamic arrays @@ -1757,13 +1842,13 @@ make_symbol_struct_from_ast :: proc(ast_context: ^AstContext, v: ast.Struct_Type return symbol; } -resolve_poly_struct :: proc(ast_context: ^AstContext, v: ast.Struct_Type, symbol: ^index.Symbol) { +resolve_poly_union :: proc(ast_context: ^AstContext, poly_params: ^ast.Field_List, symbol: ^index.Symbol) { if ast_context.call == nil { return; } - symbol_value := &symbol.value.(index.SymbolStructValue); + symbol_value := &symbol.value.(index.SymbolUnionValue); if symbol_value == nil { return; @@ -1773,10 +1858,8 @@ resolve_poly_struct :: proc(ast_context: ^AstContext, v: ast.Struct_Type, symbol poly_map := make(map[string]^ast.Expr, 0, context.temp_allocator); - for param in v.poly_params.list { - + for param in poly_params.list { for name in param.names { - if len(ast_context.call.args) <= i { break; } @@ -1784,37 +1867,96 @@ resolve_poly_struct :: proc(ast_context: ^AstContext, v: ast.Struct_Type, symbol if param.type == nil { continue; } - + if poly, ok := param.type.derived.(ast.Typeid_Type); ok { - if ident, ok := name.derived.(ast.Ident); ok { poly_map[ident.name] = ast_context.call.args[i]; + } else if poly, ok := name.derived.(ast.Poly_Type); ok { + if poly.type != nil { + poly_map[poly.type.name] = ast_context.call.args[i]; + } } } i += 1; } } - + for type, i in symbol_value.types { - if ident, ok := type.derived.(ast.Ident); ok { - if expr, ok := poly_map[ident.name]; ok { symbol_value.types[i] = expr; } } else if call_expr, ok := type.derived.(ast.Call_Expr); ok { - if call_expr.args == nil { continue; } for arg, i in call_expr.args { - if ident, ok := arg.derived.(ast.Ident); ok { + if expr, ok := poly_map[ident.name]; ok { + symbol_value.types[i] = expr; + } + } + } + } + } +} +resolve_poly_struct :: proc(ast_context: ^AstContext, poly_params: ^ast.Field_List, symbol: ^index.Symbol) { + + if ast_context.call == nil { + return; + } + + symbol_value := &symbol.value.(index.SymbolStructValue); + + if symbol_value == nil { + return; + } + + i := 0; + + poly_map := make(map[string]^ast.Expr, 0, context.temp_allocator); + + for param in poly_params.list { + for name in param.names { + if len(ast_context.call.args) <= i { + break; + } + + if param.type == nil { + continue; + } + + if poly, ok := param.type.derived.(ast.Typeid_Type); ok { + if ident, ok := name.derived.(ast.Ident); ok { + poly_map[ident.name] = ast_context.call.args[i]; + } else if poly, ok := name.derived.(ast.Poly_Type); ok { + if poly.type != nil { + poly_map[poly.type.name] = ast_context.call.args[i]; + } + } + } + + i += 1; + } + } + + for type, i in symbol_value.types { + if ident, ok := type.derived.(ast.Ident); ok { + if expr, ok := poly_map[ident.name]; ok { + symbol_value.types[i] = expr; + } + } else if call_expr, ok := type.derived.(ast.Call_Expr); ok { + if call_expr.args == nil { + continue; + } + + for arg, i in call_expr.args { + if ident, ok := arg.derived.(ast.Ident); ok { if expr, ok := poly_map[ident.name]; ok { - call_expr.args[i] = expr; + symbol_value.types[i] = expr; } } } @@ -1841,7 +1983,7 @@ get_generic_assignment :: proc(file: ast.File, value: ^ast.Expr, ast_context: ^A ast_context.use_locals = true; ast_context.use_globals = true; - switch v in value.derived { + switch v in &value.derived { case Call_Expr: ast_context.call = cast(^ast.Call_Expr)value; @@ -1874,8 +2016,16 @@ get_generic_assignment :: proc(file: ast.File, value: ^ast.Expr, ast_context: ^A } case Type_Assertion: if v.type != nil { - append(results, v.type); - append(results, make_bool_ast()); + //This is the unique .? that can only be used with maybe + if unary, ok := v.type.derived.(ast.Unary_Expr); ok && unary.op.kind == .Question { + append(results, cast(^ast.Expr)&v.node); + } else { + append(results, v.type); + } + + b := make_bool_ast(); + b.pos.file = v.type.pos.file; + append(results, b); } case: //log.debugf("default node get_generic_assignment %v", v); @@ -1884,7 +2034,6 @@ get_generic_assignment :: proc(file: ast.File, value: ^ast.Expr, ast_context: ^A } get_locals_value_decl :: proc(file: ast.File, value_decl: ast.Value_Decl, ast_context: ^AstContext) { - using ast; if len(value_decl.names) <= 0 { @@ -1892,9 +2041,11 @@ get_locals_value_decl :: proc(file: ast.File, value_decl: ast.Value_Decl, ast_co } if value_decl.type != nil { - str := common.get_ast_node_string(value_decl.names[0], file.src); - ast_context.variables[str] = value_decl.is_mutable; - store_local(ast_context, value_decl.type, value_decl.end.offset, str); + for name, i in value_decl.names { + str := common.get_ast_node_string(value_decl.names[i], file.src); + ast_context.variables[str] = value_decl.is_mutable; + store_local(ast_context, value_decl.type, value_decl.end.offset, str); + } return; } @@ -1904,13 +2055,16 @@ get_locals_value_decl :: proc(file: ast.File, value_decl: ast.Value_Decl, ast_co get_generic_assignment(file, value, ast_context, &results); } + if len(results) == 0 { + return; + } + for name, i in value_decl.names { - if i < len(results) { - str := common.get_ast_node_string(name, file.src); - ast_context.in_package[str] = get_package_from_node(results[i]); - store_local(ast_context, results[i], value_decl.end.offset, str); - ast_context.variables[str] = value_decl.is_mutable; - } + result_i := min(len(results)-1, i); + str := common.get_ast_node_string(name, file.src); + ast_context.in_package[str] = get_package_from_node(results[result_i]); + store_local(ast_context, results[result_i], value_decl.end.offset, str); + ast_context.variables[str] = value_decl.is_mutable; } } @@ -1946,9 +2100,7 @@ get_locals_stmt :: proc(file: ast.File, stmt: ^ast.Stmt, ast_context: ^AstContex case If_Stmt: get_locals_if_stmt(file, v, ast_context, document_position); case Block_Stmt: - for stmt in v.stmts { - get_locals_stmt(file, stmt, ast_context, document_position); - } + get_locals_block_stmt(file, v, ast_context, document_position); case Proc_Lit: get_locals_stmt(file, v.body, ast_context, document_position); case Assign_Stmt: @@ -1969,6 +2121,17 @@ get_locals_stmt :: proc(file: ast.File, stmt: ^ast.Stmt, ast_context: ^AstContex } } +get_locals_block_stmt :: proc(file: ast.File, block: ast.Block_Stmt, ast_context: ^AstContext, document_position: ^DocumentPositionContext) { + + if !(block.pos.offset <= document_position.position && document_position.position <= block.end.offset) { + return; + } + + for stmt in block.stmts { + get_locals_stmt(file, stmt, ast_context, document_position); + } +} + get_locals_using_stmt :: proc(stmt: ast.Using_Stmt, ast_context: ^AstContext) { for u in stmt.list { @@ -2265,11 +2428,9 @@ resolve_entire_procedure :: proc(procedure: ^ast.Proc_Type, symbols: ^[]^index.S } concatenate_symbols_information :: proc(ast_context: ^AstContext, symbol: index.Symbol, is_completion: bool) -> string { - pkg := path.base(symbol.pkg, false, context.temp_allocator); if symbol.type == .Function { - if symbol.returns != "" { return fmt.tprintf("%v.%v: proc%v -> %v", pkg, symbol.name, symbol.signature, symbol.returns); } else { @@ -2337,6 +2498,10 @@ get_signature :: proc(ast_context: ^AstContext, ident: ast.Ident, symbol: index. return symbol.signature; } + if .Distinct in symbol.flags { + return symbol.name; + } + is_variable := resolve_ident_is_variable(ast_context, ident); #partial switch v in symbol.value { @@ -2496,6 +2661,17 @@ get_call_commas :: proc(position_context: ^DocumentPositionContext, document: ^c position_context.call_commas = commas[:]; } +type_to_string :: proc(ast_context: ^AstContext, expr: ^ast.Expr) -> string { + + if symbol, ok := resolve_type_expression(ast_context, expr); ok { + if .Anonymous in symbol.flags { + return symbol.name; + } + } + + return common.node_to_string(expr); +} + /* Figure out what exactly is at the given position and whether it is in a function, struct, etc. */ @@ -2953,6 +3129,7 @@ get_document_position_node :: proc(node: ^ast.Node, position_context: ^DocumentP get_document_position(n.low, position_context); get_document_position(n.high, position_context); case Field_Value: + position_context.field_value = cast(^Field_Value)node; get_document_position(n.field, position_context); get_document_position(n.value, position_context); case Ternary_If_Expr: diff --git a/src/common/ast.odin b/src/common/ast.odin index 62ae7e9..ff6f7e2 100644 --- a/src/common/ast.odin +++ b/src/common/ast.odin @@ -771,7 +771,12 @@ build_string_node :: proc(node: ^ast.Node, builder: ^strings.Builder) { case Call_Expr: build_string(n.expr, builder); strings.write_string(builder, "("); - build_string(n.args, builder); + for arg, i in n.args { + build_string(arg, builder); + if len(n.args) - 1 != i { + strings.write_string(builder, ", "); + } + } strings.write_string(builder, ")"); case Selector_Expr: build_string(n.expr, builder); diff --git a/src/common/config.odin b/src/common/config.odin index e80d752..e3da120 100644 --- a/src/common/config.odin +++ b/src/common/config.odin @@ -18,6 +18,7 @@ Config :: struct { thread_count: int, file_log: bool, formatter: Format_Config, + odin_command: string, } Format_Config :: struct { diff --git a/src/index/collector.odin b/src/index/collector.odin index 74c47e1..077f6ee 100644 --- a/src/index/collector.odin +++ b/src/index/collector.odin @@ -119,6 +119,7 @@ collect_struct_fields :: proc(collection: ^SymbolCollection, struct_type: ast.St types = types[:], usings = usings, struct_name = get_index_unique_string(collection, ident), + poly = cast(^ast.Field_List)clone_type(struct_type.poly_params, collection.allocator, &collection.unique_strings), }; return value; @@ -151,30 +152,18 @@ collect_enum_fields :: proc(collection: ^SymbolCollection, fields: []^ast.Expr, collect_union_fields :: proc(collection: ^SymbolCollection, union_type: ast.Union_Type, package_map: map[string]string, ident: string) -> SymbolUnionValue { - names := make([dynamic]string, 0, collection.allocator); types := make([dynamic]^ast.Expr, 0, collection.allocator); for variant in union_type.variants { - - if ident, ok := variant.derived.(ast.Ident); ok { - append(&names, get_index_unique_string(collection, ident.name)); - } else if selector, ok := variant.derived.(ast.Selector_Expr); ok { - - if ident, ok := selector.field.derived.(ast.Ident); ok { - append(&names, get_index_unique_string(collection, ident.name)); - } - } - cloned := clone_type(variant, collection.allocator, &collection.unique_strings); replace_package_alias(cloned, package_map, collection); - append(&types, cloned); } value := SymbolUnionValue { - names = names[:], types = types[:], union_name = get_index_unique_string(collection, ident), + poly = cast(^ast.Field_List)clone_type(union_type.poly_params, collection.allocator, &collection.unique_strings), }; return value; @@ -320,7 +309,7 @@ collect_symbols :: proc(collection: ^SymbolCollection, file: ast.File, uri: stri symbol.signature = "enum"; case ast.Union_Type: token = v; - token_type = .Enum; + token_type = .Union; symbol.value = collect_union_fields(collection, v, package_map, name); symbol.signature = "union"; case ast.Bit_Set_Type: @@ -371,9 +360,18 @@ 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; + + if expr.deprecated { + symbol.flags |= {.Deprecated}; + } + + if expr.file_private { + symbol.flags |= {.PrivateFile}; + } + + if expr.package_private { + symbol.flags |= {.PrivatePackage}; + } 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 8e13786..5001054 100644 --- a/src/index/symbol.odin +++ b/src/index/symbol.odin @@ -15,7 +15,7 @@ SymbolStructValue :: struct { names: []string, types: []^ast.Expr, usings: map[string]bool, - generic: bool, + poly: ^ast.Field_List, } SymbolPackageValue :: struct {} @@ -42,8 +42,8 @@ SymbolEnumValue :: struct { SymbolUnionValue :: struct { union_name: string, - names: []string, types: []^ast.Expr, + poly: ^ast.Field_List, } SymbolDynamicArrayValue :: struct { @@ -102,6 +102,16 @@ SymbolValue :: union { SymbolUntypedValue, } +SymbolFlag :: enum { + Distinct, + Deprecated, + PrivateFile, + PrivatePackage, + Anonymous, +} + +SymbolFlags :: bit_set[SymbolFlag] + Symbol :: struct { range: common.Range, uri: string, @@ -114,10 +124,7 @@ Symbol :: struct { value: SymbolValue, references: []common.Location, pointers: int, - is_distinct: bool, - is_deprecated: bool, - is_private_file: bool, - is_private_package: bool, + flags: SymbolFlags, } SymbolType :: enum { @@ -130,6 +137,7 @@ SymbolType :: enum { EnumMember = 20, Constant = 21, Struct = 22, + Union = 9000, Unresolved = 9999, } @@ -163,7 +171,6 @@ free_symbol :: proc(symbol: Symbol, allocator: mem.Allocator) { case SymbolEnumValue: delete(v.names, allocator); case SymbolUnionValue: - delete(v.names, allocator); common.free_ast(v.types, allocator); case SymbolBitSetValue: common.free_ast(v.expr, allocator); diff --git a/src/odin/printer/visit.odin b/src/odin/printer/visit.odin index f20b46c..da36311 100644 --- a/src/odin/printer/visit.odin +++ b/src/odin/printer/visit.odin @@ -944,15 +944,12 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, called_from: Expr_Called_Type = document = cons_with_nopl(document, push_where_clauses(p, v.where_clauses)) - if v.variants != nil && (len(v.variants) == 0 || v.pos.line == v.end.line) { + if len(v.variants) == 0 { document = cons_with_nopl(document, text("{")) - document = cons(document, visit_exprs(p, v.variants, {.Add_Comma})) document = cons(document, text("}")) - } else if v.variants != nil { - document = cons_with_opl(document, visit_begin_brace(p, v.pos, .Generic)) - + } else { + document = cons_with_opl(document, visit_begin_brace(p, v.pos, .Generic)) set_source_position(p, v.variants[0].pos) - document = cons(document, nest(p.indentation_count, cons(newline_position(p, 1, v.variants[0].pos), visit_exprs(p, v.variants, {.Add_Comma, .Trailing, .Enforce_Newline})))) document = cons(document, visit_end_brace(p, v.end, 1)) } @@ -966,7 +963,6 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, called_from: Expr_Called_Type = if len(v.fields) == 0 { document = cons_with_nopl(document, text("{")) - document = cons(document, visit_enum_exprs(p, v.fields, {.Add_Comma})) document = cons(document, text("}")) } else { document = cons(document, cons(break_with_space(), visit_begin_brace(p, v.pos, .Generic))) diff --git a/src/server/check.odin b/src/server/check.odin index 5080c95..574227e 100644 --- a/src/server/check.odin +++ b/src/server/check.odin @@ -1,6 +1,5 @@ package server -/* import "core:fmt" import "core:log" import "core:mem" @@ -19,175 +18,214 @@ import "core:text/scanner" import "shared:common" +when ODIN_OS == "windows" { -check :: proc(uri: common.Uri, writer: ^Writer) { + is_package :: proc(file: string, pkg: string) { + + } - data := make([]byte, mem.kilobytes(10), context.temp_allocator); + check :: proc(uri: common.Uri, writer: ^Writer, config: ^common.Config) { + data := make([]byte, mem.kilobytes(10), context.temp_allocator); - buffer: []byte; - code: u32; - ok: bool; + buffer: []byte; + code: u32; + ok: bool; - collection_builder := strings.make_builder(context.temp_allocator); + collection_builder := strings.make_builder(context.temp_allocator); - for k, v in common.config.collections { - if k == "" || k == "core" { - continue; + for k, v in common.config.collections { + if k == "" || k == "core" || k == "vendor" { + continue; + } + strings.write_string(&collection_builder, fmt.aprintf("-collection:%v=%v ", k, v)); } - strings.write_string(&collection_builder, fmt.aprintf("-collection:%v=%v ", k, v)); - } - if code, ok, buffer = common.run_executable(fmt.tprintf("odin check %s %s -no-entry-point", path.dir(uri.path, context.temp_allocator), strings.to_string(collection_builder)), &data); !ok { - log.errorf("Odin check failed with code %v for file %v", code, uri.path); - return; - } - - errors := make([dynamic]Diagnostic, context.temp_allocator); + command: string; + + if config.odin_command != "" { + command = config.odin_command; + + } else { + command = "odin"; + } + + if code, ok, buffer = common.run_executable(fmt.tprintf("%v check %s %s -no-entry-point", command, path.dir(uri.path, context.temp_allocator), strings.to_string(collection_builder)), &data); !ok { + log.errorf("Odin check failed with code %v for file %v", code, uri.path); + return; + } - params := NotificationPublishDiagnosticsParams { - uri = uri.uri, - }; + s: scanner.Scanner; - s: scanner.Scanner; + scanner.init(&s, string(buffer)); - scanner.init(&s, string(buffer)); + s.whitespace = {'\t', ' '}; - s.whitespace = {'\t', ' '}; + current: rune; - current: rune; + ErrorSeperator :: struct { + message: string, + line: int, + column: int, + uri: string, + } - ErrorSeperator :: struct { - message: string, - line: int, - column: int, - uri: string, - } + error_seperators := make([dynamic]ErrorSeperator, context.temp_allocator); - error_seperators := make([dynamic]ErrorSeperator, context.temp_allocator); + //find all the signatures string(digit:digit) + loop: for scanner.peek(&s) != scanner.EOF { - //find all the signatures string(digit:digit) - loop: for scanner.peek(&s) != scanner.EOF { + error: ErrorSeperator; - error: ErrorSeperator; + source_pos := s.src_pos; - source_pos := s.src_pos; + if source_pos == 1 { + source_pos = 0; + } - if source_pos == 1 { - source_pos = 0; - } + for scanner.peek(&s) != '(' { + n := scanner.scan(&s); - for scanner.peek(&s) != '(' { - n := scanner.scan(&s); + if n == scanner.EOF { + break loop; + } + } - if n == scanner.EOF { - break loop; - } - } + error.uri = string(buffer[source_pos:s.src_pos-1]); - error.uri = string(buffer[source_pos:s.src_pos-1]); + left_paren := scanner.scan(&s); - left_paren := scanner.scan(&s); + if left_paren != '(' { + break loop; + } - if left_paren != '(' { - break loop; - } + lhs_digit := scanner.scan(&s); - lhs_digit := scanner.scan(&s); + if lhs_digit != scanner.Int { + break loop; + } - if lhs_digit != scanner.Int { - break loop; - } + line, column: int; + ok: bool; - line, column: int; - ok: bool; + line, ok = strconv.parse_int(scanner.token_text(&s)); - line, ok = strconv.parse_int(scanner.token_text(&s)); + if !ok { + break loop; + } - if !ok { - break loop; - } + seperator := scanner.scan(&s); - seperator := scanner.scan(&s); + if seperator != ':' { + break loop; + } - if seperator != ':' { - break loop; - } + rhs_digit := scanner.scan(&s) - rhs_digit := scanner.scan(&s) + if rhs_digit != scanner.Int { + break loop; + } - if rhs_digit != scanner.Int { - break loop; - } + column, ok = strconv.parse_int(scanner.token_text(&s)); - column, ok = strconv.parse_int(scanner.token_text(&s)); + if !ok { + break loop; + } - if !ok { - break loop; - } + right_paren := scanner.scan(&s); - right_paren := scanner.scan(&s); + if right_paren != ')' { + break loop; + } - if right_paren != ')' { - break loop; - } + source_pos = s.src_pos; - source_pos = s.src_pos; + for scanner.peek(&s) != '\n' { + n := scanner.scan(&s); - for scanner.peek(&s) != '\n' { - n := scanner.scan(&s); + if n == scanner.EOF { + break; + } + } - if n == scanner.EOF { - break; + if source_pos == s.src_pos { + continue; } - } - if source_pos == s.src_pos { - continue; - } + error.message = string(buffer[source_pos:s.src_pos-1]); + error.column = column; + error.line = line; - error.message = string(buffer[source_pos:s.src_pos-1]); - error.column = column; - error.line = line; + append(&error_seperators, error); + } - append(&error_seperators, error) - } + errors := make(map[string][dynamic]Diagnostic, 0, context.temp_allocator); - for error in error_seperators { + for error in error_seperators { - if error.uri != uri.path { - continue; - } + if error.uri not_in errors { + errors[error.uri] = make([dynamic]Diagnostic, context.temp_allocator); + } - append(&errors, Diagnostic { - code = "checker", - severity = .Error, - range = { - start = { - character = 0, - line = error.line - 1, + append(&errors[error.uri], Diagnostic { + code = "checker", + severity = .Error, + range = { + start = { + character = 0, + line = error.line - 1, + }, + end = { + character = 0, + line = error.line, + }, }, - end = { - character = 0, - line = error.line, - }, - }, - message = error.message, - }) - - } + message = error.message, + }); + } + + matches, err := filepath.glob(fmt.tprintf("%v/*.odin", path.dir(uri.path, context.temp_allocator))); + + if err == .None { + for match in matches { + uri := common.create_uri(match, context.temp_allocator); + + params := NotificationPublishDiagnosticsParams { + uri = uri.uri, + diagnostics = {}, + }; + + notifaction := Notification { + jsonrpc = "2.0", + method = "textDocument/publishDiagnostics", + params = params, + }; + + if writer != nil { + send_notification(notifaction, writer); + } + } + } - //fmt.println(errors) + for k, v in errors { + uri := common.create_uri(k, context.temp_allocator); - params.diagnostics = errors[:]; + params := NotificationPublishDiagnosticsParams { + uri = uri.uri, + diagnostics = v[:], + }; - notifaction := Notification { - jsonrpc = "2.0", - method = "textDocument/publishDiagnostics", - params = params, - }; + notifaction := Notification { + jsonrpc = "2.0", + method = "textDocument/publishDiagnostics", + params = params, + }; - if writer != nil { - send_notification(notifaction, writer); + if writer != nil { + send_notification(notifaction, writer); + } + } + } +} else { + check :: proc(uri: common.Uri, writer: ^Writer, config: ^common.Config) { } -} -*/
\ No newline at end of file +}
\ No newline at end of file diff --git a/src/server/completion.odin b/src/server/completion.odin index 4326c35..38b3c34 100644 --- a/src/server/completion.odin +++ b/src/server/completion.odin @@ -180,7 +180,7 @@ get_comp_lit_completion :: proc(ast_context: ^analysis.AstContext, position_cont if symbol, ok := resolve_type_expression(ast_context, position_context.parent_comp_lit.type); ok { - if comp_symbol, ok := resolve_type_comp_literal(ast_context, position_context, symbol, position_context.parent_comp_lit); ok { + if comp_symbol, _, ok := resolve_type_comp_literal(ast_context, position_context, symbol, position_context.parent_comp_lit); ok { #partial switch v in comp_symbol.value { case index.SymbolStructValue: @@ -362,13 +362,13 @@ get_selector_completion :: proc(ast_context: ^analysis.AstContext, position_cont case index.SymbolUnionValue: list.isIncomplete = false; - for name, i in v.names { - if symbol, ok := resolve_type_expression(ast_context, v.types[i]); ok { - - if symbol.pkg == ast_context.document_package { - symbol.name = fmt.aprintf("(%v)", name); + for type in v.types { + if symbol, ok := resolve_type_expression(ast_context, type); ok { + base := path.base(symbol.pkg, false, context.temp_allocator); + if symbol.pkg == ast_context.document_package || base == "runtime" { + symbol.name = fmt.aprintf("(%v)", common.node_to_string(type)); } else { - symbol.name = fmt.aprintf("(%v.%v)", path.base(symbol.pkg, false, context.temp_allocator), name); + symbol.name = fmt.aprintf("(%v.%v)", path.base(symbol.pkg, false, context.temp_allocator), common.node_to_string(type)); } item := CompletionItem { @@ -408,7 +408,6 @@ get_selector_completion :: proc(ast_context: ^analysis.AstContext, position_cont if symbol, ok := resolve_type_expression(ast_context, v.types[i]); ok { if expr, ok := position_context.selector.derived.(ast.Selector_Expr); ok { - if expr.op.text == "->" && symbol.type != .Function { continue; } @@ -421,7 +420,7 @@ get_selector_completion :: proc(ast_context: ^analysis.AstContext, position_cont item := CompletionItem { label = name, kind = .Field, - detail = fmt.tprintf("%v.%v: %v", selector.name, name, common.node_to_string(v.types[i])), + detail = fmt.tprintf("%v.%v: %v", selector.name, name, type_to_string(ast_context, v.types[i])), documentation = symbol.doc, }; @@ -449,8 +448,8 @@ get_selector_completion :: proc(ast_context: ^analysis.AstContext, position_cont symbol := search.symbol; resolve_unresolved_symbol(ast_context, &symbol); - build_symbol_return(&symbol); - build_symbol_signature(&symbol); + build_procedure_symbol_return(&symbol); + build_procedure_symbol_signature(&symbol); item := CompletionItem { label = symbol.name, @@ -463,7 +462,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; + item.deprecated = .Deprecated in symbol.flags; } append(&items, item); @@ -584,6 +583,7 @@ get_implicit_completion :: proc(ast_context: ^analysis.AstContext, position_cont } } + //infer bitset and enums based on the identifier comp_lit, i.e. a := My_Struct { my_ident = . } if position_context.comp_lit != nil { if position_context.parent_comp_lit.type == nil { return; @@ -591,37 +591,63 @@ get_implicit_completion :: proc(ast_context: ^analysis.AstContext, position_cont field_name: string; - for elem in position_context.comp_lit.elems { - if position_in_node(elem, position_context.position) { - if field, ok := elem.derived.(ast.Field_Value); ok { - field_name = field.field.derived.(ast.Ident).name; - } - } - } - - if field_name == "" { - return; + if position_context.field_value != nil { + field_name = position_context.field_value.field.derived.(ast.Ident).name; } if symbol, ok := resolve_type_expression(ast_context, position_context.parent_comp_lit.type); ok { - if comp_symbol, ok := resolve_type_comp_literal(ast_context, position_context, symbol, position_context.parent_comp_lit); ok { + if comp_symbol, comp_lit, ok := resolve_type_comp_literal(ast_context, position_context, symbol, position_context.parent_comp_lit); ok { if s, ok := comp_symbol.value.(index.SymbolStructValue); ok { + + //We can either have the final + elem_index := -1; + + for elem, i in comp_lit.elems { + if position_in_node(elem, position_context.position) { + elem_index = i; + } + } + + type: ^ast.Expr; + for name, i in s.names { if name != field_name { continue; + } + + type = s.types[i]; + break; + } + + if type == nil && len(s.types) > elem_index { + type = s.types[elem_index]; + } + + if enum_value, ok := unwrap_enum(ast_context, type); ok { + for enum_name in enum_value.names { + item := CompletionItem { + label = enum_name, + kind = .EnumMember, + detail = enum_name, + }; + + append(&items, item); } - if enum_value, ok := unwrap_enum(ast_context, s.types[i]); ok { - for enum_name in enum_value.names { + list.items = items[:]; + return; + } else if bitset_symbol, ok := resolve_type_expression(ast_context, type); ok { + if value, ok := unwrap_bitset(ast_context, bitset_symbol); ok { + for name in value.names { + item := CompletionItem { - label = enum_name, + label = name, kind = .EnumMember, - detail = enum_name, + detail = name, }; - + append(&items, item); - } - + } list.items = items[:]; return; } @@ -629,8 +655,8 @@ get_implicit_completion :: proc(ast_context: ^analysis.AstContext, position_cont } } } - } - + } + if position_context.binary != nil && (position_context.binary.op.text == "==" || position_context.binary.op.text == "!=") { context_node: ^ast.Expr; @@ -846,8 +872,8 @@ get_identifier_completion :: proc(ast_context: ^analysis.AstContext, position_co for r in results { r := r; resolve_unresolved_symbol(ast_context, &r.symbol); - build_symbol_return(&r.symbol); - build_symbol_signature(&r.symbol); + build_procedure_symbol_return(&r.symbol); + build_procedure_symbol_signature(&r.symbol); if r.symbol.uri != ast_context.uri { append(&combined, CombinedResult {score = r.score, symbol = r.symbol}); } @@ -875,12 +901,12 @@ get_identifier_completion :: proc(ast_context: ^analysis.AstContext, position_co ident := index.new_type(ast.Ident, v.expr.pos, v.expr.end, context.temp_allocator); ident.name = k; - if symbol, ok := resolve_type_identifier(ast_context, ident^); ok { - symbol.name = ident.name; + if symbol, ok := resolve_type_identifier(ast_context, ident^); ok { symbol.signature = get_signature(ast_context, ident^, symbol); + symbol.name = ident.name; - build_symbol_return(&symbol); - build_symbol_signature(&symbol); + build_procedure_symbol_return(&symbol); + build_procedure_symbol_signature(&symbol); if score, ok := common.fuzzy_match(matcher, symbol.name); ok == 1 { append(&combined, CombinedResult {score = score * 1.1, symbol = symbol, variable = ident}); @@ -901,11 +927,12 @@ get_identifier_completion :: proc(ast_context: ^analysis.AstContext, position_co ident.name = k; if symbol, ok := resolve_type_identifier(ast_context, ident^); ok { - symbol.name = ident.name; + symbol.signature = get_signature(ast_context, ident^, symbol); + symbol.name = ident.name; - build_symbol_return(&symbol); - build_symbol_signature(&symbol); + build_procedure_symbol_return(&symbol); + build_procedure_symbol_signature(&symbol); if score, ok := common.fuzzy_match(matcher, symbol.name); ok == 1 { append(&combined, CombinedResult {score = score * 1.1, symbol = symbol, variable = ident}); @@ -961,13 +988,13 @@ get_identifier_completion :: proc(ast_context: ^analysis.AstContext, position_co sort.sort(combined_sort_interface(&combined)); //hard code for now - top_results := combined[0:(min(20, len(combined)))]; + top_results := combined[0:(min(50, len(combined)))]; for result in top_results { result := result; - //Skip procedures when the position is in proc decl + //Skip procedures when the position is in proc decl if position_in_proc_decl(position_context) && result.symbol.type == .Function && common.config.enable_procedure_context { continue; } @@ -1014,7 +1041,7 @@ 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.deprecated = .Deprecated in result.symbol.flags; item.command.command = "editor.action.triggerParameterHints"; } @@ -1101,7 +1128,6 @@ search_for_packages :: proc(fullpath: string) -> [] string { } if files, err := os.read_dir(fh, 0, context.temp_allocator); err == 0 { - for file in files { if file.is_dir { append(&packages, file.fullpath); @@ -1123,13 +1149,9 @@ get_type_switch_completion :: proc(ast_context: ^analysis.AstContext, position_c used_unions := make(map[string]bool, 5, context.temp_allocator); if block, ok := position_context.switch_type_stmt.body.derived.(ast.Block_Stmt); ok { - for stmt in block.stmts { - if case_clause, ok := stmt.derived.(ast.Case_Clause); ok { - for name in case_clause.list { - if ident, ok := name.derived.(ast.Ident); ok { used_unions[ident.name] = true; } @@ -1142,23 +1164,21 @@ get_type_switch_completion :: proc(ast_context: ^analysis.AstContext, position_c ast_context.use_globals = true; if assign, ok := position_context.switch_type_stmt.tag.derived.(ast.Assign_Stmt); ok && assign.rhs != nil && len(assign.rhs) == 1 { - if union_value, ok := unwrap_union(ast_context, assign.rhs[0]); ok { - - for name, i in union_value.names { + for type, i in union_value.types { + name := common.node_to_string(type); if name in used_unions { continue; } if symbol, ok := resolve_type_expression(ast_context, union_value.types[i]); ok { - item := CompletionItem { kind = .EnumMember, }; if symbol.pkg == ast_context.document_package { - item.label = fmt.aprintf("%v", name); + item.label = fmt.aprintf("%v", common.node_to_string(union_value.types[i])); item.detail = item.label; } else { item.label = fmt.aprintf("%v.%v", path.base(symbol.pkg, false, context.temp_allocator), name); @@ -1228,11 +1248,47 @@ is_bitset_assignment_operator :: proc(op: string) -> bool { } language_keywords: []string = { - "align_of","case","defer","enum","import","proc","transmute","when", - "auto_cast","cast","distinct","fallthrough","in","notin","return","type_of", - "bit_field","const","do","for","inline","offset_of","size_of","typeid", - "bit_set","context","dynamic","foreign","opaque","struct","union", - "break","continue","else","if","map","package","switch","using", + "align_of", + "case", + "defer", + "enum", + "import", + "proc", + "transmute", + "when", + "auto_cast", + "cast", + "distinct", + "fallthrough", + "in", + "notin", + "return", + "type_of", + "bit_field", + "const", + "do", + "for", + "inline", + "offset_of", + "size_of", + "typeid", + "bit_set", + "context", + "dynamic", + "foreign", + "opaque", + "struct", + "union", + "break", + "continue", + "else", + "if", + "map", + "package", + "switch", + "using", + "or_return", + "or_else", }; swizzle_color_components: map[u8]bool = { diff --git a/src/server/hover.odin b/src/server/hover.odin index 443a528..e3e08fa 100644 --- a/src/server/hover.odin +++ b/src/server/hover.odin @@ -34,8 +34,8 @@ write_hover_content :: proc(ast_context: ^analysis.AstContext, symbol: index.Sym } } - build_symbol_return(&symbol); - build_symbol_signature(&symbol); + build_procedure_symbol_return(&symbol); + build_procedure_symbol_signature(&symbol); cat := concatenate_symbols_information(ast_context, symbol, false); @@ -95,9 +95,9 @@ get_hover_information :: proc(document: ^common.Document, position: common.Posit if ident.name == base.name { - if resolved, ok := resolve_type_identifier(&ast_context, ident); ok { - resolved.name = ident.name; + if resolved, ok := resolve_type_identifier(&ast_context, ident); ok { resolved.signature = get_signature(&ast_context, ident, resolved); + resolved.name = ident.name; if is_variable, ok := ast_context.variables[ident.name]; ok && is_variable { resolved.pkg = ast_context.document_package; @@ -162,9 +162,9 @@ get_hover_information :: proc(document: ^common.Document, position: common.Posit hover.range = common.get_token_range(position_context.identifier^, document.ast.src); - if resolved, ok := resolve_type_identifier(&ast_context, ident); ok { - resolved.name = ident.name; + if resolved, ok := resolve_type_identifier(&ast_context, ident); ok { resolved.signature = get_signature(&ast_context, ident, resolved); + resolved.name = ident.name; if is_variable, ok := ast_context.variables[ident.name]; ok && is_variable { resolved.pkg = ast_context.document_package; diff --git a/src/server/requests.odin b/src/server/requests.odin index 8fc0fa1..fc5ea68 100644 --- a/src/server/requests.odin +++ b/src/server/requests.odin @@ -85,7 +85,7 @@ read_and_parse_header :: proc (reader: ^Reader) -> (Header, bool) { header: Header; builder := strings.make_builder(context.temp_allocator); - + found_content_length := false; for true { @@ -422,7 +422,8 @@ request_initialize :: proc (task: ^common.Task) { config.verbose = ols_config.verbose; config.file_log = ols_config.file_log; config.formatter = ols_config.formatter; - + config.odin_command = strings.clone(ols_config.odin_command, context.allocator); + for p in ols_config.collections { forward_path, _ := filepath.to_slash(p.path, context.temp_allocator); @@ -947,7 +948,7 @@ notification_did_save :: proc (task: ^common.Task) { log.errorf("failed to collect symbols on save %v", ret); } - //check(uri, writer); + check(uri, writer, config); } request_semantic_token_full :: proc (task: ^common.Task) { diff --git a/src/server/signature.odin b/src/server/signature.odin index f634327..1e89dc1 100644 --- a/src/server/signature.odin +++ b/src/server/signature.odin @@ -52,7 +52,7 @@ ParameterInformation :: struct { /* Lazily build the signature and returns from ast.Nodes */ -build_symbol_signature :: proc(symbol: ^index.Symbol) { +build_procedure_symbol_signature :: proc(symbol: ^index.Symbol) { if value, ok := symbol.value.(index.SymbolProcedureValue); ok { builder := strings.make_builder(context.temp_allocator); @@ -69,7 +69,7 @@ build_symbol_signature :: proc(symbol: ^index.Symbol) { } } -build_symbol_return :: proc(symbol: ^index.Symbol) { +build_procedure_symbol_return :: proc(symbol: ^index.Symbol) { if value, ok := symbol.value.(index.SymbolProcedureValue); ok { builder := strings.make_builder(context.temp_allocator); @@ -174,8 +174,8 @@ get_signature_information :: proc(document: ^common.Document, position: common.P parameters[i].label = common.node_to_string(arg); } - build_symbol_signature(&call); - build_symbol_return(&call); + build_procedure_symbol_signature(&call); + build_procedure_symbol_return(&call); info := SignatureInformation { label = concatenate_symbols_information(&ast_context, call, false), @@ -205,8 +205,8 @@ get_signature_information :: proc(document: ^common.Document, position: common.P parameters[i].activeParameter = i; } - build_symbol_signature(&symbol); - build_symbol_return(&symbol); + build_procedure_symbol_signature(&symbol); + build_procedure_symbol_return(&symbol); info := SignatureInformation { label = concatenate_symbols_information(&ast_context, symbol, false), diff --git a/src/server/types.odin b/src/server/types.odin index d369b33..4a36d82 100644 --- a/src/server/types.odin +++ b/src/server/types.odin @@ -301,6 +301,7 @@ OlsConfig :: struct { verbose: bool, file_log: bool, formatter: common.Format_Config, + odin_command: string, } OlsConfigCollection :: struct { diff --git a/src/testing/testing.odin b/src/testing/testing.odin index 0703708..bd4e39b 100644 --- a/src/testing/testing.odin +++ b/src/testing/testing.odin @@ -160,6 +160,41 @@ expect_signature_parameter_position :: proc(t: ^testing.T, src: ^Source, positio } } +expect_completion_labels :: proc(t: ^testing.T, src: ^Source, trigger_character: string, expect_labels: []string) { + setup(src); + + completion_context := server.CompletionContext { + triggerCharacter = trigger_character, + }; + + completion_list, ok := server.get_completion_list(src.document, src.position, completion_context); + + if !ok { + testing.error(t, "Failed get_completion_list"); + } + + if len(expect_labels) == 0 && len(completion_list.items) > 0 { + testing.errorf(t, "Expected empty completion label, but received %v", completion_list.items); + } + + flags := make([]int, len(expect_labels)); + + for expect_label, i in expect_labels { + for completion, j in completion_list.items { + if expect_label == completion.label { + flags[i] += 1; + } + } + } + + for flag, i in flags { + if flag != 1 { + testing.errorf(t, "Expected completion detail %v, but received %v", expect_labels[i], completion_list.items); + } + } + +} + expect_completion_details :: proc(t: ^testing.T, src: ^Source, trigger_character: string, expect_details: []string) { setup(src); |