Skip to content

Commit e45183b

Browse files
authored
fix57127: remove linkedediting from cases where JSX tags are not closed (#57132)
1 parent 1445bd4 commit e45183b

File tree

5 files changed

+160
-9
lines changed

5 files changed

+160
-9
lines changed

src/services/services.ts

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2562,20 +2562,25 @@ export function createLanguageService(
25622562
const openTag = tag.parent.openingElement;
25632563
const closeTag = tag.parent.closingElement;
25642564

2565-
const openTagStart = openTag.tagName.getStart(sourceFile);
2566-
const openTagEnd = openTag.tagName.end;
2567-
const closeTagStart = closeTag.tagName.getStart(sourceFile);
2568-
const closeTagEnd = closeTag.tagName.end;
2565+
const openTagNameStart = openTag.tagName.getStart(sourceFile);
2566+
const openTagNameEnd = openTag.tagName.end;
2567+
const closeTagNameStart = closeTag.tagName.getStart(sourceFile);
2568+
const closeTagNameEnd = closeTag.tagName.end;
2569+
// do not return linked cursors if tags are not well-formed
2570+
if (
2571+
openTagNameStart === openTag.getStart(sourceFile) || closeTagNameStart === closeTag.getStart(sourceFile)
2572+
|| openTagNameEnd === openTag.getEnd() || closeTagNameEnd === closeTag.getEnd()
2573+
) return undefined;
25692574

25702575
// only return linked cursors if the cursor is within a tag name
2571-
if (!(openTagStart <= position && position <= openTagEnd || closeTagStart <= position && position <= closeTagEnd)) return undefined;
2576+
if (!(openTagNameStart <= position && position <= openTagNameEnd || closeTagNameStart <= position && position <= closeTagNameEnd)) return undefined;
25722577

25732578
// only return linked cursors if text in both tags is identical
25742579
const openingTagText = openTag.tagName.getText(sourceFile);
25752580
if (openingTagText !== closeTag.tagName.getText(sourceFile)) return undefined;
25762581

25772582
return {
2578-
ranges: [{ start: openTagStart, length: openTagEnd - openTagStart }, { start: closeTagStart, length: closeTagEnd - closeTagStart }],
2583+
ranges: [{ start: openTagNameStart, length: openTagNameEnd - openTagNameStart }, { start: closeTagNameStart, length: closeTagNameEnd - closeTagNameStart }],
25792584
wordPattern: jsxTagWordPattern,
25802585
};
25812586
}

tests/baselines/reference/linkedEditingJsxTag10.linkedEditing.txt

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,9 @@ const jsx = <div </div>;
5454

5555

5656
=== /jsx9.tsx ===
57-
const jsx = <[|/*0*/div|]> </[|/*0*/div|];
57+
const jsx = <div> </div;
5858

59-
=== 0 ===
60-
{"ranges":[{"start":13,"length":3},{"start":20,"length":3}],"wordPattern":"[a-zA-Z0-9:\\-\\._$]*"}
59+
--No linked edits found--
6160

6261

6362
=== /jsx10.tsx ===
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
// === Linked Editing ===
2+
=== /incomplete.tsx ===
3+
function Test() {
4+
return <[|/*0*/div|]>
5+
<
6+
<div {...{}}>
7+
</[|/*0*/div|]>
8+
</div>
9+
}
10+
11+
=== 0 ===
12+
{"ranges":[{"start":30,"length":3},{"start":77,"length":3}],"wordPattern":"[a-zA-Z0-9:\\-\\._$]*"}
13+
14+
15+
=== /incompleteMismatched.tsx ===
16+
function Test() {
17+
return <[|/*1*/div|]>
18+
<T
19+
<div {...{}}>
20+
</[|/*1*/div|]>
21+
</div>
22+
}
23+
24+
=== 1 ===
25+
{"ranges":[{"start":30,"length":3},{"start":78,"length":3}],"wordPattern":"[a-zA-Z0-9:\\-\\._$]*"}
26+
27+
28+
=== /incompleteMismatched2.tsx ===
29+
function Test() {
30+
return <[|/*2*/div|]>
31+
<T
32+
<div {...{}}>
33+
T</[|/*2*/div|]>
34+
</div>
35+
}
36+
37+
=== 2 ===
38+
{"ranges":[{"start":30,"length":3},{"start":79,"length":3}],"wordPattern":"[a-zA-Z0-9:\\-\\._$]*"}
39+
40+
41+
=== /incompleteMismatched3.tsx ===
42+
function Test() {
43+
return <[|/*3*/div|]>
44+
<[|/*4*/div|] {...{}}>
45+
</[|/*4*/div|]>
46+
<T
47+
</[|/*3*/div|]>
48+
}
49+
50+
=== 3 ===
51+
{"ranges":[{"start":30,"length":3},{"start":89,"length":3}],"wordPattern":"[a-zA-Z0-9:\\-\\._$]*"}
52+
53+
=== 4 ===
54+
{"ranges":[{"start":44,"length":3},{"start":67,"length":3}],"wordPattern":"[a-zA-Z0-9:\\-\\._$]*"}
55+
56+
57+
=== /mismatched.tsx ===
58+
function Test() {
59+
return <[|/*5*/div|]>
60+
<T>
61+
<[|/*6*/div|] {...{}}>
62+
</[|/*6*/div|]>
63+
</[|/*5*/div|]>
64+
}
65+
66+
=== 5 ===
67+
{"ranges":[{"start":30,"length":3},{"start":90,"length":3}],"wordPattern":"[a-zA-Z0-9:\\-\\._$]*"}
68+
69+
=== 6 ===
70+
{"ranges":[{"start":56,"length":3},{"start":79,"length":3}],"wordPattern":"[a-zA-Z0-9:\\-\\._$]*"}
71+
72+
73+
=== /matched.tsx ===
74+
function Test() {
75+
return <[|/*7*/div|]>
76+
77+
<[|/*8*/div|] {...{}}>
78+
</[|/*8*/div|]>
79+
</[|/*7*/div|]>
80+
}
81+
82+
=== 7 ===
83+
{"ranges":[{"start":30,"length":3},{"start":79,"length":3}],"wordPattern":"[a-zA-Z0-9:\\-\\._$]*"}
84+
85+
=== 8 ===
86+
{"ranges":[{"start":45,"length":3},{"start":68,"length":3}],"wordPattern":"[a-zA-Z0-9:\\-\\._$]*"}
87+
88+

tests/cases/fourslash/linkedEditingJsxTag10.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,4 +48,5 @@
4848
// @Filename: /jsx15.tsx
4949
////const jsx = </*15*/div> </*15a*/> <//*15b*/div> <//*15c*/>;
5050

51+
// as of #57132 none of these cases should have linked editing because the tags are mismatched or missing either < or >
5152
verify.baselineLinkedEditing();
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
// @Filename: /incomplete.tsx
4+
//// function Test() {
5+
//// return <div>
6+
//// </*0*/
7+
//// <div {...{}}>
8+
//// </div>
9+
//// </div>
10+
//// }
11+
12+
// @Filename: /incompleteMismatched.tsx
13+
//// function Test() {
14+
//// return <div>
15+
//// <T
16+
//// <div {...{}}>
17+
//// </div>
18+
//// </div>
19+
//// }
20+
21+
// @Filename: /incompleteMismatched2.tsx
22+
//// function Test() {
23+
//// return <div>
24+
//// <T
25+
//// <div {...{}}>
26+
//// T</div>
27+
//// </div>
28+
//// }
29+
30+
// @Filename: /incompleteMismatched3.tsx
31+
//// function Test() {
32+
//// return <div>
33+
//// <div {...{}}>
34+
//// </div>
35+
//// <T
36+
//// </div>
37+
//// }
38+
39+
// @Filename: /mismatched.tsx
40+
//// function Test() {
41+
//// return <div>
42+
//// <T>
43+
//// <div {...{}}>
44+
//// </div>
45+
//// </div>
46+
//// }
47+
48+
// @Filename: /matched.tsx
49+
//// function Test() {
50+
//// return <div>
51+
////
52+
//// <div {...{}}>
53+
//// </div>
54+
//// </div>
55+
//// }
56+
57+
verify.linkedEditing({ 0 : undefined });
58+
verify.baselineLinkedEditing();

0 commit comments

Comments
 (0)