diff options
| author | Daniel Gavin <danielgavin5@hotmail.com> | 2022-01-05 09:33:03 +0100 |
|---|---|---|
| committer | Daniel Gavin <danielgavin5@hotmail.com> | 2022-01-05 09:33:03 +0100 |
| commit | 93df32b34b80da4d62644004160294d1d068a934 (patch) | |
| tree | ed42f20ebda9993b1ad0ebe552043be5e9bd7bc5 /src | |
| parent | 508b2487f45fac7a58549e4c5f8cde3f250ae568 (diff) | |
more refractoring by trying to store the variable information on the symbol.
Diffstat (limited to 'src')
| -rw-r--r-- | src/analysis/analysis.odin | 142 | ||||
| -rw-r--r-- | src/common/position.odin | 1 | ||||
| -rw-r--r-- | src/common/types.odin | 3 | ||||
| -rw-r--r-- | src/index/collector.odin | 6 | ||||
| -rw-r--r-- | src/index/indexer.odin | 9 | ||||
| -rw-r--r-- | src/index/symbol.odin | 34 | ||||
| -rw-r--r-- | src/server/completion.odin | 61 | ||||
| -rw-r--r-- | src/server/definition.odin | 3 | ||||
| -rw-r--r-- | src/server/document_symbols.odin | 3 | ||||
| -rw-r--r-- | src/server/documents.odin | 12 | ||||
| -rw-r--r-- | src/server/hover.odin | 2 | ||||
| -rw-r--r-- | src/server/inlay_hints.odin | 2 | ||||
| -rw-r--r-- | src/server/lens.odin | 2 | ||||
| -rw-r--r-- | src/server/requests.odin | 4 | ||||
| -rw-r--r-- | src/server/semantic_tokens.odin | 490 | ||||
| -rw-r--r-- | src/server/signature.odin | 2 |
16 files changed, 163 insertions, 613 deletions
diff --git a/src/analysis/analysis.odin b/src/analysis/analysis.odin index f80e1d0..c0da0b6 100644 --- a/src/analysis/analysis.odin +++ b/src/analysis/analysis.odin @@ -64,6 +64,7 @@ DocumentPositionContext :: struct { DocumentLocal :: struct { expr: ^ast.Expr, offset: int, + id: int, //Id that can used to connect the local to something, i.e. for stmt begin offset } AstContext :: struct { @@ -85,10 +86,10 @@ AstContext :: struct { value_decl: ^ast.Value_Decl, field_name: string, uri: string, + symbol_cache: ^map[int]rawptr, //symbol_cache from the current document } -make_ast_context :: proc(file: ast.File, imports: []common.Package, package_name: string, uri: string, allocator := context.temp_allocator) -> AstContext { - +make_ast_context :: proc(file: ast.File, imports: []common.Package, package_name: string, uri: string, symbol_cache: ^map[int]rawptr, allocator := context.temp_allocator) -> AstContext { ast_context := AstContext { locals = make(map[string][dynamic]DocumentLocal, 0, allocator), globals = make(map[string]common.GlobalExpr, 0, allocator), @@ -103,6 +104,7 @@ make_ast_context :: proc(file: ast.File, imports: []common.Package, package_name document_package = package_name, current_package = package_name, uri = uri, + symbol_cache = symbol_cache, }; when ODIN_OS == "windows" { @@ -785,7 +787,6 @@ 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 = .Constant, }; @@ -818,8 +819,37 @@ resolve_basic_directive :: proc(ast_context: ^AstContext, directive: ast.Basic_D return {}, false; } +//Experiment with caching the results of the current file, this might just make it slower, +//but it will help with multiple requests like semantic tokens. +//If this doesn't provide good results, just handle caching explicitly on semantic tokens only. +lookup_symbol_cache :: proc(ast_context: ^AstContext, node: ast.Node) -> (index.Symbol, bool) { + if ast_context.document_package != node.pos.file || node.pos.file == "" { + return {}, false; + } + + if cached := &ast_context.symbol_cache[node.pos.offset]; cached != nil { + symbol := cast(^index.Symbol)cached^; + return symbol^, true; + } + return {}, false; +} + resolve_type_expression :: proc(ast_context: ^AstContext, node: ^ast.Expr) -> (index.Symbol, bool) { + if symbol, ok := lookup_symbol_cache(ast_context, node^); ok { + return symbol, true; + } + + if symbol, ok := internal_resolve_type_expression(ast_context, node); ok { + cached_symbol := index.new_clone_symbol(symbol); + ast_context.symbol_cache[node.pos.offset] = cast(rawptr)cached_symbol; + return symbol, true; + } + + return {}, false; +} + +internal_resolve_type_expression :: proc(ast_context: ^AstContext, node: ^ast.Expr) -> (index.Symbol, bool) { if node == nil { return {}, false; } @@ -1010,8 +1040,7 @@ resolve_type_expression :: proc(ast_context: ^AstContext, node: ^ast.Expr) -> (i return index.Symbol {}, false; } -store_local :: proc(ast_context: ^AstContext, expr: ^ast.Expr, offset: int, name: string) { - +store_local :: proc(ast_context: ^AstContext, expr: ^ast.Expr, offset: int, name: string, id := 0) { local_stack := &ast_context.locals[name]; if local_stack == nil { @@ -1019,11 +1048,10 @@ store_local :: proc(ast_context: ^AstContext, expr: ^ast.Expr, offset: int, name local_stack = &ast_context.locals[name]; } - append(local_stack, DocumentLocal {expr = expr, offset = offset}); + append(local_stack, DocumentLocal {expr = expr, offset = offset, id = id}); } -get_local :: proc(ast_context: ^AstContext, offset: int, name: string) -> ^ast.Expr { - +get_local :: proc(ast_context: ^AstContext, offset: int, name: string, id := 0) -> ^ast.Expr { previous := 0; //is the local we are getting being declared? @@ -1041,7 +1069,7 @@ get_local :: proc(ast_context: ^AstContext, offset: int, name: string) -> ^ast.E if local_stack, ok := ast_context.locals[name]; ok { for i := len(local_stack) - 1; i >= 0; i -= 1 { - if local_stack[i].offset <= offset { + if local_stack[i].offset <= offset && local_stack[i].id == id { if i - previous < 0 { return nil; } else { @@ -1055,7 +1083,20 @@ get_local :: proc(ast_context: ^AstContext, offset: int, name: string) -> ^ast.E } resolve_type_identifier :: proc(ast_context: ^AstContext, node: ast.Ident) -> (index.Symbol, bool) { + if symbol, ok := lookup_symbol_cache(ast_context, node); ok { + return symbol, true; + } + + if symbol, ok := internal_resolve_type_identifier(ast_context, node); ok { + cached_symbol := index.new_clone_symbol(symbol); + ast_context.symbol_cache[node.pos.offset] = cast(rawptr)cached_symbol; + return symbol, true; + } + return {}, false; +} + +internal_resolve_type_identifier :: proc(ast_context: ^AstContext, node: ast.Ident) -> (index.Symbol, bool) { using ast; if pkg, ok := ast_context.in_package[node.name]; ok { @@ -1078,7 +1119,6 @@ resolve_type_identifier :: proc(ast_context: ^AstContext, node: ast.Ident) -> (i //note(Daniel, if global and local ends up being 100% same just make a function that takes the map) if local := get_local(ast_context, node.pos.offset, node.name); local != nil && ast_context.use_locals { - is_distinct := false; if dist, ok := local.derived.(ast.Distinct_Type); ok { @@ -1138,7 +1178,6 @@ resolve_type_identifier :: proc(ast_context: ^AstContext, node: ast.Ident) -> (i return return_symbol, ok; } else if global, ok := ast_context.globals[node.name]; ast_context.use_globals && ok { - is_distinct := false; if dist, ok := global.expr.derived.(ast.Distinct_Type); ok { @@ -1235,7 +1274,6 @@ resolve_type_identifier :: proc(ast_context: ^AstContext, node: ast.Ident) -> (i } else { //right now we replace the package ident with the absolute directory name, so it should have '/' which is not a valid ident character if strings.contains(node.name, "/") { - symbol := index.Symbol { type = .Package, pkg = node.name, @@ -1246,9 +1284,7 @@ resolve_type_identifier :: proc(ast_context: ^AstContext, node: ast.Ident) -> (i } else { //part of the ast so we check the imports of the document for imp in ast_context.imports { - if strings.compare(imp.base, node.name) == 0 { - symbol := index.Symbol { type = .Package, pkg = imp.name, @@ -1275,39 +1311,21 @@ resolve_type_identifier :: proc(ast_context: ^AstContext, node: ast.Ident) -> (i } for u in ast_context.usings { - //TODO(Daniel, make into a map, not really required for performance but looks nicer) for imp in ast_context.imports { - if strings.compare(imp.base, u) == 0 { - if symbol, ok := index.lookup(node.name, imp.name); ok { return resolve_symbol_return(ast_context, symbol); } } } } - } return index.Symbol {}, false; } -resolve_ident_is_variable :: proc(ast_context: ^AstContext, node: ast.Ident) -> bool { - - if v, ok := ast_context.variables[node.name]; ok && v { - return true; - } - - if symbol, ok := index.lookup(node.name, ast_context.current_package); ok { - return symbol.type == .Variable; - } - - return false; -} - resolve_ident_is_package :: proc(ast_context: ^AstContext, node: ast.Ident) -> bool { - if strings.contains(node.name, "/") { return true; } else { @@ -1985,7 +2003,6 @@ get_generic_assignment :: proc(file: ast.File, value: ^ast.Expr, ast_context: ^A switch v in &value.derived { case Call_Expr: - ast_context.call = cast(^ast.Call_Expr)value; if symbol, ok := resolve_type_expression(ast_context, v.expr); ok { @@ -2400,34 +2417,71 @@ clear_locals :: proc(ast_context: ^AstContext) { clear(&ast_context.usings); } -/* -resolve_entire_file :: proc(document: ^common.Document, allocator := context.allocator) -> []^index.Symbol { - ast_context := make_ast_context(document.ast, document.imports, document.package_name, document.uri.uri); +resolve_entire_file :: proc(document: ^common.Document, allocator := context.allocator) -> []index.Symbol { + ast_context := make_ast_context(document.ast, document.imports, document.package_name, document.uri.uri, &document.symbol_cache); get_globals(document.ast, &ast_context); ast_context.current_package = ast_context.document_package; - symbols := make([]^index.Symbol, allocator); + symbols := make([dynamic]index.Symbol, allocator); for decl in document.ast.decls { switch v in decl.derived { case ast.Proc_Lit: - resolve_entire_procedure(v.type, &symbols, allocator); + resolve_entire_procedure(&ast_context, v, &symbols, allocator); } } + + return symbols[:]; } -resolve_entire_procedure :: proc(procedure: ^ast.Proc_Type, symbols: ^[]^index.Symbol, allocator := context.allocator) { - if procedure == nil { - return {}; +resolve_entire_procedure :: proc(ast_context: ^AstContext, procedure: ast.Proc_Lit, symbols: ^[dynamic]index.Symbol, allocator := context.allocator) { + Visit_Data :: struct { + ast_context: ^AstContext, + symbols: ^[dynamic]index.Symbol, } - get_locals() + data := Visit_Data { + ast_context = ast_context, + symbols = symbols, + }; + + visit :: proc(visitor: ^ast.Visitor, node: ^ast.Node) -> ^ast.Visitor { + if node == nil || visitor == nil { + return nil; + } + + data := cast(^Visit_Data)visitor.data; + ast_context := data.ast_context; + + switch v in &node.derived { + case ast.Ident: + if symbol, ok := resolve_type_identifier(ast_context, v); ok { + append(data.symbols, symbol); + } + case ast.Selector_Expr: + if symbol, ok := resolve_type_expression(ast_context, &v.node); ok { + append(data.symbols, symbol); + } + } + + return visitor; + } + visitor := ast.Visitor { + data = &data, + visit = visit, + } + ast.walk(&visitor, procedure.body); + + if procedure.type != nil { + ast.walk(&visitor, procedure.type.params); + ast.walk(&visitor, procedure.type.results); + } } -*/ + concatenate_symbol_information :: proc { concatenate_raw_symbol_information, @@ -2512,7 +2566,7 @@ get_signature :: proc(ast_context: ^AstContext, ident: ast.Ident, symbol: index. return symbol.name; } - is_variable := resolve_ident_is_variable(ast_context, ident); + is_variable := symbol.type == .Variable; #partial switch v in symbol.value { case SymbolBasicValue: diff --git a/src/common/position.odin b/src/common/position.odin index 41bf00a..4e84568 100644 --- a/src/common/position.odin +++ b/src/common/position.odin @@ -55,7 +55,6 @@ get_absolute_position :: proc(position: Position, document_text: []u8) -> (Absol } get_relative_token_position :: proc(offset: int, document_text: []u8, current_start: int) -> Position { - start_index := current_start; data := document_text[start_index:]; diff --git a/src/common/types.odin b/src/common/types.odin index 317269b..0956e89 100644 --- a/src/common/types.odin +++ b/src/common/types.odin @@ -37,8 +37,9 @@ Document :: struct { ast: ast.File, imports: []Package, package_name: string, - allocator: ^Scratch_Allocator, //because does not support freeing I use arena allocators for each document + allocator: ^Scratch_Allocator, //because parser does not support freeing I use arena allocators for each document operating_on: int, //atomic + symbol_cache: map[int]rawptr, //Stores all the symbol data for this current iteration of the file. Gets cleared every change. } parser_warning_handler :: proc(pos: tokenizer.Pos, msg: string, args: ..any) { diff --git a/src/index/collector.odin b/src/index/collector.odin index a76fef5..91a5419 100644 --- a/src/index/collector.odin +++ b/src/index/collector.odin @@ -336,7 +336,11 @@ collect_symbols :: proc(collection: ^SymbolCollection, file: ast.File, uri: stri } case: // default symbol.value = collect_generic(collection, col_expr, package_map); - token_type = .Unresolved; + if expr.mutable { + token_type = .Variable; + } else { + token_type = .Unresolved; + } token = expr.expr; } diff --git a/src/index/indexer.odin b/src/index/indexer.odin index 611b922..6c74436 100644 --- a/src/index/indexer.odin +++ b/src/index/indexer.odin @@ -33,6 +33,8 @@ import "core:sort" This index is first searched and if nothing is found look in the static index. */ + + Indexer :: struct { built_in_packages: [dynamic]string, static_index: MemoryIndex, @@ -47,7 +49,6 @@ FuzzyResult :: struct { } lookup :: proc(name: string, pkg: string, loc := #caller_location) -> (Symbol, bool) { - if symbol, ok := memory_index_lookup(&indexer.dynamic_index, name, pkg); ok { log.infof("lookup dynamic name: %v pkg: %v, symbol %v location %v", name, pkg, symbol, loc); return symbol, true; @@ -64,9 +65,9 @@ lookup :: proc(name: string, pkg: string, loc := #caller_location) -> (Symbol, b fuzzy_search :: proc(name: string, pkgs: []string) -> ([]FuzzyResult, bool) { dynamic_results, dynamic_ok := memory_index_fuzzy_search(&indexer.dynamic_index, name, pkgs); - static_results, static_ok := memory_index_fuzzy_search(&indexer.static_index, name, pkgs); - result := make([dynamic]FuzzyResult, context.temp_allocator); - files := make(map[string]bool, 0, context.temp_allocator); + static_results, static_ok := memory_index_fuzzy_search(&indexer.static_index, name, pkgs); + result := make([dynamic]FuzzyResult, context.temp_allocator); + files := make(map[string]bool, 0, context.temp_allocator); if !dynamic_ok || !static_ok { return {}, false; diff --git a/src/index/symbol.odin b/src/index/symbol.odin index 37392e4..863701c 100644 --- a/src/index/symbol.odin +++ b/src/index/symbol.odin @@ -103,24 +103,25 @@ SymbolFlag :: enum { Deprecated, PrivateFile, PrivatePackage, - Anonymous, + Anonymous, //Usually applied to structs that are defined inline inside another struct + Variable, //Symbols that are variable, this means their value decl was mutable } SymbolFlags :: bit_set[SymbolFlag] Symbol :: struct { - range: common.Range, //the range of the symbol in the file - uri: string, //uri of the file the symbol resides - pkg: string, //absolute directory path where the symbol resides - name: string, //name of the symbol - doc: string, - signature: string, //type signature - returns: string, //precedure return signature - type: SymbolType, - value: SymbolValue, - references: []common.Location, //all the places in the project that it's being referenced - pointers: int, //how many `^` are applied to the symbol - flags: SymbolFlags, + range: common.Range, //the range of the symbol in the file + uri: string, //uri of the file the symbol resides + pkg: string, //absolute directory path where the symbol resides + name: string, //name of the symbol + doc: string, + signature: string, //type signature + returns: string, //precedure return signature + type: SymbolType, + value: SymbolValue, + references: []common.Location, //all the places in the project that it's being referenced + pointers: int, //how many `^` are applied to the symbol + flags: SymbolFlags, } SymbolType :: enum { @@ -137,6 +138,13 @@ SymbolType :: enum { Unresolved = 9999, } +new_clone_symbol :: proc(data: Symbol, allocator := context.allocator) -> (^Symbol) { + new_symbol := new(Symbol, allocator); + new_symbol^ = data; + new_symbol.value = data.value; + return new_symbol; +} + free_symbol :: proc(symbol: Symbol, allocator: mem.Allocator) { if symbol.signature != "" && symbol.signature != "struct" && diff --git a/src/server/completion.odin b/src/server/completion.odin index 87490ac..0885e00 100644 --- a/src/server/completion.odin +++ b/src/server/completion.odin @@ -50,7 +50,7 @@ get_completion_list :: proc(document: ^common.Document, position: common.Positio return list, true; } - ast_context := make_ast_context(document.ast, document.imports, document.package_name, document.uri.uri); + ast_context := make_ast_context(document.ast, document.imports, document.package_name, document.uri.uri, &document.symbol_cache); get_globals(document.ast, &ast_context); @@ -232,10 +232,13 @@ get_selector_completion :: proc(ast_context: ^analysis.AstContext, position_cont } if ident, ok := position_context.selector.derived.(ast.Ident); ok { - is_variable := resolve_ident_is_variable(ast_context, ident); - is_package := resolve_ident_is_package(ast_context, ident); + symbol, ok := resolve_type_identifier(ast_context, ident); - if (!is_variable && !is_package && selector.type != .Enum && ident.name != "") || (is_variable && selector.type == .Enum) { + if !ok { + return; + } + + if (symbol.type != .Variable && symbol.type != .Package && selector.type != .Enum && ident.name != "") || (symbol.type == .Variable && selector.type == .Enum) { return; } } @@ -386,7 +389,6 @@ get_selector_completion :: proc(ast_context: ^analysis.AstContext, position_cont list.isIncomplete = false; for name in v.names { - item := CompletionItem { label = name, kind = .EnumMember, @@ -439,11 +441,9 @@ get_selector_completion :: proc(ast_context: ^analysis.AstContext, position_cont } case index.SymbolPackageValue: - list.isIncomplete = true; if searched, ok := index.fuzzy_search(field, {selector.pkg}); ok { - for search in searched { symbol := search.symbol; @@ -477,7 +477,6 @@ get_selector_completion :: proc(ast_context: ^analysis.AstContext, position_cont } get_implicit_completion :: proc(ast_context: ^analysis.AstContext, position_context: ^analysis.DocumentPositionContext, list: ^CompletionList) { - using analysis; items := make([dynamic]CompletionItem, context.temp_allocator); @@ -497,17 +496,12 @@ get_implicit_completion :: proc(ast_context: ^analysis.AstContext, position_cont //enum switch infer if position_context.switch_stmt != nil && position_context.case_clause != nil && position_context.switch_stmt.cond != nil { - used_enums := make(map[string]bool, 5, context.temp_allocator); if block, ok := position_context.switch_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 implicit, ok := name.derived.(ast.Implicit_Selector_Expr); ok { used_enums[implicit.field.name] = true; } @@ -517,9 +511,7 @@ get_implicit_completion :: proc(ast_context: ^analysis.AstContext, position_cont } if enum_value, ok := unwrap_enum(ast_context, position_context.switch_stmt.cond); ok { - for name in enum_value.names { - if name in used_enums { continue; } @@ -658,7 +650,6 @@ 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; enum_node: ^ast.Expr; @@ -673,7 +664,6 @@ get_implicit_completion :: proc(ast_context: ^analysis.AstContext, position_cont if context_node != nil && enum_node != nil { if enum_value, ok := unwrap_enum(ast_context, enum_node); ok { for name in enum_value.names { - item := CompletionItem { label = name, kind = .EnumMember, @@ -690,19 +680,15 @@ get_implicit_completion :: proc(ast_context: ^analysis.AstContext, position_cont } if position_context.assign != nil && position_context.assign.rhs != nil && position_context.assign.lhs != nil { - rhs_index: int; for elem in position_context.assign.rhs { if position_in_node(elem, position_context.position) { break; } else { - //procedures are the only types that can return more than one value if symbol, ok := resolve_type_expression(ast_context, elem); ok { - if procedure, ok := symbol.value.(index.SymbolProcedureValue); ok { - if procedure.return_types == nil { return; } @@ -718,7 +704,6 @@ get_implicit_completion :: proc(ast_context: ^analysis.AstContext, position_cont if len(position_context.assign.lhs) > rhs_index { if enum_value, ok := unwrap_enum(ast_context, position_context.assign.lhs[rhs_index]); ok { for name in enum_value.names { - item := CompletionItem { label = name, kind = .EnumMember, @@ -735,7 +720,6 @@ get_implicit_completion :: proc(ast_context: ^analysis.AstContext, position_cont } if position_context.returns != nil && position_context.function != nil { - return_index: int; if position_context.returns.results == nil { @@ -743,7 +727,6 @@ get_implicit_completion :: proc(ast_context: ^analysis.AstContext, position_cont } for result, i in position_context.returns.results { - if position_in_node(result, position_context.position) { return_index = i; break; @@ -759,11 +742,8 @@ get_implicit_completion :: proc(ast_context: ^analysis.AstContext, position_cont } if len(position_context.function.type.results.list) > return_index { - if enum_value, ok := unwrap_enum(ast_context, position_context.function.type.results.list[return_index].type); ok { - for name in enum_value.names { - item := CompletionItem { label = name, kind = .EnumMember, @@ -780,21 +760,15 @@ get_implicit_completion :: proc(ast_context: ^analysis.AstContext, position_cont } if position_context.call != nil { - if call, ok := position_context.call.derived.(ast.Call_Expr); ok { - parameter_index, parameter_ok := find_position_in_call_param(ast_context, call); - if symbol, ok := resolve_type_expression(ast_context, call.expr); ok && parameter_ok { - if proc_value, ok := symbol.value.(index.SymbolProcedureValue); ok { - if len(proc_value.arg_types) <= parameter_index { return; } if enum_value, ok := unwrap_enum(ast_context, proc_value.arg_types[parameter_index].type); ok { - for name in enum_value.names { item := CompletionItem { label = name, @@ -815,7 +789,6 @@ get_implicit_completion :: proc(ast_context: ^analysis.AstContext, position_cont } get_identifier_completion :: proc(ast_context: ^analysis.AstContext, position_context: ^analysis.DocumentPositionContext, list: ^CompletionList) { - using analysis; items := make([dynamic]CompletionItem, context.temp_allocator); @@ -824,7 +797,6 @@ get_identifier_completion :: proc(ast_context: ^analysis.AstContext, position_co CombinedResult :: struct { score: f32, - variable: ^ast.Ident, snippet: Snippet_Info, name: string, type: index.SymbolType, @@ -931,7 +903,6 @@ get_identifier_completion :: proc(ast_context: ^analysis.AstContext, position_co pkg = symbol.pkg, signature = symbol.signature, returns = symbol.returns, - variable = ident, }); } } @@ -965,7 +936,6 @@ get_identifier_completion :: proc(ast_context: ^analysis.AstContext, position_co pkg = symbol.pkg, signature = symbol.signature, returns = symbol.returns, - variable = ident, }); } } @@ -1049,7 +1019,6 @@ get_identifier_completion :: proc(ast_context: ^analysis.AstContext, position_co top_results := combined[0:(min(50, len(combined)))]; for result in top_results { - result := result; //Skip procedures when the position is in proc decl @@ -1085,16 +1054,7 @@ get_identifier_completion :: proc(ast_context: ^analysis.AstContext, position_co documentation = result.doc, }; - if result.variable != nil { - if ok := resolve_ident_is_variable(ast_context, result.variable^); ok { - item.kind = .Variable; - result.type = .Variable; - } else { - item.kind = cast(CompletionItemKind)result.type; - } - } else { - item.kind = cast(CompletionItemKind)result.type; - } + item.kind = cast(CompletionItemKind)result.type; if result.type == .Function { item.insertText = fmt.tprintf("%v($0)", item.label); @@ -1143,7 +1103,6 @@ get_package_completion :: proc(ast_context: ^analysis.AstContext, position_conte } if !strings.contains(position_context.import_stmt.fullpath, "/") && !strings.contains(position_context.import_stmt.fullpath, ":") { - for key, _ in common.config.collections { item := CompletionItem { @@ -1158,7 +1117,6 @@ get_package_completion :: proc(ast_context: ^analysis.AstContext, position_conte } for pkg in search_for_packages(absolute_path) { - item := CompletionItem { detail = pkg, label = filepath.base(pkg), @@ -1176,7 +1134,6 @@ get_package_completion :: proc(ast_context: ^analysis.AstContext, position_conte } search_for_packages :: proc(fullpath: string) -> [] string { - packages := make([dynamic]string, context.temp_allocator); fh, err := os.open(fullpath); @@ -1198,7 +1155,6 @@ search_for_packages :: proc(fullpath: string) -> [] string { } get_type_switch_completion :: proc(ast_context: ^analysis.AstContext, position_context: ^analysis.DocumentPositionContext, list: ^CompletionList) { - using analysis; items := make([dynamic]CompletionItem, context.temp_allocator); @@ -1253,7 +1209,6 @@ get_type_switch_completion :: proc(ast_context: ^analysis.AstContext, position_c } get_core_insert_package_if_non_existent :: proc(ast_context: ^analysis.AstContext, pkg: string) -> (TextEdit, bool) { - builder := strings.make_builder(context.temp_allocator); for imp in ast_context.imports { diff --git a/src/server/definition.odin b/src/server/definition.odin index 6d44227..01641b4 100644 --- a/src/server/definition.odin +++ b/src/server/definition.odin @@ -20,14 +20,13 @@ import "shared:index" import "shared:analysis" get_definition_location :: proc(document: ^common.Document, position: common.Position) -> ([]common.Location, bool) { - using analysis; locations := make([dynamic]common.Location, context.temp_allocator); location: common.Location; - ast_context := make_ast_context(document.ast, document.imports, document.package_name, document.uri.uri); + ast_context := make_ast_context(document.ast, document.imports, document.package_name, document.uri.uri, &document.symbol_cache); uri: string; diff --git a/src/server/document_symbols.odin b/src/server/document_symbols.odin index 0b4402e..db18e56 100644 --- a/src/server/document_symbols.odin +++ b/src/server/document_symbols.odin @@ -21,10 +21,9 @@ import "shared:analysis" get_document_symbols :: proc(document: ^common.Document) -> []DocumentSymbol { - using analysis; - ast_context := make_ast_context(document.ast, document.imports, document.package_name, document.uri.uri); + ast_context := make_ast_context(document.ast, document.imports, document.package_name, document.uri.uri, &document.symbol_cache); get_globals(document.ast, &ast_context); diff --git a/src/server/documents.odin b/src/server/documents.odin index 2dc1685..71e6cd0 100644 --- a/src/server/documents.odin +++ b/src/server/documents.odin @@ -105,11 +105,11 @@ document_open :: proc(uri_string: string, text: string, config: ^common.Config, return .InvalidRequest; } - document.uri = uri; + document.uri = uri; document.client_owned = true; - document.text = transmute([]u8)text; - document.used_text = len(document.text); - document.allocator = document_get_allocator(); + document.text = transmute([]u8)text; + document.used_text = len(document.text); + document.allocator = document_get_allocator(); if err := document_refresh(document, config, writer); err != .None { return err; @@ -124,6 +124,8 @@ document_open :: proc(uri_string: string, text: string, config: ^common.Config, allocator = document_get_allocator(), }; + document.symbol_cache = make(map[int]rawptr, 10, common.scratch_allocator(document.allocator)); + if err := document_refresh(&document, config, writer); err != .None { return err; } @@ -248,7 +250,7 @@ document_close :: proc(uri_string: string) -> common.Error { } document_refresh :: proc(document: ^common.Document, config: ^common.Config, writer: ^Writer) -> common.Error { - + clear(&document.symbol_cache); errors, ok := parse_document(document, config); if !ok { diff --git a/src/server/hover.odin b/src/server/hover.odin index 840e666..b77c0b1 100644 --- a/src/server/hover.odin +++ b/src/server/hover.odin @@ -60,7 +60,7 @@ get_hover_information :: proc(document: ^common.Document, position: common.Posit }, }; - ast_context := make_ast_context(document.ast, document.imports, document.package_name, document.uri.uri); + ast_context := make_ast_context(document.ast, document.imports, document.package_name, document.uri.uri, &document.symbol_cache); position_context, ok := get_document_position_context(document, position, .Hover); diff --git a/src/server/inlay_hints.odin b/src/server/inlay_hints.odin index 7d96c84..e67aac9 100644 --- a/src/server/inlay_hints.odin +++ b/src/server/inlay_hints.odin @@ -14,7 +14,7 @@ get_inlay_hints :: proc(document: ^common.Document) -> ([]InlayHint, bool) { hints := make([dynamic]InlayHint, context.temp_allocator); - ast_context := make_ast_context(document.ast, document.imports, document.package_name, document.uri.uri); + ast_context := make_ast_context(document.ast, document.imports, document.package_name, document.uri.uri, &document.symbol_cache); Visit_Data :: struct { calls: [dynamic]ast.Call_Expr, diff --git a/src/server/lens.odin b/src/server/lens.odin index 9d80d0c..822a115 100644 --- a/src/server/lens.odin +++ b/src/server/lens.odin @@ -24,7 +24,7 @@ get_code_lenses :: proc(document: ^common.Document, position: common.Position) - using analysis; - ast_context := make_ast_context(document.ast, document.imports, document.package_name, document.uri.uri); + ast_context := make_ast_context(document.ast, document.imports, document.package_name, document.uri.uri, &document.symbol_cache); get_globals(document.ast, &ast_context); diff --git a/src/server/requests.odin b/src/server/requests.odin index fc5ea68..7892432 100644 --- a/src/server/requests.odin +++ b/src/server/requests.odin @@ -674,6 +674,8 @@ request_completion :: proc (task: ^common.Task) { return; } + //context.allocator = common.scratch_allocator(document.allocator); + list: CompletionList; list, ok = get_completion_list(document, completition_params.position, completition_params.context_); @@ -912,7 +914,6 @@ notification_did_save :: proc (task: ^common.Task) { warn = index.log_warning_handler, }; - //have to cheat the parser since it really wants to parse an entire package with the new changes... dir := filepath.base(filepath.dir(fullpath, context.temp_allocator)); pkg := new(ast.Package); @@ -937,7 +938,6 @@ notification_did_save :: proc (task: ^common.Task) { } for key, value in index.indexer.dynamic_index.collection.symbols { - if value.uri == save_params.textDocument.uri { index.free_symbol(value, context.allocator); index.indexer.dynamic_index.collection.symbols[key] = {}; diff --git a/src/server/semantic_tokens.odin b/src/server/semantic_tokens.odin index 40f9020..f7d01dd 100644 --- a/src/server/semantic_tokens.odin +++ b/src/server/semantic_tokens.odin @@ -40,7 +40,7 @@ SemanticTokenModifiers :: enum { } SemanticTokensClientCapabilities :: struct { - requests: struct { + requests: struct { range: bool, }, tokenTypes: []string, @@ -75,15 +75,11 @@ SemanticTokens :: struct { } SemanticTokenBuilder :: struct { - current_function: ^ast.Node, - current_start: int, - selector_member: bool, - selector_package: bool, - tokens: [dynamic]u32, + current_start: int, + tokens: [dynamic]u32, } make_token_builder :: proc(allocator := context.temp_allocator) -> SemanticTokenBuilder { - return { tokens = make([dynamic]u32, context.temp_allocator), }; @@ -95,22 +91,20 @@ get_tokens :: proc(builder: SemanticTokenBuilder) -> SemanticTokens { }; } -get_semantic_tokens :: proc(document: ^common.Document, range: common.Range) -> SemanticTokens { - +get_semantic_tokens :: proc(document: ^common.Document, range: common.Range) -> SemanticTokens { using analysis; - ast_context := make_ast_context(document.ast, document.imports, document.package_name, document.uri.uri, context.temp_allocator); - builder := make_token_builder(); - - get_globals(document.ast, &ast_context); + builder := make_token_builder(); if document.ast.pkg_decl != nil { write_semantic_token(&builder, document.ast.pkg_token, document.ast.src, .Keyword, .None); } + resolve_entire_file(document, context.temp_allocator); + for decl in document.ast.decls { if range.start.line <= decl.pos.line && decl.end.line <= range.end.line { - write_semantic_tokens(decl, &builder, &ast_context); + } } @@ -118,7 +112,6 @@ get_semantic_tokens :: proc(document: ^common.Document, range: common.Range) -> } write_semantic_node :: proc(builder: ^SemanticTokenBuilder, node: ^ast.Node, src: string, type: SemanticTokenTypes, modifier: SemanticTokenModifiers) { - position := common.get_relative_token_position(node.pos.offset, transmute([]u8)src, builder.current_start); name := common.get_ast_node_string(node, src); @@ -129,7 +122,6 @@ write_semantic_node :: proc(builder: ^SemanticTokenBuilder, node: ^ast.Node, src } write_semantic_token :: proc(builder: ^SemanticTokenBuilder, token: tokenizer.Token, src: string, type: SemanticTokenTypes, modifier: SemanticTokenModifiers) { - position := common.get_relative_token_position(token.pos.offset, transmute([]u8)src, builder.current_start); append(&builder.tokens, cast(u32)position.line, cast(u32)position.character, cast(u32)len(token.text), cast(u32)type, 0); @@ -137,8 +129,7 @@ write_semantic_token :: proc(builder: ^SemanticTokenBuilder, token: tokenizer.To builder.current_start = token.pos.offset; } -write_semantic_token_pos :: proc(builder: ^SemanticTokenBuilder, pos: tokenizer.Pos, name: string, src: string, type: SemanticTokenTypes, modifier: SemanticTokenModifiers) { - +write_semantic_string :: proc(builder: ^SemanticTokenBuilder, pos: tokenizer.Pos, name: string, src: string, type: SemanticTokenTypes, modifier: SemanticTokenModifiers) { position := common.get_relative_token_position(pos.offset, transmute([]u8)src, builder.current_start); append(&builder.tokens, cast(u32)position.line, cast(u32)position.character, cast(u32)len(name), cast(u32)type, 0); @@ -146,466 +137,3 @@ write_semantic_token_pos :: proc(builder: ^SemanticTokenBuilder, pos: tokenizer. builder.current_start = pos.offset; } -resolve_and_write_ident :: proc(node: ^ast.Node, builder: ^SemanticTokenBuilder, ast_context: ^analysis.AstContext) -> (is_member: bool, is_package: bool, package_name: string) { - - using analysis; - - n := node.derived.(ast.Ident); - - package_name = ast_context.document_package; - ast_context.current_package = ast_context.document_package; - ast_context.use_globals = true; - ast_context.use_locals = true; - - if resolve_ident_is_variable(ast_context, n) { - write_semantic_node(builder, node, ast_context.file.src, .Variable, .None); - is_member = true; - } else if symbol, ok := resolve_type_identifier(ast_context, n); ok { - #partial switch v in symbol.value { - case index.SymbolPackageValue: - write_semantic_node(builder, node, ast_context.file.src, .Namespace, .None); - is_package = true; - package_name = symbol.pkg; - case index.SymbolStructValue: - write_semantic_node(builder, node, ast_context.file.src, .Struct, .None); - case index.SymbolEnumValue: - write_semantic_node(builder, node, ast_context.file.src, .Enum, .None); - case index.SymbolUnionValue: - write_semantic_node(builder, node, ast_context.file.src, .Enum, .None); - case index.SymbolProcedureValue: - write_semantic_node(builder, node, ast_context.file.src, .Function, .None); - case index.SymbolProcedureGroupValue: - write_semantic_node(builder, node, ast_context.file.src, .Function, .None); - case index.SymbolGenericValue: - #partial switch symbol.type { - case .Keyword: - write_semantic_node(builder, node, ast_context.file.src, .Keyword, .None); - } - } - } - - return; -} - -write_semantic_tokens :: proc { - write_semantic_tokens_node, - write_semantic_tokens_dynamic_array, - write_semantic_tokens_array, - write_semantic_tokens_stmt, -}; - -write_semantic_tokens_array :: proc(array: $A/[]^$T, builder: ^SemanticTokenBuilder, ast_context: ^analysis.AstContext) { - - for elem, i in array { - write_semantic_tokens(elem, builder, ast_context); - } -} - -write_semantic_tokens_dynamic_array :: proc(array: $A/[dynamic]^$T, builder: ^SemanticTokenBuilder, ast_context: ^analysis.AstContext) { - - for elem, i in array { - write_semantic_tokens(elem, builder, ast_context); - } -} - -write_semantic_tokens_stmt :: proc(node: ^ast.Stmt, builder: ^SemanticTokenBuilder, ast_context: ^analysis.AstContext) { - ast_context.current_package = ast_context.document_package; - ast_context.use_globals = true; - ast_context.use_locals = true; - builder.selector_member = false; - write_semantic_tokens_node(node, builder, ast_context); -} - -write_semantic_tokens_node :: proc(node: ^ast.Node, builder: ^SemanticTokenBuilder, ast_context: ^analysis.AstContext) { - - using ast; - - if node == nil { - return; - } - - switch n in node.derived { - case Ellipsis: - write_semantic_token_pos(builder, node.pos, "..", ast_context.file.src, .Operator, .None); - write_semantic_tokens(n.expr, builder, ast_context); - case Ident: - get_locals_at(builder.current_function, node, ast_context); - resolve_and_write_ident(node, builder, ast_context); - case Selector_Expr: - write_semantic_selector(cast(^Selector_Expr)node, builder, ast_context); - case Pointer_Type: - write_semantic_token_pos(builder, node.pos, "^", ast_context.file.src, .Operator, .None); - write_semantic_tokens(n.elem, builder, ast_context); - case Value_Decl: - write_semantic_tokens_value_decl(n, builder, ast_context); - case Block_Stmt: - write_semantic_tokens(n.stmts, builder, ast_context); - case Expr_Stmt: - write_semantic_tokens(n.expr, builder, ast_context); - case Range_Stmt: - write_semantic_token_pos(builder, n.for_pos, "for", ast_context.file.src, .Keyword, .None); - - for val in n.vals { - if ident, ok := val.derived.(Ident); ok { - write_semantic_node(builder, val, ast_context.file.src, .Variable, .None); - } - } - - write_semantic_token_pos(builder, n.in_pos, "in", ast_context.file.src, .Keyword, .None); - write_semantic_tokens(n.expr, builder, ast_context); - write_semantic_tokens(n.body, builder, ast_context); - case If_Stmt: - write_semantic_token_pos(builder, n.if_pos, "if", ast_context.file.src, .Keyword, .None); - write_semantic_tokens(n.init, builder, ast_context); - write_semantic_tokens(n.cond, builder, ast_context); - write_semantic_tokens(n.body, builder, ast_context); - if n.else_stmt != nil { - write_semantic_token_pos(builder, n.else_pos, "else", ast_context.file.src, .Keyword, .None); - write_semantic_tokens(n.else_stmt, builder, ast_context); - } - case For_Stmt: - write_semantic_token_pos(builder, n.for_pos, "for", ast_context.file.src, .Keyword, .None); - write_semantic_tokens(n.init, builder, ast_context); - write_semantic_tokens(n.cond, builder, ast_context); - write_semantic_tokens(n.post, builder, ast_context); - write_semantic_tokens(n.body, builder, ast_context); - case Switch_Stmt: - write_semantic_token_pos(builder, n.switch_pos, "switch", ast_context.file.src, .Keyword, .None); - write_semantic_tokens(n.init, builder, ast_context); - write_semantic_tokens(n.cond, builder, ast_context); - write_semantic_tokens(n.body, builder, ast_context); - case Type_Switch_Stmt: - write_semantic_token_pos(builder, n.switch_pos, "switch", ast_context.file.src, .Keyword, .None); - write_semantic_tokens(n.tag, builder, ast_context); - write_semantic_tokens(n.expr, builder, ast_context); - write_semantic_tokens(n.body, builder, ast_context); - case Assign_Stmt: - for l in n.lhs { - if ident, ok := l.derived.(Ident); ok { - write_semantic_node(builder, l, ast_context.file.src, .Variable, .None); - } else { - write_semantic_tokens(l, builder, ast_context); - } - } - - write_semantic_token_op(builder, n.op, ast_context.file.src); - write_semantic_tokens(n.rhs, builder, ast_context); - case Case_Clause: - write_semantic_token_pos(builder, n.case_pos, "case", ast_context.file.src, .Keyword, .None); - write_semantic_tokens(n.list, builder, ast_context); - write_semantic_tokens(n.body, builder, ast_context); - case Call_Expr: - //could there be any other type then .Function for call expr? No point of computing it if not. - if ident, ok := n.expr.derived.(Ident); ok { - write_semantic_node(builder, n.expr, ast_context.file.src, .Function, .None); - } else { - write_semantic_tokens(n.expr, builder, ast_context); - } - write_semantic_tokens(n.args, builder, ast_context); - case Implicit_Selector_Expr: - write_semantic_node(builder, n.field, ast_context.file.src, .Enum, .None); - case Array_Type: - write_semantic_tokens(n.elem, builder, ast_context); - case Binary_Expr: - write_semantic_tokens(n.left, builder, ast_context); - write_semantic_token_op(builder, n.op, ast_context.file.src); - write_semantic_tokens(n.right, builder, ast_context); - case Comp_Lit: - write_semantic_tokens(n.type, builder, ast_context); - write_semantic_tokens(n.elems, builder, ast_context); - case Struct_Type: - write_semantic_token_pos(builder, n.pos, "struct", ast_context.file.src, .Keyword, .None); - write_semantic_struct_fields(n, builder, ast_context); - case Type_Assertion: - write_semantic_tokens(n.expr, builder, ast_context); - write_semantic_tokens(n.type, builder, ast_context); - case Type_Cast: - write_semantic_token_pos(builder, n.pos, "cast", ast_context.file.src, .Keyword, .None); - write_semantic_tokens(n.type, builder, ast_context); - write_semantic_tokens(n.expr, builder, ast_context); - case Paren_Expr: - write_semantic_tokens(n.expr, builder, ast_context); - case Deref_Expr: - write_semantic_tokens(n.expr, builder, ast_context); - case Return_Stmt: - write_semantic_token_pos(builder, n.pos, "return", ast_context.file.src, .Keyword, .None); - write_semantic_tokens(n.results, builder, ast_context); - case Dynamic_Array_Type: - write_semantic_token_pos(builder, n.dynamic_pos, "dynamic", ast_context.file.src, .Keyword, .None); - write_semantic_tokens(n.elem, builder, ast_context); - case Field_Value: - if ident, ok := n.field.derived.(Ident); ok { - write_semantic_node(builder, n.field, ast_context.file.src, .Property, .None); - } - - write_semantic_tokens(n.value, builder, ast_context); - case Index_Expr: - write_semantic_tokens(n.expr, builder, ast_context); - write_semantic_tokens(n.index, builder, ast_context); - case Basic_Lit: - write_semantic_token_basic_lit(n, builder, ast_context); - case Unary_Expr: - write_semantic_tokens(n.expr, builder, ast_context); - case Implicit: - case Slice_Expr: - write_semantic_tokens(n.expr, builder, ast_context); - case Using_Stmt: - write_semantic_token_pos(builder, n.pos, "using", ast_context.file.src, .Keyword, .None); - write_semantic_tokens(n.list, builder, ast_context); - case Map_Type: - write_semantic_token_pos(builder, n.tok_pos, "map", ast_context.file.src, .Keyword, .None); - write_semantic_tokens(n.key, builder, ast_context); - write_semantic_tokens(n.value, builder, ast_context); - case Defer_Stmt: - write_semantic_token_pos(builder, n.pos, "defer", ast_context.file.src, .Keyword, .None); - write_semantic_tokens(n.stmt, builder, ast_context); - case Import_Decl: - write_semantic_token(builder, n.import_tok, ast_context.file.src, .Keyword, .None); - - if n.name.text != "" { - write_semantic_token(builder, n.name, ast_context.file.src, .Namespace, .None); - } - - write_semantic_token(builder, n.relpath, ast_context.file.src, .String, .None); - case: - log.warnf("unhandled write node %v", n); - } -} - -write_semantic_token_basic_lit :: proc(basic_lit: ast.Basic_Lit, builder: ^SemanticTokenBuilder, ast_context: ^analysis.AstContext) { - - using analysis; - - if symbol, ok := resolve_basic_lit(ast_context, basic_lit); ok { - - if generic, ok := symbol.value.(index.SymbolGenericValue); ok { - - ident := generic.expr.derived.(ast.Ident); - - if ident.name == "string" { - write_semantic_node(builder, generic.expr, ast_context.file.src, .String, .None); - } else if ident.name == "int" { - write_semantic_node(builder, generic.expr, ast_context.file.src, .Number, .None); - } else { - } - } - } -} - -write_semantic_tokens_value_decl :: proc(value_decl: ast.Value_Decl, builder: ^SemanticTokenBuilder, ast_context: ^analysis.AstContext) { - - using ast; - - if value_decl.type != nil { - - for name in value_decl.names { - write_semantic_node(builder, name, ast_context.file.src, .Variable, .None); - } - - write_semantic_tokens(value_decl.type, builder, ast_context); - - return; - } - - if len(value_decl.values) == 1 { - - switch v in value_decl.values[0].derived { - case Struct_Type: - write_semantic_node(builder, value_decl.names[0], ast_context.file.src, .Struct, .None); - write_semantic_token_pos(builder, v.pos, "struct", ast_context.file.src, .Keyword, .None); - write_semantic_struct_fields(v, builder, ast_context); - case Enum_Type: - write_semantic_node(builder, value_decl.names[0], ast_context.file.src, .Enum, .None); - write_semantic_token_pos(builder, v.pos, "enum", ast_context.file.src, .Keyword, .None); - write_semantic_enum_fields(v, builder, ast_context); - case Proc_Group: - write_semantic_node(builder, value_decl.names[0], ast_context.file.src, .Function, .None); - write_semantic_token_pos(builder, v.pos, "proc", ast_context.file.src, .Keyword, .None); - for arg in v.args { - if ident, ok := arg.derived.(Ident); ok { - write_semantic_node(builder, arg, ast_context.file.src, .Function, .None); - } - } - case Proc_Lit: - write_semantic_node(builder, value_decl.names[0], ast_context.file.src, .Function, .None); - write_semantic_token_pos(builder, v.pos, "proc", ast_context.file.src, .Keyword, .None); - write_semantic_proc_type(v.type, builder, ast_context); - - last_function := builder.current_function; - builder.current_function = value_decl.values[0]; - write_semantic_tokens(v.body, builder, ast_context); - builder.current_function = last_function; - case: - for name in value_decl.names { - write_semantic_node(builder, name, ast_context.file.src, .Variable, .None); - } - - write_semantic_tokens(value_decl.values[0], builder, ast_context); - } - } else { - - for name in value_decl.names { - write_semantic_node(builder, name, ast_context.file.src, .Variable, .None); - } - - for value in value_decl.values { - write_semantic_tokens(value, builder, ast_context); - } - } -} - -write_semantic_token_op :: proc(builder: ^SemanticTokenBuilder, token: tokenizer.Token, src: string) { - - if token.text == "=" { - write_semantic_token_pos(builder, token.pos, token.text, src, .Operator, .None); - } else if token.text == "in" { - write_semantic_token_pos(builder, token.pos, token.text, src, .Keyword, .None); - } -} - -write_semantic_proc_type :: proc(node: ^ast.Proc_Type, builder: ^SemanticTokenBuilder, ast_context: ^analysis.AstContext) { - - using ast; - - if node == nil { - return; - } - - if node.params != nil { - - for param in node.params.list { - - for name in param.names { - - if ident, ok := name.derived.(Ident); ok { - write_semantic_node(builder, name, ast_context.file.src, .Parameter, .None); - } - } - - write_semantic_tokens(param.type, builder, ast_context); - } - } - - if node.results != nil { - - for result in node.results.list { - - for name in result.names { - - if ident, ok := name.derived.(Ident); ok { - //write_semantic_node(builder, name, ast_context.file.src, .Parameter, .None); - } - } - - write_semantic_tokens(result.type, builder, ast_context); - } - } -} - -write_semantic_enum_fields :: proc(node: ast.Enum_Type, builder: ^SemanticTokenBuilder, ast_context: ^analysis.AstContext) { - - using ast; - - if node.fields == nil { - return; - } - - for field in node.fields { - - if ident, ok := field.derived.(Ident); ok { - write_semantic_node(builder, field, ast_context.file.src, .EnumMember, .None); - } - else if f, ok := field.derived.(Field_Value); ok { - if ident, ok := f.field.derived.(Ident); ok { - write_semantic_node(builder, f.field, ast_context.file.src, .EnumMember, .None); - } - write_semantic_tokens(f.value, builder, ast_context); - } - } -} - -write_semantic_struct_fields :: proc(node: ast.Struct_Type, builder: ^SemanticTokenBuilder, ast_context: ^analysis.AstContext) { - - using ast; - - if node.fields == nil { - return; - } - - for field in node.fields.list { - - for name in field.names { - if ident, ok := name.derived.(Ident); ok { - write_semantic_node(builder, name, ast_context.file.src, .Property, .None); - } - } - - write_semantic_tokens(field.type, builder, ast_context); - } -} - -write_semantic_selector :: proc(selector: ^ast.Selector_Expr, builder: ^SemanticTokenBuilder, ast_context: ^analysis.AstContext) { - - using analysis; - using ast; - - if _, ok := selector.expr.derived.(Selector_Expr); !ok { - get_locals_at(builder.current_function, selector.expr, ast_context); - - if symbol, ok := resolve_type_expression(ast_context, selector.expr); ok { - - #partial switch v in symbol.value { - case index.SymbolStructValue: - builder.selector_member = true; - } - - } - - } else { - write_semantic_tokens(selector.expr, builder, ast_context); - } - - if symbol, ok := resolve_type_expression(ast_context, selector); ok && !builder.selector_member { - - #partial switch v in symbol.value { - case index.SymbolPackageValue: - write_semantic_node(builder, selector.field, ast_context.file.src, .Namespace, .None); - case index.SymbolStructValue: - write_semantic_node(builder, selector.field, ast_context.file.src, .Struct, .None); - case index.SymbolEnumValue: - write_semantic_node(builder, selector.field, ast_context.file.src, .Enum, .None); - case index.SymbolUnionValue: - write_semantic_node(builder, selector.field, ast_context.file.src, .Enum, .None); - case index.SymbolProcedureGroupValue: - write_semantic_node(builder, selector.field, ast_context.file.src, .Function, .None); - case index.SymbolGenericValue: - #partial switch symbol.type { - case .Keyword: - write_semantic_node(builder, selector.field, ast_context.file.src, .Keyword, .None); - } - } - } else if (builder.selector_member) { - write_semantic_node(builder, selector.field, ast_context.file.src, .Property, .None); - } -} - -get_locals_at :: proc(function: ^ast.Node, position: ^ast.Node, ast_context: ^analysis.AstContext) { - - using analysis; - - clear_locals(ast_context); - - if function == nil { - return; - } - - if position == nil { - return; - } - - document_position := DocumentPositionContext { - position = position.end.offset, - }; - - get_locals(ast_context.file, function, ast_context, &document_position); -} diff --git a/src/server/signature.odin b/src/server/signature.odin index d7fe289..91e2b47 100644 --- a/src/server/signature.odin +++ b/src/server/signature.odin @@ -127,7 +127,7 @@ get_signature_information :: proc(document: ^common.Document, position: common.P signature_help: SignatureHelp; - ast_context := make_ast_context(document.ast, document.imports, document.package_name, document.uri.uri); + ast_context := make_ast_context(document.ast, document.imports, document.package_name, document.uri.uri, &document.symbol_cache); position_context, ok := get_document_position_context(document, position, .SignatureHelp); |