@@ -967,7 +967,7 @@ import {
967
967
ScriptKind,
968
968
ScriptTarget,
969
969
SetAccessorDeclaration,
970
- setCommentRange,
970
+ setCommentRange as setCommentRangeWorker ,
971
971
setEmitFlags,
972
972
setIdentifierTypeArguments,
973
973
setNodeFlags,
@@ -1094,7 +1094,7 @@ import {
1094
1094
VariableLikeDeclaration,
1095
1095
VariableStatement,
1096
1096
VarianceFlags,
1097
- visitEachChild,
1097
+ visitEachChild as visitEachChildWorker ,
1098
1098
visitNode,
1099
1099
visitNodes,
1100
1100
Visitor,
@@ -2426,7 +2426,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2426
2426
2427
2427
function markAsSynthetic<T extends Node>(node: T): VisitResult<T> {
2428
2428
setTextRangePosEnd(node, -1, -1);
2429
- return visitEachChild (node, markAsSynthetic, /*context*/ undefined);
2429
+ return visitEachChildWorker (node, markAsSynthetic, /*context*/ undefined);
2430
2430
}
2431
2431
2432
2432
function getEmitResolver(sourceFile: SourceFile, cancellationToken: CancellationToken, skipDiagnostics?: boolean) {
@@ -6032,21 +6032,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
6032
6032
* Unlike the utilities `setTextRange`, this checks if the `location` we're trying to set on `range` is within the
6033
6033
* same file as the active context. If not, the range is not applied. This prevents us from copying ranges across files,
6034
6034
* which will confuse the node printer (as it assumes all node ranges are within the current file).
6035
- * Additionally, if `range` _isn't synthetic_, and isn't in the current file, it will _copy_ it to _remove_ its' position
6035
+ * Additionally, if `range` _isn't synthetic_, or isn't in the current file, it will _copy_ it to _remove_ its' position
6036
6036
* information.
6037
6037
*
6038
6038
* It also calls `setOriginalNode` to setup a `.original` pointer, since you basically *always* want these in the node builder.
6039
6039
*/
6040
6040
function setTextRange<T extends Node>(context: NodeBuilderContext, range: T, location: Node | undefined): T {
6041
- if (!nodeIsSynthesized(range) && !(range.flags & NodeFlags.Synthesized) && ( !context.enclosingFile || context.enclosingFile !== getSourceFileOfNode(range))) {
6042
- range = factory.cloneNode(range);
6041
+ if (!nodeIsSynthesized(range) || !(range.flags & NodeFlags.Synthesized) || !context.enclosingFile || context.enclosingFile !== getSourceFileOfNode(getOriginalNode (range))) {
6042
+ range = factory.cloneNode(range); // if `range` is synthesized or originates in another file, copy it so it definitely has synthetic positions
6043
6043
}
6044
6044
if (range === location) return range;
6045
6045
if (!location) {
6046
6046
return range;
6047
6047
}
6048
6048
if (!context.enclosingFile || context.enclosingFile !== getSourceFileOfNode(getOriginalNode(location))) {
6049
- return setOriginalNode(range, location);
6049
+ return setOriginalNode(range, location); // if `location` is from another file, only set/update original pointer, and not positions, since copying text across files isn't supported by the emitter
6050
6050
}
6051
6051
return setTextRangeWorker(setOriginalNode(range, location), location);
6052
6052
}
@@ -6720,7 +6720,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
6720
6720
if (!nodeIsSynthesized(node) && getParseTreeNode(node) === node) {
6721
6721
return node;
6722
6722
}
6723
- return setTextRange(context, factory.cloneNode(visitEachChild (node, deepCloneOrReuseNode, /*context*/ undefined, deepCloneOrReuseNodes, deepCloneOrReuseNode)), node);
6723
+ return setTextRange(context, factory.cloneNode(visitEachChildWorker (node, deepCloneOrReuseNode, /*context*/ undefined, deepCloneOrReuseNodes, deepCloneOrReuseNode)), node);
6724
6724
}
6725
6725
6726
6726
function deepCloneOrReuseNodes(
@@ -7067,6 +7067,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
7067
7067
const getterSignature = getSignatureFromDeclaration(getterDeclaration);
7068
7068
typeElements.push(
7069
7069
setCommentRange(
7070
+ context,
7070
7071
signatureToSignatureDeclarationHelper(getterSignature, SyntaxKind.GetAccessor, context, { name: propertyName }) as GetAccessorDeclaration,
7071
7072
getterDeclaration,
7072
7073
),
@@ -7075,6 +7076,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
7075
7076
const setterSignature = getSignatureFromDeclaration(setterDeclaration);
7076
7077
typeElements.push(
7077
7078
setCommentRange(
7079
+ context,
7078
7080
signatureToSignatureDeclarationHelper(setterSignature, SyntaxKind.SetAccessor, context, { name: propertyName }) as SetAccessorDeclaration,
7079
7081
setterDeclaration,
7080
7082
),
@@ -7132,12 +7134,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
7132
7134
}
7133
7135
else if (propertySymbol.valueDeclaration) {
7134
7136
// Copy comments to node for declaration emit
7135
- setCommentRange(node, propertySymbol.valueDeclaration);
7137
+ setCommentRange(context, node, propertySymbol.valueDeclaration);
7136
7138
}
7137
7139
return node;
7138
7140
}
7139
7141
}
7140
7142
7143
+ function setCommentRange<T extends Node>(context: NodeBuilderContext, node: T, range: Node): T {
7144
+ if (context.enclosingFile && context.enclosingFile === getSourceFileOfNode(range)) {
7145
+ // Copy comments to node for declaration emit
7146
+ return setCommentRangeWorker(node, range);
7147
+ }
7148
+ return node;
7149
+ }
7150
+
7141
7151
function mapToTypeNodes(types: readonly Type[] | undefined, context: NodeBuilderContext, isBareList?: boolean): TypeNode[] | undefined {
7142
7152
if (some(types)) {
7143
7153
if (checkTruncationLength(context)) {
@@ -7579,7 +7589,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
7579
7589
if (context.tracker.canTrackSymbol && isComputedPropertyName(node) && isLateBindableName(node)) {
7580
7590
trackComputedName(node.expression, context.enclosingDeclaration, context);
7581
7591
}
7582
- let visited = visitEachChild (node, elideInitializerAndSetEmitFlags, /*context*/ undefined, /*nodesVisitor*/ undefined, elideInitializerAndSetEmitFlags);
7592
+ let visited = visitEachChildWorker (node, elideInitializerAndSetEmitFlags, /*context*/ undefined, /*nodesVisitor*/ undefined, elideInitializerAndSetEmitFlags);
7583
7593
if (isBindingElement(visited)) {
7584
7594
visited = factory.updateBindingElement(
7585
7595
visited,
@@ -7992,6 +8002,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
7992
8002
if (!(result.kind & SyntaxKind.Identifier)) {
7993
8003
return factory.createIdentifier("(Missing type parameter)");
7994
8004
}
8005
+ const decl = type.symbol?.declarations?.[0];
8006
+ if (decl && isTypeParameterDeclaration(decl)) {
8007
+ result = setTextRange(context, result, decl.name);
8008
+ }
7995
8009
if (context.flags & NodeBuilderFlags.GenerateNamesForShadowedTypeParams) {
7996
8010
const rawtext = result.escapedText as string;
7997
8011
let i = context.typeParameterNamesByTextNextNameCount?.get(rawtext) || 0;
@@ -8393,7 +8407,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
8393
8407
name.symbol = sym!; // for quickinfo, which uses identifier symbol information
8394
8408
return setTextRange(context, setEmitFlags(name, EmitFlags.NoAsciiEscaping), node);
8395
8409
}
8396
- const updated = visitEachChild (node, c => attachSymbolToLeftmostIdentifier(c), /*context*/ undefined);
8410
+ const updated = visitEachChildWorker (node, c => attachSymbolToLeftmostIdentifier(c), /*context*/ undefined);
8397
8411
if (updated !== node) {
8398
8412
setTextRange(context, updated, node);
8399
8413
}
@@ -8504,7 +8518,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
8504
8518
// is set to build for (even though we are reusing the node structure, the position information
8505
8519
// would make the printer print invalid spans for literals and identifiers, and the formatter would
8506
8520
// choke on the mismatched positonal spans between a parent and an injected child from another file).
8507
- return result === node ? setTextRange(context, factory.cloneNode( result) , node) : result ;
8521
+ return result ? setTextRange(context, result, node) : undefined ;
8508
8522
}
8509
8523
8510
8524
function createRecoveryBoundary() {
@@ -8769,7 +8783,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
8769
8783
|| (isPropertySignature(node) && !node.type && !node.initializer)
8770
8784
|| (isParameter(node) && !node.type && !node.initializer)
8771
8785
) {
8772
- let visited = visitEachChild(node, visitExistingNodeTreeSymbols, /*context*/ undefined );
8786
+ let visited = visitEachChild(node, visitExistingNodeTreeSymbols);
8773
8787
if (visited === node) {
8774
8788
visited = setTextRange(context, factory.cloneNode(node), node);
8775
8789
}
@@ -8831,7 +8845,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
8831
8845
}
8832
8846
8833
8847
if (isTupleTypeNode(node) || isTypeLiteralNode(node) || isMappedTypeNode(node)) {
8834
- const visited = visitEachChild(node, visitExistingNodeTreeSymbols, /*context*/ undefined );
8848
+ const visited = visitEachChild(node, visitExistingNodeTreeSymbols);
8835
8849
const clone = setTextRange(context, visited === node ? factory.cloneNode(node) : visited, node);
8836
8850
const flags = getEmitFlags(clone);
8837
8851
setEmitFlags(clone, flags | (context.flags & NodeBuilderFlags.MultilineObjectLiterals && isTypeLiteralNode(node) ? 0 : EmitFlags.SingleLine));
@@ -8878,7 +8892,33 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
8878
8892
}
8879
8893
}
8880
8894
8881
- return visitEachChild(node, visitExistingNodeTreeSymbols, /*context*/ undefined);
8895
+ return visitEachChild(node, visitExistingNodeTreeSymbols);
8896
+
8897
+ function visitEachChild<T extends Node>(node: T, visitor: Visitor): T;
8898
+ function visitEachChild<T extends Node>(node: T | undefined, visitor: Visitor): T | undefined;
8899
+ function visitEachChild<T extends Node>(node: T | undefined, visitor: Visitor): T | undefined {
8900
+ const nonlocalNode = !context.enclosingFile || context.enclosingFile !== getSourceFileOfNode(node);
8901
+ return visitEachChildWorker(node, visitor, /*context*/ undefined, nonlocalNode ? visitNodesWithoutCopyingPositions : undefined);
8902
+ }
8903
+
8904
+ function visitNodesWithoutCopyingPositions(
8905
+ nodes: NodeArray<Node> | undefined,
8906
+ visitor: Visitor,
8907
+ test?: (node: Node) => boolean,
8908
+ start?: number,
8909
+ count?: number,
8910
+ ): NodeArray<Node> | undefined {
8911
+ let result = visitNodes(nodes, visitor, test, start, count);
8912
+ if (result) {
8913
+ if (result.pos !== -1 || result.end !== -1) {
8914
+ if (result === nodes) {
8915
+ result = factory.createNodeArray(nodes, nodes.hasTrailingComma);
8916
+ }
8917
+ setTextRangePosEnd(result, -1, -1);
8918
+ }
8919
+ }
8920
+ return result;
8921
+ }
8882
8922
8883
8923
function getEffectiveDotDotDotForParameter(p: ParameterDeclaration) {
8884
8924
return p.dotDotDotToken || (p.type && isJSDocVariadicType(p.type) ? factory.createToken(SyntaxKind.DotDotDotToken) : undefined);
0 commit comments