mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-20 13:45:34 -05:00
Add collision check for 'Reflect' when using super in static initializers (#44876)
* Add collision check for 'Reflect' when using super in static initializers * PR feedback * Accept baseline for new failing test
This commit is contained in:
@@ -959,6 +959,7 @@ namespace ts {
|
||||
const potentialThisCollisions: Node[] = [];
|
||||
const potentialNewTargetCollisions: Node[] = [];
|
||||
const potentialWeakMapSetCollisions: Node[] = [];
|
||||
const potentialReflectCollisions: Node[] = [];
|
||||
const awaitedTypeStack: number[] = [];
|
||||
|
||||
const diagnostics = createDiagnosticCollection();
|
||||
@@ -24873,6 +24874,18 @@ namespace ts {
|
||||
|
||||
if (isStatic(container) || isCallExpression) {
|
||||
nodeCheckFlag = NodeCheckFlags.SuperStatic;
|
||||
if (!isCallExpression &&
|
||||
languageVersion >= ScriptTarget.ES2015 && languageVersion <= ScriptTarget.ES2021 &&
|
||||
(isPropertyDeclaration(container) || isClassStaticBlockDeclaration(container))) {
|
||||
// for `super.x` or `super[x]` in a static initializer, mark all enclosing
|
||||
// block scope containers so that we can report potential collisions with
|
||||
// `Reflect`.
|
||||
forEachEnclosingBlockScopeContainer(node.parent, current => {
|
||||
if (!isSourceFile(current) || isExternalOrCommonJsModule(current)) {
|
||||
getNodeLinks(current).flags |= NodeCheckFlags.ContainsSuperPropertyInStaticInitializer;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
else {
|
||||
nodeCheckFlag = NodeCheckFlags.SuperInstance;
|
||||
@@ -31159,6 +31172,10 @@ namespace ts {
|
||||
Debug.assert(node.kind !== SyntaxKind.MethodDeclaration || isObjectLiteralMethod(node));
|
||||
checkNodeDeferred(node);
|
||||
|
||||
if (isFunctionExpression(node)) {
|
||||
checkCollisionsForDeclarationName(node, node.name);
|
||||
}
|
||||
|
||||
// The identityMapper object is used to indicate that function expressions are wildcards
|
||||
if (checkMode && checkMode & CheckMode.SkipContextSensitive && isContextSensitive(node)) {
|
||||
// Skip parameters, return signature with return type that retains noncontextual parts so inferences can still be drawn in an early stage
|
||||
@@ -34946,8 +34963,7 @@ namespace ts {
|
||||
if (produceDiagnostics) {
|
||||
checkFunctionOrMethodDeclaration(node);
|
||||
checkGrammarForGenerator(node);
|
||||
checkCollisionWithRequireExportsInGeneratedCode(node, node.name!);
|
||||
checkCollisionWithGlobalPromiseInGeneratedCode(node, node.name!);
|
||||
checkCollisionsForDeclarationName(node, node.name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35470,8 +35486,13 @@ namespace ts {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether an {@link Identifier}, in the context of another {@link Node}, would collide with a runtime value
|
||||
* of {@link name} in an outer scope. This is used to check for collisions for downlevel transformations that
|
||||
* require names like `Object`, `Promise`, `Reflect`, `require`, `exports`, etc.
|
||||
*/
|
||||
function needCollisionCheckForIdentifier(node: Node, identifier: Identifier | undefined, name: string): boolean {
|
||||
if (!(identifier && identifier.escapedText === name)) {
|
||||
if (identifier?.escapedText !== name) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -35480,8 +35501,9 @@ namespace ts {
|
||||
node.kind === SyntaxKind.MethodDeclaration ||
|
||||
node.kind === SyntaxKind.MethodSignature ||
|
||||
node.kind === SyntaxKind.GetAccessor ||
|
||||
node.kind === SyntaxKind.SetAccessor) {
|
||||
// it is ok to have member named '_super' or '_this' - member access is always qualified
|
||||
node.kind === SyntaxKind.SetAccessor ||
|
||||
node.kind === SyntaxKind.PropertyAssignment) {
|
||||
// it is ok to have member named '_super', '_this', `Promise`, etc. - member access is always qualified
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -35490,8 +35512,15 @@ namespace ts {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isImportClause(node) || isImportEqualsDeclaration(node) || isImportSpecifier(node)) {
|
||||
// type-only imports do not require collision checks against runtime values.
|
||||
if (isTypeOnlyImportOrExportDeclaration(node)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const root = getRootDeclaration(node);
|
||||
if (root.kind === SyntaxKind.Parameter && nodeIsMissing((root.parent as FunctionLikeDeclaration).body)) {
|
||||
if (isParameter(root) && nodeIsMissing((root.parent as FunctionLikeDeclaration).body)) {
|
||||
// just an overload - no codegen impact
|
||||
return false;
|
||||
}
|
||||
@@ -35532,21 +35561,13 @@ namespace ts {
|
||||
});
|
||||
}
|
||||
|
||||
function checkWeakMapSetCollision(node: Node) {
|
||||
const enclosingBlockScope = getEnclosingBlockScopeContainer(node);
|
||||
if (getNodeCheckFlags(enclosingBlockScope) & NodeCheckFlags.ContainsClassWithPrivateIdentifiers) {
|
||||
Debug.assert(isNamedDeclaration(node) && isIdentifier(node.name) && typeof node.name.escapedText === "string", "The target of a WeakMap/WeakSet collision check should be an identifier");
|
||||
errorSkippedOn("noEmit", node, Diagnostics.Compiler_reserves_name_0_when_emitting_private_identifier_downlevel, node.name.escapedText);
|
||||
}
|
||||
}
|
||||
|
||||
function checkCollisionWithRequireExportsInGeneratedCode(node: Node, name: Identifier) {
|
||||
function checkCollisionWithRequireExportsInGeneratedCode(node: Node, name: Identifier | undefined) {
|
||||
// No need to check for require or exports for ES6 modules and later
|
||||
if (moduleKind >= ModuleKind.ES2015) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!needCollisionCheckForIdentifier(node, name, "require") && !needCollisionCheckForIdentifier(node, name, "exports")) {
|
||||
if (!name || !needCollisionCheckForIdentifier(node, name, "require") && !needCollisionCheckForIdentifier(node, name, "exports")) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -35564,8 +35585,8 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function checkCollisionWithGlobalPromiseInGeneratedCode(node: Node, name: Identifier): void {
|
||||
if (languageVersion >= ScriptTarget.ES2017 || !needCollisionCheckForIdentifier(node, name, "Promise")) {
|
||||
function checkCollisionWithGlobalPromiseInGeneratedCode(node: Node, name: Identifier | undefined): void {
|
||||
if (!name || languageVersion >= ScriptTarget.ES2017 || !needCollisionCheckForIdentifier(node, name, "Promise")) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -35583,6 +35604,76 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function recordPotentialCollisionWithWeakMapSetInGeneratedCode(node: Node, name: Identifier): void {
|
||||
if (languageVersion <= ScriptTarget.ES2021
|
||||
&& (needCollisionCheckForIdentifier(node, name, "WeakMap") || needCollisionCheckForIdentifier(node, name, "WeakSet"))) {
|
||||
potentialWeakMapSetCollisions.push(node);
|
||||
}
|
||||
}
|
||||
|
||||
function checkWeakMapSetCollision(node: Node) {
|
||||
const enclosingBlockScope = getEnclosingBlockScopeContainer(node);
|
||||
if (getNodeCheckFlags(enclosingBlockScope) & NodeCheckFlags.ContainsClassWithPrivateIdentifiers) {
|
||||
Debug.assert(isNamedDeclaration(node) && isIdentifier(node.name) && typeof node.name.escapedText === "string", "The target of a WeakMap/WeakSet collision check should be an identifier");
|
||||
errorSkippedOn("noEmit", node, Diagnostics.Compiler_reserves_name_0_when_emitting_private_identifier_downlevel, node.name.escapedText);
|
||||
}
|
||||
}
|
||||
|
||||
function recordPotentialCollisionWithReflectInGeneratedCode(node: Node, name: Identifier | undefined): void {
|
||||
if (name && languageVersion >= ScriptTarget.ES2015 && languageVersion <= ScriptTarget.ES2021
|
||||
&& needCollisionCheckForIdentifier(node, name, "Reflect")) {
|
||||
potentialReflectCollisions.push(node);
|
||||
}
|
||||
}
|
||||
|
||||
function checkReflectCollision(node: Node) {
|
||||
let hasCollision = false;
|
||||
if (isClassExpression(node)) {
|
||||
// ClassExpression names don't contribute to their containers, but do matter for any of their block-scoped members.
|
||||
for (const member of node.members) {
|
||||
if (getNodeCheckFlags(member) & NodeCheckFlags.ContainsSuperPropertyInStaticInitializer) {
|
||||
hasCollision = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (isFunctionExpression(node)) {
|
||||
// FunctionExpression names don't contribute to their containers, but do matter for their contents
|
||||
if (getNodeCheckFlags(node) & NodeCheckFlags.ContainsSuperPropertyInStaticInitializer) {
|
||||
hasCollision = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
const container = getEnclosingBlockScopeContainer(node);
|
||||
if (container && getNodeCheckFlags(container) & NodeCheckFlags.ContainsSuperPropertyInStaticInitializer) {
|
||||
hasCollision = true;
|
||||
}
|
||||
}
|
||||
if (hasCollision) {
|
||||
Debug.assert(isNamedDeclaration(node) && isIdentifier(node.name), "The target of a Reflect collision check should be an identifier");
|
||||
errorSkippedOn("noEmit", node, Diagnostics.Duplicate_identifier_0_Compiler_reserves_name_1_when_emitting_super_references_in_static_initializers,
|
||||
declarationNameToString(node.name),
|
||||
"Reflect");
|
||||
}
|
||||
}
|
||||
|
||||
function checkCollisionsForDeclarationName(node: Node, name: Identifier | undefined) {
|
||||
if (!name) return;
|
||||
checkCollisionWithRequireExportsInGeneratedCode(node, name);
|
||||
checkCollisionWithGlobalPromiseInGeneratedCode(node, name);
|
||||
recordPotentialCollisionWithWeakMapSetInGeneratedCode(node, name);
|
||||
recordPotentialCollisionWithReflectInGeneratedCode(node, name);
|
||||
if (isClassLike(node)) {
|
||||
checkTypeNameIsReserved(name, Diagnostics.Class_name_cannot_be_0);
|
||||
if (!(node.flags & NodeFlags.Ambient)) {
|
||||
checkClassNameCollisionWithObject(name);
|
||||
}
|
||||
}
|
||||
else if (isEnumDeclaration(node)) {
|
||||
checkTypeNameIsReserved(name, Diagnostics.Enum_name_cannot_be_0);
|
||||
}
|
||||
}
|
||||
|
||||
function checkVarDeclaredNamesNotShadowed(node: VariableDeclaration | BindingElement) {
|
||||
// - ScriptBody : StatementList
|
||||
// It is a Syntax Error if any element of the LexicallyDeclaredNames of StatementList
|
||||
@@ -35801,12 +35892,7 @@ namespace ts {
|
||||
if (node.kind === SyntaxKind.VariableDeclaration || node.kind === SyntaxKind.BindingElement) {
|
||||
checkVarDeclaredNamesNotShadowed(node);
|
||||
}
|
||||
checkCollisionWithRequireExportsInGeneratedCode(node, node.name);
|
||||
checkCollisionWithGlobalPromiseInGeneratedCode(node, node.name);
|
||||
if (languageVersion < ScriptTarget.ESNext
|
||||
&& (needCollisionCheckForIdentifier(node, node.name, "WeakMap") || needCollisionCheckForIdentifier(node, node.name, "WeakSet"))) {
|
||||
potentialWeakMapSetCollisions.push(node);
|
||||
}
|
||||
checkCollisionsForDeclarationName(node, node.name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37365,14 +37451,7 @@ namespace ts {
|
||||
function checkClassLikeDeclaration(node: ClassLikeDeclaration) {
|
||||
checkGrammarClassLikeDeclaration(node);
|
||||
checkDecorators(node);
|
||||
if (node.name) {
|
||||
checkTypeNameIsReserved(node.name, Diagnostics.Class_name_cannot_be_0);
|
||||
checkCollisionWithRequireExportsInGeneratedCode(node, node.name);
|
||||
checkCollisionWithGlobalPromiseInGeneratedCode(node, node.name);
|
||||
if (!(node.flags & NodeFlags.Ambient)) {
|
||||
checkClassNameCollisionWithObject(node.name);
|
||||
}
|
||||
}
|
||||
checkCollisionsForDeclarationName(node, node.name);
|
||||
checkTypeParameters(getEffectiveTypeParameterDeclarations(node));
|
||||
checkExportsOnMergedDeclarations(node);
|
||||
const symbol = getSymbolOfNode(node);
|
||||
@@ -38099,9 +38178,7 @@ namespace ts {
|
||||
// Grammar checking
|
||||
checkGrammarDecoratorsAndModifiers(node);
|
||||
|
||||
checkTypeNameIsReserved(node.name, Diagnostics.Enum_name_cannot_be_0);
|
||||
checkCollisionWithRequireExportsInGeneratedCode(node, node.name);
|
||||
checkCollisionWithGlobalPromiseInGeneratedCode(node, node.name);
|
||||
checkCollisionsForDeclarationName(node, node.name);
|
||||
checkExportsOnMergedDeclarations(node);
|
||||
node.members.forEach(checkEnumMember);
|
||||
|
||||
@@ -38210,8 +38287,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
if (isIdentifier(node.name)) {
|
||||
checkCollisionWithRequireExportsInGeneratedCode(node, node.name);
|
||||
checkCollisionWithGlobalPromiseInGeneratedCode(node, node.name);
|
||||
checkCollisionsForDeclarationName(node, node.name);
|
||||
}
|
||||
|
||||
checkExportsOnMergedDeclarations(node);
|
||||
@@ -38428,8 +38504,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function checkImportBinding(node: ImportEqualsDeclaration | ImportClause | NamespaceImport | ImportSpecifier) {
|
||||
checkCollisionWithRequireExportsInGeneratedCode(node, node.name!);
|
||||
checkCollisionWithGlobalPromiseInGeneratedCode(node, node.name!);
|
||||
checkCollisionsForDeclarationName(node, node.name);
|
||||
checkAliasSymbol(node);
|
||||
if (node.kind === SyntaxKind.ImportSpecifier &&
|
||||
idText(node.propertyName || node.name) === "default" &&
|
||||
@@ -39147,6 +39222,7 @@ namespace ts {
|
||||
clear(potentialThisCollisions);
|
||||
clear(potentialNewTargetCollisions);
|
||||
clear(potentialWeakMapSetCollisions);
|
||||
clear(potentialReflectCollisions);
|
||||
|
||||
forEach(node.statements, checkSourceElement);
|
||||
checkSourceElement(node.endOfFileToken);
|
||||
@@ -39191,6 +39267,11 @@ namespace ts {
|
||||
clear(potentialWeakMapSetCollisions);
|
||||
}
|
||||
|
||||
if (potentialReflectCollisions.length) {
|
||||
forEach(potentialReflectCollisions, checkReflectCollision);
|
||||
clear(potentialReflectCollisions);
|
||||
}
|
||||
|
||||
links.flags |= NodeCheckFlags.TypeChecked;
|
||||
}
|
||||
}
|
||||
@@ -40303,7 +40384,9 @@ namespace ts {
|
||||
}
|
||||
|
||||
function getNodeCheckFlags(node: Node): NodeCheckFlags {
|
||||
return getNodeLinks(node).flags || 0;
|
||||
const nodeId = node.id || 0;
|
||||
if (nodeId < 0 || nodeId >= nodeLinks.length) return 0;
|
||||
return nodeLinks[nodeId]?.flags || 0;
|
||||
}
|
||||
|
||||
function getEnumMemberValue(node: EnumMember): string | number | undefined {
|
||||
|
||||
@@ -3352,6 +3352,10 @@
|
||||
"category": "Error",
|
||||
"code": 2817
|
||||
},
|
||||
"Duplicate identifier '{0}'. Compiler reserves name '{1}' when emitting 'super' references in static initializers.": {
|
||||
"category": "Error",
|
||||
"code": 2818
|
||||
},
|
||||
|
||||
"Import declaration '{0}' is using private name '{1}'.": {
|
||||
"category": "Error",
|
||||
|
||||
@@ -4983,29 +4983,30 @@ namespace ts {
|
||||
|
||||
/* @internal */
|
||||
export const enum NodeCheckFlags {
|
||||
TypeChecked = 0x00000001, // Node has been type checked
|
||||
LexicalThis = 0x00000002, // Lexical 'this' reference
|
||||
CaptureThis = 0x00000004, // Lexical 'this' used in body
|
||||
CaptureNewTarget = 0x00000008, // Lexical 'new.target' used in body
|
||||
SuperInstance = 0x00000100, // Instance 'super' reference
|
||||
SuperStatic = 0x00000200, // Static 'super' reference
|
||||
ContextChecked = 0x00000400, // Contextual types have been assigned
|
||||
AsyncMethodWithSuper = 0x00000800, // An async method that reads a value from a member of 'super'.
|
||||
AsyncMethodWithSuperBinding = 0x00001000, // An async method that assigns a value to a member of 'super'.
|
||||
CaptureArguments = 0x00002000, // Lexical 'arguments' used in body
|
||||
EnumValuesComputed = 0x00004000, // Values for enum members have been computed, and any errors have been reported for them.
|
||||
LexicalModuleMergesWithClass = 0x00008000, // Instantiated lexical module declaration is merged with a previous class declaration.
|
||||
LoopWithCapturedBlockScopedBinding = 0x00010000, // Loop that contains block scoped variable captured in closure
|
||||
ContainsCapturedBlockScopeBinding = 0x00020000, // Part of a loop that contains block scoped variable captured in closure
|
||||
CapturedBlockScopedBinding = 0x00040000, // Block-scoped binding that is captured in some function
|
||||
BlockScopedBindingInLoop = 0x00080000, // Block-scoped binding with declaration nested inside iteration statement
|
||||
ClassWithBodyScopedClassBinding = 0x00100000, // Decorated class that contains a binding to itself inside of the class body.
|
||||
BodyScopedClassBinding = 0x00200000, // Binding to a decorated class inside of the class's body.
|
||||
NeedsLoopOutParameter = 0x00400000, // Block scoped binding whose value should be explicitly copied outside of the converted loop
|
||||
AssignmentsMarked = 0x00800000, // Parameter assignments have been marked
|
||||
ClassWithConstructorReference = 0x01000000, // Class that contains a binding to its constructor inside of the class body.
|
||||
ConstructorReferenceInClass = 0x02000000, // Binding to a class constructor inside of the class's body.
|
||||
ContainsClassWithPrivateIdentifiers = 0x04000000, // Marked on all block-scoped containers containing a class with private identifiers.
|
||||
TypeChecked = 0x00000001, // Node has been type checked
|
||||
LexicalThis = 0x00000002, // Lexical 'this' reference
|
||||
CaptureThis = 0x00000004, // Lexical 'this' used in body
|
||||
CaptureNewTarget = 0x00000008, // Lexical 'new.target' used in body
|
||||
SuperInstance = 0x00000100, // Instance 'super' reference
|
||||
SuperStatic = 0x00000200, // Static 'super' reference
|
||||
ContextChecked = 0x00000400, // Contextual types have been assigned
|
||||
AsyncMethodWithSuper = 0x00000800, // An async method that reads a value from a member of 'super'.
|
||||
AsyncMethodWithSuperBinding = 0x00001000, // An async method that assigns a value to a member of 'super'.
|
||||
CaptureArguments = 0x00002000, // Lexical 'arguments' used in body
|
||||
EnumValuesComputed = 0x00004000, // Values for enum members have been computed, and any errors have been reported for them.
|
||||
LexicalModuleMergesWithClass = 0x00008000, // Instantiated lexical module declaration is merged with a previous class declaration.
|
||||
LoopWithCapturedBlockScopedBinding = 0x00010000, // Loop that contains block scoped variable captured in closure
|
||||
ContainsCapturedBlockScopeBinding = 0x00020000, // Part of a loop that contains block scoped variable captured in closure
|
||||
CapturedBlockScopedBinding = 0x00040000, // Block-scoped binding that is captured in some function
|
||||
BlockScopedBindingInLoop = 0x00080000, // Block-scoped binding with declaration nested inside iteration statement
|
||||
ClassWithBodyScopedClassBinding = 0x00100000, // Decorated class that contains a binding to itself inside of the class body.
|
||||
BodyScopedClassBinding = 0x00200000, // Binding to a decorated class inside of the class's body.
|
||||
NeedsLoopOutParameter = 0x00400000, // Block scoped binding whose value should be explicitly copied outside of the converted loop
|
||||
AssignmentsMarked = 0x00800000, // Parameter assignments have been marked
|
||||
ClassWithConstructorReference = 0x01000000, // Class that contains a binding to its constructor inside of the class body.
|
||||
ConstructorReferenceInClass = 0x02000000, // Binding to a class constructor inside of the class's body.
|
||||
ContainsClassWithPrivateIdentifiers = 0x04000000, // Marked on all block-scoped containers containing a class with private identifiers.
|
||||
ContainsSuperPropertyInStaticInitializer = 0x08000000, // Marked on all block-scoped containers containing a static initializer with 'super.x' or 'super[x]'.
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
|
||||
@@ -285,7 +285,6 @@ namespace ts {
|
||||
case SyntaxKind.ForStatement:
|
||||
case SyntaxKind.ForInStatement:
|
||||
case SyntaxKind.ForOfStatement:
|
||||
case SyntaxKind.ClassStaticBlockDeclaration:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -833,7 +832,7 @@ namespace ts {
|
||||
return false;
|
||||
}
|
||||
|
||||
export function isBlockScope(node: Node, parentNode: Node): boolean {
|
||||
export function isBlockScope(node: Node, parentNode: Node | undefined): boolean {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.SourceFile:
|
||||
case SyntaxKind.CaseBlock:
|
||||
@@ -849,6 +848,8 @@ namespace ts {
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
case SyntaxKind.FunctionExpression:
|
||||
case SyntaxKind.ArrowFunction:
|
||||
case SyntaxKind.PropertyDeclaration:
|
||||
case SyntaxKind.ClassStaticBlockDeclaration:
|
||||
return true;
|
||||
|
||||
case SyntaxKind.Block:
|
||||
@@ -943,6 +944,14 @@ namespace ts {
|
||||
return findAncestor(node.parent, current => isBlockScope(current, current.parent))!;
|
||||
}
|
||||
|
||||
export function forEachEnclosingBlockScopeContainer(node: Node, cb: (container: Node) => void): void {
|
||||
let container = getEnclosingBlockScopeContainer(node);
|
||||
while (container) {
|
||||
cb(container);
|
||||
container = getEnclosingBlockScopeContainer(container);
|
||||
}
|
||||
}
|
||||
|
||||
// Return display name of an identifier
|
||||
// Computed property names will just be emitted as "[<expr>]", where <expr> is the source
|
||||
// text of the expression in the computed property.
|
||||
@@ -1114,6 +1123,7 @@ namespace ts {
|
||||
case SyntaxKind.TypeAliasDeclaration:
|
||||
case SyntaxKind.PropertyDeclaration:
|
||||
case SyntaxKind.PropertySignature:
|
||||
case SyntaxKind.NamespaceImport:
|
||||
errorNode = (node as NamedDeclaration).name;
|
||||
break;
|
||||
case SyntaxKind.ArrowFunction:
|
||||
|
||||
Reference in New Issue
Block a user