Handle different default export forms the same way in import code fixes - #21014
Conversation
`export default C` and `export { C as default }` should be handled the
same as `export default class C { }`.
Fixes microsoft#19115
The regular displayName had special handling for `as` clauses in imports and exports but the fullDisplayName did not. They should be consistent. (The impact of this change is very minor - it only affects the root node of the tree control in the rename preview, which is off by default.) Bonus: Eliminate `getDeclaredName` which is only called by rename. Note: Special handling of default exports was not preserved since `default` cannot be renamed.
| const displayName = stripQuotes(getDeclaredName(typeChecker, symbol, node)); | ||
| const kind = SymbolDisplay.getSymbolKind(typeChecker, symbol, node); | ||
| return kind ? getRenameInfoSuccess(displayName, typeChecker.getFullyQualifiedName(symbol), kind, SymbolDisplay.getSymbolModifiers(symbol), node, sourceFile) : undefined; | ||
| if (!kind) { |
There was a problem hiding this comment.
This change could use a test.
There was a problem hiding this comment.
We don't have a good way to test that it shows up in the right place in the UI, but I can try to add a lower-level test of the rename info.
There was a problem hiding this comment.
Just to clarify, what is the expected change to rename behavior due to this PR?
There was a problem hiding this comment.
Different strings are displayed in VS dialogs. No impact on renaming.
There was a problem hiding this comment.
There must be some function that returns a different value than before in some situation?
There was a problem hiding this comment.
Yes, of course. And I believe I've found a fourslash helper for testing it. I just meant that the same user actions would result in the same result (i.e. renaming) after the change.
| @@ -0,0 +1,21 @@ | |||
| /// <reference path="fourslash.ts" /> | |||
|
|
|||
| // @allowJs: true | |||
There was a problem hiding this comment.
Is it necessary that this test be JS? Should work exactly the same in TS?
There was a problem hiding this comment.
This test matches the repro steps in the bug. If a TS test would be preferable, I can change it (it should be equivalent).
There was a problem hiding this comment.
If it's exactly the same with these lines removed I would do that.
There was a problem hiding this comment.
Assuming you also meant to update the file extensions (so that diagnostics are produced at all), it would still not be exactly the same since the suppression fixes would not be offered (though that distinction is not important to the test/change).
There was a problem hiding this comment.
Yeah, I agree it's OK to remove the JS-specific suppression codefixes from this test since that's not what the point of the test is.
| createSearch(location: Node, symbol: Symbol, comingFrom: ImportExport | undefined, searchOptions: { text?: string, allSearchSymbols?: Symbol[] } = {}): Search { | ||
| // Note: if this is an external module symbol, the name doesn't include quotes. | ||
| // Note: getLocalSymbolForExportDefault handles `export default class C {}`, but not `export default C` or `export { C as default }`. | ||
| // The other two forms seem to be handled downstream (i.e. special-casing the first form here appears to be intentional). |
There was a problem hiding this comment.
This may be because we don't get a default export alias symbol here. See for example skipPastExportOrImportSpecifier.
There was a problem hiding this comment.
Supplemented the comment with that information.
|
|
||
| function getEscapedNameForExportDefault(symbol: Symbol): __String | undefined { | ||
| const declarations = symbol.declarations; | ||
| if (length(declarations) > 0) { |
There was a problem hiding this comment.
Might was well return firstDefined(symbol.declarations, declaration => ...
There was a problem hiding this comment.
That's not equivalent, is it? It'll check subsequent declarations if the lambda returns undefined for the first one?
There was a problem hiding this comment.
You're right, it's not exactly equivalent, but I don't think it hurts to loop through declarations (and there is usually only one).
There was a problem hiding this comment.
And the advantage is removing one bounds check?
There was a problem hiding this comment.
If you like it this way that's fine, I just find it suspicious when we depend on declarations[0] being something particular, although that should be work in this case since the symbol for an export assignment or export specifier should always have exactly one declaration.
There was a problem hiding this comment.
I can check that the length is one if that would be more robust.
There was a problem hiding this comment.
I don't think that's necessary, it shouldn't really matter whether it has other declarations or not.
| @@ -0,0 +1,21 @@ | |||
| /// <reference path="fourslash.ts" /> | |||
|
|
|||
| // @allowJs: true | |||
There was a problem hiding this comment.
This doesn't really need to be a JS test, right?
There was a problem hiding this comment.
While I can no longer recall my original motivation, it appears to be a JS version of the TS test in importNameCodeFixDefaultExport2.ts.
There was a problem hiding this comment.
Well, I don't think we need the same test twice -- the same services code will be tested either way.
export default Candexport { C as default }should be handled the same asexport default class C { }.Fixes #19115