Skip to content

Commit 459bd19

Browse files
authored
Add unqualified JSDoc member references (#44202)
* Add unqualified JSDoc member references This allows unqualified references like: ```ts class Zero { /** @param buddy Must be {@link D_HORSE} or {@link D_DOG}. */ deploy(buddy: number) { } static D_HORSE = 1 static D_DOG = 2 } ``` I surveyed @see and @link again to estimate how common this is. I found a little over 200 uses, which is around 2%. Sorted by frequency, this *is* the next feature on the list, along with the `module:` prefix. So I think this is about the right point to stop adding code. In this case, however, I liked most of the uses -- there were a lot of deprecated functions that referenced a function just below, where it would be wordy to qualify the name, but the reader would benefit from a link. Note that unqualified references do *not* work inside type or object literals. The code I ended up with is quite complicated and I didn't observe any uses in the wild. Fixes #43595 * Remove type/object literal container check Since they don't work anyway
1 parent 3ffa245 commit 459bd19

File tree

2 files changed

+121
-22
lines changed

2 files changed

+121
-22
lines changed

src/compiler/checker.ts

+21-12
Original file line numberDiff line numberDiff line change
@@ -39335,7 +39335,14 @@ namespace ts {
3933539335
const symbol = getIntrinsicTagSymbol(name.parent as JsxOpeningLikeElement);
3933639336
return symbol === unknownSymbol ? undefined : symbol;
3933739337
}
39338-
return resolveEntityName(name, meaning, /*ignoreErrors*/ false, /*dontResolveAlias*/ !isJSDoc, getHostSignatureFromJSDoc(name));
39338+
const result = resolveEntityName(name, meaning, /*ignoreErrors*/ false, /*dontResolveAlias*/ !isJSDoc, getHostSignatureFromJSDoc(name));
39339+
if (!result && isJSDoc) {
39340+
const container = findAncestor(name, or(isClassLike, isInterfaceDeclaration));
39341+
if (container) {
39342+
return resolveJSDocMemberName(name, getSymbolOfNode(container));
39343+
}
39344+
}
39345+
return result;
3933939346
}
3934039347
else if (name.kind === SyntaxKind.PropertyAccessExpression || name.kind === SyntaxKind.QualifiedName) {
3934139348
const links = getNodeLinks(name);
@@ -39374,25 +39381,27 @@ namespace ts {
3937439381
* 1. K#m as K.prototype.m for a class (or other value) K
3937539382
* 2. K.m as K.prototype.m
3937639383
* 3. I.m as I.m for a type I, or any other I.m that fails to resolve in (1) or (2)
39384+
*
39385+
* For unqualified names, a container K may be provided as a second argument.
3937739386
*/
39378-
function resolveJSDocMemberName(name: EntityName | JSDocMemberName): Symbol | undefined {
39387+
function resolveJSDocMemberName(name: EntityName | JSDocMemberName, container?: Symbol): Symbol | undefined {
3937939388
if (isEntityName(name)) {
39380-
const symbol = resolveEntityName(
39381-
name,
39382-
SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Value,
39383-
/*ignoreErrors*/ false,
39384-
/*dontResolveAlias*/ true,
39385-
getHostSignatureFromJSDoc(name));
39386-
if (symbol || isIdentifier(name)) {
39387-
// can't recur on identifier, so just return when it's undefined
39389+
// resolve static values first
39390+
const meaning = SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Value;
39391+
let symbol = resolveEntityName(name, meaning, /*ignoreErrors*/ false, /*dontResolveAlias*/ true, getHostSignatureFromJSDoc(name));
39392+
if (!symbol && isIdentifier(name) && container) {
39393+
symbol = getMergedSymbol(getSymbol(getExportsOfSymbol(container), name.escapedText, meaning));
39394+
}
39395+
if (symbol) {
3938839396
return symbol;
3938939397
}
3939039398
}
39391-
const left = resolveJSDocMemberName(name.left);
39399+
const left = isIdentifier(name) ? container : resolveJSDocMemberName(name.left);
39400+
const right = isIdentifier(name) ? name.escapedText : name.right.escapedText;
3939239401
if (left) {
3939339402
const proto = left.flags & SymbolFlags.Value && getPropertyOfType(getTypeOfSymbol(left), "prototype" as __String);
3939439403
const t = proto ? getTypeOfSymbol(proto) : getDeclaredTypeOfSymbol(left);
39395-
return getPropertyOfType(t, name.right.escapedText);
39404+
return getPropertyOfType(t, right);
3939639405
}
3939739406
}
3939839407

tests/baselines/reference/findAllReferencesLinkTag1.baseline.jsonc

+100-10
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
// n = 1
55
// static s() { }
66
// /**
7-
// * {@link m}
8-
// * @see {m}
7+
// * {@link [|m|]}
8+
// * @see {[|m|]}
99
// * {@link C.[|m|]}
1010
// * @see {C.[|m|]}
1111
// * {@link C#[|m|]}
@@ -144,6 +144,24 @@
144144
"isWriteAccess": true,
145145
"isDefinition": true
146146
},
147+
{
148+
"textSpan": {
149+
"start": 73,
150+
"length": 1
151+
},
152+
"fileName": "/tests/cases/fourslash/findAllReferencesLinkTag1.ts",
153+
"isWriteAccess": false,
154+
"isDefinition": false
155+
},
156+
{
157+
"textSpan": {
158+
"start": 89,
159+
"length": 1
160+
},
161+
"fileName": "/tests/cases/fourslash/findAllReferencesLinkTag1.ts",
162+
"isWriteAccess": false,
163+
"isDefinition": false
164+
},
147165
{
148166
"textSpan": {
149167
"start": 108,
@@ -219,8 +237,8 @@
219237
// */
220238
// p() { }
221239
// /**
222-
// * {@link n}
223-
// * @see {n}
240+
// * {@link [|n|]}
241+
// * @see {[|n|]}
224242
// * {@link C.[|n|]}
225243
// * @see {C.[|n|]}
226244
// * {@link C#[|n|]}
@@ -340,6 +358,24 @@
340358
"isWriteAccess": true,
341359
"isDefinition": true
342360
},
361+
{
362+
"textSpan": {
363+
"start": 265,
364+
"length": 1
365+
},
366+
"fileName": "/tests/cases/fourslash/findAllReferencesLinkTag1.ts",
367+
"isWriteAccess": false,
368+
"isDefinition": false
369+
},
370+
{
371+
"textSpan": {
372+
"start": 281,
373+
"length": 1
374+
},
375+
"fileName": "/tests/cases/fourslash/findAllReferencesLinkTag1.ts",
376+
"isWriteAccess": false,
377+
"isDefinition": false
378+
},
343379
{
344380
"textSpan": {
345381
"start": 300,
@@ -426,8 +462,8 @@
426462
// */
427463
// q() { }
428464
// /**
429-
// * {@link s}
430-
// * @see {s}
465+
// * {@link [|s|]}
466+
// * @see {[|s|]}
431467
// * {@link C.[|s|]}
432468
// * @see {C.[|s|]}
433469
// */
@@ -544,6 +580,24 @@
544580
"isWriteAccess": true,
545581
"isDefinition": true
546582
},
583+
{
584+
"textSpan": {
585+
"start": 457,
586+
"length": 1
587+
},
588+
"fileName": "/tests/cases/fourslash/findAllReferencesLinkTag1.ts",
589+
"isWriteAccess": false,
590+
"isDefinition": false
591+
},
592+
{
593+
"textSpan": {
594+
"start": 473,
595+
"length": 1
596+
},
597+
"fileName": "/tests/cases/fourslash/findAllReferencesLinkTag1.ts",
598+
"isWriteAccess": false,
599+
"isDefinition": false
600+
},
547601
{
548602
"textSpan": {
549603
"start": 492,
@@ -606,8 +660,8 @@
606660
// [|a|]/*FIND ALL REFS*/()
607661
// b: 1
608662
// /**
609-
// * {@link a}
610-
// * @see {a}
663+
// * {@link [|a|]}
664+
// * @see {[|a|]}
611665
// * {@link I.[|a|]}
612666
// * @see {I.[|a|]}
613667
// * {@link I#[|a|]}
@@ -712,6 +766,24 @@
712766
"isWriteAccess": false,
713767
"isDefinition": true
714768
},
769+
{
770+
"textSpan": {
771+
"start": 589,
772+
"length": 1
773+
},
774+
"fileName": "/tests/cases/fourslash/findAllReferencesLinkTag1.ts",
775+
"isWriteAccess": false,
776+
"isDefinition": false
777+
},
778+
{
779+
"textSpan": {
780+
"start": 605,
781+
"length": 1
782+
},
783+
"fileName": "/tests/cases/fourslash/findAllReferencesLinkTag1.ts",
784+
"isWriteAccess": false,
785+
"isDefinition": false
786+
},
715787
{
716788
"textSpan": {
717789
"start": 624,
@@ -801,8 +873,8 @@
801873
// */
802874
// c()
803875
// /**
804-
// * {@link b}
805-
// * @see {b}
876+
// * {@link [|b|]}
877+
// * @see {[|b|]}
806878
// * {@link I.[|b|]}
807879
// * @see {I.[|b|]}
808880
// */
@@ -890,6 +962,24 @@
890962
"isWriteAccess": false,
891963
"isDefinition": true
892964
},
965+
{
966+
"textSpan": {
967+
"start": 720,
968+
"length": 1
969+
},
970+
"fileName": "/tests/cases/fourslash/findAllReferencesLinkTag1.ts",
971+
"isWriteAccess": false,
972+
"isDefinition": false
973+
},
974+
{
975+
"textSpan": {
976+
"start": 736,
977+
"length": 1
978+
},
979+
"fileName": "/tests/cases/fourslash/findAllReferencesLinkTag1.ts",
980+
"isWriteAccess": false,
981+
"isDefinition": false
982+
},
893983
{
894984
"textSpan": {
895985
"start": 755,

0 commit comments

Comments
 (0)