Skip to content

Commit 8423ecf

Browse files
committed
refactor, fix and update tests
1 parent c920059 commit 8423ecf

13 files changed

+169
-146
lines changed

internal/api/api.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ func (api *API) GetSymbolAtPosition(ctx context.Context, projectId Handle[projec
160160
return nil, errors.New("project not found")
161161
}
162162

163-
languageService := ls.NewLanguageService(project, snapshot.Converters(), snapshot.ReadFile, snapshot.UseCaseSensitiveFileNames())
163+
languageService := ls.NewLanguageService(project, snapshot.Converters(), snapshot.ReadFile, snapshot.FileExists, snapshot.UseCaseSensitiveFileNames())
164164
symbol, err := languageService.GetSymbolAtPosition(ctx, fileName, position)
165165
if err != nil || symbol == nil {
166166
return nil, err
@@ -202,7 +202,7 @@ func (api *API) GetSymbolAtLocation(ctx context.Context, projectId Handle[projec
202202
if node == nil {
203203
return nil, fmt.Errorf("node of kind %s not found at position %d in file %q", kind.String(), pos, sourceFile.FileName())
204204
}
205-
languageService := ls.NewLanguageService(project, snapshot.Converters(), snapshot.ReadFile, snapshot.UseCaseSensitiveFileNames())
205+
languageService := ls.NewLanguageService(project, snapshot.Converters(), snapshot.ReadFile, snapshot.FileExists, snapshot.UseCaseSensitiveFileNames())
206206
symbol := languageService.GetSymbolAtLocation(ctx, node)
207207
if symbol == nil {
208208
return nil, nil
@@ -232,7 +232,7 @@ func (api *API) GetTypeOfSymbol(ctx context.Context, projectId Handle[project.Pr
232232
if !ok {
233233
return nil, fmt.Errorf("symbol %q not found", symbolHandle)
234234
}
235-
languageService := ls.NewLanguageService(project, snapshot.Converters(), snapshot.ReadFile, snapshot.UseCaseSensitiveFileNames())
235+
languageService := ls.NewLanguageService(project, snapshot.Converters(), snapshot.ReadFile, snapshot.FileExists, snapshot.UseCaseSensitiveFileNames())
236236
t := languageService.GetTypeOfSymbol(ctx, symbol)
237237
if t == nil {
238238
return nil, nil

internal/ls/definition.go

Lines changed: 32 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import (
88
"github.com/microsoft/typescript-go/internal/astnav"
99
"github.com/microsoft/typescript-go/internal/checker"
1010
"github.com/microsoft/typescript-go/internal/core"
11-
"github.com/microsoft/typescript-go/internal/debug"
1211
"github.com/microsoft/typescript-go/internal/lsp/lsproto"
1312
"github.com/microsoft/typescript-go/internal/scanner"
1413
)
@@ -23,54 +22,28 @@ func (l *LanguageService) ProvideDefinition(ctx context.Context, documentURI lsp
2322
c, done := program.GetTypeCheckerForFile(ctx, file)
2423
defer done()
2524

26-
return l.getMappedDefinition(l.provideDefinitions(c, node)), nil
27-
}
28-
29-
func (l *LanguageService) getMappedDefinition(definitions lsproto.DefinitionResponse) lsproto.DefinitionResponse {
30-
if definitions.Location != nil {
31-
definitions.Location = l.getMappedLocation(definitions.Location)
32-
}
33-
if definitions.Locations != nil {
34-
for i, loc := range *definitions.Locations {
35-
(*definitions.Locations)[i] = *l.getMappedLocation(&loc)
36-
}
37-
}
38-
if definitions.DefinitionLinks != nil {
39-
for i, link := range *definitions.DefinitionLinks {
40-
mappedTarget := l.getMappedLocation(&lsproto.Location{Uri: link.TargetUri, Range: link.TargetRange})
41-
mappedSelection := l.getMappedLocation(&lsproto.Location{Uri: link.TargetUri, Range: link.TargetSelectionRange})
42-
debug.Assert(mappedTarget.Uri == mappedSelection.Uri, "target and selection should be in same file")
43-
(*definitions.DefinitionLinks)[i].TargetUri = mappedTarget.Uri
44-
(*definitions.DefinitionLinks)[i].TargetRange = mappedTarget.Range
45-
(*definitions.DefinitionLinks)[i].TargetSelectionRange = mappedSelection.Range
46-
}
47-
}
48-
return definitions
49-
}
50-
51-
func (l *LanguageService) provideDefinitions(c *checker.Checker, node *ast.Node) lsproto.DefinitionResponse {
5225
if node.Kind == ast.KindOverrideKeyword {
5326
if sym := getSymbolForOverriddenMember(c, node); sym != nil {
54-
return l.createLocationsFromDeclarations(sym.Declarations)
27+
return l.createLocationsFromDeclarations(sym.Declarations), nil
5528
}
5629
}
5730

5831
if ast.IsJumpStatementTarget(node) {
5932
if label := getTargetLabel(node.Parent, node.Text()); label != nil {
60-
return l.createLocationsFromDeclarations([]*ast.Node{label})
33+
return l.createLocationsFromDeclarations([]*ast.Node{label}), nil
6134
}
6235
}
6336

6437
if node.Kind == ast.KindCaseKeyword || node.Kind == ast.KindDefaultKeyword && ast.IsDefaultClause(node.Parent) {
6538
if stmt := ast.FindAncestor(node.Parent, ast.IsSwitchStatement); stmt != nil {
6639
file := ast.GetSourceFileOfNode(stmt)
67-
return l.createLocationFromFileAndRange(file, scanner.GetRangeOfTokenAtPosition(file, stmt.Pos()))
40+
return l.createLocationFromFileAndRange(file, scanner.GetRangeOfTokenAtPosition(file, stmt.Pos())), nil
6841
}
6942
}
7043

7144
if node.Kind == ast.KindReturnKeyword || node.Kind == ast.KindYieldKeyword || node.Kind == ast.KindAwaitKeyword {
7245
if fn := ast.FindAncestor(node, ast.IsFunctionLikeDeclaration); fn != nil {
73-
return l.createLocationsFromDeclarations([]*ast.Node{fn})
46+
return l.createLocationsFromDeclarations([]*ast.Node{fn}), nil
7447
}
7548
}
7649

@@ -81,9 +54,31 @@ func (l *LanguageService) provideDefinitions(c *checker.Checker, node *ast.Node)
8154
nonFunctionDeclarations := core.Filter(slices.Clip(declarations), func(node *ast.Node) bool { return !ast.IsFunctionLike(node) })
8255
declarations = append(nonFunctionDeclarations, calledDeclaration)
8356
}
84-
return l.createLocationsFromDeclarations(declarations)
57+
return l.createLocationsFromDeclarations(declarations), nil
8558
}
8659

60+
// func (l *LanguageService) getMappedDefinition(definitions lsproto.DefinitionResponse) lsproto.DefinitionResponse {
61+
// if definitions.Location != nil {
62+
// definitions.Location = l.getMappedLocation(definitions.Location)
63+
// }
64+
// if definitions.Locations != nil {
65+
// for i, loc := range *definitions.Locations {
66+
// (*definitions.Locations)[i] = *l.getMappedLocation(&loc)
67+
// }
68+
// }
69+
// if definitions.DefinitionLinks != nil {
70+
// for i, link := range *definitions.DefinitionLinks {
71+
// mappedTarget := l.getMappedLocation(&lsproto.Location{Uri: link.TargetUri, Range: link.TargetRange})
72+
// mappedSelection := l.getMappedLocation(&lsproto.Location{Uri: link.TargetUri, Range: link.TargetSelectionRange})
73+
// debug.Assert(mappedTarget.Uri == mappedSelection.Uri, "target and selection should be in same file")
74+
// (*definitions.DefinitionLinks)[i].TargetUri = mappedTarget.Uri
75+
// (*definitions.DefinitionLinks)[i].TargetRange = mappedTarget.Range
76+
// (*definitions.DefinitionLinks)[i].TargetSelectionRange = mappedSelection.Range
77+
// }
78+
// }
79+
// return definitions
80+
// }
81+
8782
func (l *LanguageService) ProvideTypeDefinition(ctx context.Context, documentURI lsproto.DocumentUri, position lsproto.Position) (lsproto.DefinitionResponse, error) {
8883
program, file := l.getProgramAndFile(documentURI)
8984
node := astnav.GetTouchingPropertyName(file, int(l.converters.LineAndCharacterToPosition(file, position)))
@@ -131,20 +126,17 @@ func (l *LanguageService) createLocationsFromDeclarations(declarations []*ast.No
131126
for _, decl := range declarations {
132127
file := ast.GetSourceFileOfNode(decl)
133128
name := core.OrElse(ast.GetNameOfDeclaration(decl), decl)
134-
locations = core.AppendIfUnique(locations, lsproto.Location{
135-
Uri: FileNameToDocumentURI(file.FileName()),
136-
Range: *l.createLspRangeFromNode(name, file),
137-
})
129+
nodeRange := createRangeFromNode(name, file)
130+
mappedLocation := l.getMappedLocation(file.FileName(), nodeRange)
131+
locations = core.AppendIfUnique(locations, mappedLocation)
138132
}
139133
return lsproto.LocationOrLocationsOrDefinitionLinksOrNull{Locations: &locations}
140134
}
141135

142136
func (l *LanguageService) createLocationFromFileAndRange(file *ast.SourceFile, textRange core.TextRange) lsproto.DefinitionResponse {
137+
mappedLocation := l.getMappedLocation(file.FileName(), textRange)
143138
return lsproto.LocationOrLocationsOrDefinitionLinksOrNull{
144-
Location: &lsproto.Location{
145-
Uri: FileNameToDocumentURI(file.FileName()),
146-
Range: *l.createLspRangeFromBounds(textRange.Pos(), textRange.End(), file),
147-
},
139+
Location: &mappedLocation,
148140
}
149141
}
150142

internal/ls/languageservice.go

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,23 +10,26 @@ import (
1010
type LanguageService struct {
1111
host Host
1212
converters *Converters
13-
documentPositionMappers map[string]sourcemap.DocumentPositionMapper // !!! TODO: needs sync?
13+
documentPositionMappers map[string]*sourcemap.DocumentPositionMapper
1414
useCaseSensitiveFileNames bool
1515
readFile func(path string) (contents string, ok bool)
16+
fileExists func(path string) bool
1617
}
1718

1819
func NewLanguageService(
1920
host Host,
2021
converters *Converters,
2122
readFile func(path string) (contents string, ok bool),
23+
fileExists func(path string) bool,
2224
useCaseSensitiveFileNames bool,
2325
) *LanguageService {
2426
return &LanguageService{
2527
host: host,
2628
converters: converters,
2729
readFile: readFile,
30+
fileExists: fileExists,
2831
useCaseSensitiveFileNames: useCaseSensitiveFileNames,
29-
documentPositionMappers: map[string]sourcemap.DocumentPositionMapper{},
32+
documentPositionMappers: map[string]*sourcemap.DocumentPositionMapper{},
3033
}
3134
}
3235

@@ -49,7 +52,7 @@ func (l *LanguageService) getProgramAndFile(documentURI lsproto.DocumentUri) (*c
4952
return program, file
5053
}
5154

52-
func (l *LanguageService) GetDocumentPositionMapper(fileName string) sourcemap.DocumentPositionMapper {
55+
func (l *LanguageService) GetDocumentPositionMapper(fileName string) *sourcemap.DocumentPositionMapper {
5356
d, ok := l.documentPositionMappers[fileName]
5457
if !ok {
5558
d = sourcemap.GetDocumentPositionMapper(l, fileName)

internal/ls/source_map.go

Lines changed: 35 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -8,24 +8,25 @@ import (
88
"github.com/microsoft/typescript-go/internal/tspath"
99
)
1010

11-
func (l *LanguageService) getMappedLocation(location *lsproto.Location) *lsproto.Location {
12-
uriStart, start := l.tryGetSourceLSPPosition(location.Uri.FileName(), &location.Range.Start)
13-
if uriStart == nil {
14-
return location
11+
func (l *LanguageService) getMappedLocation(fileName string, fileRange core.TextRange) lsproto.Location {
12+
startPos := l.tryGetSourcePosition(fileName, core.TextPos(fileRange.Pos()))
13+
if startPos == nil {
14+
lspRange := l.createLspRangeFromRange(fileRange, l.getScript(fileName))
15+
return lsproto.Location{
16+
Uri: FileNameToDocumentURI(fileName),
17+
Range: *lspRange,
18+
}
1519
}
16-
uriEnd, end := l.tryGetSourceLSPPosition(location.Uri.FileName(), &location.Range.End)
17-
debug.Assert(uriEnd == uriStart, "start and end should be in same file")
18-
debug.Assert(end != nil, "end position should be valid")
19-
return &lsproto.Location{
20-
Uri: *uriStart,
21-
Range: lsproto.Range{Start: *start, End: *end},
20+
endPos := l.tryGetSourcePosition(fileName, core.TextPos(fileRange.End()))
21+
debug.Assert(endPos.FileName == startPos.FileName, "start and end should be in same file")
22+
newRange := core.NewTextRange(startPos.Pos, endPos.Pos)
23+
lspRange := l.createLspRangeFromRange(newRange, l.getScript(startPos.FileName))
24+
return lsproto.Location{
25+
Uri: FileNameToDocumentURI(startPos.FileName),
26+
Range: *lspRange,
2227
}
2328
}
2429

25-
func (l *LanguageService) getMappedPosition() {
26-
// !!! HERE
27-
}
28-
2930
type script struct {
3031
fileName string
3132
text string
@@ -39,45 +40,41 @@ func (s *script) Text() string {
3940
return s.text
4041
}
4142

42-
func (l *LanguageService) tryGetSourceLSPPosition(
43-
genFileName string,
44-
position *lsproto.Position,
45-
) (*lsproto.DocumentUri, *lsproto.Position) {
46-
genText, ok := l.ReadFile(genFileName)
47-
if !ok {
48-
return nil, nil // That shouldn't happen
49-
}
50-
genPos := l.converters.LineAndCharacterToPosition(&script{fileName: genFileName, text: genText}, *position)
51-
documentPos := l.tryGetSourcePosition(genFileName, genPos)
52-
if documentPos == nil {
53-
return nil, nil
54-
}
55-
documentURI := FileNameToDocumentURI(documentPos.FileName)
56-
sourceText, ok := l.ReadFile(documentPos.FileName)
43+
func (l *LanguageService) getScript(fileName string) *script {
44+
text, ok := l.readFile(fileName)
5745
if !ok {
58-
return nil, nil
46+
return nil
5947
}
60-
sourcePos := l.converters.PositionToLineAndCharacter(
61-
&script{fileName: documentPos.FileName, text: sourceText},
62-
core.TextPos(documentPos.Pos),
63-
)
64-
return &documentURI, &sourcePos
48+
return &script{fileName: fileName, text: text}
6549
}
6650

6751
func (l *LanguageService) tryGetSourcePosition(
6852
fileName string,
69-
genPosition core.TextPos,
53+
position core.TextPos,
54+
) *sourcemap.DocumentPosition {
55+
newPos := l.tryGetSourcePositionWorker(fileName, position)
56+
if newPos != nil {
57+
if !l.fileExists(newPos.FileName) {
58+
return nil
59+
}
60+
}
61+
return newPos
62+
}
63+
64+
func (l *LanguageService) tryGetSourcePositionWorker(
65+
fileName string,
66+
position core.TextPos,
7067
) *sourcemap.DocumentPosition {
7168
if !tspath.IsDeclarationFileName(fileName) {
7269
return nil
7370
}
7471

7572
positionMapper := l.GetDocumentPositionMapper(fileName)
76-
documentPos := positionMapper.GetSourcePosition(&sourcemap.DocumentPosition{FileName: fileName, Pos: int(genPosition)})
73+
documentPos := positionMapper.GetSourcePosition(&sourcemap.DocumentPosition{FileName: fileName, Pos: int(position)})
7774
if documentPos == nil {
7875
return nil
7976
}
80-
if newPos := l.tryGetSourcePosition(documentPos.FileName, core.TextPos(documentPos.Pos)); newPos != nil {
77+
if newPos := l.tryGetSourcePositionWorker(documentPos.FileName, core.TextPos(documentPos.Pos)); newPos != nil {
8178
return newPos
8279
}
8380
return documentPos

internal/ls/utilities.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -433,11 +433,20 @@ func (l *LanguageService) createLspRangeFromNode(node *ast.Node, file *ast.Sourc
433433
return l.createLspRangeFromBounds(scanner.GetTokenPosOfNode(node, file, false /*includeJSDoc*/), node.End(), file)
434434
}
435435

436+
func createRangeFromNode(node *ast.Node, file *ast.SourceFile) core.TextRange {
437+
return core.NewTextRange(scanner.GetTokenPosOfNode(node, file, false /*includeJSDoc*/), node.End())
438+
}
439+
436440
func (l *LanguageService) createLspRangeFromBounds(start, end int, file *ast.SourceFile) *lsproto.Range {
437441
lspRange := l.converters.ToLSPRange(file, core.NewTextRange(start, end))
438442
return &lspRange
439443
}
440444

445+
func (l *LanguageService) createLspRangeFromRange(textRange core.TextRange, script Script) *lsproto.Range {
446+
lspRange := l.converters.ToLSPRange(script, textRange)
447+
return &lspRange
448+
}
449+
441450
func (l *LanguageService) createLspPosition(position int, file *ast.SourceFile) lsproto.Position {
442451
return l.converters.PositionToLineAndCharacter(file, core.TextPos(position))
443452
}

internal/project/session.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -367,7 +367,7 @@ func (s *Session) GetLanguageService(ctx context.Context, uri lsproto.DocumentUr
367367
if project == nil {
368368
return nil, fmt.Errorf("no project found for URI %s", uri)
369369
}
370-
return ls.NewLanguageService(project, snapshot.Converters(), snapshot.ReadFile, snapshot.UseCaseSensitiveFileNames()), nil
370+
return ls.NewLanguageService(project, snapshot.Converters(), snapshot.ReadFile, snapshot.FileExists, snapshot.UseCaseSensitiveFileNames()), nil
371371
}
372372

373373
func (s *Session) UpdateSnapshot(ctx context.Context, overlays map[tspath.Path]*overlay, change SnapshotChange) *Snapshot {

internal/project/snapshot.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,10 @@ func (s *Snapshot) ReadFile(fileName string) (string, bool) {
101101
return handle.Content(), true
102102
}
103103

104+
func (s *Snapshot) FileExists(fileName string) bool {
105+
return s.fs.fs.FileExists(fileName)
106+
}
107+
104108
type APISnapshotRequest struct {
105109
OpenProjects *collections.Set[string]
106110
CloseProjects *collections.Set[tspath.Path]

0 commit comments

Comments
 (0)