Skip to content

Commit 322515c

Browse files
committed
Make pos/end/parent and JSDoc 'comment' read-only
1 parent 602efc5 commit 322515c

File tree

19 files changed

+460
-404
lines changed

19 files changed

+460
-404
lines changed

src/compat/deprecations.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1933,13 +1933,12 @@ namespace ts {
19331933
* NOTE: It is unsafe to change any properties of a `Node` that relate to its AST children, as those changes won't be
19341934
* captured with respect to transformations.
19351935
*
1936-
* @deprecated Use `factory.cloneNode` instead and set `pos`, `end`, and `parent` as needed.
1936+
* @deprecated Use `factory.cloneNode` instead and use `setCommentRange` or `setSourceMapRange` and avoid setting `parent`.
19371937
*/
19381938
export function getMutableClone<T extends Node>(node: T): T {
19391939
const clone = factory.cloneNode(node);
1940-
clone.pos = node.pos;
1941-
clone.end = node.end;
1942-
clone.parent = node.parent;
1940+
setTextRange(clone, node);
1941+
setParent(clone, node.parent);
19431942
return clone;
19441943
}
19451944

src/compiler/binder.ts

Lines changed: 20 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ namespace ts {
1717
export function getModuleInstanceState(node: ModuleDeclaration, visited?: Map<ModuleInstanceState | undefined>): ModuleInstanceState {
1818
if (node.body && !node.body.parent) {
1919
// getModuleInstanceStateForAliasTarget needs to walk up the parent chain, so parent pointers must be set on this tree already
20-
setParentPointers(node, node.body);
20+
setParent(node.body, node);
21+
setParentRecursive(node.body, /*incremental*/ false);
2122
}
2223
return node.body ? getModuleInstanceStateCached(node.body, visited) : ModuleInstanceState.Instantiated;
2324
}
@@ -114,7 +115,8 @@ namespace ts {
114115
for (const statement of statements) {
115116
if (nodeHasName(statement, name)) {
116117
if (!statement.parent) {
117-
setParentPointers(p, statement);
118+
setParent(statement, p);
119+
setParentRecursive(statement, /*incremental*/ false);
118120
}
119121
const state = getModuleInstanceStateCached(statement, visited);
120122
if (found === undefined || state > found) {
@@ -467,7 +469,7 @@ namespace ts {
467469
else if (!(includes & SymbolFlags.Variable && symbol.flags & SymbolFlags.Assignment)) {
468470
// Assignment declarations are allowed to merge with variables, no matter what other flags they have.
469471
if (isNamedDeclaration(node)) {
470-
node.name.parent = node;
472+
setParent(node.name, node);
471473
}
472474

473475
// Report errors every position with duplicate declaration
@@ -1484,9 +1486,10 @@ namespace ts {
14841486
}
14851487

14861488
function bindJSDocTypeAlias(node: JSDocTypedefTag | JSDocCallbackTag | JSDocEnumTag) {
1487-
node.tagName.parent = node;
1489+
setParent(node.tagName, node);
14881490
if (node.kind !== SyntaxKind.JSDocEnumTag && node.fullName) {
1489-
setParentPointers(node, node.fullName);
1491+
setParent(node.fullName, node);
1492+
setParentRecursive(node.fullName, /*incremental*/ false);
14901493
}
14911494
}
14921495

@@ -2174,7 +2177,7 @@ namespace ts {
21742177
if (!node) {
21752178
return;
21762179
}
2177-
node.parent = parent;
2180+
setParent(node, parent);
21782181
const saveInStrictMode = inStrictMode;
21792182

21802183
// Even though in the AST the jsdoc @typedef node belongs to the current node,
@@ -2233,7 +2236,8 @@ namespace ts {
22332236
}
22342237
else {
22352238
for (const j of node.jsDoc!) {
2236-
setParentPointers(node, j);
2239+
setParent(j, node);
2240+
setParentRecursive(j, /*incremental*/ false);
22372241
}
22382242
}
22392243
}
@@ -2726,8 +2730,8 @@ namespace ts {
27262730

27272731
/** For `x.prototype = { p, ... }`, declare members p,... if `x` is function/class/{}, or not declared. */
27282732
function bindPrototypeAssignment(node: BindableStaticPropertyAssignmentExpression) {
2729-
node.left.parent = node;
2730-
node.right.parent = node;
2733+
setParent(node.left, node);
2734+
setParent(node.right, node);
27312735
bindPropertyAssignment(node.left.expression, node.left, /*isPrototypeProperty*/ false, /*containerIsClass*/ true);
27322736
}
27332737

@@ -2751,9 +2755,9 @@ namespace ts {
27512755
const constructorFunction = classPrototype.expression;
27522756

27532757
// Fix up parent pointers since we're going to use these nodes before we bind into them
2754-
lhs.parent = parent;
2755-
constructorFunction.parent = classPrototype;
2756-
classPrototype.parent = lhs;
2758+
setParent(constructorFunction, classPrototype);
2759+
setParent(classPrototype, lhs);
2760+
setParent(lhs, parent);
27572761

27582762
bindPropertyAssignment(constructorFunction, lhs, /*isPrototypeProperty*/ true, /*containerIsClass*/ true);
27592763
}
@@ -2772,8 +2776,8 @@ namespace ts {
27722776
return;
27732777
}
27742778
// Fix up parent pointers since we're going to use these nodes before we bind into them
2775-
node.left.parent = node;
2776-
node.right.parent = node;
2779+
setParent(node.left, node);
2780+
setParent(node.right, node);
27772781
if (isIdentifier(node.left.expression) && container === file && isExportsOrModuleExportsOrAlias(file, node.left.expression)) {
27782782
// This can be an alias for the 'exports' or 'module.exports' names, e.g.
27792783
// var util = module.exports;
@@ -2797,7 +2801,7 @@ namespace ts {
27972801
* Also works for expression statements preceded by JSDoc, like / ** @type number * / x.y;
27982802
*/
27992803
function bindStaticPropertyAssignment(node: BindableStaticAccessExpression) {
2800-
node.expression.parent = node;
2804+
setParent(node.expression, node);
28012805
bindPropertyAssignment(node.expression, node, /*isPrototypeProperty*/ false, /*containerIsClass*/ false);
28022806
}
28032807

@@ -2979,7 +2983,7 @@ namespace ts {
29792983
const symbolExport = symbol.exports!.get(prototypeSymbol.escapedName);
29802984
if (symbolExport) {
29812985
if (node.name) {
2982-
node.name.parent = node;
2986+
setParent(node.name, node);
29832987
}
29842988
file.bindDiagnostics.push(createDiagnosticForNode(symbolExport.declarations[0], Diagnostics.Duplicate_identifier_0, symbolName(prototypeSymbol)));
29852989
}
@@ -3241,13 +3245,4 @@ namespace ts {
32413245
}
32423246
return container.symbol && container.symbol.exports && container.symbol.exports.get(name);
32433247
}
3244-
3245-
/**
3246-
* "Binds" JSDoc nodes in TypeScript code.
3247-
* Since we will never create symbols for JSDoc, we just set parent pointers instead.
3248-
*/
3249-
function setParentPointers(parent: Node, child: Node): void {
3250-
child.parent = parent;
3251-
forEachChild(child, grandchild => setParentPointers(child, grandchild));
3252-
}
32533248
}

src/compiler/checker.ts

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5616,7 +5616,7 @@ namespace ts {
56165616
// Add a namespace
56175617
// Create namespace as non-synthetic so it is usable as an enclosing declaration
56185618
let fakespace = parseNodeFactory.createModuleDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, factory.createIdentifier(localName), factory.createModuleBlock([]), NodeFlags.Namespace);
5619-
fakespace.parent = enclosingDeclaration as SourceFile | NamespaceDeclaration;
5619+
setParent(fakespace, enclosingDeclaration as SourceFile | NamespaceDeclaration);
56205620
fakespace.locals = createSymbolTable(props);
56215621
fakespace.symbol = props[0].parent!;
56225622

@@ -6775,8 +6775,8 @@ namespace ts {
67756775
if (propName) {
67766776
const literal = setTextRange(parseNodeFactory.createStringLiteral(propName), node);
67776777
const result = setTextRange(parseNodeFactory.createElementAccess(parentAccess, literal), node);
6778-
literal.parent = result;
6779-
result.parent = node;
6778+
setParent(literal, result);
6779+
setParent(result, node);
67806780
result.flowNode = parentAccess.flowNode;
67816781
return result;
67826782
}
@@ -20313,9 +20313,10 @@ namespace ts {
2031320313
const unionTypes = (<UnionTypeNode>funcTypeNode.type).types;
2031420314
if (unionTypes && unionTypes[unionTypes.length - 1].kind === SyntaxKind.UndefinedKeyword) {
2031520315
// TODO(rbuckton): Does this need to be parented?
20316-
const parenedFuncType = setParent(setTextRange(factory.cloneNode(funcTypeNode), funcTypeNode), funcTypeNode.parent);
2031720316
// Highlight to the end of the second to last constituent of the union
20318-
parenedFuncType.end = unionTypes[unionTypes.length - 2].end;
20317+
const parenedFuncType = setParent(
20318+
setTextRangePosEnd(factory.cloneNode(funcTypeNode), funcTypeNode.pos, unionTypes[unionTypes.length - 2].end),
20319+
funcTypeNode.parent);
2031920320
addRelatedInfo(diag, createDiagnosticForNode(parenedFuncType, Diagnostics.Did_you_mean_to_parenthesize_this_function_type));
2032020321
}
2032120322
}
@@ -22371,7 +22372,7 @@ namespace ts {
2237122372
(getArrayLiteralTupleTypeIfApplicable(childrenTypes, childrenContextualType, /*hasRestElement*/ false) || createArrayType(getUnionType(childrenTypes)));
2237222373
// Fake up a property declaration for the children
2237322374
childrenPropSymbol.valueDeclaration = factory.createPropertySignature(/*modifiers*/ undefined, unescapeLeadingUnderscores(jsxChildrenPropertyName), /*questionToken*/ undefined, /*type*/ undefined);
22374-
childrenPropSymbol.valueDeclaration.parent = attributes;
22375+
setParent(childrenPropSymbol.valueDeclaration, attributes);
2237522376
childrenPropSymbol.valueDeclaration.symbol = childrenPropSymbol;
2237622377
const childPropMap = createSymbolTable();
2237722378
childPropMap.set(jsxChildrenPropertyName, childrenPropSymbol);
@@ -23985,7 +23986,7 @@ namespace ts {
2398523986
function createSyntheticExpression(parent: Node, type: Type, isSpread?: boolean) {
2398623987
const result = parseNodeFactory.createSyntheticExpression(type, isSpread);
2398723988
setTextRange(result, parent);
23988-
result.parent = parent;
23989+
setParent(result, parent);
2398923990
return result;
2399023991
}
2399123992

@@ -24181,11 +24182,12 @@ namespace ts {
2418124182
spanArray = factory.createNodeArray(args.slice(max));
2418224183
}
2418324184

24184-
spanArray.pos = first(spanArray).pos;
24185-
spanArray.end = last(spanArray).end;
24186-
if (spanArray.end === spanArray.pos) {
24187-
spanArray.end++;
24185+
const pos = first(spanArray).pos;
24186+
let end = last(spanArray).end;
24187+
if (end === pos) {
24188+
end++;
2418824189
}
24190+
setTextRangePosEnd(spanArray, pos, end);
2418924191
const diagnostic = createDiagnosticForNodeArray(
2419024192
getSourceFileOfNode(node), spanArray, error, paramRange, argCount);
2419124193
return related ? addRelatedInfo(diagnostic, related) : diagnostic;
@@ -32044,8 +32046,8 @@ namespace ts {
3204432046

3204532047
function isPropertyInitializedInConstructor(propName: Identifier, propType: Type, constructor: ConstructorDeclaration) {
3204632048
const reference = factory.createPropertyAccess(factory.createThis(), propName);
32047-
reference.expression.parent = reference;
32048-
reference.parent = constructor;
32049+
setParent(reference.expression, reference);
32050+
setParent(reference, constructor);
3204932051
reference.flowNode = constructor.returnFlowNode;
3205032052
const flowType = getFlowTypeOfReference(reference, propType, getOptionalType(propType));
3205132053
return !(getFalsyFlags(flowType) & TypeFlags.Undefined);

src/compiler/emitter.ts

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -681,7 +681,7 @@ namespace ts {
681681
const statements = prologueInfo?.directives.map(directive => {
682682
const literal = setTextRange(factory.createStringLiteral(directive.expression.text), directive.expression);
683683
const statement = setTextRange(factory.createExpressionStatement(literal), directive);
684-
literal.parent = statement;
684+
setParent(literal, statement);
685685
return statement;
686686
});
687687
const eofToken = factory.createToken(SyntaxKind.EndOfFileToken);
@@ -692,14 +692,10 @@ namespace ts {
692692
!host.useCaseSensitiveFileNames()
693693
);
694694
sourceFile.text = prologueInfo?.text ?? "";
695-
sourceFile.pos = 0;
696-
sourceFile.end = prologueInfo?.text.length ?? 0;
697-
for (const statement of sourceFile.statements) {
698-
statement.parent = sourceFile;
699-
}
700-
eofToken.pos = sourceFile.end;
701-
eofToken.end = sourceFile.end;
702-
eofToken.parent = sourceFile;
695+
setTextRangePosWidth(sourceFile, 0, prologueInfo?.text.length ?? 0);
696+
setEachParent(sourceFile.statements, sourceFile);
697+
setTextRangePosWidth(eofToken, sourceFile.end, 0);
698+
setParent(eofToken, sourceFile);
703699
return sourceFile;
704700
});
705701
}

src/compiler/factory/nodeFactory.ts

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -525,8 +525,7 @@ namespace ts {
525525
// small arrays (1 to 4 elements) to give the VM a chance to allocate an optimal representation.
526526
const length = elements.length;
527527
const array = <NodeArray<T>>(length >= 1 && length <= 4 ? elements.slice() : elements);
528-
array.pos = -1;
529-
array.end = -1;
528+
setTextRangePosEnd(array, -1, -1);
530529
if (hasTrailingComma) {
531530
array.hasTrailingComma = hasTrailingComma;
532531
}
@@ -3942,8 +3941,8 @@ namespace ts {
39423941
}
39433942

39443943
// @api
3945-
function createJSDocTemplateTag(tagName: Identifier | undefined, constraint: JSDocTypeExpression | undefined, typeParameters: readonly TypeParameterDeclaration[]): JSDocTemplateTag {
3946-
const node = createBaseJSDocTag<JSDocTemplateTag>(SyntaxKind.JSDocTemplateTag, tagName || createIdentifier("template"), /*comment*/ undefined);
3944+
function createJSDocTemplateTag(tagName: Identifier | undefined, constraint: JSDocTypeExpression | undefined, typeParameters: readonly TypeParameterDeclaration[], comment?: string): JSDocTemplateTag {
3945+
const node = createBaseJSDocTag<JSDocTemplateTag>(SyntaxKind.JSDocTemplateTag, tagName || createIdentifier("template"), comment);
39473946
setChild(node, node.constraint = constraint);
39483947
setChildren(node, node.typeParameters = createNodeArray(typeParameters));
39493948
return finishJSDoc(node);
@@ -3973,8 +3972,8 @@ namespace ts {
39733972
}
39743973

39753974
// @api
3976-
function createJSDocThisTag(tagName: Identifier | undefined, typeExpression?: JSDocTypeExpression): JSDocThisTag {
3977-
const node = createBaseJSDocTag<JSDocThisTag>(SyntaxKind.JSDocThisTag, tagName || createIdentifier("this"), /*comment*/ undefined);
3975+
function createJSDocThisTag(tagName: Identifier | undefined, typeExpression?: JSDocTypeExpression, comment?: string): JSDocThisTag {
3976+
const node = createBaseJSDocTag<JSDocThisTag>(SyntaxKind.JSDocThisTag, tagName || createIdentifier("this"), comment);
39783977
setChild(node, node.typeExpression = typeExpression);
39793978
return finishJSDoc(node);
39803979
}
@@ -4006,8 +4005,8 @@ namespace ts {
40064005
}
40074006

40084007
// @api
4009-
function createJSDocAugmentsTag(tagName: Identifier | undefined, className: JSDocAugmentsTag["class"]): JSDocAugmentsTag {
4010-
const node = createBaseJSDocTag<JSDocAugmentsTag>(SyntaxKind.JSDocAugmentsTag, tagName || createIdentifier("augments"), /*comment*/ undefined);
4008+
function createJSDocAugmentsTag(tagName: Identifier | undefined, className: JSDocAugmentsTag["class"], comment?: string): JSDocAugmentsTag {
4009+
const node = createBaseJSDocTag<JSDocAugmentsTag>(SyntaxKind.JSDocAugmentsTag, tagName || createIdentifier("augments"), comment);
40114010
setChild(node, node.class = className);
40124011
return finishJSDoc(node);
40134012
}
@@ -4022,21 +4021,21 @@ namespace ts {
40224021
}
40234022

40244023
// @api
4025-
function createJSDocClassTag(tagName: Identifier | undefined): JSDocClassTag {
4026-
const node = createBaseJSDocTag<JSDocClassTag>(SyntaxKind.JSDocClassTag, tagName || createIdentifier("class"), /*comment*/ undefined);
4024+
function createJSDocClassTag(tagName: Identifier | undefined, comment?: string): JSDocClassTag {
4025+
const node = createBaseJSDocTag<JSDocClassTag>(SyntaxKind.JSDocClassTag, tagName || createIdentifier("class"), comment);
40274026
return finishJSDoc(node);
40284027
}
40294028

40304029
// @api
4031-
function createJSDocEnumTag(tagName: Identifier | undefined, typeExpression?: JSDocTypeExpression): JSDocEnumTag {
4032-
const node = createBaseJSDocTag<JSDocEnumTag>(SyntaxKind.JSDocEnumTag, tagName || createIdentifier("enum"), /*comment*/ undefined);
4030+
function createJSDocEnumTag(tagName: Identifier | undefined, typeExpression?: JSDocTypeExpression, comment?: string): JSDocEnumTag {
4031+
const node = createBaseJSDocTag<JSDocEnumTag>(SyntaxKind.JSDocEnumTag, tagName || createIdentifier("enum"), comment);
40334032
setChild(node, node.typeExpression = typeExpression);
40344033
return finishJSDoc(node);
40354034
}
40364035

40374036
// @api
4038-
function createJSDocUnknownTag(tagName: Identifier): JSDocUnknownTag {
4039-
const node = createBaseJSDocTag<JSDocUnknownTag>(SyntaxKind.JSDocTag, tagName, /*comment*/ undefined);
4037+
function createJSDocUnknownTag(tagName: Identifier, comment?: string): JSDocUnknownTag {
4038+
const node = createBaseJSDocTag<JSDocUnknownTag>(SyntaxKind.JSDocTag, tagName, comment);
40404039
return finishJSDoc(node);
40414040
}
40424041

@@ -5803,8 +5802,7 @@ namespace ts {
58035802

58045803
if (!texts) {
58055804
const textNode = factory.createUnparsedTextLike(/*data*/ undefined, /*internal*/ false);
5806-
textNode.pos = 0;
5807-
textNode.end = typeof length === "function" ? length() : length;
5805+
setTextRangePosWidth(textNode, 0, typeof length === "function" ? length() : length);
58085806
texts = [textNode];
58095807
}
58105808

src/compiler/factory/utilities.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ namespace ts {
3030
const react = parseNodeFactory.createIdentifier(reactNamespace || "React");
3131
// Set the parent that is in parse tree
3232
// this makes sure that parent chain is intact for checker to traverse complete scope tree
33-
react.parent = getParseTreeNode(parent)!;
33+
setParent(react, getParseTreeNode(parent));
3434
return react;
3535
}
3636

0 commit comments

Comments
 (0)