Skip to content

Conversation

kyliau
Copy link
Contributor

@kyliau kyliau commented Jun 9, 2020

This commit fixes a bug whereby the language service would incorrectly
return HTML elements if autocomplete is requested for an unknown symbol.
This is because we walk through every possible scenario, and fallback to
element autocomplete if none of the scenarios match. See screenshot below.

Screen Shot 2020-06-09 at 4 29 02 PM

The fix here is to return results only for interpolation if we know for sure
we are in a bound text. This means we will now return an empty results if
there is no suggestions.

This commit also refactors the code a little to make it easier to
understand.

PR Checklist

Please check if your PR fulfills the following requirements:

PR Type

What kind of change does this PR introduce?

  • Bugfix
  • Feature
  • Code style update (formatting, local variables)
  • Refactoring (no functional changes, no api changes)
  • Build related changes
  • CI related changes
  • Documentation content changes
  • angular.io application / infrastructure changes
  • Other... Please describe:

What is the current behavior?

Issue Number: N/A

What is the new behavior?

Does this PR introduce a breaking change?

  • Yes
  • No

Other information

@kyliau kyliau added area: language-service Issues related to Angular's VS Code language service target: patch This PR is targeted for the next patch release labels Jun 9, 2020
@ngbot ngbot bot added this to the needsTriage milestone Jun 9, 2020
@kyliau kyliau force-pushed the fix-invalid-autocomplete-results branch 3 times, most recently from c7db2d7 to 3197a39 Compare June 10, 2020 18:58
@kyliau kyliau requested a review from ayazhafiz June 10, 2020 20:07
@kyliau kyliau force-pushed the fix-invalid-autocomplete-results branch from 3197a39 to ccbce4e Compare June 10, 2020 20:07
@kyliau kyliau marked this pull request as ready for review June 10, 2020 20:07
return {
...entry,
replacementSpan,
};
});
}

class HtmlVisitor implements Visitor {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This whole section is mostly a refactoring, except for visitText(), where I've moved the logic around a little.

Copy link
Contributor

Choose a reason for hiding this comment

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

(meta point about walkers, not actionable but you might find this interesting)
Angular's AST walkers as classes might be an anti-pattern; see the TypeScript lead's issue on TSLint regarding their walkers of the TS AST: palantir/tslint#2522

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Initially I implemented the visitor as a plain object:

function createVisitor(): Visitor {
  return {
    // ...
    visitText() { /* ... */ },
    // ...
  };
}

But it masked a bug that was not caught by the type system. This is because Angular's own typing for Visitor is not great:

export interface Visitor {
// Returning a truthy value from `visit()` will prevent `visitAll()` from the call to the typed
// method and result returned will become the result included in `visitAll()`s result array.
visit?(node: Node, context: any): any;
visitElement(element: Element, context: any): any;
visitAttribute(attribute: Attribute, context: any): any;
visitText(text: Text, context: any): any;
visitComment(comment: Comment, context: any): any;
visitExpansion(expansion: Expansion, context: any): any;
visitExpansionCase(expansionCase: ExpansionCase, context: any): any;
}

In this use case, all methods need to explicitly return ng.CompletionEntry[], but visitComment() et al. return undefined. It'd cause a crash at runtime.
I wanted a way to implement the Visitor interface yet I don't want to inherit the default signatures. In the end I thought implementing it as a class is the best compromise.

Copy link
Contributor

Choose a reason for hiding this comment

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

I agree, your solution is better. The issue I linked to basically says the problem is with classes in the first place, so the visitor classes in the compiler package would have to be reconsidered

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ah I see. So essentially a imperative visitor with if-else statements is more performant than a class-based one.
I think that is still achievable here with the .visit() method. I'll definitely keep this in mind when working on Ivy LS.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Just for discussion sake, if we go with the if-else approach, don't we lose the benefits provided by the type system? The type system guarantees that every "branch" has an appropriate handler/visitor.
Maybe a switch statement could provide the same benefit.

return {
...entry,
replacementSpan,
};
});
}

class HtmlVisitor implements Visitor {
Copy link
Contributor

Choose a reason for hiding this comment

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

(meta point about walkers, not actionable but you might find this interesting)
Angular's AST walkers as classes might be an anti-pattern; see the TypeScript lead's issue on TSLint regarding their walkers of the TS AST: palantir/tslint#2522

@kyliau kyliau force-pushed the fix-invalid-autocomplete-results branch from ccbce4e to c753688 Compare June 26, 2020 17:12
This commit fixes a bug whereby the language service would incorrectly
return HTML elements if autocomplete is requested for an unknown symbol.
This is because we walk through every possible scenario, and fallback to
element autocomplete if none of the scenarios match.

The fix here is to return results from interpolation if we know for sure
we are in a bound text. This means we will now return an empty results if
there is no suggestions.

This commit also refactors the code a little to make it easier to
understand.
@kyliau kyliau force-pushed the fix-invalid-autocomplete-results branch from c753688 to 7414d96 Compare June 26, 2020 18:25
@kyliau kyliau added the action: merge The PR is ready for merge by the caretaker label Jun 26, 2020
AndrewKushnir pushed a commit that referenced this pull request Jun 26, 2020
…ol (#37518)

This commit fixes a bug whereby the language service would incorrectly
return HTML elements if autocomplete is requested for an unknown symbol.
This is because we walk through every possible scenario, and fallback to
element autocomplete if none of the scenarios match.

The fix here is to return results from interpolation if we know for sure
we are in a bound text. This means we will now return an empty results if
there is no suggestions.

This commit also refactors the code a little to make it easier to
understand.

PR Close #37518
@angular-automatic-lock-bot
Copy link

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

@angular-automatic-lock-bot angular-automatic-lock-bot bot locked and limited conversation to collaborators Jul 27, 2020
profanis pushed a commit to profanis/angular that referenced this pull request Sep 5, 2020
…ol (angular#37518)

This commit fixes a bug whereby the language service would incorrectly
return HTML elements if autocomplete is requested for an unknown symbol.
This is because we walk through every possible scenario, and fallback to
element autocomplete if none of the scenarios match.

The fix here is to return results from interpolation if we know for sure
we are in a bound text. This means we will now return an empty results if
there is no suggestions.

This commit also refactors the code a little to make it easier to
understand.

PR Close angular#37518
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
action: merge The PR is ready for merge by the caretaker area: language-service Issues related to Angular's VS Code language service cla: yes target: patch This PR is targeted for the next patch release
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants