-
Notifications
You must be signed in to change notification settings - Fork 12.6k
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
Go to Implementation #10482
Go to Implementation #10482
Conversation
* "implementation". Return response giving the file locations that | ||
* implement the symbol found in file at location line, col. | ||
*/ | ||
export interface ImplementationRequest extends FileLocationRequest { |
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.
question: why you make this empty interface?
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.
I was following what TypeDefinitionRequest
and DefinitionRequest
did (see above).
} | ||
|
||
const referenceParentDeclarations = referenceSymbol.parent.getDeclarations(); | ||
if (referenceParentDeclarations.length) { |
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.
you should be able to check referenceSymbol.parent.valueDeclaration
here instead of length and first declaration
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.
nevermind, you could just get the type for the getTypeOfSymbolAtLocation
Updated the PR to remove the filtering and instead filter the search set for find all references |
return true; | ||
} | ||
|
||
if (node.parent.kind === SyntaxKind.PropertyAccessExpression || node.parent.kind === SyntaxKind.ElementAccessExpression) { |
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 not:
if (node.parent.kind === SyntaxKind.PropertyAccessExpression || node.parent.kind === SyntaxKind.ElementAccessExpression) {
return definitionIsImplementation((<ElementAccessExpression | PropertyAccessExpression>node.parent).expression, typeChecker);
}
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.
forget about this.
@mhegazy I've updated the branch with your last round of feedback |
} | ||
} | ||
|
||
function isClassOrInterfaceReference(toCheck: Symbol) { |
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.
this is used in only one place. consider in lining it.
// symbol of the local type of the symbol the property is being accessed on. This is because our search | ||
// symbol may have a different parent symbol if the local type's symbol does not declare the property | ||
// being accessed (i.e. it is declared in some parent class or interface) | ||
let parents: Symbol[]; |
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 compiler doesn't check this yet, but this is Symbol[] | undefined
since it's only used if implementations
is true, and so is its use in getRelatedSymbol
, where it should be documented that it's only set for implementations
.
Other than comments from @andy-ms, no comments on my side. |
👍 |
Now that review is through, I'm going to close this PR and open two new ones: One that merges into release-2.0.5 and one that merges into master. Both of those will probably require some rebasing/git wizardry. |
…n_pr Refactored goToImplementation out of services
Okay, strike that. I'm leaving this PR open and have merged in master. This feature is not going to be merged into release-2.0.5. I factored the "go to implementation" stuff into its own file like we've done with the rest of the features, but I wonder if perhaps it should just be part of "find all references" since the majority of the implementation is in that file. |
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.
👍
Fixes #6209
This PR adds "Go To Implementation" functionality to the typescript language service.
The code works as follows:
First, if a symbol's definition is the same as its implementation, then "Go to Definition" is invoked. This covers most symbols, but not classes, interfaces, or unions/intersections and their members.
For symbols where the implementation is not the same as the definition, it performs "Find all References" and then filters the results down to those that are implementations. If anything is not caught by "Find all References", it won't show up in the results.
For example:
Both
Bar
andBaz
implementFoo
, but onlyBar
will show up in the results of "Go to Implementation" when invoked onFoo
. You'll get the same results if you use "Go to Implementation" onFoo.hello
."Find all References" is based on a text search, so if something implements a given interface but does not do so explicitly (i.e. using the name of the thing being referenced), it won't show up in the results. In general, it's more useful to invoke "Go to Implementation" on a member of the interface instead of the interface itself, since the names of members always show up in the implementation.
Here are some examples that illustrate that:
Still, I tried to capture most the usual patterns for creating instances of an interface. All of the following will work if invoked on
Foo
:Another point of interest is the members of classes. If "Go to Implementation" is invoked on the member of a class, the results will also contain implementations in sub-classes. For example, if "Go to Implementation" was invoked on the reference
x.hello
below:And there it is! I'm sure I missed some edge cases somewhere along the way, but they'll hopefully be caught once people start trying out the code. I tried the current implementation out on the TypeScript code base, and it seems to work pretty well. Implementations in JS files are not supported.