Skip to content

Commit cf394cf

Browse files
authored
Merge branch 'main' into fix/2674
2 parents 8975489 + bdee9eb commit cf394cf

19 files changed

Lines changed: 132 additions & 1192 deletions

internal/fourslash/_scripts/failingTests.txt

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -411,7 +411,6 @@ TestLocalFunction
411411
TestMemberListInReopenedEnum
412412
TestMemberListInWithBlock
413413
TestMemberListOfExportedClass
414-
TestMemberListOnContextualThis
415414
TestMultilineCommentBeforeOpenBrace
416415
TestMultiModuleFundule
417416
TestNgProxy1
@@ -508,10 +507,7 @@ TestQuickInfoOnPropertyAccessInWriteLocation2
508507
TestQuickInfoOnPropertyAccessInWriteLocation3
509508
TestQuickInfoOnPropertyAccessInWriteLocation4
510509
TestQuickInfoOnPropertyAccessInWriteLocation5
511-
TestQuickInfoOnThis
512-
TestQuickInfoOnThis2
513510
TestQuickInfoOnThis3
514-
TestQuickInfoOnThis4
515511
TestQuickInfoOnUndefined
516512
TestQuickInfoOnVarInArrowExpression
517513
TestQuickInfoPrivateIdentifierInTypeReferenceNoCrash1
@@ -551,7 +547,6 @@ TestSymbolCompletionLowerPriority
551547
TestSyntheticImportFromBabelGeneratedFile1
552548
TestSyntheticImportFromBabelGeneratedFile2
553549
TestTabbingAfterNewlineInsertedBeforeWhile
554-
TestThisBindingInLambda
555550
TestThisPredicateFunctionQuickInfo01
556551
TestThisPredicateFunctionQuickInfo02
557552
TestTsxCompletionNonTagLessThan

internal/fourslash/fourslash.go

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -735,12 +735,21 @@ func (f *FourslashTest) writeMsg(t *testing.T, msg *lsproto.Message) {
735735
}
736736

