2020-11-19 16:31:34 -05:00
|
|
|
/**
|
|
|
|
* @license
|
|
|
|
* Copyright Google LLC All Rights Reserved.
|
|
|
|
*
|
|
|
|
* Use of this source code is governed by an MIT-style license that can be
|
|
|
|
* found in the LICENSE file at https://angular.io/license
|
|
|
|
*/
|
2021-01-21 11:42:23 -05:00
|
|
|
import {AST, TmplAstNode} from '@angular/compiler';
|
2020-11-19 16:31:34 -05:00
|
|
|
import {NgCompiler} from '@angular/compiler-cli/src/ngtsc/core';
|
2021-01-21 11:42:23 -05:00
|
|
|
import {absoluteFrom} from '@angular/compiler-cli/src/ngtsc/file_system';
|
feat(language-service): Enable renaming of pipes (#40523)
This commit updates the logic in the LS renaming to handle renaming of
pipes, both from the name expression in the pipe metadata as well as
from the template.
The approach here is to introduce a new concept for renaming: an
"indirect" rename. In this type of rename, we find rename locations
in with the native TS Language Service using a different node than the
one we are renaming. Using pipes as an example, if we want to rename the
pipe name from the string literal expression, we use the transform
method to find rename locations rather than the string literal itself
(which will not return any results because it's just a string).
So the general approach is:
* Determine the details about the requested rename location, i.e. the
targeted template node and symbol for a template rename, or the TS
node for a rename outside a template.
* Using the details of the location, determine if the node is attempting
to rename something that is an indirect rename (pipes, selectors,
bindings). Other renames are considered "direct" and we use whatever
results the native TSLS returns for the rename locations.
* In the case of indirect renames, we throw out results that do not
appear in the templates (in this case, the shim files). These results will be
for the "indirect" rename that we don't want to touch, but are only
using to find template results.
* Create an additional rename result for the string literal expression
that is used for the input/output alias, the pipe name, or the
selector.
Note that renaming is moving towards being much more accurate in its
results than "find references". When the approach for renaming
stabilizes, we may want to then port the changes back to being shared
with the approach for retrieving references.
PR Close #40523
2021-01-20 20:54:20 -05:00
|
|
|
import {MetaType, PipeMeta} from '@angular/compiler-cli/src/ngtsc/metadata';
|
2021-03-15 18:23:03 -04:00
|
|
|
import {PerfPhase} from '@angular/compiler-cli/src/ngtsc/perf';
|
fix(compiler-cli): ensure the compiler tracks `ts.Program`s correctly (#41291)
`NgCompiler` previously had a notion of the "next" `ts.Program`, which
served two purposes:
* it allowed a client using the `ts.createProgram` API to query for the
latest program produced by the previous `NgCompiler`, as a starting
point for building the _next_ program that incorporated any new user
changes.
* it allowed the old `NgCompiler` to be queried for the `ts.Program` on
which all prior state is based, which is needed to compute the delta
from the new program to ultimately determine how much of the prior
state can be reused.
This system contained a flaw: it relied on the `NgCompiler` knowing when
the `ts.Program` would be changed. This works fine for changes that
originate in `NgCompiler` APIs, but a client of the `TemplateTypeChecker`
may use that API in ways that create new `ts.Program`s without the
`NgCompiler`'s knowledge. This caused the `NgCompiler`'s concept of the
"next" program to get out of sync, causing incorrectness in future
incremental analysis.
This refactoring cleans up the compiler's `ts.Program` management in
several ways:
* `TypeCheckingProgramStrategy`, the API which controls `ts.Program`
updating, is renamed to the `ProgramDriver` and extracted to a separate
ngtsc package.
* It loses its responsibility of determining component shim filenames. That
functionality now lives exclusively in the template type-checking package.
* The "next" `ts.Program` concept is renamed to the "current" program, as
the "next" name was misleading in several ways.
* `NgCompiler` now wraps the `ProgramDriver` used in the
`TemplateTypeChecker` to know when a new `ts.Program` is created,
regardless of which API drove the creation, which actually fixes the bug.
PR Close #41291
2021-03-19 20:06:10 -04:00
|
|
|
import {ProgramDriver} from '@angular/compiler-cli/src/ngtsc/program_driver';
|
feat(language-service): Enable renaming of pipes (#40523)
This commit updates the logic in the LS renaming to handle renaming of
pipes, both from the name expression in the pipe metadata as well as
from the template.
The approach here is to introduce a new concept for renaming: an
"indirect" rename. In this type of rename, we find rename locations
in with the native TS Language Service using a different node than the
one we are renaming. Using pipes as an example, if we want to rename the
pipe name from the string literal expression, we use the transform
method to find rename locations rather than the string literal itself
(which will not return any results because it's just a string).
So the general approach is:
* Determine the details about the requested rename location, i.e. the
targeted template node and symbol for a template rename, or the TS
node for a rename outside a template.
* Using the details of the location, determine if the node is attempting
to rename something that is an indirect rename (pipes, selectors,
bindings). Other renames are considered "direct" and we use whatever
results the native TSLS returns for the rename locations.
* In the case of indirect renames, we throw out results that do not
appear in the templates (in this case, the shim files). These results will be
for the "indirect" rename that we don't want to touch, but are only
using to find template results.
* Create an additional rename result for the string literal expression
that is used for the input/output alias, the pipe name, or the
selector.
Note that renaming is moving towards being much more accurate in its
results than "find references". When the approach for renaming
stabilizes, we may want to then port the changes back to being shared
with the approach for retrieving references.
PR Close #40523
2021-01-20 20:54:20 -05:00
|
|
|
import {SymbolKind} from '@angular/compiler-cli/src/ngtsc/typecheck/api';
|
2020-11-19 16:31:34 -05:00
|
|
|
import * as ts from 'typescript';
|
|
|
|
|
feat(language-service): Enable renaming of pipes (#40523)
This commit updates the logic in the LS renaming to handle renaming of
pipes, both from the name expression in the pipe metadata as well as
from the template.
The approach here is to introduce a new concept for renaming: an
"indirect" rename. In this type of rename, we find rename locations
in with the native TS Language Service using a different node than the
one we are renaming. Using pipes as an example, if we want to rename the
pipe name from the string literal expression, we use the transform
method to find rename locations rather than the string literal itself
(which will not return any results because it's just a string).
So the general approach is:
* Determine the details about the requested rename location, i.e. the
targeted template node and symbol for a template rename, or the TS
node for a rename outside a template.
* Using the details of the location, determine if the node is attempting
to rename something that is an indirect rename (pipes, selectors,
bindings). Other renames are considered "direct" and we use whatever
results the native TSLS returns for the rename locations.
* In the case of indirect renames, we throw out results that do not
appear in the templates (in this case, the shim files). These results will be
for the "indirect" rename that we don't want to touch, but are only
using to find template results.
* Create an additional rename result for the string literal expression
that is used for the input/output alias, the pipe name, or the
selector.
Note that renaming is moving towards being much more accurate in its
results than "find references". When the approach for renaming
stabilizes, we may want to then port the changes back to being shared
with the approach for retrieving references.
PR Close #40523
2021-01-20 20:54:20 -05:00
|
|
|
import {convertToTemplateDocumentSpan, createLocationKey, FilePosition, getParentClassMeta, getRenameTextAndSpanAtPosition, getTargetDetailsAtTemplatePosition, TemplateLocationDetails} from './references_and_rename_utils';
|
|
|
|
import {collectMemberMethods, findTightestNode} from './ts_utils';
|
2021-01-21 11:42:23 -05:00
|
|
|
import {getTemplateInfoAtPosition, TemplateInfo} from './utils';
|
2020-11-19 16:31:34 -05:00
|
|
|
|
2021-01-21 11:46:40 -05:00
|
|
|
export class ReferencesBuilder {
|
|
|
|
private readonly ttc = this.compiler.getTemplateTypeChecker();
|
|
|
|
|
|
|
|
constructor(
|
|
|
|
private readonly driver: ProgramDriver, private readonly tsLS: ts.LanguageService,
|
|
|
|
private readonly compiler: NgCompiler) {}
|
|
|
|
|
|
|
|
getReferencesAtPosition(filePath: string, position: number): ts.ReferenceEntry[]|undefined {
|
|
|
|
this.ttc.generateAllTypeCheckBlocks();
|
|
|
|
const templateInfo = getTemplateInfoAtPosition(filePath, position, this.compiler);
|
|
|
|
if (templateInfo === undefined) {
|
|
|
|
return this.getReferencesAtTypescriptPosition(filePath, position);
|
|
|
|
}
|
|
|
|
return this.getReferencesAtTemplatePosition(templateInfo, position);
|
|
|
|
}
|
|
|
|
|
|
|
|
private getReferencesAtTemplatePosition(templateInfo: TemplateInfo, position: number):
|
|
|
|
ts.ReferenceEntry[]|undefined {
|
|
|
|
const allTargetDetails = getTargetDetailsAtTemplatePosition(templateInfo, position, this.ttc);
|
|
|
|
if (allTargetDetails === null) {
|
|
|
|
return undefined;
|
|
|
|
}
|
|
|
|
const allReferences: ts.ReferenceEntry[] = [];
|
|
|
|
for (const targetDetails of allTargetDetails) {
|
|
|
|
for (const location of targetDetails.typescriptLocations) {
|
|
|
|
const refs = this.getReferencesAtTypescriptPosition(location.fileName, location.position);
|
|
|
|
if (refs !== undefined) {
|
|
|
|
allReferences.push(...refs);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return allReferences.length > 0 ? allReferences : undefined;
|
|
|
|
}
|
|
|
|
|
|
|
|
private getReferencesAtTypescriptPosition(fileName: string, position: number):
|
|
|
|
ts.ReferenceEntry[]|undefined {
|
|
|
|
const refs = this.tsLS.getReferencesAtPosition(fileName, position);
|
|
|
|
if (refs === undefined) {
|
|
|
|
return undefined;
|
|
|
|
}
|
|
|
|
|
2021-01-21 18:28:42 -05:00
|
|
|
const entries: ts.ReferenceEntry[] = [];
|
2021-01-21 11:46:40 -05:00
|
|
|
for (const ref of refs) {
|
|
|
|
if (this.ttc.isTrackedTypeCheckFile(absoluteFrom(ref.fileName))) {
|
|
|
|
const entry = convertToTemplateDocumentSpan(ref, this.ttc, this.driver.getProgram());
|
|
|
|
if (entry !== null) {
|
2021-01-21 18:28:42 -05:00
|
|
|
entries.push(entry);
|
2021-01-21 11:46:40 -05:00
|
|
|
}
|
|
|
|
} else {
|
2021-01-21 18:28:42 -05:00
|
|
|
entries.push(ref);
|
2021-01-21 11:46:40 -05:00
|
|
|
}
|
|
|
|
}
|
2021-01-21 18:28:42 -05:00
|
|
|
return entries;
|
2021-01-21 11:46:40 -05:00
|
|
|
}
|
|
|
|
}
|
feat(language-service): initial implementation for `findRenameLocations` (#40140)
This commit lays the groundwork for potentially providing rename
locations from the Ivy native LS. The approach is very similar to what
was done with the feature to find references. One difference, however,
is that we did not require the references to be fully "correct". That
is, the exact text spans did not matter so much, as long as we provide a
location that logically includes the referenced item.
An example of a necessary difference between rename locations and references is
directives. The entire element in the template is a "reference" of the
directive's class. However, it's not a valid location to be renamed. The
same goes for aliased inputs/outputs. The locations in the template
directly map to the class property, which is correct for references, but
would not be correct for rename locations, which should instead map to
the string node fo the alias.
As an initial approach to address the aforementioned issues with rename
locations, we check that all the rename location nodes have the same text. If
_any_ node has text that differs from the request, we do not return any
rename locations. This works as a way to prevent renames that could
break the the program by missing some required nodes in the rename action, but
allowing other nodes to be renamed.
PR Close #40140
2020-11-30 14:16:48 -05:00
|
|
|
|
|
|
|
enum RequestKind {
|
feat(language-service): Enable renaming of pipes (#40523)
This commit updates the logic in the LS renaming to handle renaming of
pipes, both from the name expression in the pipe metadata as well as
from the template.
The approach here is to introduce a new concept for renaming: an
"indirect" rename. In this type of rename, we find rename locations
in with the native TS Language Service using a different node than the
one we are renaming. Using pipes as an example, if we want to rename the
pipe name from the string literal expression, we use the transform
method to find rename locations rather than the string literal itself
(which will not return any results because it's just a string).
So the general approach is:
* Determine the details about the requested rename location, i.e. the
targeted template node and symbol for a template rename, or the TS
node for a rename outside a template.
* Using the details of the location, determine if the node is attempting
to rename something that is an indirect rename (pipes, selectors,
bindings). Other renames are considered "direct" and we use whatever
results the native TSLS returns for the rename locations.
* In the case of indirect renames, we throw out results that do not
appear in the templates (in this case, the shim files). These results will be
for the "indirect" rename that we don't want to touch, but are only
using to find template results.
* Create an additional rename result for the string literal expression
that is used for the input/output alias, the pipe name, or the
selector.
Note that renaming is moving towards being much more accurate in its
results than "find references". When the approach for renaming
stabilizes, we may want to then port the changes back to being shared
with the approach for retrieving references.
PR Close #40523
2021-01-20 20:54:20 -05:00
|
|
|
DirectFromTemplate,
|
|
|
|
DirectFromTypeScript,
|
|
|
|
PipeName,
|
|
|
|
Selector,
|
feat(language-service): initial implementation for `findRenameLocations` (#40140)
This commit lays the groundwork for potentially providing rename
locations from the Ivy native LS. The approach is very similar to what
was done with the feature to find references. One difference, however,
is that we did not require the references to be fully "correct". That
is, the exact text spans did not matter so much, as long as we provide a
location that logically includes the referenced item.
An example of a necessary difference between rename locations and references is
directives. The entire element in the template is a "reference" of the
directive's class. However, it's not a valid location to be renamed. The
same goes for aliased inputs/outputs. The locations in the template
directly map to the class property, which is correct for references, but
would not be correct for rename locations, which should instead map to
the string node fo the alias.
As an initial approach to address the aforementioned issues with rename
locations, we check that all the rename location nodes have the same text. If
_any_ node has text that differs from the request, we do not return any
rename locations. This works as a way to prevent renames that could
break the the program by missing some required nodes in the rename action, but
allowing other nodes to be renamed.
PR Close #40140
2020-11-30 14:16:48 -05:00
|
|
|
}
|
|
|
|
|
feat(language-service): Enable renaming of pipes (#40523)
This commit updates the logic in the LS renaming to handle renaming of
pipes, both from the name expression in the pipe metadata as well as
from the template.
The approach here is to introduce a new concept for renaming: an
"indirect" rename. In this type of rename, we find rename locations
in with the native TS Language Service using a different node than the
one we are renaming. Using pipes as an example, if we want to rename the
pipe name from the string literal expression, we use the transform
method to find rename locations rather than the string literal itself
(which will not return any results because it's just a string).
So the general approach is:
* Determine the details about the requested rename location, i.e. the
targeted template node and symbol for a template rename, or the TS
node for a rename outside a template.
* Using the details of the location, determine if the node is attempting
to rename something that is an indirect rename (pipes, selectors,
bindings). Other renames are considered "direct" and we use whatever
results the native TSLS returns for the rename locations.
* In the case of indirect renames, we throw out results that do not
appear in the templates (in this case, the shim files). These results will be
for the "indirect" rename that we don't want to touch, but are only
using to find template results.
* Create an additional rename result for the string literal expression
that is used for the input/output alias, the pipe name, or the
selector.
Note that renaming is moving towards being much more accurate in its
results than "find references". When the approach for renaming
stabilizes, we may want to then port the changes back to being shared
with the approach for retrieving references.
PR Close #40523
2021-01-20 20:54:20 -05:00
|
|
|
/** The context needed to perform a rename of a pipe name. */
|
|
|
|
interface PipeRenameContext {
|
|
|
|
type: RequestKind.PipeName;
|
|
|
|
|
|
|
|
/** The string literal for the pipe name that appears in the @Pipe meta */
|
|
|
|
pipeNameExpr: ts.StringLiteral;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The location to use for querying the native TS LS for rename positions. This will be the
|
|
|
|
* pipe's transform method.
|
|
|
|
*/
|
|
|
|
renamePosition: FilePosition;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** The context needed to perform a rename of a directive/component selector. */
|
|
|
|
interface SelectorRenameContext {
|
|
|
|
type: RequestKind.Selector;
|
|
|
|
|
|
|
|
/** The string literal that appears in the directive/component metadata. */
|
|
|
|
selectorExpr: ts.StringLiteral;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The location to use for querying the native TS LS for rename positions. This will be the
|
|
|
|
* component/directive class itself. Doing so will allow us to find the location of the
|
|
|
|
* directive/component instantiations, which map to template elements.
|
|
|
|
*/
|
|
|
|
renamePosition: FilePosition;
|
feat(language-service): initial implementation for `findRenameLocations` (#40140)
This commit lays the groundwork for potentially providing rename
locations from the Ivy native LS. The approach is very similar to what
was done with the feature to find references. One difference, however,
is that we did not require the references to be fully "correct". That
is, the exact text spans did not matter so much, as long as we provide a
location that logically includes the referenced item.
An example of a necessary difference between rename locations and references is
directives. The entire element in the template is a "reference" of the
directive's class. However, it's not a valid location to be renamed. The
same goes for aliased inputs/outputs. The locations in the template
directly map to the class property, which is correct for references, but
would not be correct for rename locations, which should instead map to
the string node fo the alias.
As an initial approach to address the aforementioned issues with rename
locations, we check that all the rename location nodes have the same text. If
_any_ node has text that differs from the request, we do not return any
rename locations. This works as a way to prevent renames that could
break the the program by missing some required nodes in the rename action, but
allowing other nodes to be renamed.
PR Close #40140
2020-11-30 14:16:48 -05:00
|
|
|
}
|
|
|
|
|
feat(language-service): Enable renaming of pipes (#40523)
This commit updates the logic in the LS renaming to handle renaming of
pipes, both from the name expression in the pipe metadata as well as
from the template.
The approach here is to introduce a new concept for renaming: an
"indirect" rename. In this type of rename, we find rename locations
in with the native TS Language Service using a different node than the
one we are renaming. Using pipes as an example, if we want to rename the
pipe name from the string literal expression, we use the transform
method to find rename locations rather than the string literal itself
(which will not return any results because it's just a string).
So the general approach is:
* Determine the details about the requested rename location, i.e. the
targeted template node and symbol for a template rename, or the TS
node for a rename outside a template.
* Using the details of the location, determine if the node is attempting
to rename something that is an indirect rename (pipes, selectors,
bindings). Other renames are considered "direct" and we use whatever
results the native TSLS returns for the rename locations.
* In the case of indirect renames, we throw out results that do not
appear in the templates (in this case, the shim files). These results will be
for the "indirect" rename that we don't want to touch, but are only
using to find template results.
* Create an additional rename result for the string literal expression
that is used for the input/output alias, the pipe name, or the
selector.
Note that renaming is moving towards being much more accurate in its
results than "find references". When the approach for renaming
stabilizes, we may want to then port the changes back to being shared
with the approach for retrieving references.
PR Close #40523
2021-01-20 20:54:20 -05:00
|
|
|
interface DirectFromTypescriptRenameContext {
|
|
|
|
type: RequestKind.DirectFromTypeScript;
|
|
|
|
|
|
|
|
/** The node that is being renamed. */
|
feat(language-service): initial implementation for `findRenameLocations` (#40140)
This commit lays the groundwork for potentially providing rename
locations from the Ivy native LS. The approach is very similar to what
was done with the feature to find references. One difference, however,
is that we did not require the references to be fully "correct". That
is, the exact text spans did not matter so much, as long as we provide a
location that logically includes the referenced item.
An example of a necessary difference between rename locations and references is
directives. The entire element in the template is a "reference" of the
directive's class. However, it's not a valid location to be renamed. The
same goes for aliased inputs/outputs. The locations in the template
directly map to the class property, which is correct for references, but
would not be correct for rename locations, which should instead map to
the string node fo the alias.
As an initial approach to address the aforementioned issues with rename
locations, we check that all the rename location nodes have the same text. If
_any_ node has text that differs from the request, we do not return any
rename locations. This works as a way to prevent renames that could
break the the program by missing some required nodes in the rename action, but
allowing other nodes to be renamed.
PR Close #40140
2020-11-30 14:16:48 -05:00
|
|
|
requestNode: ts.Node;
|
|
|
|
}
|
|
|
|
|
feat(language-service): Enable renaming of pipes (#40523)
This commit updates the logic in the LS renaming to handle renaming of
pipes, both from the name expression in the pipe metadata as well as
from the template.
The approach here is to introduce a new concept for renaming: an
"indirect" rename. In this type of rename, we find rename locations
in with the native TS Language Service using a different node than the
one we are renaming. Using pipes as an example, if we want to rename the
pipe name from the string literal expression, we use the transform
method to find rename locations rather than the string literal itself
(which will not return any results because it's just a string).
So the general approach is:
* Determine the details about the requested rename location, i.e. the
targeted template node and symbol for a template rename, or the TS
node for a rename outside a template.
* Using the details of the location, determine if the node is attempting
to rename something that is an indirect rename (pipes, selectors,
bindings). Other renames are considered "direct" and we use whatever
results the native TSLS returns for the rename locations.
* In the case of indirect renames, we throw out results that do not
appear in the templates (in this case, the shim files). These results will be
for the "indirect" rename that we don't want to touch, but are only
using to find template results.
* Create an additional rename result for the string literal expression
that is used for the input/output alias, the pipe name, or the
selector.
Note that renaming is moving towards being much more accurate in its
results than "find references". When the approach for renaming
stabilizes, we may want to then port the changes back to being shared
with the approach for retrieving references.
PR Close #40523
2021-01-20 20:54:20 -05:00
|
|
|
interface DirectFromTemplateRenameContext {
|
|
|
|
type: RequestKind.DirectFromTemplate;
|
|
|
|
|
|
|
|
/** The position in the TCB file to use as the request to the native TSLS for renaming. */
|
|
|
|
renamePosition: FilePosition;
|
|
|
|
|
|
|
|
/** The position in the template the request originated from. */
|
|
|
|
templatePosition: number;
|
|
|
|
|
|
|
|
/** The target node in the template AST that corresponds to the template position. */
|
|
|
|
requestNode: AST|TmplAstNode;
|
|
|
|
}
|
|
|
|
|
|
|
|
type IndirectRenameContext = PipeRenameContext|SelectorRenameContext;
|
|
|
|
type RenameRequest =
|
|
|
|
IndirectRenameContext|DirectFromTemplateRenameContext|DirectFromTypescriptRenameContext;
|
feat(language-service): initial implementation for `findRenameLocations` (#40140)
This commit lays the groundwork for potentially providing rename
locations from the Ivy native LS. The approach is very similar to what
was done with the feature to find references. One difference, however,
is that we did not require the references to be fully "correct". That
is, the exact text spans did not matter so much, as long as we provide a
location that logically includes the referenced item.
An example of a necessary difference between rename locations and references is
directives. The entire element in the template is a "reference" of the
directive's class. However, it's not a valid location to be renamed. The
same goes for aliased inputs/outputs. The locations in the template
directly map to the class property, which is correct for references, but
would not be correct for rename locations, which should instead map to
the string node fo the alias.
As an initial approach to address the aforementioned issues with rename
locations, we check that all the rename location nodes have the same text. If
_any_ node has text that differs from the request, we do not return any
rename locations. This works as a way to prevent renames that could
break the the program by missing some required nodes in the rename action, but
allowing other nodes to be renamed.
PR Close #40140
2020-11-30 14:16:48 -05:00
|
|
|
|
feat(language-service): Enable renaming of pipes (#40523)
This commit updates the logic in the LS renaming to handle renaming of
pipes, both from the name expression in the pipe metadata as well as
from the template.
The approach here is to introduce a new concept for renaming: an
"indirect" rename. In this type of rename, we find rename locations
in with the native TS Language Service using a different node than the
one we are renaming. Using pipes as an example, if we want to rename the
pipe name from the string literal expression, we use the transform
method to find rename locations rather than the string literal itself
(which will not return any results because it's just a string).
So the general approach is:
* Determine the details about the requested rename location, i.e. the
targeted template node and symbol for a template rename, or the TS
node for a rename outside a template.
* Using the details of the location, determine if the node is attempting
to rename something that is an indirect rename (pipes, selectors,
bindings). Other renames are considered "direct" and we use whatever
results the native TSLS returns for the rename locations.
* In the case of indirect renames, we throw out results that do not
appear in the templates (in this case, the shim files). These results will be
for the "indirect" rename that we don't want to touch, but are only
using to find template results.
* Create an additional rename result for the string literal expression
that is used for the input/output alias, the pipe name, or the
selector.
Note that renaming is moving towards being much more accurate in its
results than "find references". When the approach for renaming
stabilizes, we may want to then port the changes back to being shared
with the approach for retrieving references.
PR Close #40523
2021-01-20 20:54:20 -05:00
|
|
|
function isDirectRenameContext(context: RenameRequest): context is DirectFromTemplateRenameContext|
|
|
|
|
DirectFromTypescriptRenameContext {
|
|
|
|
return context.type === RequestKind.DirectFromTemplate ||
|
|
|
|
context.type === RequestKind.DirectFromTypeScript;
|
|
|
|
}
|
2021-01-21 11:46:40 -05:00
|
|
|
|
|
|
|
export class RenameBuilder {
|
2020-11-19 16:31:34 -05:00
|
|
|
private readonly ttc = this.compiler.getTemplateTypeChecker();
|
|
|
|
|
|
|
|
constructor(
|
fix(compiler-cli): ensure the compiler tracks `ts.Program`s correctly (#41291)
`NgCompiler` previously had a notion of the "next" `ts.Program`, which
served two purposes:
* it allowed a client using the `ts.createProgram` API to query for the
latest program produced by the previous `NgCompiler`, as a starting
point for building the _next_ program that incorporated any new user
changes.
* it allowed the old `NgCompiler` to be queried for the `ts.Program` on
which all prior state is based, which is needed to compute the delta
from the new program to ultimately determine how much of the prior
state can be reused.
This system contained a flaw: it relied on the `NgCompiler` knowing when
the `ts.Program` would be changed. This works fine for changes that
originate in `NgCompiler` APIs, but a client of the `TemplateTypeChecker`
may use that API in ways that create new `ts.Program`s without the
`NgCompiler`'s knowledge. This caused the `NgCompiler`'s concept of the
"next" program to get out of sync, causing incorrectness in future
incremental analysis.
This refactoring cleans up the compiler's `ts.Program` management in
several ways:
* `TypeCheckingProgramStrategy`, the API which controls `ts.Program`
updating, is renamed to the `ProgramDriver` and extracted to a separate
ngtsc package.
* It loses its responsibility of determining component shim filenames. That
functionality now lives exclusively in the template type-checking package.
* The "next" `ts.Program` concept is renamed to the "current" program, as
the "next" name was misleading in several ways.
* `NgCompiler` now wraps the `ProgramDriver` used in the
`TemplateTypeChecker` to know when a new `ts.Program` is created,
regardless of which API drove the creation, which actually fixes the bug.
PR Close #41291
2021-03-19 20:06:10 -04:00
|
|
|
private readonly driver: ProgramDriver, private readonly tsLS: ts.LanguageService,
|
|
|
|
private readonly compiler: NgCompiler) {}
|
2020-11-19 16:31:34 -05:00
|
|
|
|
2020-12-01 17:55:57 -05:00
|
|
|
getRenameInfo(filePath: string, position: number):
|
|
|
|
Omit<ts.RenameInfoSuccess, 'kind'|'kindModifiers'>|ts.RenameInfoFailure {
|
2021-03-15 18:23:03 -04:00
|
|
|
return this.compiler.perfRecorder.inPhase(PerfPhase.LsReferencesAndRenames, () => {
|
|
|
|
const templateInfo = getTemplateInfoAtPosition(filePath, position, this.compiler);
|
|
|
|
// We could not get a template at position so we assume the request came from outside the
|
|
|
|
// template.
|
|
|
|
if (templateInfo === undefined) {
|
|
|
|
return this.tsLS.getRenameInfo(filePath, position);
|
|
|
|
}
|
2020-12-01 17:55:57 -05:00
|
|
|
|
2021-01-21 11:42:23 -05:00
|
|
|
const allTargetDetails = getTargetDetailsAtTemplatePosition(templateInfo, position, this.ttc);
|
2021-03-15 18:23:03 -04:00
|
|
|
if (allTargetDetails === null) {
|
|
|
|
return {
|
|
|
|
canRename: false,
|
2021-01-21 11:42:23 -05:00
|
|
|
localizedErrorMessage: 'Could not find template node at position.'
|
2021-03-15 18:23:03 -04:00
|
|
|
};
|
|
|
|
}
|
|
|
|
const {templateTarget} = allTargetDetails[0];
|
2021-01-21 11:42:23 -05:00
|
|
|
const templateTextAndSpan = getRenameTextAndSpanAtPosition(
|
|
|
|
templateTarget,
|
|
|
|
position,
|
|
|
|
);
|
2021-03-15 18:23:03 -04:00
|
|
|
if (templateTextAndSpan === null) {
|
|
|
|
return {canRename: false, localizedErrorMessage: 'Could not determine template node text.'};
|
|
|
|
}
|
|
|
|
const {text, span} = templateTextAndSpan;
|
|
|
|
return {
|
|
|
|
canRename: true,
|
|
|
|
displayName: text,
|
|
|
|
fullDisplayName: text,
|
|
|
|
triggerSpan: span,
|
|
|
|
};
|
|
|
|
});
|
2020-12-01 17:55:57 -05:00
|
|
|
}
|
|
|
|
|
feat(language-service): Enable renaming of pipes (#40523)
This commit updates the logic in the LS renaming to handle renaming of
pipes, both from the name expression in the pipe metadata as well as
from the template.
The approach here is to introduce a new concept for renaming: an
"indirect" rename. In this type of rename, we find rename locations
in with the native TS Language Service using a different node than the
one we are renaming. Using pipes as an example, if we want to rename the
pipe name from the string literal expression, we use the transform
method to find rename locations rather than the string literal itself
(which will not return any results because it's just a string).
So the general approach is:
* Determine the details about the requested rename location, i.e. the
targeted template node and symbol for a template rename, or the TS
node for a rename outside a template.
* Using the details of the location, determine if the node is attempting
to rename something that is an indirect rename (pipes, selectors,
bindings). Other renames are considered "direct" and we use whatever
results the native TSLS returns for the rename locations.
* In the case of indirect renames, we throw out results that do not
appear in the templates (in this case, the shim files). These results will be
for the "indirect" rename that we don't want to touch, but are only
using to find template results.
* Create an additional rename result for the string literal expression
that is used for the input/output alias, the pipe name, or the
selector.
Note that renaming is moving towards being much more accurate in its
results than "find references". When the approach for renaming
stabilizes, we may want to then port the changes back to being shared
with the approach for retrieving references.
PR Close #40523
2021-01-20 20:54:20 -05:00
|
|
|
findRenameLocations(filePath: string, position: number): readonly ts.RenameLocation[]|null {
|
feat(language-service): initial implementation for `findRenameLocations` (#40140)
This commit lays the groundwork for potentially providing rename
locations from the Ivy native LS. The approach is very similar to what
was done with the feature to find references. One difference, however,
is that we did not require the references to be fully "correct". That
is, the exact text spans did not matter so much, as long as we provide a
location that logically includes the referenced item.
An example of a necessary difference between rename locations and references is
directives. The entire element in the template is a "reference" of the
directive's class. However, it's not a valid location to be renamed. The
same goes for aliased inputs/outputs. The locations in the template
directly map to the class property, which is correct for references, but
would not be correct for rename locations, which should instead map to
the string node fo the alias.
As an initial approach to address the aforementioned issues with rename
locations, we check that all the rename location nodes have the same text. If
_any_ node has text that differs from the request, we do not return any
rename locations. This works as a way to prevent renames that could
break the the program by missing some required nodes in the rename action, but
allowing other nodes to be renamed.
PR Close #40140
2020-11-30 14:16:48 -05:00
|
|
|
this.ttc.generateAllTypeCheckBlocks();
|
2021-03-15 18:23:03 -04:00
|
|
|
return this.compiler.perfRecorder.inPhase(PerfPhase.LsReferencesAndRenames, () => {
|
|
|
|
const templateInfo = getTemplateInfoAtPosition(filePath, position, this.compiler);
|
|
|
|
// We could not get a template at position so we assume the request came from outside the
|
|
|
|
// template.
|
|
|
|
if (templateInfo === undefined) {
|
feat(language-service): Enable renaming of pipes (#40523)
This commit updates the logic in the LS renaming to handle renaming of
pipes, both from the name expression in the pipe metadata as well as
from the template.
The approach here is to introduce a new concept for renaming: an
"indirect" rename. In this type of rename, we find rename locations
in with the native TS Language Service using a different node than the
one we are renaming. Using pipes as an example, if we want to rename the
pipe name from the string literal expression, we use the transform
method to find rename locations rather than the string literal itself
(which will not return any results because it's just a string).
So the general approach is:
* Determine the details about the requested rename location, i.e. the
targeted template node and symbol for a template rename, or the TS
node for a rename outside a template.
* Using the details of the location, determine if the node is attempting
to rename something that is an indirect rename (pipes, selectors,
bindings). Other renames are considered "direct" and we use whatever
results the native TSLS returns for the rename locations.
* In the case of indirect renames, we throw out results that do not
appear in the templates (in this case, the shim files). These results will be
for the "indirect" rename that we don't want to touch, but are only
using to find template results.
* Create an additional rename result for the string literal expression
that is used for the input/output alias, the pipe name, or the
selector.
Note that renaming is moving towards being much more accurate in its
results than "find references". When the approach for renaming
stabilizes, we may want to then port the changes back to being shared
with the approach for retrieving references.
PR Close #40523
2021-01-20 20:54:20 -05:00
|
|
|
const renameRequest = this.buildRenameRequestAtTypescriptPosition(filePath, position);
|
|
|
|
if (renameRequest === null) {
|
|
|
|
return null;
|
2021-03-15 18:23:03 -04:00
|
|
|
}
|
feat(language-service): Enable renaming of pipes (#40523)
This commit updates the logic in the LS renaming to handle renaming of
pipes, both from the name expression in the pipe metadata as well as
from the template.
The approach here is to introduce a new concept for renaming: an
"indirect" rename. In this type of rename, we find rename locations
in with the native TS Language Service using a different node than the
one we are renaming. Using pipes as an example, if we want to rename the
pipe name from the string literal expression, we use the transform
method to find rename locations rather than the string literal itself
(which will not return any results because it's just a string).
So the general approach is:
* Determine the details about the requested rename location, i.e. the
targeted template node and symbol for a template rename, or the TS
node for a rename outside a template.
* Using the details of the location, determine if the node is attempting
to rename something that is an indirect rename (pipes, selectors,
bindings). Other renames are considered "direct" and we use whatever
results the native TSLS returns for the rename locations.
* In the case of indirect renames, we throw out results that do not
appear in the templates (in this case, the shim files). These results will be
for the "indirect" rename that we don't want to touch, but are only
using to find template results.
* Create an additional rename result for the string literal expression
that is used for the input/output alias, the pipe name, or the
selector.
Note that renaming is moving towards being much more accurate in its
results than "find references". When the approach for renaming
stabilizes, we may want to then port the changes back to being shared
with the approach for retrieving references.
PR Close #40523
2021-01-20 20:54:20 -05:00
|
|
|
return this.findRenameLocationsAtTypescriptPosition(renameRequest);
|
feat(language-service): initial implementation for `findRenameLocations` (#40140)
This commit lays the groundwork for potentially providing rename
locations from the Ivy native LS. The approach is very similar to what
was done with the feature to find references. One difference, however,
is that we did not require the references to be fully "correct". That
is, the exact text spans did not matter so much, as long as we provide a
location that logically includes the referenced item.
An example of a necessary difference between rename locations and references is
directives. The entire element in the template is a "reference" of the
directive's class. However, it's not a valid location to be renamed. The
same goes for aliased inputs/outputs. The locations in the template
directly map to the class property, which is correct for references, but
would not be correct for rename locations, which should instead map to
the string node fo the alias.
As an initial approach to address the aforementioned issues with rename
locations, we check that all the rename location nodes have the same text. If
_any_ node has text that differs from the request, we do not return any
rename locations. This works as a way to prevent renames that could
break the the program by missing some required nodes in the rename action, but
allowing other nodes to be renamed.
PR Close #40140
2020-11-30 14:16:48 -05:00
|
|
|
}
|
2021-03-15 18:23:03 -04:00
|
|
|
return this.findRenameLocationsAtTemplatePosition(templateInfo, position);
|
|
|
|
});
|
feat(language-service): initial implementation for `findRenameLocations` (#40140)
This commit lays the groundwork for potentially providing rename
locations from the Ivy native LS. The approach is very similar to what
was done with the feature to find references. One difference, however,
is that we did not require the references to be fully "correct". That
is, the exact text spans did not matter so much, as long as we provide a
location that logically includes the referenced item.
An example of a necessary difference between rename locations and references is
directives. The entire element in the template is a "reference" of the
directive's class. However, it's not a valid location to be renamed. The
same goes for aliased inputs/outputs. The locations in the template
directly map to the class property, which is correct for references, but
would not be correct for rename locations, which should instead map to
the string node fo the alias.
As an initial approach to address the aforementioned issues with rename
locations, we check that all the rename location nodes have the same text. If
_any_ node has text that differs from the request, we do not return any
rename locations. This works as a way to prevent renames that could
break the the program by missing some required nodes in the rename action, but
allowing other nodes to be renamed.
PR Close #40140
2020-11-30 14:16:48 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
private findRenameLocationsAtTemplatePosition(templateInfo: TemplateInfo, position: number):
|
feat(language-service): Enable renaming of pipes (#40523)
This commit updates the logic in the LS renaming to handle renaming of
pipes, both from the name expression in the pipe metadata as well as
from the template.
The approach here is to introduce a new concept for renaming: an
"indirect" rename. In this type of rename, we find rename locations
in with the native TS Language Service using a different node than the
one we are renaming. Using pipes as an example, if we want to rename the
pipe name from the string literal expression, we use the transform
method to find rename locations rather than the string literal itself
(which will not return any results because it's just a string).
So the general approach is:
* Determine the details about the requested rename location, i.e. the
targeted template node and symbol for a template rename, or the TS
node for a rename outside a template.
* Using the details of the location, determine if the node is attempting
to rename something that is an indirect rename (pipes, selectors,
bindings). Other renames are considered "direct" and we use whatever
results the native TSLS returns for the rename locations.
* In the case of indirect renames, we throw out results that do not
appear in the templates (in this case, the shim files). These results will be
for the "indirect" rename that we don't want to touch, but are only
using to find template results.
* Create an additional rename result for the string literal expression
that is used for the input/output alias, the pipe name, or the
selector.
Note that renaming is moving towards being much more accurate in its
results than "find references". When the approach for renaming
stabilizes, we may want to then port the changes back to being shared
with the approach for retrieving references.
PR Close #40523
2021-01-20 20:54:20 -05:00
|
|
|
readonly ts.RenameLocation[]|null {
|
2021-01-21 11:42:23 -05:00
|
|
|
const allTargetDetails = getTargetDetailsAtTemplatePosition(templateInfo, position, this.ttc);
|
feat(language-service): initial implementation for `findRenameLocations` (#40140)
This commit lays the groundwork for potentially providing rename
locations from the Ivy native LS. The approach is very similar to what
was done with the feature to find references. One difference, however,
is that we did not require the references to be fully "correct". That
is, the exact text spans did not matter so much, as long as we provide a
location that logically includes the referenced item.
An example of a necessary difference between rename locations and references is
directives. The entire element in the template is a "reference" of the
directive's class. However, it's not a valid location to be renamed. The
same goes for aliased inputs/outputs. The locations in the template
directly map to the class property, which is correct for references, but
would not be correct for rename locations, which should instead map to
the string node fo the alias.
As an initial approach to address the aforementioned issues with rename
locations, we check that all the rename location nodes have the same text. If
_any_ node has text that differs from the request, we do not return any
rename locations. This works as a way to prevent renames that could
break the the program by missing some required nodes in the rename action, but
allowing other nodes to be renamed.
PR Close #40140
2020-11-30 14:16:48 -05:00
|
|
|
if (allTargetDetails === null) {
|
feat(language-service): Enable renaming of pipes (#40523)
This commit updates the logic in the LS renaming to handle renaming of
pipes, both from the name expression in the pipe metadata as well as
from the template.
The approach here is to introduce a new concept for renaming: an
"indirect" rename. In this type of rename, we find rename locations
in with the native TS Language Service using a different node than the
one we are renaming. Using pipes as an example, if we want to rename the
pipe name from the string literal expression, we use the transform
method to find rename locations rather than the string literal itself
(which will not return any results because it's just a string).
So the general approach is:
* Determine the details about the requested rename location, i.e. the
targeted template node and symbol for a template rename, or the TS
node for a rename outside a template.
* Using the details of the location, determine if the node is attempting
to rename something that is an indirect rename (pipes, selectors,
bindings). Other renames are considered "direct" and we use whatever
results the native TSLS returns for the rename locations.
* In the case of indirect renames, we throw out results that do not
appear in the templates (in this case, the shim files). These results will be
for the "indirect" rename that we don't want to touch, but are only
using to find template results.
* Create an additional rename result for the string literal expression
that is used for the input/output alias, the pipe name, or the
selector.
Note that renaming is moving towards being much more accurate in its
results than "find references". When the approach for renaming
stabilizes, we may want to then port the changes back to being shared
with the approach for retrieving references.
PR Close #40523
2021-01-20 20:54:20 -05:00
|
|
|
return null;
|
|
|
|
}
|
|
|
|
const renameRequests = this.buildRenameRequestsFromTemplateDetails(allTargetDetails, position);
|
|
|
|
if (renameRequests === null) {
|
|
|
|
return null;
|
feat(language-service): initial implementation for `findRenameLocations` (#40140)
This commit lays the groundwork for potentially providing rename
locations from the Ivy native LS. The approach is very similar to what
was done with the feature to find references. One difference, however,
is that we did not require the references to be fully "correct". That
is, the exact text spans did not matter so much, as long as we provide a
location that logically includes the referenced item.
An example of a necessary difference between rename locations and references is
directives. The entire element in the template is a "reference" of the
directive's class. However, it's not a valid location to be renamed. The
same goes for aliased inputs/outputs. The locations in the template
directly map to the class property, which is correct for references, but
would not be correct for rename locations, which should instead map to
the string node fo the alias.
As an initial approach to address the aforementioned issues with rename
locations, we check that all the rename location nodes have the same text. If
_any_ node has text that differs from the request, we do not return any
rename locations. This works as a way to prevent renames that could
break the the program by missing some required nodes in the rename action, but
allowing other nodes to be renamed.
PR Close #40140
2020-11-30 14:16:48 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
const allRenameLocations: ts.RenameLocation[] = [];
|
feat(language-service): Enable renaming of pipes (#40523)
This commit updates the logic in the LS renaming to handle renaming of
pipes, both from the name expression in the pipe metadata as well as
from the template.
The approach here is to introduce a new concept for renaming: an
"indirect" rename. In this type of rename, we find rename locations
in with the native TS Language Service using a different node than the
one we are renaming. Using pipes as an example, if we want to rename the
pipe name from the string literal expression, we use the transform
method to find rename locations rather than the string literal itself
(which will not return any results because it's just a string).
So the general approach is:
* Determine the details about the requested rename location, i.e. the
targeted template node and symbol for a template rename, or the TS
node for a rename outside a template.
* Using the details of the location, determine if the node is attempting
to rename something that is an indirect rename (pipes, selectors,
bindings). Other renames are considered "direct" and we use whatever
results the native TSLS returns for the rename locations.
* In the case of indirect renames, we throw out results that do not
appear in the templates (in this case, the shim files). These results will be
for the "indirect" rename that we don't want to touch, but are only
using to find template results.
* Create an additional rename result for the string literal expression
that is used for the input/output alias, the pipe name, or the
selector.
Note that renaming is moving towards being much more accurate in its
results than "find references". When the approach for renaming
stabilizes, we may want to then port the changes back to being shared
with the approach for retrieving references.
PR Close #40523
2021-01-20 20:54:20 -05:00
|
|
|
for (const renameRequest of renameRequests) {
|
|
|
|
const locations = this.findRenameLocationsAtTypescriptPosition(renameRequest);
|
|
|
|
// If we couldn't find rename locations for _any_ result, we should not allow renaming to
|
|
|
|
// proceed instead of having a partially complete rename.
|
|
|
|
if (locations === null) {
|
|
|
|
return null;
|
feat(language-service): initial implementation for `findRenameLocations` (#40140)
This commit lays the groundwork for potentially providing rename
locations from the Ivy native LS. The approach is very similar to what
was done with the feature to find references. One difference, however,
is that we did not require the references to be fully "correct". That
is, the exact text spans did not matter so much, as long as we provide a
location that logically includes the referenced item.
An example of a necessary difference between rename locations and references is
directives. The entire element in the template is a "reference" of the
directive's class. However, it's not a valid location to be renamed. The
same goes for aliased inputs/outputs. The locations in the template
directly map to the class property, which is correct for references, but
would not be correct for rename locations, which should instead map to
the string node fo the alias.
As an initial approach to address the aforementioned issues with rename
locations, we check that all the rename location nodes have the same text. If
_any_ node has text that differs from the request, we do not return any
rename locations. This works as a way to prevent renames that could
break the the program by missing some required nodes in the rename action, but
allowing other nodes to be renamed.
PR Close #40140
2020-11-30 14:16:48 -05:00
|
|
|
}
|
feat(language-service): Enable renaming of pipes (#40523)
This commit updates the logic in the LS renaming to handle renaming of
pipes, both from the name expression in the pipe metadata as well as
from the template.
The approach here is to introduce a new concept for renaming: an
"indirect" rename. In this type of rename, we find rename locations
in with the native TS Language Service using a different node than the
one we are renaming. Using pipes as an example, if we want to rename the
pipe name from the string literal expression, we use the transform
method to find rename locations rather than the string literal itself
(which will not return any results because it's just a string).
So the general approach is:
* Determine the details about the requested rename location, i.e. the
targeted template node and symbol for a template rename, or the TS
node for a rename outside a template.
* Using the details of the location, determine if the node is attempting
to rename something that is an indirect rename (pipes, selectors,
bindings). Other renames are considered "direct" and we use whatever
results the native TSLS returns for the rename locations.
* In the case of indirect renames, we throw out results that do not
appear in the templates (in this case, the shim files). These results will be
for the "indirect" rename that we don't want to touch, but are only
using to find template results.
* Create an additional rename result for the string literal expression
that is used for the input/output alias, the pipe name, or the
selector.
Note that renaming is moving towards being much more accurate in its
results than "find references". When the approach for renaming
stabilizes, we may want to then port the changes back to being shared
with the approach for retrieving references.
PR Close #40523
2021-01-20 20:54:20 -05:00
|
|
|
allRenameLocations.push(...locations);
|
feat(language-service): initial implementation for `findRenameLocations` (#40140)
This commit lays the groundwork for potentially providing rename
locations from the Ivy native LS. The approach is very similar to what
was done with the feature to find references. One difference, however,
is that we did not require the references to be fully "correct". That
is, the exact text spans did not matter so much, as long as we provide a
location that logically includes the referenced item.
An example of a necessary difference between rename locations and references is
directives. The entire element in the template is a "reference" of the
directive's class. However, it's not a valid location to be renamed. The
same goes for aliased inputs/outputs. The locations in the template
directly map to the class property, which is correct for references, but
would not be correct for rename locations, which should instead map to
the string node fo the alias.
As an initial approach to address the aforementioned issues with rename
locations, we check that all the rename location nodes have the same text. If
_any_ node has text that differs from the request, we do not return any
rename locations. This works as a way to prevent renames that could
break the the program by missing some required nodes in the rename action, but
allowing other nodes to be renamed.
PR Close #40140
2020-11-30 14:16:48 -05:00
|
|
|
}
|
feat(language-service): Enable renaming of pipes (#40523)
This commit updates the logic in the LS renaming to handle renaming of
pipes, both from the name expression in the pipe metadata as well as
from the template.
The approach here is to introduce a new concept for renaming: an
"indirect" rename. In this type of rename, we find rename locations
in with the native TS Language Service using a different node than the
one we are renaming. Using pipes as an example, if we want to rename the
pipe name from the string literal expression, we use the transform
method to find rename locations rather than the string literal itself
(which will not return any results because it's just a string).
So the general approach is:
* Determine the details about the requested rename location, i.e. the
targeted template node and symbol for a template rename, or the TS
node for a rename outside a template.
* Using the details of the location, determine if the node is attempting
to rename something that is an indirect rename (pipes, selectors,
bindings). Other renames are considered "direct" and we use whatever
results the native TSLS returns for the rename locations.
* In the case of indirect renames, we throw out results that do not
appear in the templates (in this case, the shim files). These results will be
for the "indirect" rename that we don't want to touch, but are only
using to find template results.
* Create an additional rename result for the string literal expression
that is used for the input/output alias, the pipe name, or the
selector.
Note that renaming is moving towards being much more accurate in its
results than "find references". When the approach for renaming
stabilizes, we may want to then port the changes back to being shared
with the approach for retrieving references.
PR Close #40523
2021-01-20 20:54:20 -05:00
|
|
|
return allRenameLocations.length > 0 ? allRenameLocations : null;
|
feat(language-service): initial implementation for `findRenameLocations` (#40140)
This commit lays the groundwork for potentially providing rename
locations from the Ivy native LS. The approach is very similar to what
was done with the feature to find references. One difference, however,
is that we did not require the references to be fully "correct". That
is, the exact text spans did not matter so much, as long as we provide a
location that logically includes the referenced item.
An example of a necessary difference between rename locations and references is
directives. The entire element in the template is a "reference" of the
directive's class. However, it's not a valid location to be renamed. The
same goes for aliased inputs/outputs. The locations in the template
directly map to the class property, which is correct for references, but
would not be correct for rename locations, which should instead map to
the string node fo the alias.
As an initial approach to address the aforementioned issues with rename
locations, we check that all the rename location nodes have the same text. If
_any_ node has text that differs from the request, we do not return any
rename locations. This works as a way to prevent renames that could
break the the program by missing some required nodes in the rename action, but
allowing other nodes to be renamed.
PR Close #40140
2020-11-30 14:16:48 -05:00
|
|
|
}
|
|
|
|
|
feat(language-service): Enable renaming of pipes (#40523)
This commit updates the logic in the LS renaming to handle renaming of
pipes, both from the name expression in the pipe metadata as well as
from the template.
The approach here is to introduce a new concept for renaming: an
"indirect" rename. In this type of rename, we find rename locations
in with the native TS Language Service using a different node than the
one we are renaming. Using pipes as an example, if we want to rename the
pipe name from the string literal expression, we use the transform
method to find rename locations rather than the string literal itself
(which will not return any results because it's just a string).
So the general approach is:
* Determine the details about the requested rename location, i.e. the
targeted template node and symbol for a template rename, or the TS
node for a rename outside a template.
* Using the details of the location, determine if the node is attempting
to rename something that is an indirect rename (pipes, selectors,
bindings). Other renames are considered "direct" and we use whatever
results the native TSLS returns for the rename locations.
* In the case of indirect renames, we throw out results that do not
appear in the templates (in this case, the shim files). These results will be
for the "indirect" rename that we don't want to touch, but are only
using to find template results.
* Create an additional rename result for the string literal expression
that is used for the input/output alias, the pipe name, or the
selector.
Note that renaming is moving towards being much more accurate in its
results than "find references". When the approach for renaming
stabilizes, we may want to then port the changes back to being shared
with the approach for retrieving references.
PR Close #40523
2021-01-20 20:54:20 -05:00
|
|
|
findRenameLocationsAtTypescriptPosition(renameRequest: RenameRequest):
|
|
|
|
readonly ts.RenameLocation[]|null {
|
2021-03-15 18:23:03 -04:00
|
|
|
return this.compiler.perfRecorder.inPhase(PerfPhase.LsReferencesAndRenames, () => {
|
feat(language-service): Enable renaming of pipes (#40523)
This commit updates the logic in the LS renaming to handle renaming of
pipes, both from the name expression in the pipe metadata as well as
from the template.
The approach here is to introduce a new concept for renaming: an
"indirect" rename. In this type of rename, we find rename locations
in with the native TS Language Service using a different node than the
one we are renaming. Using pipes as an example, if we want to rename the
pipe name from the string literal expression, we use the transform
method to find rename locations rather than the string literal itself
(which will not return any results because it's just a string).
So the general approach is:
* Determine the details about the requested rename location, i.e. the
targeted template node and symbol for a template rename, or the TS
node for a rename outside a template.
* Using the details of the location, determine if the node is attempting
to rename something that is an indirect rename (pipes, selectors,
bindings). Other renames are considered "direct" and we use whatever
results the native TSLS returns for the rename locations.
* In the case of indirect renames, we throw out results that do not
appear in the templates (in this case, the shim files). These results will be
for the "indirect" rename that we don't want to touch, but are only
using to find template results.
* Create an additional rename result for the string literal expression
that is used for the input/output alias, the pipe name, or the
selector.
Note that renaming is moving towards being much more accurate in its
results than "find references". When the approach for renaming
stabilizes, we may want to then port the changes back to being shared
with the approach for retrieving references.
PR Close #40523
2021-01-20 20:54:20 -05:00
|
|
|
const renameInfo = getExpectedRenameTextAndInitalRenameEntries(renameRequest);
|
|
|
|
if (renameInfo === null) {
|
|
|
|
return null;
|
feat(language-service): initial implementation for `findRenameLocations` (#40140)
This commit lays the groundwork for potentially providing rename
locations from the Ivy native LS. The approach is very similar to what
was done with the feature to find references. One difference, however,
is that we did not require the references to be fully "correct". That
is, the exact text spans did not matter so much, as long as we provide a
location that logically includes the referenced item.
An example of a necessary difference between rename locations and references is
directives. The entire element in the template is a "reference" of the
directive's class. However, it's not a valid location to be renamed. The
same goes for aliased inputs/outputs. The locations in the template
directly map to the class property, which is correct for references, but
would not be correct for rename locations, which should instead map to
the string node fo the alias.
As an initial approach to address the aforementioned issues with rename
locations, we check that all the rename location nodes have the same text. If
_any_ node has text that differs from the request, we do not return any
rename locations. This works as a way to prevent renames that could
break the the program by missing some required nodes in the rename action, but
allowing other nodes to be renamed.
PR Close #40140
2020-11-30 14:16:48 -05:00
|
|
|
}
|
feat(language-service): Enable renaming of pipes (#40523)
This commit updates the logic in the LS renaming to handle renaming of
pipes, both from the name expression in the pipe metadata as well as
from the template.
The approach here is to introduce a new concept for renaming: an
"indirect" rename. In this type of rename, we find rename locations
in with the native TS Language Service using a different node than the
one we are renaming. Using pipes as an example, if we want to rename the
pipe name from the string literal expression, we use the transform
method to find rename locations rather than the string literal itself
(which will not return any results because it's just a string).
So the general approach is:
* Determine the details about the requested rename location, i.e. the
targeted template node and symbol for a template rename, or the TS
node for a rename outside a template.
* Using the details of the location, determine if the node is attempting
to rename something that is an indirect rename (pipes, selectors,
bindings). Other renames are considered "direct" and we use whatever
results the native TSLS returns for the rename locations.
* In the case of indirect renames, we throw out results that do not
appear in the templates (in this case, the shim files). These results will be
for the "indirect" rename that we don't want to touch, but are only
using to find template results.
* Create an additional rename result for the string literal expression
that is used for the input/output alias, the pipe name, or the
selector.
Note that renaming is moving towards being much more accurate in its
results than "find references". When the approach for renaming
stabilizes, we may want to then port the changes back to being shared
with the approach for retrieving references.
PR Close #40523
2021-01-20 20:54:20 -05:00
|
|
|
const {entries, expectedRenameText} = renameInfo;
|
|
|
|
const {fileName, position} = getRenameRequestPosition(renameRequest);
|
|
|
|
const findInStrings = false;
|
|
|
|
const findInComments = false;
|
|
|
|
const locations =
|
|
|
|
this.tsLS.findRenameLocations(fileName, position, findInStrings, findInComments);
|
2021-03-15 18:23:03 -04:00
|
|
|
if (locations === undefined) {
|
feat(language-service): Enable renaming of pipes (#40523)
This commit updates the logic in the LS renaming to handle renaming of
pipes, both from the name expression in the pipe metadata as well as
from the template.
The approach here is to introduce a new concept for renaming: an
"indirect" rename. In this type of rename, we find rename locations
in with the native TS Language Service using a different node than the
one we are renaming. Using pipes as an example, if we want to rename the
pipe name from the string literal expression, we use the transform
method to find rename locations rather than the string literal itself
(which will not return any results because it's just a string).
So the general approach is:
* Determine the details about the requested rename location, i.e. the
targeted template node and symbol for a template rename, or the TS
node for a rename outside a template.
* Using the details of the location, determine if the node is attempting
to rename something that is an indirect rename (pipes, selectors,
bindings). Other renames are considered "direct" and we use whatever
results the native TSLS returns for the rename locations.
* In the case of indirect renames, we throw out results that do not
appear in the templates (in this case, the shim files). These results will be
for the "indirect" rename that we don't want to touch, but are only
using to find template results.
* Create an additional rename result for the string literal expression
that is used for the input/output alias, the pipe name, or the
selector.
Note that renaming is moving towards being much more accurate in its
results than "find references". When the approach for renaming
stabilizes, we may want to then port the changes back to being shared
with the approach for retrieving references.
PR Close #40523
2021-01-20 20:54:20 -05:00
|
|
|
return null;
|
2021-03-15 18:23:03 -04:00
|
|
|
}
|
feat(language-service): initial implementation for `findRenameLocations` (#40140)
This commit lays the groundwork for potentially providing rename
locations from the Ivy native LS. The approach is very similar to what
was done with the feature to find references. One difference, however,
is that we did not require the references to be fully "correct". That
is, the exact text spans did not matter so much, as long as we provide a
location that logically includes the referenced item.
An example of a necessary difference between rename locations and references is
directives. The entire element in the template is a "reference" of the
directive's class. However, it's not a valid location to be renamed. The
same goes for aliased inputs/outputs. The locations in the template
directly map to the class property, which is correct for references, but
would not be correct for rename locations, which should instead map to
the string node fo the alias.
As an initial approach to address the aforementioned issues with rename
locations, we check that all the rename location nodes have the same text. If
_any_ node has text that differs from the request, we do not return any
rename locations. This works as a way to prevent renames that could
break the the program by missing some required nodes in the rename action, but
allowing other nodes to be renamed.
PR Close #40140
2020-11-30 14:16:48 -05:00
|
|
|
|
2021-03-15 18:23:03 -04:00
|
|
|
for (const location of locations) {
|
|
|
|
if (this.ttc.isTrackedTypeCheckFile(absoluteFrom(location.fileName))) {
|
2021-01-21 11:42:23 -05:00
|
|
|
const entry = convertToTemplateDocumentSpan(
|
feat(language-service): Enable renaming of pipes (#40523)
This commit updates the logic in the LS renaming to handle renaming of
pipes, both from the name expression in the pipe metadata as well as
from the template.
The approach here is to introduce a new concept for renaming: an
"indirect" rename. In this type of rename, we find rename locations
in with the native TS Language Service using a different node than the
one we are renaming. Using pipes as an example, if we want to rename the
pipe name from the string literal expression, we use the transform
method to find rename locations rather than the string literal itself
(which will not return any results because it's just a string).
So the general approach is:
* Determine the details about the requested rename location, i.e. the
targeted template node and symbol for a template rename, or the TS
node for a rename outside a template.
* Using the details of the location, determine if the node is attempting
to rename something that is an indirect rename (pipes, selectors,
bindings). Other renames are considered "direct" and we use whatever
results the native TSLS returns for the rename locations.
* In the case of indirect renames, we throw out results that do not
appear in the templates (in this case, the shim files). These results will be
for the "indirect" rename that we don't want to touch, but are only
using to find template results.
* Create an additional rename result for the string literal expression
that is used for the input/output alias, the pipe name, or the
selector.
Note that renaming is moving towards being much more accurate in its
results than "find references". When the approach for renaming
stabilizes, we may want to then port the changes back to being shared
with the approach for retrieving references.
PR Close #40523
2021-01-20 20:54:20 -05:00
|
|
|
location, this.ttc, this.driver.getProgram(), expectedRenameText);
|
2021-03-15 18:23:03 -04:00
|
|
|
// There is no template node whose text matches the original rename request. Bail on
|
|
|
|
// renaming completely rather than providing incomplete results.
|
|
|
|
if (entry === null) {
|
feat(language-service): Enable renaming of pipes (#40523)
This commit updates the logic in the LS renaming to handle renaming of
pipes, both from the name expression in the pipe metadata as well as
from the template.
The approach here is to introduce a new concept for renaming: an
"indirect" rename. In this type of rename, we find rename locations
in with the native TS Language Service using a different node than the
one we are renaming. Using pipes as an example, if we want to rename the
pipe name from the string literal expression, we use the transform
method to find rename locations rather than the string literal itself
(which will not return any results because it's just a string).
So the general approach is:
* Determine the details about the requested rename location, i.e. the
targeted template node and symbol for a template rename, or the TS
node for a rename outside a template.
* Using the details of the location, determine if the node is attempting
to rename something that is an indirect rename (pipes, selectors,
bindings). Other renames are considered "direct" and we use whatever
results the native TSLS returns for the rename locations.
* In the case of indirect renames, we throw out results that do not
appear in the templates (in this case, the shim files). These results will be
for the "indirect" rename that we don't want to touch, but are only
using to find template results.
* Create an additional rename result for the string literal expression
that is used for the input/output alias, the pipe name, or the
selector.
Note that renaming is moving towards being much more accurate in its
results than "find references". When the approach for renaming
stabilizes, we may want to then port the changes back to being shared
with the approach for retrieving references.
PR Close #40523
2021-01-20 20:54:20 -05:00
|
|
|
return null;
|
2021-03-15 18:23:03 -04:00
|
|
|
}
|
2021-01-21 18:28:42 -05:00
|
|
|
entries.push(entry);
|
2021-03-15 18:23:03 -04:00
|
|
|
} else {
|
feat(language-service): Enable renaming of pipes (#40523)
This commit updates the logic in the LS renaming to handle renaming of
pipes, both from the name expression in the pipe metadata as well as
from the template.
The approach here is to introduce a new concept for renaming: an
"indirect" rename. In this type of rename, we find rename locations
in with the native TS Language Service using a different node than the
one we are renaming. Using pipes as an example, if we want to rename the
pipe name from the string literal expression, we use the transform
method to find rename locations rather than the string literal itself
(which will not return any results because it's just a string).
So the general approach is:
* Determine the details about the requested rename location, i.e. the
targeted template node and symbol for a template rename, or the TS
node for a rename outside a template.
* Using the details of the location, determine if the node is attempting
to rename something that is an indirect rename (pipes, selectors,
bindings). Other renames are considered "direct" and we use whatever
results the native TSLS returns for the rename locations.
* In the case of indirect renames, we throw out results that do not
appear in the templates (in this case, the shim files). These results will be
for the "indirect" rename that we don't want to touch, but are only
using to find template results.
* Create an additional rename result for the string literal expression
that is used for the input/output alias, the pipe name, or the
selector.
Note that renaming is moving towards being much more accurate in its
results than "find references". When the approach for renaming
stabilizes, we may want to then port the changes back to being shared
with the approach for retrieving references.
PR Close #40523
2021-01-20 20:54:20 -05:00
|
|
|
if (!isDirectRenameContext(renameRequest)) {
|
|
|
|
// Discard any non-template results for non-direct renames. We should only rename
|
|
|
|
// template results + the name/selector/alias `ts.Expression`. The other results
|
|
|
|
// will be the the `ts.Identifier` of the transform method (pipe rename) or the
|
|
|
|
// directive class (selector rename).
|
|
|
|
continue;
|
|
|
|
}
|
2021-03-15 18:23:03 -04:00
|
|
|
// Ensure we only allow renaming a TS result with matching text
|
|
|
|
const refNode = this.getTsNodeAtPosition(location.fileName, location.textSpan.start);
|
feat(language-service): Enable renaming of pipes (#40523)
This commit updates the logic in the LS renaming to handle renaming of
pipes, both from the name expression in the pipe metadata as well as
from the template.
The approach here is to introduce a new concept for renaming: an
"indirect" rename. In this type of rename, we find rename locations
in with the native TS Language Service using a different node than the
one we are renaming. Using pipes as an example, if we want to rename the
pipe name from the string literal expression, we use the transform
method to find rename locations rather than the string literal itself
(which will not return any results because it's just a string).
So the general approach is:
* Determine the details about the requested rename location, i.e. the
targeted template node and symbol for a template rename, or the TS
node for a rename outside a template.
* Using the details of the location, determine if the node is attempting
to rename something that is an indirect rename (pipes, selectors,
bindings). Other renames are considered "direct" and we use whatever
results the native TSLS returns for the rename locations.
* In the case of indirect renames, we throw out results that do not
appear in the templates (in this case, the shim files). These results will be
for the "indirect" rename that we don't want to touch, but are only
using to find template results.
* Create an additional rename result for the string literal expression
that is used for the input/output alias, the pipe name, or the
selector.
Note that renaming is moving towards being much more accurate in its
results than "find references". When the approach for renaming
stabilizes, we may want to then port the changes back to being shared
with the approach for retrieving references.
PR Close #40523
2021-01-20 20:54:20 -05:00
|
|
|
if (refNode === null || refNode.getText() !== expectedRenameText) {
|
|
|
|
return null;
|
2021-03-15 18:23:03 -04:00
|
|
|
}
|
2021-01-21 18:28:42 -05:00
|
|
|
entries.push(location);
|
feat(language-service): initial implementation for `findRenameLocations` (#40140)
This commit lays the groundwork for potentially providing rename
locations from the Ivy native LS. The approach is very similar to what
was done with the feature to find references. One difference, however,
is that we did not require the references to be fully "correct". That
is, the exact text spans did not matter so much, as long as we provide a
location that logically includes the referenced item.
An example of a necessary difference between rename locations and references is
directives. The entire element in the template is a "reference" of the
directive's class. However, it's not a valid location to be renamed. The
same goes for aliased inputs/outputs. The locations in the template
directly map to the class property, which is correct for references, but
would not be correct for rename locations, which should instead map to
the string node fo the alias.
As an initial approach to address the aforementioned issues with rename
locations, we check that all the rename location nodes have the same text. If
_any_ node has text that differs from the request, we do not return any
rename locations. This works as a way to prevent renames that could
break the the program by missing some required nodes in the rename action, but
allowing other nodes to be renamed.
PR Close #40140
2020-11-30 14:16:48 -05:00
|
|
|
}
|
|
|
|
}
|
2021-01-21 18:28:42 -05:00
|
|
|
return entries;
|
2021-03-15 18:23:03 -04:00
|
|
|
});
|
feat(language-service): initial implementation for `findRenameLocations` (#40140)
This commit lays the groundwork for potentially providing rename
locations from the Ivy native LS. The approach is very similar to what
was done with the feature to find references. One difference, however,
is that we did not require the references to be fully "correct". That
is, the exact text spans did not matter so much, as long as we provide a
location that logically includes the referenced item.
An example of a necessary difference between rename locations and references is
directives. The entire element in the template is a "reference" of the
directive's class. However, it's not a valid location to be renamed. The
same goes for aliased inputs/outputs. The locations in the template
directly map to the class property, which is correct for references, but
would not be correct for rename locations, which should instead map to
the string node fo the alias.
As an initial approach to address the aforementioned issues with rename
locations, we check that all the rename location nodes have the same text. If
_any_ node has text that differs from the request, we do not return any
rename locations. This works as a way to prevent renames that could
break the the program by missing some required nodes in the rename action, but
allowing other nodes to be renamed.
PR Close #40140
2020-11-30 14:16:48 -05:00
|
|
|
}
|
|
|
|
|
2021-01-21 11:46:40 -05:00
|
|
|
private getTsNodeAtPosition(filePath: string, position: number): ts.Node|null {
|
|
|
|
const sf = this.driver.getProgram().getSourceFile(filePath);
|
|
|
|
if (!sf) {
|
|
|
|
return null;
|
2020-11-19 16:31:34 -05:00
|
|
|
}
|
2021-01-21 11:46:40 -05:00
|
|
|
return findTightestNode(sf, position) ?? null;
|
2020-11-19 16:31:34 -05:00
|
|
|
}
|
feat(language-service): Enable renaming of pipes (#40523)
This commit updates the logic in the LS renaming to handle renaming of
pipes, both from the name expression in the pipe metadata as well as
from the template.
The approach here is to introduce a new concept for renaming: an
"indirect" rename. In this type of rename, we find rename locations
in with the native TS Language Service using a different node than the
one we are renaming. Using pipes as an example, if we want to rename the
pipe name from the string literal expression, we use the transform
method to find rename locations rather than the string literal itself
(which will not return any results because it's just a string).
So the general approach is:
* Determine the details about the requested rename location, i.e. the
targeted template node and symbol for a template rename, or the TS
node for a rename outside a template.
* Using the details of the location, determine if the node is attempting
to rename something that is an indirect rename (pipes, selectors,
bindings). Other renames are considered "direct" and we use whatever
results the native TSLS returns for the rename locations.
* In the case of indirect renames, we throw out results that do not
appear in the templates (in this case, the shim files). These results will be
for the "indirect" rename that we don't want to touch, but are only
using to find template results.
* Create an additional rename result for the string literal expression
that is used for the input/output alias, the pipe name, or the
selector.
Note that renaming is moving towards being much more accurate in its
results than "find references". When the approach for renaming
stabilizes, we may want to then port the changes back to being shared
with the approach for retrieving references.
PR Close #40523
2021-01-20 20:54:20 -05:00
|
|
|
|
|
|
|
private buildRenameRequestsFromTemplateDetails(
|
|
|
|
allTargetDetails: TemplateLocationDetails[], templatePosition: number): RenameRequest[]|null {
|
|
|
|
const renameRequests: RenameRequest[] = [];
|
|
|
|
for (const targetDetails of allTargetDetails) {
|
|
|
|
for (const location of targetDetails.typescriptLocations) {
|
|
|
|
if (targetDetails.symbol.kind === SymbolKind.Pipe) {
|
|
|
|
const meta =
|
|
|
|
this.compiler.getMeta(targetDetails.symbol.classSymbol.tsSymbol.valueDeclaration);
|
|
|
|
if (meta === null || meta.type !== MetaType.Pipe) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
const renameRequest = this.buildPipeRenameRequest(meta);
|
|
|
|
if (renameRequest === null) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
renameRequests.push(renameRequest);
|
|
|
|
} else {
|
|
|
|
const renameRequest: RenameRequest = {
|
|
|
|
type: RequestKind.DirectFromTemplate,
|
|
|
|
templatePosition,
|
|
|
|
requestNode: targetDetails.templateTarget,
|
|
|
|
renamePosition: location
|
|
|
|
};
|
|
|
|
renameRequests.push(renameRequest);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return renameRequests;
|
|
|
|
}
|
|
|
|
|
|
|
|
private buildRenameRequestAtTypescriptPosition(filePath: string, position: number): RenameRequest
|
|
|
|
|null {
|
|
|
|
const requestNode = this.getTsNodeAtPosition(filePath, position);
|
|
|
|
if (requestNode === null) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
const meta = getParentClassMeta(requestNode, this.compiler);
|
|
|
|
if (meta !== null && meta.type === MetaType.Pipe && meta.nameExpr === requestNode) {
|
|
|
|
return this.buildPipeRenameRequest(meta);
|
|
|
|
} else {
|
|
|
|
return {type: RequestKind.DirectFromTypeScript, requestNode};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private buildPipeRenameRequest(meta: PipeMeta): PipeRenameContext|null {
|
|
|
|
if (!ts.isClassDeclaration(meta.ref.node) || meta.nameExpr === null ||
|
|
|
|
!ts.isStringLiteral(meta.nameExpr)) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
const typeChecker = this.driver.getProgram().getTypeChecker();
|
|
|
|
const memberMethods = collectMemberMethods(meta.ref.node, typeChecker) ?? [];
|
|
|
|
const pipeTransformNode: ts.MethodDeclaration|undefined =
|
|
|
|
memberMethods.find(m => m.name.getText() === 'transform');
|
|
|
|
if (pipeTransformNode === undefined) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
return {
|
|
|
|
type: RequestKind.PipeName,
|
|
|
|
pipeNameExpr: meta.nameExpr,
|
|
|
|
renamePosition: {
|
|
|
|
fileName: pipeTransformNode.getSourceFile().fileName,
|
|
|
|
position: pipeTransformNode.getStart(),
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* From the provided `RenameRequest`, determines what text we should expect all produced
|
|
|
|
* `ts.RenameLocation`s to have and creates an initial entry for indirect renames (one which is
|
|
|
|
* required for the rename operation, but cannot be found by the native TS LS).
|
|
|
|
*/
|
|
|
|
function getExpectedRenameTextAndInitalRenameEntries(renameRequest: RenameRequest):
|
2021-01-21 18:28:42 -05:00
|
|
|
{expectedRenameText: string, entries: ts.RenameLocation[]}|null {
|
feat(language-service): Enable renaming of pipes (#40523)
This commit updates the logic in the LS renaming to handle renaming of
pipes, both from the name expression in the pipe metadata as well as
from the template.
The approach here is to introduce a new concept for renaming: an
"indirect" rename. In this type of rename, we find rename locations
in with the native TS Language Service using a different node than the
one we are renaming. Using pipes as an example, if we want to rename the
pipe name from the string literal expression, we use the transform
method to find rename locations rather than the string literal itself
(which will not return any results because it's just a string).
So the general approach is:
* Determine the details about the requested rename location, i.e. the
targeted template node and symbol for a template rename, or the TS
node for a rename outside a template.
* Using the details of the location, determine if the node is attempting
to rename something that is an indirect rename (pipes, selectors,
bindings). Other renames are considered "direct" and we use whatever
results the native TSLS returns for the rename locations.
* In the case of indirect renames, we throw out results that do not
appear in the templates (in this case, the shim files). These results will be
for the "indirect" rename that we don't want to touch, but are only
using to find template results.
* Create an additional rename result for the string literal expression
that is used for the input/output alias, the pipe name, or the
selector.
Note that renaming is moving towards being much more accurate in its
results than "find references". When the approach for renaming
stabilizes, we may want to then port the changes back to being shared
with the approach for retrieving references.
PR Close #40523
2021-01-20 20:54:20 -05:00
|
|
|
let expectedRenameText: string;
|
2021-01-21 18:28:42 -05:00
|
|
|
const entries: ts.RenameLocation[] = [];
|
feat(language-service): Enable renaming of pipes (#40523)
This commit updates the logic in the LS renaming to handle renaming of
pipes, both from the name expression in the pipe metadata as well as
from the template.
The approach here is to introduce a new concept for renaming: an
"indirect" rename. In this type of rename, we find rename locations
in with the native TS Language Service using a different node than the
one we are renaming. Using pipes as an example, if we want to rename the
pipe name from the string literal expression, we use the transform
method to find rename locations rather than the string literal itself
(which will not return any results because it's just a string).
So the general approach is:
* Determine the details about the requested rename location, i.e. the
targeted template node and symbol for a template rename, or the TS
node for a rename outside a template.
* Using the details of the location, determine if the node is attempting
to rename something that is an indirect rename (pipes, selectors,
bindings). Other renames are considered "direct" and we use whatever
results the native TSLS returns for the rename locations.
* In the case of indirect renames, we throw out results that do not
appear in the templates (in this case, the shim files). These results will be
for the "indirect" rename that we don't want to touch, but are only
using to find template results.
* Create an additional rename result for the string literal expression
that is used for the input/output alias, the pipe name, or the
selector.
Note that renaming is moving towards being much more accurate in its
results than "find references". When the approach for renaming
stabilizes, we may want to then port the changes back to being shared
with the approach for retrieving references.
PR Close #40523
2021-01-20 20:54:20 -05:00
|
|
|
if (renameRequest.type === RequestKind.DirectFromTypeScript) {
|
|
|
|
expectedRenameText = renameRequest.requestNode.getText();
|
|
|
|
} else if (renameRequest.type === RequestKind.DirectFromTemplate) {
|
|
|
|
const templateNodeText =
|
|
|
|
getRenameTextAndSpanAtPosition(renameRequest.requestNode, renameRequest.templatePosition);
|
|
|
|
if (templateNodeText === null) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
expectedRenameText = templateNodeText.text;
|
|
|
|
} else if (renameRequest.type === RequestKind.PipeName) {
|
|
|
|
const {pipeNameExpr} = renameRequest;
|
|
|
|
expectedRenameText = pipeNameExpr.text;
|
|
|
|
const entry: ts.RenameLocation = {
|
|
|
|
fileName: renameRequest.pipeNameExpr.getSourceFile().fileName,
|
|
|
|
textSpan: {start: pipeNameExpr.getStart() + 1, length: pipeNameExpr.getText().length - 2},
|
|
|
|
};
|
2021-01-21 18:28:42 -05:00
|
|
|
entries.push(entry);
|
feat(language-service): Enable renaming of pipes (#40523)
This commit updates the logic in the LS renaming to handle renaming of
pipes, both from the name expression in the pipe metadata as well as
from the template.
The approach here is to introduce a new concept for renaming: an
"indirect" rename. In this type of rename, we find rename locations
in with the native TS Language Service using a different node than the
one we are renaming. Using pipes as an example, if we want to rename the
pipe name from the string literal expression, we use the transform
method to find rename locations rather than the string literal itself
(which will not return any results because it's just a string).
So the general approach is:
* Determine the details about the requested rename location, i.e. the
targeted template node and symbol for a template rename, or the TS
node for a rename outside a template.
* Using the details of the location, determine if the node is attempting
to rename something that is an indirect rename (pipes, selectors,
bindings). Other renames are considered "direct" and we use whatever
results the native TSLS returns for the rename locations.
* In the case of indirect renames, we throw out results that do not
appear in the templates (in this case, the shim files). These results will be
for the "indirect" rename that we don't want to touch, but are only
using to find template results.
* Create an additional rename result for the string literal expression
that is used for the input/output alias, the pipe name, or the
selector.
Note that renaming is moving towards being much more accurate in its
results than "find references". When the approach for renaming
stabilizes, we may want to then port the changes back to being shared
with the approach for retrieving references.
PR Close #40523
2021-01-20 20:54:20 -05:00
|
|
|
} else {
|
|
|
|
// TODO(atscott): Implement other types of special renames
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
return {entries, expectedRenameText};
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Given a `RenameRequest`, determines the `FilePosition` to use asking the native TS LS for rename
|
|
|
|
* locations.
|
|
|
|
*/
|
|
|
|
function getRenameRequestPosition(renameRequest: RenameRequest): FilePosition {
|
|
|
|
const fileName = renameRequest.type === RequestKind.DirectFromTypeScript ?
|
|
|
|
renameRequest.requestNode.getSourceFile().fileName :
|
|
|
|
renameRequest.renamePosition.fileName;
|
|
|
|
const position = renameRequest.type === RequestKind.DirectFromTypeScript ?
|
|
|
|
renameRequest.requestNode.getStart() :
|
|
|
|
renameRequest.renamePosition.position;
|
|
|
|
return {fileName, position};
|
2021-01-15 13:47:39 -05:00
|
|
|
}
|