-
Notifications
You must be signed in to change notification settings - Fork 12.9k
Zip @param tags and parameters together instead of looking for a name #18832
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -722,10 +722,49 @@ namespace ts { | |
break; | ||
default: | ||
bindEachChild(node); | ||
if (isFunctionLikeDeclaration(node)) { | ||
bindJSDocParameters(node); | ||
} | ||
break; | ||
} | ||
} | ||
|
||
function bindJSDocParameters(node: SignatureDeclaration): void { | ||
const { parameters } = node; | ||
if (parameters.length === 0) { | ||
return; | ||
} | ||
|
||
// Clear any previous binding | ||
for (const p of parameters) { | ||
p.jsdocParamTags = undefined; | ||
} | ||
|
||
let paramIndex = 0; | ||
for (const tag of getJSDocTags(parent)) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is going to be O(mn) where m = |tags| and n = |params|. That's because, for each tag, we examine every parameter starting at 0. Is this necessary? I think it would suffice to increment paramIndex until a single matching tag is found. Even better, you could iterate over the parameters instead and keep a non-restarting index into the tags. You can give up when the tags run out. zip :: [Tag] -> [Param] -> [Param]
zip (t:tags) (p:params) | name t == name p = p { tags = Just t } : zip tags params
zip (t:tags) params = zip tags params
zip [] params = params
zip tags [] = [] Note that the Haskell version doesn't side-effect, it just assumes there is a field let tagIndex = 0;
for (const param of parameters) {
while (tags[tagIndex].name.escapedText !== param.name.escapedText && tagIndex < tags.length) {
tagIndex++;
}
if (tagIndex >= tags.length) {
break;
}
if (tags[tagIndex].name.escapedText === param.name.escapedText) {
param.jsdocParamTags = append(param.jsdocParamTags, tags[tagIndex]);
}
} There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We want to keep supporting out-of-order There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see. I misunderstood the |
||
if (!isJSDocParameterTag(tag)) { | ||
continue; | ||
} | ||
|
||
// If we run out of parameters, just do nothing. | ||
// Will error in `checkJSDocParameterTag` since it will have no symbol. | ||
const startParamIndex = paramIndex; | ||
do { | ||
const param = parameters[paramIndex]; | ||
paramIndex++; | ||
if (paramIndex === parameters.length) { | ||
paramIndex = 0; | ||
} | ||
|
||
if (param.name.kind !== SyntaxKind.Identifier || getLeftmostName(tag.name).escapedText === param.name.escapedText) { | ||
tag.symbol = param.symbol; | ||
param.jsdocParamTags = append(param.jsdocParamTags, tag); | ||
break; | ||
} | ||
} while (paramIndex !== startParamIndex); | ||
} | ||
} | ||
|
||
function isNarrowingExpression(expr: Expression): boolean { | ||
switch (expr.kind) { | ||
case SyntaxKind.Identifier: | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -855,6 +855,7 @@ namespace ts { | |
questionToken?: QuestionToken; // Present on optional parameter | ||
type?: TypeNode; // Optional type annotation | ||
initializer?: Expression; // Optional initializer | ||
/* @internal */ jsdocParamTags?: JSDocParameterTag[]; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. how does doing this in the binder instead of the checker affect performance? I don't understand the performance characteristics of the binder well enough to predict, so maybe a perf test is in order. |
||
} | ||
|
||
export interface BindingElement extends NamedDeclaration { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
=== /a.js === | ||
/** | ||
* @param {{ x: number, y: string }} p | ||
* @param {number} m | ||
*/ | ||
function f({ x, y }, m) { | ||
>f : Symbol(f, Decl(a.js, 0, 0)) | ||
>x : Symbol(x, Decl(a.js, 4, 12)) | ||
>y : Symbol(y, Decl(a.js, 4, 15)) | ||
>m : Symbol(m, Decl(a.js, 4, 20)) | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
=== /a.js === | ||
/** | ||
* @param {{ x: number, y: string }} p | ||
* @param {number} m | ||
*/ | ||
function f({ x, y }, m) { | ||
>f : ({ x, y }: { x: number; y: string; }, m: number) => void | ||
>x : number | ||
>y : string | ||
>m : number | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
// @allowJs: true | ||
// @checkJs: true | ||
// @noEmit: true | ||
// @Filename: /a.js | ||
|
||
/** | ||
* @param {{ x: number, y: string }} p | ||
* @param {number} m | ||
*/ | ||
function f({ x, y }, m) { | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
/// <reference path='fourslash.ts' /> | ||
|
||
/////** @param [|s|] */ | ||
////const x = [|{| "isWriteAccess": true, "isDefinition": true |}s|] => [|s|]; | ||
|
||
verify.singleReferenceGroup("(parameter) s: any"); |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -30,4 +30,4 @@ | |
//// } | ||
//// foo1({x: 'abc'}); | ||
|
||
verify.baselineQuickInfo(); | ||
verify.baselineQuickInfo(); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,30 +1,15 @@ | ||
/// <reference path='fourslash.ts' /> | ||
|
||
// @noLib: true | ||
/////** | ||
//// * Returns the substring at the specified location within a String object. | ||
//// * @param start The zero-based index integer indicating the beginning of the substring. | ||
//// * @param end Zero-based index integer indicating the end of the substring. The substring includes the characters up to, but not including, the character indicated by end. | ||
//// * If end is omitted, the characters from start through the end of the original string are returned. | ||
//// */ | ||
////function foo(start: number, end?: number) { | ||
//// * @param start START | ||
//// */ | ||
////function foo(start: number) { | ||
//// return ""; | ||
////} | ||
//// | ||
////fo/*1*/ | ||
////foo/*1*/ | ||
goTo.marker('1'); | ||
verify.not.signatureHelpPresent(); | ||
edit.insert("o"); | ||
verify.not.signatureHelpPresent(); | ||
edit.insert("("); | ||
verify.currentParameterHelpArgumentDocCommentIs("The zero-based index integer indicating the beginning of the substring."); | ||
edit.insert("10,"); | ||
verify.currentParameterHelpArgumentDocCommentIs("Zero-based index integer indicating the end of the substring. The substring includes the characters up to, but not including, the character indicated by end.\nIf end is omitted, the characters from start through the end of the original string are returned."); | ||
edit.insert(" "); | ||
verify.currentParameterHelpArgumentDocCommentIs("Zero-based index integer indicating the end of the substring. The substring includes the characters up to, but not including, the character indicated by end.\nIf end is omitted, the characters from start through the end of the original string are returned."); | ||
edit.insert(", "); | ||
edit.backspace(3); | ||
verify.currentParameterHelpArgumentDocCommentIs("Zero-based index integer indicating the end of the substring. The substring includes the characters up to, but not including, the character indicated by end.\nIf end is omitted, the characters from start through the end of the original string are returned."); | ||
edit.insert("12"); | ||
verify.currentParameterHelpArgumentDocCommentIs("Zero-based index integer indicating the end of the substring. The substring includes the characters up to, but not including, the character indicated by end.\nIf end is omitted, the characters from start through the end of the original string are returned."); | ||
edit.insert(")"); | ||
verify.not.signatureHelpPresent(); | ||
verify.currentParameterHelpArgumentDocCommentIs("START"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why do we need to do this? Is it because the binder is retained between edits?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The source tree node may have been reused from a previous version of the AST so its properties must be reset.