From 3ee67e7cf68a4944d56938b5048c0b98e58dec53 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Tue, 22 Mar 2016 14:55:24 -0700 Subject: [PATCH] Fix #7637: treat jsx tag names as expressions --- src/compiler/checker.ts | 29 +++++++------------ src/compiler/utilities.ts | 14 +++++++-- .../reference/jsxReactTestSuite.symbols | 2 ++ .../reference/jsxReactTestSuite.types | 3 ++ .../reference/tsxAttributeResolution13.types | 4 +-- .../reference/tsxElementResolution.symbols | 2 ++ .../reference/tsxElementResolution.types | 5 ++-- .../reference/tsxElementResolution17.symbols | 2 ++ .../reference/tsxElementResolution17.types | 5 ++-- tests/baselines/reference/tsxEmit3.symbols | 2 ++ tests/baselines/reference/tsxEmit3.types | 5 ++-- .../reference/tsxOpeningClosingNames.symbols | 14 +++++++++ .../reference/tsxOpeningClosingNames.types | 18 ++++++++---- .../fourslash/findReferencesJSXTagName2.ts | 11 +++++++ 14 files changed, 81 insertions(+), 35 deletions(-) create mode 100644 tests/cases/fourslash/findReferencesJSXTagName2.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index cb266c3ace4be..cde0dde8607e7 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -9033,7 +9033,12 @@ namespace ts { checkJsxOpeningLikeElement(node.openingElement); // Perform resolution on the closing tag so that rename/go to definition/etc work - getJsxTagSymbol(node.closingElement); + if (isJsxIntrinsicIdentifier(node.closingElement.tagName)) { + getIntrinsicTagSymbol(node.closingElement); + } + else { + checkExpression(node.closingElement.tagName); + } // Check children for (const child of node.children) { @@ -9143,18 +9148,6 @@ namespace ts { return jsxTypes[name]; } - function getJsxTagSymbol(node: JsxOpeningLikeElement | JsxClosingElement): Symbol { - if (isJsxIntrinsicIdentifier(node.tagName)) { - return getIntrinsicTagSymbol(node); - } - else if (node.tagName.kind === SyntaxKind.Identifier) { - return resolveEntityName(node.tagName, SymbolFlags.Value | SymbolFlags.Alias); - } - else { - return checkExpression(node.tagName).symbol; - } - } - /** * Looks up an intrinsic tag name and returns a symbol that either points to an intrinsic * property (in which case nodeLinks.jsxFlags will be IntrinsicNamedElement) or an intrinsic @@ -16211,12 +16204,6 @@ namespace ts { meaning |= SymbolFlags.Alias; return resolveEntityName(entityName, meaning); } - else if ((entityName.parent.kind === SyntaxKind.JsxOpeningElement) || - (entityName.parent.kind === SyntaxKind.JsxSelfClosingElement) || - (entityName.parent.kind === SyntaxKind.JsxClosingElement)) { - - return getJsxTagSymbol(entityName.parent); - } else if (isExpression(entityName)) { if (nodeIsMissing(entityName)) { // Missing entity name. @@ -16224,6 +16211,10 @@ namespace ts { } if (entityName.kind === SyntaxKind.Identifier) { + if (isJSXTagName(entityName) && isJsxIntrinsicIdentifier(entityName)) { + return getIntrinsicTagSymbol(entityName.parent); + } + // Include aliases in the meaning, this ensures that we do not follow aliases to where they point and instead // return the alias symbol. const meaning: SymbolFlags = SymbolFlags.Value | SymbolFlags.Alias; diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 2966af3cb76f3..4356486d3b5aa 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -953,6 +953,16 @@ namespace ts { return node.kind === SyntaxKind.ElementAccessExpression; } + export function isJSXTagName(node: Node) { + const parent = node.parent; + if (parent.kind === SyntaxKind.JsxOpeningElement || + parent.kind === SyntaxKind.JsxSelfClosingElement || + parent.kind === SyntaxKind.JsxClosingElement) { + return (parent).tagName === node; + } + return false; + } + export function isExpression(node: Node): boolean { switch (node.kind) { case SyntaxKind.SuperKeyword: @@ -994,9 +1004,9 @@ namespace ts { while (node.parent.kind === SyntaxKind.QualifiedName) { node = node.parent; } - return node.parent.kind === SyntaxKind.TypeQuery; + return node.parent.kind === SyntaxKind.TypeQuery || isJSXTagName(node); case SyntaxKind.Identifier: - if (node.parent.kind === SyntaxKind.TypeQuery) { + if (node.parent.kind === SyntaxKind.TypeQuery || isJSXTagName(node)) { return true; } // fall through diff --git a/tests/baselines/reference/jsxReactTestSuite.symbols b/tests/baselines/reference/jsxReactTestSuite.symbols index 24ff3a1cf3d6f..956b4cff6f7b3 100644 --- a/tests/baselines/reference/jsxReactTestSuite.symbols +++ b/tests/baselines/reference/jsxReactTestSuite.symbols @@ -178,8 +178,10 @@ var x = >constructor : Symbol(unknown) ; +>Namespace : Symbol(Namespace, Decl(jsxReactTestSuite.tsx, 6, 11)) ; +>Namespace : Symbol(Namespace, Decl(jsxReactTestSuite.tsx, 6, 11)) Component : Symbol(Component, Decl(jsxReactTestSuite.tsx, 2, 11)) diff --git a/tests/baselines/reference/jsxReactTestSuite.types b/tests/baselines/reference/jsxReactTestSuite.types index 88c2c278e59a3..8bab7ce6e7df0 100644 --- a/tests/baselines/reference/jsxReactTestSuite.types +++ b/tests/baselines/reference/jsxReactTestSuite.types @@ -235,11 +235,14 @@ var x = ; > : any +>Namespace.Component : any >Namespace : any >Component : any ; > : any +>Namespace.DeepNamespace.Component : any +>Namespace.DeepNamespace : any >Namespace : any >DeepNamespace : any >Component : any diff --git a/tests/baselines/reference/tsxAttributeResolution13.types b/tests/baselines/reference/tsxAttributeResolution13.types index f0435b8081265..1a426d86e7d98 100644 --- a/tests/baselines/reference/tsxAttributeResolution13.types +++ b/tests/baselines/reference/tsxAttributeResolution13.types @@ -5,6 +5,6 @@ function Test() { } > : any ->Test : any ->Test : any +>Test : () => void +>Test : () => void diff --git a/tests/baselines/reference/tsxElementResolution.symbols b/tests/baselines/reference/tsxElementResolution.symbols index e9756e9efc974..cd7ac7807f145 100644 --- a/tests/baselines/reference/tsxElementResolution.symbols +++ b/tests/baselines/reference/tsxElementResolution.symbols @@ -47,5 +47,7 @@ var d = ; var e = ; >e : Symbol(e, Decl(tsxElementResolution.tsx, 23, 3)) +>Dotted.Name : Symbol(Dotted.Name, Decl(tsxElementResolution.tsx, 12, 15)) +>Dotted : Symbol(Dotted, Decl(tsxElementResolution.tsx, 10, 14)) >Name : Symbol(Dotted.Name, Decl(tsxElementResolution.tsx, 12, 15)) diff --git a/tests/baselines/reference/tsxElementResolution.types b/tests/baselines/reference/tsxElementResolution.types index 89600bbbc2f34..a1c2abcef7c5f 100644 --- a/tests/baselines/reference/tsxElementResolution.types +++ b/tests/baselines/reference/tsxElementResolution.types @@ -51,6 +51,7 @@ var d = ; var e = ; >e : any > : any ->Dotted : any ->Name : any +>Dotted.Name : typeof Dotted.Name +>Dotted : typeof Dotted +>Name : typeof Dotted.Name diff --git a/tests/baselines/reference/tsxElementResolution17.symbols b/tests/baselines/reference/tsxElementResolution17.symbols index 0b4459552de39..0225cc35d9141 100644 --- a/tests/baselines/reference/tsxElementResolution17.symbols +++ b/tests/baselines/reference/tsxElementResolution17.symbols @@ -8,6 +8,8 @@ import s2 = require('elements2'); >s2 : Symbol(s2, Decl(consumer.tsx, 2, 33)) ; +>s1.MyElement : Symbol(s1.MyElement, Decl(file.tsx, 6, 28)) +>s1 : Symbol(s1, Decl(consumer.tsx, 0, 0)) >MyElement : Symbol(s1.MyElement, Decl(file.tsx, 6, 28)) === tests/cases/conformance/jsx/file.tsx === diff --git a/tests/baselines/reference/tsxElementResolution17.types b/tests/baselines/reference/tsxElementResolution17.types index e6396a9a60be5..c68c19f58e73a 100644 --- a/tests/baselines/reference/tsxElementResolution17.types +++ b/tests/baselines/reference/tsxElementResolution17.types @@ -9,8 +9,9 @@ import s2 = require('elements2'); ; > : JSX.Element ->s1 : any ->MyElement : any +>s1.MyElement : typeof s1.MyElement +>s1 : typeof s1 +>MyElement : typeof s1.MyElement === tests/cases/conformance/jsx/file.tsx === diff --git a/tests/baselines/reference/tsxEmit3.symbols b/tests/baselines/reference/tsxEmit3.symbols index 3b88d4e03719f..3eb4ef3b05df2 100644 --- a/tests/baselines/reference/tsxEmit3.symbols +++ b/tests/baselines/reference/tsxEmit3.symbols @@ -59,6 +59,8 @@ module M { >S.Bar : Symbol(S.Bar, Decl(file.tsx, 8, 18)) >S : Symbol(S, Decl(file.tsx, 7, 39), Decl(file.tsx, 18, 14)) >Bar : Symbol(S.Bar, Decl(file.tsx, 8, 18)) +>S.Bar : Symbol(S.Bar, Decl(file.tsx, 8, 18)) +>S : Symbol(S, Decl(file.tsx, 7, 39), Decl(file.tsx, 18, 14)) >Bar : Symbol(S.Bar, Decl(file.tsx, 8, 18)) } diff --git a/tests/baselines/reference/tsxEmit3.types b/tests/baselines/reference/tsxEmit3.types index 49a5cf8a51b3f..e70c44d00418d 100644 --- a/tests/baselines/reference/tsxEmit3.types +++ b/tests/baselines/reference/tsxEmit3.types @@ -67,8 +67,9 @@ module M { >S : typeof S >Bar : typeof S.Bar > : JSX.Element ->S : any ->Bar : any +>S.Bar : typeof S.Bar +>S : typeof S +>Bar : typeof S.Bar } module M { diff --git a/tests/baselines/reference/tsxOpeningClosingNames.symbols b/tests/baselines/reference/tsxOpeningClosingNames.symbols index e61d209e231c0..66010f74d2f92 100644 --- a/tests/baselines/reference/tsxOpeningClosingNames.symbols +++ b/tests/baselines/reference/tsxOpeningClosingNames.symbols @@ -16,4 +16,18 @@ declare module A.B.C { } foo +>A.B.C.D : Symbol(A.B.C.D, Decl(file.tsx, 5, 5)) +>A.B.C : Symbol(A.B.C, Decl(file.tsx, 4, 19)) +>A.B : Symbol(A.B, Decl(file.tsx, 4, 17)) +>A : Symbol(A, Decl(file.tsx, 2, 1)) +>B : Symbol(A.B, Decl(file.tsx, 4, 17)) +>C : Symbol(A.B.C, Decl(file.tsx, 4, 19)) +>D : Symbol(A.B.C.D, Decl(file.tsx, 5, 5)) +>A . B . C.D : Symbol(A.B.C.D, Decl(file.tsx, 5, 5)) +>A . B . C : Symbol(A.B.C, Decl(file.tsx, 4, 19)) +>A . B : Symbol(A.B, Decl(file.tsx, 4, 17)) +>A : Symbol(A, Decl(file.tsx, 2, 1)) +>B : Symbol(A.B, Decl(file.tsx, 4, 17)) +>C : Symbol(A.B.C, Decl(file.tsx, 4, 19)) +>D : Symbol(A.B.C.D, Decl(file.tsx, 5, 5)) diff --git a/tests/baselines/reference/tsxOpeningClosingNames.types b/tests/baselines/reference/tsxOpeningClosingNames.types index ac36205029e46..2e21f346d10cd 100644 --- a/tests/baselines/reference/tsxOpeningClosingNames.types +++ b/tests/baselines/reference/tsxOpeningClosingNames.types @@ -17,12 +17,18 @@ declare module A.B.C { foo >foo : JSX.Element ->A : any ->B : any ->C : any +>A.B.C.D : any +>A.B.C : typeof A.B.C +>A.B : typeof A.B +>A : typeof A +>B : typeof A.B +>C : typeof A.B.C >D : any ->A : any ->B : any ->C : any +>A . B . C.D : any +>A . B . C : typeof A.B.C +>A . B : typeof A.B +>A : typeof A +>B : typeof A.B +>C : typeof A.B.C >D : any diff --git a/tests/cases/fourslash/findReferencesJSXTagName2.ts b/tests/cases/fourslash/findReferencesJSXTagName2.ts new file mode 100644 index 0000000000000..a7bb7fd97dd17 --- /dev/null +++ b/tests/cases/fourslash/findReferencesJSXTagName2.ts @@ -0,0 +1,11 @@ +/// + +// @Filename: index.tsx +////const /*1*/obj = {Component: () =>
}; +////const element = ; + +goTo.marker("1"); +verify.referencesCountIs(2); + +goTo.marker("2"); +verify.referencesCountIs(2); \ No newline at end of file