@@ -3,8 +3,8 @@ namespace ts.SymbolDisplay {
3
3
const symbolDisplayNodeBuilderFlags = NodeBuilderFlags . OmitParameterModifiers | NodeBuilderFlags . IgnoreErrors | NodeBuilderFlags . UseAliasDefinedOutsideCurrentScope ;
4
4
5
5
// TODO(drosen): use contextual SemanticMeaning.
6
- export function getSymbolKind ( typeChecker : TypeChecker , symbol : Symbol , location : Node ) : ScriptElementKind {
7
- const result = getSymbolKindOfConstructorPropertyMethodAccessorFunctionOrVar ( typeChecker , symbol , location ) ;
6
+ export function getSymbolKind ( typeChecker : TypeChecker , symbol : Symbol , location : Node , contextToken ?: Node ) : ScriptElementKind {
7
+ const result = getSymbolKindOfConstructorPropertyMethodAccessorFunctionOrVar ( typeChecker , symbol , location , contextToken ) ;
8
8
if ( result !== ScriptElementKind . unknown ) {
9
9
return result ;
10
10
}
@@ -25,7 +25,7 @@ namespace ts.SymbolDisplay {
25
25
return result ;
26
26
}
27
27
28
- function getSymbolKindOfConstructorPropertyMethodAccessorFunctionOrVar ( typeChecker : TypeChecker , symbol : Symbol , location : Node ) : ScriptElementKind {
28
+ function getSymbolKindOfConstructorPropertyMethodAccessorFunctionOrVar ( typeChecker : TypeChecker , symbol : Symbol , location : Node , contextToken ?: Node ) : ScriptElementKind {
29
29
const roots = typeChecker . getRootSymbols ( symbol ) ;
30
30
// If this is a method from a mapped type, leave as a method so long as it still has a call signature.
31
31
if ( roots . length === 1
@@ -83,6 +83,20 @@ namespace ts.SymbolDisplay {
83
83
}
84
84
return unionPropertyKind ;
85
85
}
86
+
87
+ if ( contextToken ) {
88
+ const result = getSymbolKindOfJsxTagNameOrAttribute ( location , contextToken ) ;
89
+ if ( result !== ScriptElementKind . unknown ) {
90
+ return result ;
91
+ }
92
+ }
93
+
94
+ if ( isJsxAttribute ( location ) || location . parent && isJsxAttribute ( location . parent ) && location . parent . name === location ) {
95
+ return ScriptElementKind . jsxAttribute ;
96
+ }
97
+
98
+ // TODO(jakebailey): Delete the below code, once the edge cases it handles are handled above.
99
+
86
100
// If we requested completions after `x.` at the top-level, we may be at a source file location.
87
101
switch ( location . parent && location . parent . kind ) {
88
102
// If we've typed a character of the attribute name, will be 'JsxAttribute', else will be 'JsxOpeningElement'.
@@ -100,6 +114,50 @@ namespace ts.SymbolDisplay {
100
114
return ScriptElementKind . unknown ;
101
115
}
102
116
117
+ function getSymbolKindOfJsxTagNameOrAttribute ( location : Node , contextToken : Node ) : ScriptElementKind {
118
+ const symbolKindFromContext = forEachAncestor ( contextToken , ( n ) => {
119
+ if ( isJsxAttributeLike ( n ) ) {
120
+ return ScriptElementKind . jsxAttribute ;
121
+ }
122
+
123
+ if ( isJsxFragment ( n ) || isJsxOpeningFragment ( n ) || isJsxClosingFragment ( n ) ) {
124
+ return "quit" ;
125
+ }
126
+
127
+ if ( isJsxOpeningElement ( n ) || isJsxSelfClosingElement ( n ) || isJsxClosingElement ( n ) ) {
128
+ if ( contextToken . getEnd ( ) <= n . tagName . getFullStart ( ) ) {
129
+ // Definitely completing part of the tag name.
130
+ return ScriptElementKind . jsxTagName ;
131
+ }
132
+
133
+ if ( rangeContainsRange ( n . tagName , contextToken ) ) {
134
+ // We are to the right of the tag name, as the context is there.
135
+ // figure out where we are based on where the location is.
136
+
137
+ // TODO(jakebailey): This seems hacky.
138
+ if ( contextToken . kind === SyntaxKind . DotToken || contextToken . kind === SyntaxKind . QuestionDotToken ) {
139
+ // Unfinished dotted tag name.
140
+ return ScriptElementKind . jsxTagName ;
141
+ }
142
+
143
+ if ( ! rangeContainsRange ( n , location ) ) {
144
+ // Unclosed JSX element; location is entirely outside the element.
145
+ return ScriptElementKind . jsxAttribute ;
146
+ }
147
+
148
+ if ( n . tagName . getEnd ( ) <= location . getFullStart ( ) ) {
149
+ // After existing attributes, so is another attribute.
150
+ return ScriptElementKind . jsxAttribute ;
151
+ }
152
+ }
153
+
154
+ return "quit" ;
155
+ }
156
+ } ) ;
157
+
158
+ return symbolKindFromContext || ScriptElementKind . unknown ;
159
+ }
160
+
103
161
function getNormalizedSymbolModifiers ( symbol : Symbol ) {
104
162
if ( symbol . declarations && symbol . declarations . length ) {
105
163
const [ declaration , ...declarations ] = symbol . declarations ;
0 commit comments