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/server | |
| parent | bb1379a911f43134b8dc5ed9ec2eebb889b800fb (diff) | |
| parent | e587db0c06c0972a67867282eb9f16448101f34b (diff) | |
Merge branch 'master' into refractor-analysis
Diffstat (limited to 'src/server')
| -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 |
6 files changed, 291 insertions, 195 deletions
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 { |