diff --git a/internal/ls/definition.go b/internal/ls/definition.go index fa77e30081..8044845b29 100644 --- a/internal/ls/definition.go +++ b/internal/ls/definition.go @@ -1,17 +1,22 @@ package ls import ( + "fmt" "github.com/microsoft/typescript-go/internal/ast" "github.com/microsoft/typescript-go/internal/astnav" "github.com/microsoft/typescript-go/internal/core" "github.com/microsoft/typescript-go/internal/scanner" ) -func (l *LanguageService) ProvideDefinitions(fileName string, position int) []Location { - program, file := l.getProgramAndFile(fileName) +func (l *LanguageService) ProvideDefinitions(fileName string, position int) ([]Location, error) { + program, file, err := l.getProgramAndFile(fileName) + if err != nil { + return nil, fmt.Errorf("failed to get program and file: %w", err) + } + node := astnav.GetTouchingPropertyName(file, position) if node.Kind == ast.KindSourceFile { - return nil + return nil, nil } checker := program.GetTypeChecker() @@ -33,7 +38,7 @@ func (l *LanguageService) ProvideDefinitions(fileName string, position int) []Lo Range: core.NewTextRange(pos, loc.End()), }) } - return locations + return locations, nil } - return nil + return nil, nil } diff --git a/internal/ls/diagnostics.go b/internal/ls/diagnostics.go index c4aab7db06..14d522b70d 100644 --- a/internal/ls/diagnostics.go +++ b/internal/ls/diagnostics.go @@ -1,14 +1,18 @@ package ls import ( + "fmt" "slices" "github.com/microsoft/typescript-go/internal/ast" ) -func (l *LanguageService) GetDocumentDiagnostics(fileName string) []*ast.Diagnostic { - program, file := l.getProgramAndFile(fileName) +func (l *LanguageService) GetDocumentDiagnostics(fileName string) ([]*ast.Diagnostic, error) { + program, file, err := l.getProgramAndFile(fileName) + if err != nil { + return nil, fmt.Errorf("failed to get program and file for diagnostics: %w", err) + } syntaxDiagnostics := program.GetSyntacticDiagnostics(file) semanticDiagnostics := program.GetSemanticDiagnostics(file) - return slices.Concat(syntaxDiagnostics, semanticDiagnostics) + return slices.Concat(syntaxDiagnostics, semanticDiagnostics), nil } diff --git a/internal/ls/hover.go b/internal/ls/hover.go index f979fde906..e040144b94 100644 --- a/internal/ls/hover.go +++ b/internal/ls/hover.go @@ -1,23 +1,28 @@ package ls import ( + "fmt" + "github.com/microsoft/typescript-go/internal/ast" "github.com/microsoft/typescript-go/internal/astnav" ) -func (l *LanguageService) ProvideHover(fileName string, position int) string { - program, file := l.getProgramAndFile(fileName) +func (l *LanguageService) ProvideHover(fileName string, position int) (string, error) { + program, file, err := l.getProgramAndFile(fileName) + if err != nil { + return "", fmt.Errorf("failed to get program and file for hover: %w", err) + } node := astnav.GetTouchingPropertyName(file, position) if node.Kind == ast.KindSourceFile { // Avoid giving quickInfo for the sourceFile as a whole. - return "" + return "", nil } checker := program.GetTypeChecker() if symbol := checker.GetSymbolAtLocation(node); symbol != nil { if t := checker.GetTypeOfSymbolAtLocation(symbol, node); t != nil { - return checker.TypeToString(t) + return checker.TypeToString(t), nil } } - return "" + return "", nil } diff --git a/internal/ls/languageservice.go b/internal/ls/languageservice.go index 815278749b..2e032c7ed6 100644 --- a/internal/ls/languageservice.go +++ b/internal/ls/languageservice.go @@ -1,6 +1,8 @@ package ls import ( + "fmt" + "github.com/microsoft/typescript-go/internal/ast" "github.com/microsoft/typescript-go/internal/compiler" "github.com/microsoft/typescript-go/internal/core" @@ -55,11 +57,11 @@ func (l *LanguageService) GetProgram() *compiler.Program { return l.host.GetProgram() } -func (l *LanguageService) getProgramAndFile(fileName string) (*compiler.Program, *ast.SourceFile) { +func (l *LanguageService) getProgramAndFile(fileName string) (*compiler.Program, *ast.SourceFile, error) { program := l.GetProgram() file := program.GetSourceFile(fileName) if file == nil { - panic("file not found") + return nil, nil, fmt.Errorf("file not found") } - return program, file + return program, file, nil } diff --git a/internal/lsp/converters.go b/internal/lsp/converters.go index 7009e9989e..1a9e00d899 100644 --- a/internal/lsp/converters.go +++ b/internal/lsp/converters.go @@ -34,10 +34,18 @@ func (c *converters) fromLspRange(textRange lsproto.Range, fileName string) (cor if scriptInfo == nil { return core.TextRange{}, fmt.Errorf("no script info found for %s", fileName) } - return core.NewTextRange( - lineAndCharacterToPosition(textRange.Start, scriptInfo.LineMap()), - lineAndCharacterToPosition(textRange.End, scriptInfo.LineMap()), - ), nil + + startPos, err := lineAndCharacterToPosition(textRange.Start, scriptInfo.LineMap()) + if err != nil { + return core.TextRange{}, fmt.Errorf("error converting start position: %w", err) + } + + endPos, err := lineAndCharacterToPosition(textRange.End, scriptInfo.LineMap()) + if err != nil { + return core.TextRange{}, fmt.Errorf("error converting end position: %w", err) + } + + return core.NewTextRange(startPos, endPos), nil } func (c *converters) fromLspTextChange(change *lsproto.TextDocumentContentChangePartial, fileName string) (ls.TextChange, error) { @@ -124,7 +132,7 @@ func (c *converters) lineAndCharacterToPosition(lineAndCharacter lsproto.Positio if scriptInfo == nil { return 0, fmt.Errorf("no script info found for %s", fileName) } - return lineAndCharacterToPosition(lineAndCharacter, scriptInfo.LineMap()), nil + return lineAndCharacterToPosition(lineAndCharacter, scriptInfo.LineMap()) } func languageKindToScriptKind(languageID lsproto.LanguageKind) core.ScriptKind { @@ -188,19 +196,20 @@ func fileNameToDocumentUri(fileName string) lsproto.DocumentUri { return lsproto.DocumentUri("file://" + fileName) } -func lineAndCharacterToPosition(lineAndCharacter lsproto.Position, lineMap []core.TextPos) int { +func lineAndCharacterToPosition(lineAndCharacter lsproto.Position, lineMap []core.TextPos) (int, error) { line := int(lineAndCharacter.Line) offset := int(lineAndCharacter.Character) if line < 0 || line >= len(lineMap) { - panic(fmt.Sprintf("bad line number. Line: %d, lineMap length: %d", line, len(lineMap))) + return 0, fmt.Errorf("bad line number. Line: %d, lineMap length: %d", line, len(lineMap)) } res := int(lineMap[line]) + offset if line < len(lineMap)-1 && res >= int(lineMap[line+1]) { - panic("resulting position is out of bounds") + return 0, fmt.Errorf("resulting position is out of bounds") } - return res + + return res, nil } func positionToLineAndCharacter(position int, lineMap []core.TextPos) lsproto.Position { diff --git a/internal/lsp/server.go b/internal/lsp/server.go index d3200178d5..19d4aaac26 100644 --- a/internal/lsp/server.go +++ b/internal/lsp/server.go @@ -303,7 +303,11 @@ func (s *Server) handleDidClose(req *lsproto.RequestMessage) error { func (s *Server) handleDocumentDiagnostic(req *lsproto.RequestMessage) error { params := req.Params.(*lsproto.DocumentDiagnosticParams) file, project := s.getFileAndProject(params.TextDocument.Uri) - diagnostics := project.LanguageService().GetDocumentDiagnostics(file.FileName()) + diagnostics, err := project.LanguageService().GetDocumentDiagnostics(file.FileName()) + if err != nil { + return s.sendError(req.ID, err) + } + lspDiagnostics := make([]lsproto.Diagnostic, len(diagnostics)) for i, diag := range diagnostics { if lspDiagnostic, err := s.converters.toLspDiagnostic(diag); err != nil { @@ -330,7 +334,11 @@ func (s *Server) handleHover(req *lsproto.RequestMessage) error { return s.sendError(req.ID, err) } - hoverText := project.LanguageService().ProvideHover(file.FileName(), pos) + hoverText, err := project.LanguageService().ProvideHover(file.FileName(), pos) + if err != nil { + return s.sendError(req.ID, err) + } + return s.sendResult(req.ID, &lsproto.Hover{ Contents: lsproto.MarkupContentOrMarkedStringOrMarkedStrings{ MarkupContent: &lsproto.MarkupContent{ @@ -349,7 +357,11 @@ func (s *Server) handleDefinition(req *lsproto.RequestMessage) error { return s.sendError(req.ID, err) } - locations := project.LanguageService().ProvideDefinitions(file.FileName(), pos) + locations, err := project.LanguageService().ProvideDefinitions(file.FileName(), pos) + if err != nil { + return s.sendError(req.ID, err) + } + lspLocations := make([]lsproto.Location, len(locations)) for i, loc := range locations { if lspLocation, err := s.converters.toLspLocation(loc); err != nil {