737737
func sendRequest[Params, Resp any](t *testing.T, f *FourslashTest, info lsproto.RequestInfo[Params, Resp], params Params) Resp {
738+
t.Helper()
739+
return sendRequestAndBaselineWorker(t, f, info, params, true)
740+
}
741+
742+
func sendRequestAndBaselineWorker[Params, Resp any](t *testing.T, f *FourslashTest, info lsproto.RequestInfo[Params, Resp], params Params, baselineProjects bool) Resp {
738743
t.Helper()
739744
prefix := f.getCurrentPositionPrefix()
740-
f.baselineState(t)
745+
if baselineProjects {
746+
f.baselineState(t)
747+
}
741748
f.baselineRequestOrNotification(t, info.Method, params)
742749
resMsg, result, resultOk := sendRequestWorker(t, f, info, params)
743-
f.baselineState(t)
750+
if baselineProjects {
751+
f.baselineState(t)
752+
}
744753
switch info.Method {
745754
case lsproto.MethodTextDocumentOnTypeFormatting:
746755
if !f.reportFormatOnTypeCrash {
@@ -764,8 +773,14 @@ func sendRequest[Params, Resp any](t *testing.T, f *FourslashTest, info lsproto.
764773

765774
func sendNotification[Params any](t *testing.T, f *FourslashTest, info lsproto.NotificationInfo[Params], params Params) {
766775
t.Helper()
767-
f.baselineState(t)
768-
f.updateState(info.Method, params)
776+
if info.Method != lsproto.MethodTextDocumentDidChange {
777+
// This is called eg when doing typeText = which is series of edits and formatting - which becomes non deterministic "after state"
778+
// The notification can only guarantee before state and thats what it baselines, but in case of type it creates
779+
// multiple edits which results in getting different state -based on if the snapshot was updated or not at the time of formatting requests
780+
// So this is used for all the incremental edits - to baseline only request data but not project state between those edits
781+
f.baselineState(t)
782+
f.updateState(info.Method, params)
783+
}
769784
f.baselineRequestOrNotification(t, info.Method, params)
770785
sendNotificationWorker(t, f, info, params)
771786
}
@@ -1665,7 +1680,6 @@ func (f *FourslashTest) VerifyImportFixAtPosition(t *testing.T, expectedTexts []
16651680
// Save the original content before any edits
16661681
script := f.getScriptInfo(f.activeFilename)
16671682
originalContent := script.content
1668-
16691683
// For each import action, apply it and check the result
16701684
actualTextArray := make([]string, 0, len(importActions))
16711685
for _, action := range importActions {
@@ -2809,19 +2823,22 @@ func roundtripThroughJson[T any](value any) (T, error) {
28092823
// Insert text at the current caret position.
28102824
func (f *FourslashTest) Insert(t *testing.T, text string) {
28112825
t.Helper()
2826+
f.baselineState(t)
28122827
f.typeText(t, text)
28132828
}
28142829

28152830
// Insert text and a new line at the current caret position.
28162831
func (f *FourslashTest) InsertLine(t *testing.T, text string) {
28172832
t.Helper()
2833+
f.baselineState(t)
28182834
f.typeText(t, text+"\n")
28192835
}
28202836

28212837
// Removes the text at the current caret position as if the user pressed backspace `count` times.
28222838
func (f *FourslashTest) Backspace(t *testing.T, count int) {
28232839
script := f.getScriptInfo(f.activeFilename)
28242840
offset := int(f.converters.LineAndCharacterToPosition(script, f.currentCaretPosition))
2841+
f.baselineState(t)
28252842

28262843
for range count {
28272844
offset--
@@ -2837,6 +2854,7 @@ func (f *FourslashTest) Backspace(t *testing.T, count int) {
28372854
func (f *FourslashTest) DeleteAtCaret(t *testing.T, count int) {
28382855
script := f.getScriptInfo(f.activeFilename)
28392856
offset := int(f.converters.LineAndCharacterToPosition(script, f.currentCaretPosition))
2857+
f.baselineState(t)
28402858

28412859
for range count {
28422860
f.editScriptAndUpdateMarkers(t, f.activeFilename, offset, offset+1, "")
@@ -2848,11 +2866,12 @@ func (f *FourslashTest) DeleteAtCaret(t *testing.T, count int) {
28482866
func (f *FourslashTest) Paste(t *testing.T, text string) {
28492867
script := f.getScriptInfo(f.activeFilename)
28502868
start := int(f.converters.LineAndCharacterToPosition(script, f.currentCaretPosition))
2869+
f.baselineState(t)
28512870
f.editScriptAndUpdateMarkers(t, f.activeFilename, start, start, text)
28522871

28532872
// post-paste fomatting
28542873
if f.stateEnableFormatting {
2855-
result := sendRequest(t, f, lsproto.TextDocumentRangeFormattingInfo, &lsproto.DocumentRangeFormattingParams{
2874+
result := sendRequestAndBaselineWorker(t, f, lsproto.TextDocumentRangeFormattingInfo, &lsproto.DocumentRangeFormattingParams{
28562875
TextDocument: lsproto.TextDocumentIdentifier{
28572876
Uri: lsconv.FileNameToDocumentURI(f.activeFilename),
28582877
},
@@ -2861,7 +2880,7 @@ func (f *FourslashTest) Paste(t *testing.T, text string) {
28612880
End: f.converters.PositionToLineAndCharacter(script, core.TextPos(start+len(text))),
28622881
},
28632882
Options: f.userPreferences.FormatCodeSettings.ToLSFormatOptions(),
2864-
})
2883+
}, false)
28652884
if result.TextEdits != nil {
28662885
f.applyTextEdits(t, *result.TextEdits)
28672886
}
@@ -2871,6 +2890,7 @@ func (f *FourslashTest) Paste(t *testing.T, text string) {
28712890

28722891
// Selects a line and replaces it with a new text.
28732892
func (f *FourslashTest) ReplaceLine(t *testing.T, lineIndex int, text string) {
2893+
f.baselineState(t)
28742894
f.selectLine(t, lineIndex)
28752895
f.typeText(t, text)
28762896
}
@@ -2944,6 +2964,12 @@ func (f *FourslashTest) applyTextEdits(t *testing.T, edits []*lsproto.TextEdit)
29442964
}
29452965

29462966
func (f *FourslashTest) Replace(t *testing.T, start int, length int, text string) {
2967+
f.baselineState(t)
2968+
f.replaceWorker(t, start, length, text)
2969+
}
2970+
2971+
func (f *FourslashTest) replaceWorker(t *testing.T, start int, length int, text string) {
2972+
t.Helper()
29472973
f.editScriptAndUpdateMarkers(t, f.activeFilename, start, start+length, text)
29482974
// f.checkPostEditInvariants() // !!! do we need this?
29492975
}
@@ -2958,7 +2984,7 @@ func (f *FourslashTest) typeText(t *testing.T, text string) {
29582984

29592985
script := f.getScriptInfo(f.activeFilename)
29602986
selection := f.getSelection()
2961-
f.Replace(t, selection.Pos(), selection.End()-selection.Pos(), "")
2987+
f.replaceWorker(t, selection.Pos(), selection.End()-selection.Pos(), "")
29622988

29632989
totalSize := 0
29642990

@@ -2973,14 +2999,14 @@ func (f *FourslashTest) typeText(t *testing.T, text string) {
29732999

29743000
// Handle post-keystroke formatting
29753001
if f.stateEnableFormatting {
2976-
result := sendRequest(t, f, lsproto.TextDocumentOnTypeFormattingInfo, &lsproto.DocumentOnTypeFormattingParams{
3002+
result := sendRequestAndBaselineWorker(t, f, lsproto.TextDocumentOnTypeFormattingInfo, &lsproto.DocumentOnTypeFormattingParams{
29773003
TextDocument: lsproto.TextDocumentIdentifier{
29783004
Uri: lsconv.FileNameToDocumentURI(f.activeFilename),
29793005
},
29803006
Position: f.currentCaretPosition,
29813007
Ch: string(r),
29823008
Options: f.userPreferences.FormatCodeSettings.ToLSFormatOptions(),
2983-
})
3009+
}, false)
29843010
if result.TextEdits != nil {
29853011
offset += f.applyTextEdits(t, *result.TextEdits)
29863012
}

internal/ls/hover.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ func formatQuickInfo(quickInfo string) string {
174174
func getQuickInfoAndDeclarationAtLocation(c *checker.Checker, symbol *ast.Symbol, node *ast.Node) (string, *ast.Node) {
175175
container := getContainerNode(node)
176176
if node.Kind == ast.KindThisKeyword && ast.IsInExpressionContext(node) || ast.IsThisInTypeQuery(node) {
177-
return c.TypeToStringEx(c.GetTypeAtLocation(node), container, typeFormatFlags), nil
177+
return "this: " + c.TypeToStringEx(c.GetTypeAtLocation(node), container, typeFormatFlags), nil
178178
}
179179
if symbol == nil {
180180
return "", nil

internal/ls/selectionranges.go

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,10 +142,35 @@ func getSmartSelectionRange(l *LanguageService, sourceFile *ast.SourceFile, pos
142142
}
143143
}
144144

145+
// Synthesize a stop for '${ ... }' since '${' and '}' actually belong to siblings.
146+
if ast.IsTemplateSpan(parent) {
147+
templateSpan := parent.AsTemplateSpan()
148+
if templateSpan.Literal != nil {
149+
// Start from just before the '${' and end after the '}'
150+
// The '${' is 2 characters before the expression start
151+
spanStart := node.Pos() - 2
152+
// The '}' is the first character of the template literal (middle or tail)
153+
spanEnd := astnav.GetStartOfNode(templateSpan.Literal, sourceFile, false) + 1
154+
// Validate the positions are reasonable
155+
text := sourceFile.Text()
156+
if spanStart >= 0 && spanEnd <= len(text) && spanStart < spanEnd {
157+
result = pushSelectionRange(result, spanStart, spanEnd)
158+
}
159+
}
160+
}
161+
145162
if !shouldSkipNode(node, parent) {
146163
start := astnav.GetStartOfNode(node, sourceFile, false)
147164
end := node.End()
148165
result = pushSelectionRange(result, start, end)
166+
167+
// String literals should have a stop both inside and outside their quotes.
168+
if ast.IsStringLiteral(node) || node.Kind == ast.KindTemplateExpression || node.Kind == ast.KindNoSubstitutionTemplateLiteral {
169+
// Only add inner content range if there's actually content (handles unterminated literals)
170+
if start+1 < end-1 {
171+
result = pushSelectionRange(result, start+1, end-1)
172+
}
173+
}
149174
}
150175

151176
next = node
@@ -156,7 +181,7 @@ func getSmartSelectionRange(l *LanguageService, sourceFile *ast.SourceFile, pos
156181

157182
visitNodes := func(nodes *ast.NodeList, v *ast.NodeVisitor) *ast.NodeList {
158183
if nodes != nil && len(nodes.Nodes) > 0 {
159-
shouldSkipList := parent != nil && ast.IsVariableDeclarationList(parent)
184+
shouldSkipList := parent != nil && (ast.IsVariableDeclarationList(parent) || ast.IsTemplateExpression(parent))
160185

161186
if !shouldSkipList {
162187
start := astnav.GetStartOfNode(nodes.Nodes[0], sourceFile, false)

testdata/baselines/reference/fourslash/quickInfo/quickInfoCommentsClassMembers.baseline

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -751,7 +751,7 @@
751751
// ^^^^
752752
// | ----------------------------------------------------------------------
753753
// | ```tsx
754-
// | this
754+
// | this: this
755755
// | ```
756756
// |
757757
// | ----------------------------------------------------------------------
@@ -3168,7 +3168,7 @@
31683168
"item": {
31693169
"contents": {
31703170
"kind": "markdown",
3171-
"value": "```tsx\nthis\n```\n"
3171+
"value": "```tsx\nthis: this\n```\n"
31723172
},
31733173
"range": {
31743174
"start": {

testdata/baselines/reference/fourslash/quickInfo/quickInfoOnThis5.baseline

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,15 @@
77
// ^^^^
88
// | ----------------------------------------------------------------------
99
// | ```tsx
10-
// | { num: number; f(): void; g(this: number): void; }
10+
// | this: { num: number; f(): void; g(this: number): void; }
1111
// | ```
1212
// |
1313
// | ----------------------------------------------------------------------
1414
// type Z = typeof this.num;
1515
// ^^^^
1616
// | ----------------------------------------------------------------------
1717
// | ```tsx
18-
// | { num: number; f(): void; g(this: number): void; }
18+
// | this: { num: number; f(): void; g(this: number): void; }
1919
// | ```
2020
// |
2121
// | ----------------------------------------------------------------------
@@ -25,7 +25,7 @@
2525
// ^^^^
2626
// | ----------------------------------------------------------------------
2727
// | ```tsx
28-
// | number
28+
// | this: number
2929
// | ```
3030
// |
3131
// | ----------------------------------------------------------------------
@@ -38,15 +38,15 @@
3838
// ^^^^
3939
// | ----------------------------------------------------------------------
4040
// | ```tsx
41-
// | this
41+
// | this: this
4242
// | ```
4343
// |
4444
// | ----------------------------------------------------------------------
4545
// type Z = typeof this.num;
4646
// ^^^^
4747
// | ----------------------------------------------------------------------
4848
// | ```tsx
49-
// | this
49+
// | this: this
5050
// | ```
5151
// |
5252
// | ----------------------------------------------------------------------
@@ -56,7 +56,7 @@
5656
// ^^^^
5757
// | ----------------------------------------------------------------------
5858
// | ```tsx
59-
// | number
59+
// | this: number
6060
// | ```
6161
// |
6262
// | ----------------------------------------------------------------------
@@ -76,7 +76,7 @@
7676
"item": {
7777
"contents": {
7878
"kind": "markdown",
79-
"value": "```tsx\n{ num: number; f(): void; g(this: number): void; }\n```\n"
79+
"value": "```tsx\nthis: { num: number; f(): void; g(this: number): void; }\n```\n"
8080
},
8181
"range": {
8282
"start": {
@@ -103,7 +103,7 @@
103103
"item": {
104104
"contents": {
105105
"kind": "markdown",
106-
"value": "```tsx\n{ num: number; f(): void; g(this: number): void; }\n```\n"
106+
"value": "```tsx\nthis: { num: number; f(): void; g(this: number): void; }\n```\n"
107107
},
108108
"range": {
109109
"start": {
@@ -130,7 +130,7 @@
130130
"item": {
131131
"contents": {
132132
"kind": "markdown",
133-
"value": "```tsx\nnumber\n```\n"
133+
"value": "```tsx\nthis: number\n```\n"
134134
},
135135
"range": {
136136
"start": {
@@ -157,7 +157,7 @@
157157
"item": {
158158
"contents": {
159159
"kind": "markdown",
160-
"value": "```tsx\nthis\n```\n"
160+
"value": "```tsx\nthis: this\n```\n"
161161
},
162162
"range": {
163163
"start": {
@@ -184,7 +184,7 @@
184184
"item": {
185185
"contents": {
186186
"kind": "markdown",
187-
"value": "```tsx\nthis\n```\n"
187+
"value": "```tsx\nthis: this\n```\n"
188188
},
189189
"range": {
190190
"start": {
@@ -211,7 +211,7 @@
211211
"item": {
212212
"contents": {
213213
"kind": "markdown",
214-
"value": "```tsx\nnumber\n```\n"
214+
"value": "```tsx\nthis: number\n```\n"
215215
},
216216
"range": {
217217
"start": {

0 commit comments

Comments
 (0)