Merge pull request #6006 from Microsoft/fix5953_crashJSX
Fix crash inside JSX Closing tag
This commit is contained in:
commit
8cf347c088
|
@ -65,6 +65,7 @@ namespace ts {
|
|||
getTypeCount: () => typeCount,
|
||||
isUndefinedSymbol: symbol => symbol === undefinedSymbol,
|
||||
isArgumentsSymbol: symbol => symbol === argumentsSymbol,
|
||||
isUnknownSymbol: symbol => symbol === unknownSymbol,
|
||||
getDiagnostics,
|
||||
getGlobalDiagnostics,
|
||||
|
||||
|
@ -8112,6 +8113,7 @@ namespace ts {
|
|||
if (compilerOptions.noImplicitAny) {
|
||||
error(node, Diagnostics.JSX_element_implicitly_has_type_any_because_no_interface_JSX_0_exists, JsxNames.IntrinsicElements);
|
||||
}
|
||||
return unknownSymbol;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1738,6 +1738,7 @@ namespace ts {
|
|||
isImplementationOfOverload(node: FunctionLikeDeclaration): boolean;
|
||||
isUndefinedSymbol(symbol: Symbol): boolean;
|
||||
isArgumentsSymbol(symbol: Symbol): boolean;
|
||||
isUnknownSymbol(symbol: Symbol): boolean;
|
||||
|
||||
getConstantValue(node: EnumMember | PropertyAccessExpression | ElementAccessExpression): number;
|
||||
isValidPropertyAccess(node: PropertyAccessExpression | QualifiedName, propertyName: string): boolean;
|
||||
|
|
|
@ -3100,6 +3100,7 @@ namespace ts {
|
|||
}
|
||||
else if (kind === SyntaxKind.SlashToken && contextToken.parent.kind === SyntaxKind.JsxClosingElement) {
|
||||
isStartingCloseTag = true;
|
||||
location = contextToken;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3125,8 +3126,11 @@ namespace ts {
|
|||
}
|
||||
else if (isStartingCloseTag) {
|
||||
const tagName = (<JsxElement>contextToken.parent.parent).openingElement.tagName;
|
||||
symbols = [typeChecker.getSymbolAtLocation(tagName)];
|
||||
const tagSymbol = typeChecker.getSymbolAtLocation(tagName);
|
||||
|
||||
if (!typeChecker.isUnknownSymbol(tagSymbol)) {
|
||||
symbols = [tagSymbol];
|
||||
}
|
||||
isMemberCompletion = true;
|
||||
isNewIdentifierLocation = false;
|
||||
}
|
||||
|
@ -3832,7 +3836,23 @@ namespace ts {
|
|||
}
|
||||
else {
|
||||
if (!symbols || symbols.length === 0) {
|
||||
return undefined;
|
||||
if (sourceFile.languageVariant === LanguageVariant.JSX &&
|
||||
location.parent && location.parent.kind === SyntaxKind.JsxClosingElement) {
|
||||
// In the TypeScript JSX element, if such element is not defined. When users query for completion at closing tag,
|
||||
// instead of simply giving unknown value, the completion will return the tag-name of an associated opening-element.
|
||||
// For example:
|
||||
// var x = <div> </ /*1*/> completion list at "1" will contain "div" with type any
|
||||
const tagName = (<JsxElement>location.parent.parent).openingElement.tagName;
|
||||
entries.push({
|
||||
name: (<Identifier>tagName).text,
|
||||
kind: undefined,
|
||||
kindModifiers: undefined,
|
||||
sortText: "0",
|
||||
});
|
||||
}
|
||||
else {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
getCompletionEntriesFromSymbols(symbols, entries);
|
||||
|
@ -4440,7 +4460,7 @@ namespace ts {
|
|||
const typeChecker = program.getTypeChecker();
|
||||
const symbol = typeChecker.getSymbolAtLocation(node);
|
||||
|
||||
if (!symbol) {
|
||||
if (!symbol || typeChecker.isUnknownSymbol(symbol)) {
|
||||
// Try getting just type at this position and show
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.Identifier:
|
||||
|
|
|
@ -4,5 +4,6 @@ declare var React: any;
|
|||
>React : Symbol(React, Decl(jsxEmitAttributeWithPreserve.tsx, 1, 11))
|
||||
|
||||
<foo data/>
|
||||
>foo : Symbol(unknown)
|
||||
>data : Symbol(unknown)
|
||||
|
||||
|
|
|
@ -1,34 +1,68 @@
|
|||
=== tests/cases/compiler/jsxHash.tsx ===
|
||||
var t02 = <a>{0}#</a>;
|
||||
>t02 : Symbol(t02, Decl(jsxHash.tsx, 0, 3))
|
||||
>a : Symbol(unknown)
|
||||
>a : Symbol(unknown)
|
||||
|
||||
var t03 = <a>#{0}</a>;
|
||||
>t03 : Symbol(t03, Decl(jsxHash.tsx, 1, 3))
|
||||
>a : Symbol(unknown)
|
||||
>a : Symbol(unknown)
|
||||
|
||||
var t04 = <a>#{0}#</a>;
|
||||
>t04 : Symbol(t04, Decl(jsxHash.tsx, 2, 3))
|
||||
>a : Symbol(unknown)
|
||||
>a : Symbol(unknown)
|
||||
|
||||
var t05 = <a>#<i></i></a>;
|
||||
>t05 : Symbol(t05, Decl(jsxHash.tsx, 3, 3))
|
||||
>a : Symbol(unknown)
|
||||
>i : Symbol(unknown)
|
||||
>i : Symbol(unknown)
|
||||
>a : Symbol(unknown)
|
||||
|
||||
var t06 = <a>#<i></i></a>;
|
||||
>t06 : Symbol(t06, Decl(jsxHash.tsx, 4, 3))
|
||||
>a : Symbol(unknown)
|
||||
>i : Symbol(unknown)
|
||||
>i : Symbol(unknown)
|
||||
>a : Symbol(unknown)
|
||||
|
||||
var t07 = <a>#<i>#</i></a>;
|
||||
>t07 : Symbol(t07, Decl(jsxHash.tsx, 5, 3))
|
||||
>a : Symbol(unknown)
|
||||
>i : Symbol(unknown)
|
||||
>i : Symbol(unknown)
|
||||
>a : Symbol(unknown)
|
||||
|
||||
var t08 = <a><i></i>#</a>;
|
||||
>t08 : Symbol(t08, Decl(jsxHash.tsx, 6, 3))
|
||||
>a : Symbol(unknown)
|
||||
>i : Symbol(unknown)
|
||||
>i : Symbol(unknown)
|
||||
>a : Symbol(unknown)
|
||||
|
||||
var t09 = <a>#<i></i>#</a>;
|
||||
>t09 : Symbol(t09, Decl(jsxHash.tsx, 7, 3))
|
||||
>a : Symbol(unknown)
|
||||
>i : Symbol(unknown)
|
||||
>i : Symbol(unknown)
|
||||
>a : Symbol(unknown)
|
||||
|
||||
var t10 = <a><i/>#</a>;
|
||||
>t10 : Symbol(t10, Decl(jsxHash.tsx, 8, 3))
|
||||
>a : Symbol(unknown)
|
||||
>i : Symbol(unknown)
|
||||
>a : Symbol(unknown)
|
||||
|
||||
var t11 = <a>#<i/></a>;
|
||||
>t11 : Symbol(t11, Decl(jsxHash.tsx, 9, 3))
|
||||
>a : Symbol(unknown)
|
||||
>i : Symbol(unknown)
|
||||
>a : Symbol(unknown)
|
||||
|
||||
var t12 = <a>#</a>;
|
||||
>t12 : Symbol(t12, Decl(jsxHash.tsx, 10, 3))
|
||||
>a : Symbol(unknown)
|
||||
>a : Symbol(unknown)
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ let x = Test; // emit test_1.default
|
|||
>Test : Symbol(Test, Decl(consumer.tsx, 1, 6))
|
||||
|
||||
<anything attr={Test} />; // ?
|
||||
>anything : Symbol(unknown)
|
||||
>attr : Symbol(unknown)
|
||||
>Test : Symbol(Test, Decl(consumer.tsx, 1, 6))
|
||||
|
||||
|
|
|
@ -37,21 +37,36 @@ declare var hasOwnProperty:any;
|
|||
>hasOwnProperty : Symbol(hasOwnProperty, Decl(jsxReactTestSuite.tsx, 12, 11))
|
||||
|
||||
<div>text</div>;
|
||||
>div : Symbol(unknown)
|
||||
>div : Symbol(unknown)
|
||||
|
||||
<div>
|
||||
>div : Symbol(unknown)
|
||||
|
||||
{this.props.children}
|
||||
</div>;
|
||||
>div : Symbol(unknown)
|
||||
|
||||
<div>
|
||||
>div : Symbol(unknown)
|
||||
|
||||
<div><br /></div>
|
||||
>div : Symbol(unknown)
|
||||
>br : Symbol(unknown)
|
||||
>div : Symbol(unknown)
|
||||
|
||||
<Component>{foo}<br />{bar}</Component>
|
||||
>Component : Symbol(Component, Decl(jsxReactTestSuite.tsx, 2, 11))
|
||||
>foo : Symbol(foo, Decl(jsxReactTestSuite.tsx, 7, 11))
|
||||
>br : Symbol(unknown)
|
||||
>bar : Symbol(bar, Decl(jsxReactTestSuite.tsx, 8, 11))
|
||||
>Component : Symbol(Component, Decl(jsxReactTestSuite.tsx, 2, 11))
|
||||
|
||||
<br />
|
||||
>br : Symbol(unknown)
|
||||
|
||||
</div>;
|
||||
>div : Symbol(unknown)
|
||||
|
||||
|
||||
<Composite>
|
||||
|
@ -74,6 +89,8 @@ var x =
|
|||
>x : Symbol(x, Decl(jsxReactTestSuite.tsx, 10, 11), Decl(jsxReactTestSuite.tsx, 35, 3))
|
||||
|
||||
<div
|
||||
>div : Symbol(unknown)
|
||||
|
||||
attr1={
|
||||
>attr1 : Symbol(unknown)
|
||||
|
||||
|
@ -97,41 +114,64 @@ var x =
|
|||
>attr4 : Symbol(unknown)
|
||||
|
||||
</div>;
|
||||
>div : Symbol(unknown)
|
||||
|
||||
(
|
||||
<div>
|
||||
>div : Symbol(unknown)
|
||||
|
||||
{/* A comment at the beginning */}
|
||||
{/* A second comment at the beginning */}
|
||||
<span>
|
||||
>span : Symbol(unknown)
|
||||
|
||||
{/* A nested comment */}
|
||||
</span>
|
||||
>span : Symbol(unknown)
|
||||
|
||||
{/* A sandwiched comment */}
|
||||
<br />
|
||||
>br : Symbol(unknown)
|
||||
|
||||
{/* A comment at the end */}
|
||||
{/* A second comment at the end */}
|
||||
</div>
|
||||
>div : Symbol(unknown)
|
||||
|
||||
);
|
||||
|
||||
(
|
||||
<div
|
||||
>div : Symbol(unknown)
|
||||
|
||||
/* a multi-line
|
||||
comment */
|
||||
attr1="foo">
|
||||
>attr1 : Symbol(unknown)
|
||||
|
||||
<span // a double-slash comment
|
||||
>span : Symbol(unknown)
|
||||
|
||||
attr2="bar"
|
||||
>attr2 : Symbol(unknown)
|
||||
|
||||
/>
|
||||
</div>
|
||||
>div : Symbol(unknown)
|
||||
|
||||
);
|
||||
|
||||
<div> </div>;
|
||||
>div : Symbol(unknown)
|
||||
>div : Symbol(unknown)
|
||||
|
||||
<div> </div>;
|
||||
>div : Symbol(unknown)
|
||||
>div : Symbol(unknown)
|
||||
|
||||
<hasOwnProperty>testing</hasOwnProperty>;
|
||||
>hasOwnProperty : Symbol(unknown)
|
||||
>hasOwnProperty : Symbol(unknown)
|
||||
|
||||
<Component constructor="foo" />;
|
||||
>Component : Symbol(Component, Decl(jsxReactTestSuite.tsx, 2, 11))
|
||||
|
@ -158,6 +198,7 @@ var x =
|
|||
>sound : Symbol(unknown)
|
||||
|
||||
<font-face />;
|
||||
>font-face : Symbol(unknown)
|
||||
|
||||
<Component x={y} />;
|
||||
>Component : Symbol(Component, Decl(jsxReactTestSuite.tsx, 2, 11))
|
||||
|
@ -165,6 +206,7 @@ var x =
|
|||
>y : Symbol(y, Decl(jsxReactTestSuite.tsx, 9, 11))
|
||||
|
||||
<x-component />;
|
||||
>x-component : Symbol(unknown)
|
||||
|
||||
<Component {...x} />;
|
||||
>Component : Symbol(Component, Decl(jsxReactTestSuite.tsx, 2, 11))
|
||||
|
|
|
@ -4,14 +4,18 @@ declare var React: any;
|
|||
>React : Symbol(React, Decl(keywordInJsxIdentifier.tsx, 1, 11))
|
||||
|
||||
<foo class-id/>;
|
||||
>foo : Symbol(unknown)
|
||||
>class-id : Symbol(unknown)
|
||||
|
||||
<foo class/>;
|
||||
>foo : Symbol(unknown)
|
||||
>class : Symbol(unknown)
|
||||
|
||||
<foo class-id="1"/>;
|
||||
>foo : Symbol(unknown)
|
||||
>class-id : Symbol(unknown)
|
||||
|
||||
<foo class="1"/>;
|
||||
>foo : Symbol(unknown)
|
||||
>class : Symbol(unknown)
|
||||
|
||||
|
|
|
@ -16,5 +16,6 @@ declare var foo: any;
|
|||
>foo : Symbol(foo, Decl(test.tsx, 1, 11))
|
||||
|
||||
<foo data/>;
|
||||
>foo : Symbol(unknown)
|
||||
>data : Symbol(unknown)
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ declare var x: any;
|
|||
>x : Symbol(x, Decl(reactNamespaceJSXEmit.tsx, 4, 11))
|
||||
|
||||
<foo data/>;
|
||||
>foo : Symbol(unknown)
|
||||
>data : Symbol(unknown)
|
||||
|
||||
<Bar x={x} />;
|
||||
|
@ -21,6 +22,8 @@ declare var x: any;
|
|||
>x : Symbol(x, Decl(reactNamespaceJSXEmit.tsx, 4, 11))
|
||||
|
||||
<x-component />;
|
||||
>x-component : Symbol(unknown)
|
||||
|
||||
<Bar {...x} />;
|
||||
>Bar : Symbol(Bar, Decl(reactNamespaceJSXEmit.tsx, 3, 11))
|
||||
>x : Symbol(x, Decl(reactNamespaceJSXEmit.tsx, 4, 11))
|
||||
|
|
|
@ -22,5 +22,6 @@ var obj1: Obj1;
|
|||
>Obj1 : Symbol(Obj1, Decl(file.tsx, 3, 1))
|
||||
|
||||
<obj1 x={10} />; // Error
|
||||
>obj1 : Symbol(unknown)
|
||||
>x : Symbol(unknown)
|
||||
|
||||
|
|
|
@ -17,5 +17,6 @@ var obj1: Obj1;
|
|||
>Obj1 : Symbol(Obj1, Decl(file.tsx, 2, 1))
|
||||
|
||||
<obj1 x={10} />; // OK
|
||||
>obj1 : Symbol(unknown)
|
||||
>x : Symbol(unknown)
|
||||
|
||||
|
|
|
@ -8,5 +8,6 @@ declare module JSX {
|
|||
|
||||
// OK, but implicit any
|
||||
<div n='x' />;
|
||||
>div : Symbol(unknown)
|
||||
>n : Symbol(unknown)
|
||||
|
||||
|
|
|
@ -44,6 +44,8 @@ export class Button extends React.Component<any, any> {
|
|||
>render : Symbol(render, Decl(button.tsx, 2, 55))
|
||||
|
||||
return <button>Some button</button>;
|
||||
>button : Symbol(unknown)
|
||||
>button : Symbol(unknown)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
=== tests/cases/conformance/jsx/tsxNoJsx.tsx ===
|
||||
|
||||
No type information for this code.<nope />;
|
||||
No type information for this code.
|
||||
No type information for this code.
|
||||
<nope />;
|
||||
>nope : Symbol(unknown)
|
||||
|
||||
|
|
|
@ -3,11 +3,13 @@
|
|||
// A built-in element (OK)
|
||||
var a1 = <div id="foo" />;
|
||||
>a1 : Symbol(a1, Decl(tsxTypeErrors.tsx, 2, 3))
|
||||
>div : Symbol(unknown)
|
||||
>id : Symbol(unknown)
|
||||
|
||||
// A built-in element with a mistyped property (error)
|
||||
var a2 = <img srce="foo.jpg" />
|
||||
>a2 : Symbol(a2, Decl(tsxTypeErrors.tsx, 5, 3))
|
||||
>img : Symbol(unknown)
|
||||
>srce : Symbol(unknown)
|
||||
|
||||
// A built-in element with a badly-typed attribute value (error)
|
||||
|
@ -17,12 +19,14 @@ var thing = { oops: 100 };
|
|||
|
||||
var a3 = <div id={thing} />
|
||||
>a3 : Symbol(a3, Decl(tsxTypeErrors.tsx, 9, 3))
|
||||
>div : Symbol(unknown)
|
||||
>id : Symbol(unknown)
|
||||
>thing : Symbol(thing, Decl(tsxTypeErrors.tsx, 8, 3))
|
||||
|
||||
// Mistyped html name (error)
|
||||
var e1 = <imag src="bar.jpg" />
|
||||
>e1 : Symbol(e1, Decl(tsxTypeErrors.tsx, 12, 3))
|
||||
>imag : Symbol(unknown)
|
||||
>src : Symbol(unknown)
|
||||
|
||||
// A custom type
|
||||
|
|
14
tests/cases/fourslash/tsxCompletionOnClosingTag1.ts
Normal file
14
tests/cases/fourslash/tsxCompletionOnClosingTag1.ts
Normal file
|
@ -0,0 +1,14 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
//@Filename: file.tsx
|
||||
//// declare module JSX {
|
||||
//// interface Element { }
|
||||
//// interface IntrinsicElements {
|
||||
//// div: { ONE: string; TWO: number; }
|
||||
//// }
|
||||
//// }
|
||||
//// var x1 = <div><//**/
|
||||
|
||||
goTo.marker();
|
||||
verify.memberListCount(1);
|
||||
verify.completionListContains('div');
|
20
tests/cases/fourslash/tsxCompletionOnClosingTag2.ts
Normal file
20
tests/cases/fourslash/tsxCompletionOnClosingTag2.ts
Normal file
|
@ -0,0 +1,20 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
//@Filename: file.tsx
|
||||
//// declare module JSX {
|
||||
//// interface Element { }
|
||||
//// interface IntrinsicElements {
|
||||
//// div: { ONE: string; TWO: number; }
|
||||
//// }
|
||||
//// }
|
||||
//// var x1 = <div>
|
||||
//// <h1> Hello world </ /*2*/>
|
||||
//// </ /*1*/>
|
||||
|
||||
goTo.marker("1");
|
||||
verify.memberListCount(1);
|
||||
verify.completionListContains('div');
|
||||
|
||||
goTo.marker("2");
|
||||
verify.memberListCount(1);
|
||||
verify.completionListContains('h1')
|
|
@ -0,0 +1,8 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
//@Filename: file.tsx
|
||||
//// var x1 = <div><//**/
|
||||
|
||||
goTo.marker();
|
||||
verify.memberListCount(1);
|
||||
verify.completionListContains('div');
|
|
@ -0,0 +1,14 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
//@Filename: file.tsx
|
||||
//// var x1 = <div>
|
||||
//// <h1> Hello world </ /*2*/>
|
||||
//// </ /*1*/>
|
||||
|
||||
goTo.marker("1");
|
||||
verify.memberListCount(1);
|
||||
verify.completionListContains('div');
|
||||
|
||||
goTo.marker("2");
|
||||
verify.memberListCount(1);
|
||||
verify.completionListContains('h1')
|
|
@ -0,0 +1,7 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
//@Filename: file.tsx
|
||||
//// var x = </**/;
|
||||
|
||||
goTo.marker();
|
||||
verify.memberListCount(41);
|
18
tests/cases/fourslash/tsxQuickInfo1.ts
Normal file
18
tests/cases/fourslash/tsxQuickInfo1.ts
Normal file
|
@ -0,0 +1,18 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
//@Filename: file.tsx
|
||||
//// var x1 = <di/*1*/v></di/*2*/v>
|
||||
//// class MyElement {}
|
||||
//// var z = <My/*3*/Element></My/*4*/Element>
|
||||
|
||||
goTo.marker("1");
|
||||
verify.quickInfoIs("any", undefined);
|
||||
|
||||
goTo.marker("2");
|
||||
verify.quickInfoIs("any", undefined);;
|
||||
|
||||
goTo.marker("3");
|
||||
verify.quickInfoIs("class MyElement", undefined);;
|
||||
|
||||
goTo.marker("4");
|
||||
verify.quickInfoIs("class MyElement", undefined);;
|
24
tests/cases/fourslash/tsxQuickInfo2.ts
Normal file
24
tests/cases/fourslash/tsxQuickInfo2.ts
Normal file
|
@ -0,0 +1,24 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
//@Filename: file.tsx
|
||||
//// declare module JSX {
|
||||
//// interface Element { }
|
||||
//// interface IntrinsicElements {
|
||||
//// div: any
|
||||
//// }
|
||||
//// }
|
||||
//// var x1 = <di/*1*/v></di/*2*/v>
|
||||
//// class MyElement {}
|
||||
//// var z = <My/*3*/Element></My/*4*/Element>
|
||||
|
||||
goTo.marker("1");
|
||||
verify.quickInfoIs("(property) JSX.IntrinsicElements.div: any", undefined);
|
||||
|
||||
goTo.marker("2");
|
||||
verify.quickInfoIs("(property) JSX.IntrinsicElements.div: any", undefined);;
|
||||
|
||||
goTo.marker("3");
|
||||
verify.quickInfoIs("class MyElement", undefined);;
|
||||
|
||||
goTo.marker("4");
|
||||
verify.quickInfoIs("class MyElement", undefined);;
|
Loading…
Reference in a new issue