Skip to content

Support 'find references' on most declaration-related keywords #36490

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

Merged
merged 4 commits into from
Jan 31, 2020

Conversation

rbuckton
Copy link
Contributor

@rbuckton rbuckton commented Jan 28, 2020

This change lets "find references" requests to the server find references to a declaration when the cursor is on certain keywords:

  • Modifiers (public, private, protected, static, readonly, abstract, declare, export, and const (enums)) will find references to the declaration they modify.
  • Declaration keywords (class, interface, type (type aliases), enum, module, namespace, function, get (get accessors), and set (set accessors)) will find references to the declaration they declare.
  • Clause Keywords (extends, implements) in a class/interface declaration will find references to the type in the heritage clause, as long as that clause has only one type (as more than one type would be ambiguous).
  • Variable declaration keywords (const, let, var) will find references to the variable declared if declaration list contains a single declaration.
  • Export/Import keywords also have unique handling:
    • import
      • import "module" will find references to module
      • import X from "module" will find references to X (if there are no named bindings)
      • import * as X from "module" will find references to X
      • import { X } from "module" will find references to X (if there is no default binding and only one named binding)
      • import { X, Y } from "module" will find references to module (since it would be ambiguous between X and Y).
      • import X = Y will find references to X
      • import X = require("module") will find references to X
    • export
      • export * from "module" will find references to module
      • export * as X from "module" will find references to X
      • export { X } from "module" will find references to X (if there is only one named binding)
      • export { X } will find references to X (if there is only one named binding)
      • export = X will find references to X
      • export default X will find references to X
    • as
      • import * as X from "module" will find references to X
      • import { Y as X } from "module" will find references to X
      • export * as X from "module" will find references to X
      • export { Y as X } from "module" will find references to X
      • export { Y as X } will find references to X
    • from
      • import ... from "module" will find references to module
      • export ... from "module" will find references to module
    • require (in an import= declaration)
      • import X = require("module") will find references to module
    • type (in an import/export declaration) has the same behavior as import or export (above), where applicable.
  • Unary Expression keywords (new, void, typeof, delete, yield, await) will find references to the declaration referenced in the operand (as long as the operand is an identifier or property access).
  • Binary Expression keywords (in, instanceof, as) will find references to the declaration on the right.
  • Typespace keywords also have special handling:
    • extends in <T extends U> (type parameter list) will find references to U
    • extends in T extends U ? A : B (conditional type) will find references to U
    • infer in T extends infer U ? A : B (conditional type) will find references to U
    • in in { [P in K]: T } (mapped type) will find references to P
    • keyof in keyof T will find references to T
    • readonly in readonly T[] will find references to T (not supported on tuple types)

I've also updated runCode in our fourslash tests so that errors are reported at the source location in the test file (using source maps), and so that you can step through the ts file when debugging.

Fixes #13309
Fixes #28268

@rbuckton
Copy link
Contributor Author

I've moved the logic out of checker and into services in a getAdjustedLocation function that handles both references and renames (i.e., renames have fewer adjusted locations for cases when there isn't a valid element to rename).

@rbuckton
Copy link
Contributor Author

@sheetalkamat do you have any further feedback?

@rbuckton rbuckton merged commit 01af3aa into master Jan 31, 2020
@rbuckton rbuckton deleted the fix13309 branch January 31, 2020 19:54
@fatcerberus
Copy link

fatcerberus commented Jan 31, 2020

  • import { X } from "module" will find references to X (if there is no default binding and only one named binding)
  • import { X, Y } from "module" will find references to module (since it would be ambiguous between X and Y).

This seems needlessly inconsistent. I don’t like this as it means if I delete X from the second import, the behavior of Find References suddenly changes. Either both cases should find refs for module or else the second case should just be an error.

@rbuckton
Copy link
Contributor Author

@fatcerberus that's an interesting point. @DanielRosenwasser do you have any preference here?

@DanielRosenwasser
Copy link
Member

I think it's often nice to have something just do the only possible successful action. We can change this later if people do find it confusing.

@rbuckton
Copy link
Contributor Author

I'll create a PR for this change shortly.

@rbuckton
Copy link
Contributor Author

I've put up a PR with the following changes:

  • import or type in import type { X, Y } from "module" will not be adjusted because it is ambiguous
  • import or type in import type { } from "module" will not be adjusted because there are no bindings
  • import in import X, { Y } from "module" will not be adjusted because it is ambiguous
  • import in import X, { } from "module" will not be adjusted because it is ambiguous
  • export or type in export type { X, Y } from "module" will not be adjusted because it is ambiguous
  • export or type in export type { } from "module" will not be adjusted because there are no bindings.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
5 participants