diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index adbe97212e2b0..356eb54165e2b 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -2273,7 +2273,7 @@ namespace ts { function emitPropertyAccessExpression(node: PropertyAccessExpression) { const expression = cast(emitExpression(node.expression), isExpression); - const token = getDotOrQuestionDotToken(node); + const token = node.questionDotToken || createNode(SyntaxKind.DotToken, node.expression.end, node.name.pos) as DotToken; const indentBeforeDot = needsIndentation(node, node.expression, token); const indentAfterDot = needsIndentation(node, token, node.name); @@ -2289,7 +2289,12 @@ namespace ts { writePunctuation("."); } - emitTokenWithComment(token.kind, node.expression.end, writePunctuation, node); + if (node.questionDotToken) { + emit(token); + } + else { + emitTokenWithComment(token.kind, node.expression.end, writePunctuation, node); + } increaseIndentIf(indentAfterDot, /*writeSpaceIfNotIndenting*/ false); emit(node.name); decreaseIndentIf(indentBeforeDot, indentAfterDot); diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index ba4cc0106b9b1..a1fdc9baaca97 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -5035,10 +5035,6 @@ namespace ts { } } - export function getDotOrQuestionDotToken(node: PropertyAccessExpression) { - return node.questionDotToken || createNode(SyntaxKind.DotToken, node.expression.end, node.name.pos) as DotToken; - } - export function isNamedImportsOrExports(node: Node): node is NamedImportsOrExports { return node.kind === SyntaxKind.NamedImports || node.kind === SyntaxKind.NamedExports; } diff --git a/src/compiler/visitorPublic.ts b/src/compiler/visitorPublic.ts index 42e3e82540092..fa611bc9bde3e 100644 --- a/src/compiler/visitorPublic.ts +++ b/src/compiler/visitorPublic.ts @@ -459,7 +459,7 @@ namespace ts { if (node.flags & NodeFlags.OptionalChain) { return updatePropertyAccessChain(node, visitNode((node).expression, visitor, isExpression), - visitNode((node).questionDotToken, visitor, isToken), + visitNode((node).questionDotToken, tokenVisitor, isToken), visitNode((node).name, visitor, isIdentifier)); } return updatePropertyAccess(node, @@ -470,7 +470,7 @@ namespace ts { if (node.flags & NodeFlags.OptionalChain) { return updateElementAccessChain(node, visitNode((node).expression, visitor, isExpression), - visitNode((node).questionDotToken, visitor, isToken), + visitNode((node).questionDotToken, tokenVisitor, isToken), visitNode((node).argumentExpression, visitor, isExpression)); } return updateElementAccess(node, @@ -481,7 +481,7 @@ namespace ts { if (node.flags & NodeFlags.OptionalChain) { return updateCallChain(node, visitNode((node).expression, visitor, isExpression), - visitNode((node).questionDotToken, visitor, isToken), + visitNode((node).questionDotToken, tokenVisitor, isToken), nodesVisitor((node).typeArguments, visitor, isTypeNode), nodesVisitor((node).arguments, visitor, isExpression)); } @@ -527,7 +527,7 @@ namespace ts { nodesVisitor((node).typeParameters, visitor, isTypeParameterDeclaration), visitParameterList((node).parameters, visitor, context, nodesVisitor), visitNode((node).type, visitor, isTypeNode), - visitNode((node).equalsGreaterThanToken, visitor, isToken), + visitNode((node).equalsGreaterThanToken, tokenVisitor, isToken), visitFunctionBody((node).body, visitor, context)); case SyntaxKind.DeleteExpression: @@ -558,14 +558,14 @@ namespace ts { return updateBinary(node, visitNode((node).left, visitor, isExpression), visitNode((node).right, visitor, isExpression), - visitNode((node).operatorToken, visitor, isToken)); + visitNode((node).operatorToken, tokenVisitor, isToken)); case SyntaxKind.ConditionalExpression: return updateConditional(node, visitNode((node).condition, visitor, isExpression), - visitNode((node).questionToken, visitor, isToken), + visitNode((node).questionToken, tokenVisitor, isToken), visitNode((node).whenTrue, visitor, isExpression), - visitNode((node).colonToken, visitor, isToken), + visitNode((node).colonToken, tokenVisitor, isToken), visitNode((node).whenFalse, visitor, isExpression)); case SyntaxKind.TemplateExpression: @@ -659,7 +659,7 @@ namespace ts { case SyntaxKind.ForOfStatement: return updateForOf(node, - visitNode((node).awaitModifier, visitor, isToken), + visitNode((node).awaitModifier, tokenVisitor, isToken), visitNode((node).initializer, visitor, isForInitializer), visitNode((node).expression, visitor, isExpression), visitNode((node).statement, visitor, isStatement, liftToBlock)); diff --git a/src/services/textChanges.ts b/src/services/textChanges.ts index 49f75cf41ecb4..7d424506dc39e 100644 --- a/src/services/textChanges.ts +++ b/src/services/textChanges.ts @@ -966,7 +966,6 @@ namespace ts.textChanges { function createWriter(newLine: string): TextChangesWriter { let lastNonTriviaPosition = 0; - const writer = createTextWriter(newLine); const onEmitNode: PrintHandlers["onEmitNode"] = (hint, node, printCallback) => { if (node) { diff --git a/tests/baselines/reference/propertyAccessExpressionInnerComments.js b/tests/baselines/reference/propertyAccessExpressionInnerComments.js index 3348c0432194d..f8a57d1c0ac55 100644 --- a/tests/baselines/reference/propertyAccessExpressionInnerComments.js +++ b/tests/baselines/reference/propertyAccessExpressionInnerComments.js @@ -13,6 +13,23 @@ /*1*/Array // Single-line comment /*2*/./*3*/toString/*4*/ + +/* Existing issue: the "2" comments below are duplicated and "3"s are missing */ + +/*1*/Array/*2*/?./*3*/toString/*4*/ + +/*1*/Array +/*2*/?./*3*/ + // Single-line comment + toString/*4*/ + +/*1*/Array/*2*/?./*3*/ + // Single-line comment + toString/*4*/ + +/*1*/Array + // Single-line comment + /*2*/?./*3*/toString/*4*/ //// [propertyAccessExpressionInnerComments.js] @@ -27,3 +44,15 @@ /*1*/ Array // Single-line comment /*2*/ . /*3*/toString; /*4*/ +/* Existing issue: the "2" comments below are duplicated and "3"s are missing */ +/*1*/ Array /*2*/ === null || Array /*2*/ === void 0 ? void 0 : Array /*2*/.toString; /*4*/ +/*1*/ Array === null || Array === void 0 ? void 0 : Array +/*2*/ . +// Single-line comment +toString; /*4*/ +/*1*/ Array /*2*/ === null || Array /*2*/ === void 0 ? void 0 : Array /*2*/. +// Single-line comment +toString; /*4*/ +/*1*/ Array === null || Array === void 0 ? void 0 : Array +// Single-line comment +/*2*/ .toString; /*4*/ diff --git a/tests/baselines/reference/propertyAccessExpressionInnerComments.symbols b/tests/baselines/reference/propertyAccessExpressionInnerComments.symbols index 439195f985b72..6a0ae25059eac 100644 --- a/tests/baselines/reference/propertyAccessExpressionInnerComments.symbols +++ b/tests/baselines/reference/propertyAccessExpressionInnerComments.symbols @@ -29,3 +29,35 @@ /*2*/./*3*/toString/*4*/ >toString : Symbol(Function.toString, Decl(lib.es5.d.ts, --, --)) +/* Existing issue: the "2" comments below are duplicated and "3"s are missing */ + +/*1*/Array/*2*/?./*3*/toString/*4*/ +>Array/*2*/?./*3*/toString : Symbol(Function.toString, Decl(lib.es5.d.ts, --, --)) +>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>toString : Symbol(Function.toString, Decl(lib.es5.d.ts, --, --)) + +/*1*/Array +>Array/*2*/?./*3*/ // Single-line comment toString : Symbol(Function.toString, Decl(lib.es5.d.ts, --, --)) +>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) + +/*2*/?./*3*/ + // Single-line comment + toString/*4*/ +>toString : Symbol(Function.toString, Decl(lib.es5.d.ts, --, --)) + +/*1*/Array/*2*/?./*3*/ +>Array/*2*/?./*3*/ // Single-line comment toString : Symbol(Function.toString, Decl(lib.es5.d.ts, --, --)) +>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) + + // Single-line comment + toString/*4*/ +>toString : Symbol(Function.toString, Decl(lib.es5.d.ts, --, --)) + +/*1*/Array +>Array // Single-line comment /*2*/?./*3*/toString : Symbol(Function.toString, Decl(lib.es5.d.ts, --, --)) +>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) + + // Single-line comment + /*2*/?./*3*/toString/*4*/ +>toString : Symbol(Function.toString, Decl(lib.es5.d.ts, --, --)) + diff --git a/tests/baselines/reference/propertyAccessExpressionInnerComments.types b/tests/baselines/reference/propertyAccessExpressionInnerComments.types index 63bd06c68d4a8..d9bc3c2fa498d 100644 --- a/tests/baselines/reference/propertyAccessExpressionInnerComments.types +++ b/tests/baselines/reference/propertyAccessExpressionInnerComments.types @@ -29,3 +29,35 @@ /*2*/./*3*/toString/*4*/ >toString : () => string +/* Existing issue: the "2" comments below are duplicated and "3"s are missing */ + +/*1*/Array/*2*/?./*3*/toString/*4*/ +>Array/*2*/?./*3*/toString : () => string +>Array : ArrayConstructor +>toString : () => string + +/*1*/Array +>Array/*2*/?./*3*/ // Single-line comment toString : () => string +>Array : ArrayConstructor + +/*2*/?./*3*/ + // Single-line comment + toString/*4*/ +>toString : () => string + +/*1*/Array/*2*/?./*3*/ +>Array/*2*/?./*3*/ // Single-line comment toString : () => string +>Array : ArrayConstructor + + // Single-line comment + toString/*4*/ +>toString : () => string + +/*1*/Array +>Array // Single-line comment /*2*/?./*3*/toString : () => string +>Array : ArrayConstructor + + // Single-line comment + /*2*/?./*3*/toString/*4*/ +>toString : () => string + diff --git a/tests/cases/compiler/propertyAccessExpressionInnerComments.ts b/tests/cases/compiler/propertyAccessExpressionInnerComments.ts index f4efc986b3803..fff9401468a5b 100644 --- a/tests/cases/compiler/propertyAccessExpressionInnerComments.ts +++ b/tests/cases/compiler/propertyAccessExpressionInnerComments.ts @@ -12,3 +12,20 @@ /*1*/Array // Single-line comment /*2*/./*3*/toString/*4*/ + +/* Existing issue: the "2" comments below are duplicated and "3"s are missing */ + +/*1*/Array/*2*/?./*3*/toString/*4*/ + +/*1*/Array +/*2*/?./*3*/ + // Single-line comment + toString/*4*/ + +/*1*/Array/*2*/?./*3*/ + // Single-line comment + toString/*4*/ + +/*1*/Array + // Single-line comment + /*2*/?./*3*/toString/*4*/ diff --git a/tests/cases/fourslash/extract-const2.ts b/tests/cases/fourslash/extract-const2.ts new file mode 100644 index 0000000000000..00a9ca6ca52ba --- /dev/null +++ b/tests/cases/fourslash/extract-const2.ts @@ -0,0 +1,16 @@ +/// + +////function foo(bar: number) { +//// /*a*/bar.toString();/*b*/ +////} + +goTo.select("a", "b"); +edit.applyRefactor({ + refactorName: "Extract Symbol", + actionName: "constant_scope_0", + actionDescription: "Extract to constant in enclosing scope", + newContent: +`function foo(bar: number) { + const /*RENAME*/newLocal = bar.toString(); +}` +}); diff --git a/tests/cases/fourslash/extract-const3.ts b/tests/cases/fourslash/extract-const3.ts new file mode 100644 index 0000000000000..c4e79ccb746ca --- /dev/null +++ b/tests/cases/fourslash/extract-const3.ts @@ -0,0 +1,18 @@ +/// + +// GH#35372 + +////function foo(bar?: number) { +//// /*a*/bar?.toString();/*b*/ +////} + +goTo.select("a", "b"); +edit.applyRefactor({ + refactorName: "Extract Symbol", + actionName: "constant_scope_0", + actionDescription: "Extract to constant in enclosing scope", + newContent: +`function foo(bar?: number) { + const /*RENAME*/newLocal = bar?.toString(); +}` +});