Skip to content

Feat/exclude completions of variable initializers #42087

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

Conversation

chenjigeng
Copy link
Contributor

Fixes #41731

@chenjigeng
Copy link
Contributor Author

@andrewbranch Please look at this PR here.I am doing the same thing as you thought.
Walk up parent nodes, and bail if the current node is FunctionLikeDeclaration. Keep going until we find the variable declaration.

I changed the existing test cases (because they had previously considered undeclared variables) and added a new test cases

Copy link
Member

@andrewbranch andrewbranch left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, but I want to wait until more of the team is back after the holidays to add an additional review.

}

const variableDeclaration = findAncestor(property, (node) => {
if (isFunctionLikeDeclaration(node)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You may want to check if you’re actually in the body of the function, since this fails to filter out e.g. parameter defaults:

const fn = (p = /* 'fn' appears here */) => {}

That said, leaving in some bad completions that we already have is not a big problem IMO, so this is a minor nitpick.

A similar comment applies to isVariableDeclaration(node): what you’re interested in is whether we walked up from the initializer of a variable declaration, but you might have a false positive on a case like this:

const { a, b = /**/ } = { ... }

We’re not interested in getting the variable declaration if we started at the default binding for b. But, it ends up having no effect on the outcome, since there will be no symbol where symbol.valueDeclaration === variableDeclaration. But if it’s easy to skip that property access and equality check, we should do it, since it runs for every completion item. It could maybe shave off a couple milliseconds if the list is long.

This also brings up another point worth noting, that this logic won’t work for destructuring:

const { a, b } = { /** }; // 'a' and 'b' are offered

but I don’t think it’s worth doing anything about this. I really don’t want to have to loop through every binding element declaration for every symbol—I’m happy that currently the check is only one equality comparison per symbol.

Copy link
Contributor Author

@chenjigeng chenjigeng Dec 24, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. You may want to check if you’re actually in the body of the function, since this fails to filter out e.g. parameter defaults:

    Yes. You are right, maybe we should use isFunctionBlock to check.

  2. We’re not interested in getting the variable declaration if we started at the default binding for b. But, it ends up having no effect on the outcome, since there will be no symbol where symbol.valueDeclaration === variableDeclaration. But if it’s easy to skip that property access and equality check, we should do it, since it runs for every completion item. It could maybe shave off a couple milliseconds if the list is long.

    I think we can use the isBindingPattern to filter out this two situations

const { a, b = /**/ } = { ... }
const [ a, b = /**/ ] = [ ... ]
  1. This also brings up another point worth noting, that this logic won’t work for destructuring

    I have the same idea with you. I think the time loss may be too much

For the 1 and 2, I have updated the code and added some test cases. Please help check it @andrewbranch

@andrewbranch
Copy link
Member

Supersedes #42056

@@ -1543,7 +1543,7 @@ namespace ts.Completions {

function getVariableDeclaration(property: Node): VariableDeclaration | undefined {
const variableDeclaration = findAncestor(property, (node) => {
if (isFunctionLikeDeclaration(node)) {
if (isFunctionBlock(node) || isBindingPattern(node)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn’t work for arrow function expressions without braces, e.g. () => expression/**/. It seems like there should be a util for this but I can’t find an existing one: isFunctionBlock(node) || isArrowFunction(node.parent) && node.parent.expression === node

Copy link
Contributor Author

@chenjigeng chenjigeng Dec 29, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. But I found no node.parent.expression. maybe node.parent.body?
isFunctionBlock(node) || (isArrowFunction(node.parent) && node.parent.body === node)
I has updated the code and add a new test case of arrow function expressions without braces

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, body is what I meant 👍

@chenjigeng chenjigeng force-pushed the feat/exclude-completions-of-variable-initializers branch from d9ab307 to 7b7cc24 Compare December 29, 2020 02:56
@@ -2,4 +2,4 @@

//// var x = this as/*1*/

verify.completions({marker: "1", exact: completion.globalsPlus(["x"]) })
verify.completions({marker: "1", exact: completion.globals })
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was a very strange test

Copy link
Contributor Author

@chenjigeng chenjigeng Dec 30, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test has existed before, after this modification, there should be no 'x'. Let me optimize it

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I’m not saying there’s anything wrong here, just observing that it was weird for someone to write this test this way in the first place, a long time ago. I think the changes you made to these make sense 👍

@chenjigeng chenjigeng force-pushed the feat/exclude-completions-of-variable-initializers branch from b66e039 to 578a1ce Compare December 30, 2020 00:33
Copy link
Member

@andrewbranch andrewbranch left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me 🌟

Copy link
Member

@sandersn sandersn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just some minor formatting requests -- the check and its tests look correct to me.

@chenjigeng
Copy link
Contributor Author

chenjigeng commented Jan 13, 2021

Just some minor formatting requests -- the check and its tests look correct to me.

thanks for you suggestions. done @sandersn

Copy link
Member

@sandersn sandersn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One minor nit with a cast

? "quit"
: isVariableDeclaration(node));

return variableDeclaration as VariableDeclaration;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldn't this be as VariableDeclaration | undefined?

Copy link
Contributor Author

@chenjigeng chenjigeng Jan 15, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. You are right. Done

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
For Backlog Bug PRs that fix a backlog bug
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

Object literal completions in declaration initializer include declared variable
4 participants