Change static fields emits (#43114)

* use emit into iife

* Update emit

* Revert un-related changes

* Allow super in static context

* Allow this and super in static property declaration

* Add more tests

* Avoid errors

* Accept baseline

* Accept baseline

* Add decorated classes test

* Add errors

* Avoid this in emitter

* make lint happy

* Add class expression tests

* Add computed name test

* Avoid super if target below es6

* Adjust function boundary

* Add internal

* Fix minor CR issues

* accept baseline

* Update behavior

* Avoid spaces

* Make lint happy

* Avoid function boundary utils

* Update baseline

* Avoid errors

* Accept baseline

* Accept baseline

* Accept baseline

* Accept baseline

* Use substitutions

* Full coverage for super, this, merge static and private context

* Fix use-before-def in static fields

Co-authored-by: Ron Buckton <ron.buckton@microsoft.com>
This commit is contained in:
Wenlu Wang
2021-06-25 15:49:27 -07:00
committed by GitHub
co-authored by Ron Buckton
parent 328e888a9d
commit dc237b317e
215 changed files with 9185 additions and 782 deletions
+7 -7
View File
@@ -669,7 +669,7 @@ namespace ts {
}
// We create a return control flow graph for IIFEs and constructors. For constructors
// we use the return control flow graph in strict property initialization checks.
currentReturnTarget = isIIFE || node.kind === SyntaxKind.Constructor || (isInJSFile(node) && (node.kind === SyntaxKind.FunctionDeclaration || node.kind === SyntaxKind.FunctionExpression)) ? createBranchLabel() : undefined;
currentReturnTarget = isIIFE || node.kind === SyntaxKind.Constructor || node.kind === SyntaxKind.ClassStaticBlockDeclaration || (isInJSFile(node) && (node.kind === SyntaxKind.FunctionDeclaration || node.kind === SyntaxKind.FunctionExpression)) ? createBranchLabel() : undefined;
currentExceptionTarget = undefined;
currentBreakTarget = undefined;
currentContinueTarget = undefined;
@@ -678,10 +678,10 @@ namespace ts {
bindChildren(node);
// Reset all reachability check related flags on node (for incremental scenarios)
node.flags &= ~NodeFlags.ReachabilityAndEmitFlags;
if (!(currentFlow.flags & FlowFlags.Unreachable) && containerFlags & ContainerFlags.IsFunctionLike && nodeIsPresent((node as FunctionLikeDeclaration).body)) {
if (!(currentFlow.flags & FlowFlags.Unreachable) && containerFlags & ContainerFlags.IsFunctionLike && nodeIsPresent((node as FunctionLikeDeclaration | ClassStaticBlockDeclaration).body)) {
node.flags |= NodeFlags.HasImplicitReturn;
if (hasExplicitReturn) node.flags |= NodeFlags.HasExplicitReturn;
(node as FunctionLikeDeclaration).endFlowNode = currentFlow;
(node as FunctionLikeDeclaration | ClassStaticBlockDeclaration).endFlowNode = currentFlow;
}
if (node.kind === SyntaxKind.SourceFile) {
node.flags |= emitFlags;
@@ -691,8 +691,8 @@ namespace ts {
if (currentReturnTarget) {
addAntecedent(currentReturnTarget, currentFlow);
currentFlow = finishFlowLabel(currentReturnTarget);
if (node.kind === SyntaxKind.Constructor || (isInJSFile(node) && (node.kind === SyntaxKind.FunctionDeclaration || node.kind === SyntaxKind.FunctionExpression))) {
(node as FunctionLikeDeclaration).returnFlowNode = currentFlow;
if (node.kind === SyntaxKind.Constructor || node.kind === SyntaxKind.ClassStaticBlockDeclaration || (isInJSFile(node) && (node.kind === SyntaxKind.FunctionDeclaration || node.kind === SyntaxKind.FunctionExpression))) {
(node as FunctionLikeDeclaration | ClassStaticBlockDeclaration).returnFlowNode = currentFlow;
}
}
if (!isIIFE) {
@@ -1944,7 +1944,7 @@ namespace ts {
}
function declareClassMember(node: Declaration, symbolFlags: SymbolFlags, symbolExcludes: SymbolFlags) {
return hasSyntacticModifier(node, ModifierFlags.Static)
return isStatic(node)
? declareSymbol(container.symbol.exports!, container.symbol, node, symbolFlags, symbolExcludes)
: declareSymbol(container.symbol.members!, container.symbol, node, symbolFlags, symbolExcludes);
}
@@ -2950,7 +2950,7 @@ namespace ts {
// this.foo assignment in a JavaScript class
// Bind this property to the containing class
const containingClass = thisContainer.parent;
const symbolTable = hasSyntacticModifier(thisContainer, ModifierFlags.Static) ? containingClass.symbol.exports! : containingClass.symbol.members!;
const symbolTable = isStatic(thisContainer) ? containingClass.symbol.exports! : containingClass.symbol.members!;
if (hasDynamicName(node)) {
bindDynamicallyNamedThisPropertyAssignment(node, containingClass.symbol, symbolTable);
}
+136 -75
View File
@@ -1579,21 +1579,34 @@ namespace ts {
if (isFunctionLike(current)) {
return true;
}
if (isClassStaticBlockDeclaration(current)) {
return declaration.pos < usage.pos;
}
const initializerOfProperty = current.parent &&
current.parent.kind === SyntaxKind.PropertyDeclaration &&
(current.parent as PropertyDeclaration).initializer === current;
if (initializerOfProperty) {
if (hasSyntacticModifier(current.parent, ModifierFlags.Static)) {
if (declaration.kind === SyntaxKind.MethodDeclaration) {
return true;
const propertyDeclaration = tryCast(current.parent, isPropertyDeclaration);
if (propertyDeclaration) {
const initializerOfProperty = propertyDeclaration.initializer === current;
if (initializerOfProperty) {
if (isStatic(current.parent)) {
if (declaration.kind === SyntaxKind.MethodDeclaration) {
return true;
}
if (isPropertyDeclaration(declaration) && getContainingClass(usage) === getContainingClass(declaration)) {
const propName = declaration.name;
if (isIdentifier(propName) || isPrivateIdentifier(propName)) {
const type = getTypeOfSymbol(getSymbolOfNode(declaration));
const staticBlocks = filter(declaration.parent.members, isClassStaticBlockDeclaration);
if (isPropertyInitializedInStaticBlocks(propName, type, staticBlocks, declaration.parent.pos, current.pos)) {
return true;
}
}
}
}
}
else {
const isDeclarationInstanceProperty = declaration.kind === SyntaxKind.PropertyDeclaration && !hasSyntacticModifier(declaration, ModifierFlags.Static);
if (!isDeclarationInstanceProperty || getContainingClass(usage) !== getContainingClass(declaration)) {
return true;
else {
const isDeclarationInstanceProperty = declaration.kind === SyntaxKind.PropertyDeclaration && !isStatic(declaration);
if (!isDeclarationInstanceProperty || getContainingClass(usage) !== getContainingClass(declaration)) {
return true;
}
}
}
}
@@ -1857,7 +1870,7 @@ namespace ts {
// local variables of the constructor. This effectively means that entities from outer scopes
// by the same name as a constructor parameter or local variable are inaccessible
// in initializer expressions for instance member variables.
if (!hasSyntacticModifier(location, ModifierFlags.Static)) {
if (!isStatic(location)) {
const ctor = findConstructorDeclaration(location.parent as ClassLikeDeclaration);
if (ctor && ctor.locals) {
if (lookup(ctor.locals, name, meaning & SymbolFlags.Value)) {
@@ -1879,7 +1892,7 @@ namespace ts {
result = undefined;
break;
}
if (lastLocation && hasSyntacticModifier(lastLocation, ModifierFlags.Static)) {
if (lastLocation && isStatic(lastLocation)) {
// TypeScript 1.0 spec (April 2014): 3.4.1
// The scope of a type parameter extends over the entire declaration with which the type
// parameter list is associated, with the exception of static member declarations in classes.
@@ -2189,7 +2202,7 @@ namespace ts {
// initializers in instance property declaration of class like entities are executed in constructor and thus deferred
return isTypeQueryNode(location) || ((
isFunctionLikeDeclaration(location) ||
(location.kind === SyntaxKind.PropertyDeclaration && !hasSyntacticModifier(location, ModifierFlags.Static))
(location.kind === SyntaxKind.PropertyDeclaration && !isStatic(location))
) && (!lastLocation || lastLocation !== (location as SignatureDeclaration | PropertyDeclaration).name)); // A name is evaluated within the enclosing scope - so it shouldn't count as deferred
}
if (lastLocation && lastLocation === (location as FunctionExpression | ArrowFunction).name) {
@@ -2258,7 +2271,7 @@ namespace ts {
// No static member is present.
// Check if we're in an instance method and look for a relevant instance member.
if (location === container && !hasSyntacticModifier(location, ModifierFlags.Static)) {
if (location === container && !isStatic(location)) {
const instanceType = (getDeclaredTypeOfSymbol(classSymbol) as InterfaceType).thisType!; // TODO: GH#18217
if (getPropertyOfType(instanceType, name)) {
error(errorLocation, Diagnostics.Cannot_find_name_0_Did_you_mean_the_instance_member_this_0, diagnosticName(nameArg));
@@ -4855,7 +4868,7 @@ namespace ts {
}
function shouldWriteTypeOfFunctionSymbol() {
const isStaticMethodSymbol = !!(symbol.flags & SymbolFlags.Method) && // typeof static method
some(symbol.declarations, declaration => hasSyntacticModifier(declaration, ModifierFlags.Static));
some(symbol.declarations, declaration => isStatic(declaration));
const isNonLocalFunctionSymbol = !!(symbol.flags & SymbolFlags.Function) &&
(symbol.parent || // is exported function symbol
forEach(symbol.declarations, declaration =>
@@ -7008,7 +7021,7 @@ namespace ts {
function isNamespaceMember(p: Symbol) {
return !!(p.flags & (SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Alias)) ||
!(p.flags & SymbolFlags.Prototype || p.escapedName === "prototype" || p.valueDeclaration && getEffectiveModifierFlags(p.valueDeclaration) & ModifierFlags.Static && isClassLike(p.valueDeclaration.parent));
!(p.flags & SymbolFlags.Prototype || p.escapedName === "prototype" || p.valueDeclaration && isStatic(p.valueDeclaration) && isClassLike(p.valueDeclaration.parent));
}
function sanitizeJSDocImplements(clauses: readonly ExpressionWithTypeArguments[]): ExpressionWithTypeArguments[] | undefined {
@@ -8448,14 +8461,23 @@ namespace ts {
return addOptionality(type, isProperty, isOptional);
}
if (isPropertyDeclaration(declaration) && !hasStaticModifier(declaration) && (noImplicitAny || isInJSFile(declaration))) {
if (isPropertyDeclaration(declaration) && (noImplicitAny || isInJSFile(declaration))) {
// We have a property declaration with no type annotation or initializer, in noImplicitAny mode or a .js file.
// Use control flow analysis of this.xxx assignments in the constructor to determine the type of the property.
const constructor = findConstructorDeclaration(declaration.parent);
const type = constructor ? getFlowTypeInConstructor(declaration.symbol, constructor) :
getEffectiveModifierFlags(declaration) & ModifierFlags.Ambient ? getTypeOfPropertyInBaseClass(declaration.symbol) :
undefined;
return type && addOptionality(type, /*isProperty*/ true, isOptional);
// Use control flow analysis of this.xxx assignments in the constructor or static block to determine the type of the property.
if (!hasStaticModifier(declaration)) {
const constructor = findConstructorDeclaration(declaration.parent);
const type = constructor ? getFlowTypeInConstructor(declaration.symbol, constructor) :
getEffectiveModifierFlags(declaration) & ModifierFlags.Ambient ? getTypeOfPropertyInBaseClass(declaration.symbol) :
undefined;
return type && addOptionality(type, /*isProperty*/ true, isOptional);
}
else {
const staticBlocks = filter(declaration.parent.members, isClassStaticBlockDeclaration);
const type = staticBlocks.length ? getFlowTypeInStaticBlocks(declaration.symbol, staticBlocks) :
getEffectiveModifierFlags(declaration) & ModifierFlags.Ambient ? getTypeOfPropertyInBaseClass(declaration.symbol) :
undefined;
return type && addOptionality(type, /*isProperty*/ true, isOptional);
}
}
if (isJsxAttribute(declaration)) {
@@ -8530,6 +8552,27 @@ namespace ts {
return getFlowTypeOfReference(reference, autoType, undefinedType);
}
function getFlowTypeInStaticBlocks(symbol: Symbol, staticBlocks: readonly ClassStaticBlockDeclaration[]) {
const accessName = startsWith(symbol.escapedName as string, "__#")
? factory.createPrivateIdentifier((symbol.escapedName as string).split("@")[1])
: unescapeLeadingUnderscores(symbol.escapedName);
for (const staticBlock of staticBlocks) {
const reference = factory.createPropertyAccessExpression(factory.createThis(), accessName);
setParent(reference.expression, reference);
setParent(reference, staticBlock);
reference.flowNode = staticBlock.returnFlowNode;
const flowType = getFlowTypeOfProperty(reference, symbol);
if (noImplicitAny && (flowType === autoType || flowType === autoArrayType)) {
error(symbol.valueDeclaration, Diagnostics.Member_0_implicitly_has_an_1_type, symbolToString(symbol), typeToString(flowType));
}
// We don't infer a type if assignments are only null or undefined.
if (everyType(flowType, isNullableType)) {
continue;
}
return convertAutoToAny(flowType);
}
}
function getFlowTypeInConstructor(symbol: Symbol, constructor: ConstructorDeclaration) {
const accessName = startsWith(symbol.escapedName as string, "__#")
? factory.createPrivateIdentifier((symbol.escapedName as string).split("@")[1])
@@ -10131,7 +10174,7 @@ namespace ts {
}
function isStaticPrivateIdentifierProperty(s: Symbol): boolean {
return !!s.valueDeclaration && isPrivateIdentifierClassElementDeclaration(s.valueDeclaration) && hasSyntacticModifier(s.valueDeclaration, ModifierFlags.Static);
return !!s.valueDeclaration && isPrivateIdentifierClassElementDeclaration(s.valueDeclaration) && isStatic(s.valueDeclaration);
}
function resolveDeclaredMembers(type: InterfaceType): InterfaceTypeWithDeclaredMembers {
@@ -15617,7 +15660,7 @@ namespace ts {
const container = getThisContainer(node, /*includeArrowFunctions*/ false);
const parent = container && container.parent;
if (parent && (isClassLike(parent) || parent.kind === SyntaxKind.InterfaceDeclaration)) {
if (!hasSyntacticModifier(container, ModifierFlags.Static) &&
if (!isStatic(container) &&
(!isConstructorDeclaration(container) || isNodeDescendantOf(node, container.body))) {
return getDeclaredTypeOfClassOrInterface(getSymbolOfNode(parent as ClassLikeDeclaration | InterfaceDeclaration)).thisType!;
}
@@ -24298,7 +24341,7 @@ namespace ts {
let container = getThisContainer(node, /*includeArrowFunctions*/ false);
while (container.kind !== SyntaxKind.SourceFile) {
if (container.parent === declaration) {
if (container.kind === SyntaxKind.PropertyDeclaration && hasSyntacticModifier(container, ModifierFlags.Static)) {
if (container.kind === SyntaxKind.PropertyDeclaration && isStatic(container)) {
getNodeLinks(declaration).flags |= NodeCheckFlags.ClassWithConstructorReference;
getNodeLinks(node).flags |= NodeCheckFlags.ConstructorReferenceInClass;
}
@@ -24561,6 +24604,13 @@ namespace ts {
}
}
function checkThisInStaticClassFieldInitializerInDecoratedClass(thisExpression: Node, container: Node) {
if (isPropertyDeclaration(container) && hasStaticModifier(container) &&
container.initializer && textRangeContainsPositionInclusive(container.initializer, thisExpression.pos) && length(container.parent.decorators)) {
error(thisExpression, Diagnostics.Cannot_use_this_in_a_static_property_initializer_of_a_decorated_class);
}
}
function checkThisExpression(node: Node): Type {
const isNodeInTypeQuery = isInTypeQuery(node);
// Stop at the first arrow function so that we can
@@ -24578,6 +24628,7 @@ namespace ts {
capturedByArrowFunction = true;
}
checkThisInStaticClassFieldInitializerInDecoratedClass(node, container);
switch (container.kind) {
case SyntaxKind.ModuleDeclaration:
error(node, Diagnostics.this_cannot_be_referenced_in_a_module_or_namespace_body);
@@ -24593,16 +24644,6 @@ namespace ts {
// do not return here so in case if lexical this is captured - it will be reflected in flags on NodeLinks
}
break;
case SyntaxKind.PropertyDeclaration:
case SyntaxKind.PropertySignature:
if (hasSyntacticModifier(container, ModifierFlags.Static) && !(compilerOptions.target === ScriptTarget.ESNext && useDefineForClassFields)) {
error(node, Diagnostics.this_cannot_be_referenced_in_a_static_property_initializer);
// do not return here so in case if lexical this is captured - it will be reflected in flags on NodeLinks
}
break;
case SyntaxKind.ClassStaticBlockDeclaration:
error(node, Diagnostics.this_cannot_be_referenced_in_current_location);
break;
case SyntaxKind.ComputedPropertyName:
error(node, Diagnostics.this_cannot_be_referenced_in_a_computed_property_name);
break;
@@ -24661,8 +24702,7 @@ namespace ts {
if (isClassLike(container.parent)) {
const symbol = getSymbolOfNode(container.parent);
const isStatic = hasSyntacticModifier(container, ModifierFlags.Static) || isClassStaticBlockDeclaration(container);
const type = isStatic ? getTypeOfSymbol(symbol) : (getDeclaredTypeOfSymbol(symbol) as InterfaceType).thisType!;
const type = isStatic(container) ? getTypeOfSymbol(symbol) : (getDeclaredTypeOfSymbol(symbol) as InterfaceType).thisType!;
return getFlowTypeOfReference(node, type);
}
@@ -24692,7 +24732,7 @@ namespace ts {
}
if (isClassLike(container.parent)) {
const symbol = getSymbolOfNode(container.parent);
return hasSyntacticModifier(container, ModifierFlags.Static) ? getTypeOfSymbol(symbol) : (getDeclaredTypeOfSymbol(symbol) as InterfaceType).thisType!;
return isStatic(container) ? getTypeOfSymbol(symbol) : (getDeclaredTypeOfSymbol(symbol) as InterfaceType).thisType!;
}
}
@@ -24813,7 +24853,7 @@ namespace ts {
checkThisBeforeSuper(node, container, Diagnostics.super_must_be_called_before_accessing_a_property_of_super_in_the_constructor_of_a_derived_class);
}
if (hasSyntacticModifier(container, ModifierFlags.Static) || isCallExpression) {
if (isStatic(container) || isCallExpression) {
nodeCheckFlag = NodeCheckFlags.SuperStatic;
}
else {
@@ -24949,11 +24989,13 @@ namespace ts {
// topmost container must be something that is directly nested in the class declaration\object literal expression
if (isClassLike(container.parent) || container.parent.kind === SyntaxKind.ObjectLiteralExpression) {
if (hasSyntacticModifier(container, ModifierFlags.Static)) {
if (isStatic(container)) {
return container.kind === SyntaxKind.MethodDeclaration ||
container.kind === SyntaxKind.MethodSignature ||
container.kind === SyntaxKind.GetAccessor ||
container.kind === SyntaxKind.SetAccessor;
container.kind === SyntaxKind.SetAccessor ||
container.kind === SyntaxKind.PropertyDeclaration ||
container.kind === SyntaxKind.ClassStaticBlockDeclaration;
}
else {
return container.kind === SyntaxKind.MethodDeclaration ||
@@ -25092,7 +25134,7 @@ namespace ts {
case SyntaxKind.BindingElement:
return getContextualTypeForBindingElement(declaration);
case SyntaxKind.PropertyDeclaration:
if (hasSyntacticModifier(declaration, ModifierFlags.Static)) {
if (isStatic(declaration)) {
return getContextualTypeForStaticPropertyDeclaration(declaration);
}
// By default, do nothing and return undefined - only the above cases have context implied by a parent
@@ -27595,10 +27637,12 @@ namespace ts {
let assumeUninitialized = false;
if (strictNullChecks && strictPropertyInitialization && isAccessExpression(node) && node.expression.kind === SyntaxKind.ThisKeyword) {
const declaration = prop && prop.valueDeclaration;
if (declaration && isInstancePropertyWithoutInitializer(declaration)) {
const flowContainer = getControlFlowContainer(node);
if (flowContainer.kind === SyntaxKind.Constructor && flowContainer.parent === declaration.parent && !(declaration.flags & NodeFlags.Ambient)) {
assumeUninitialized = true;
if (declaration && isPropertyWithoutInitializer(declaration)) {
if (!isStatic(declaration)) {
const flowContainer = getControlFlowContainer(node);
if (flowContainer.kind === SyntaxKind.Constructor && flowContainer.parent === declaration.parent && !(declaration.flags & NodeFlags.Ambient)) {
assumeUninitialized = true;
}
}
}
}
@@ -27764,7 +27808,7 @@ namespace ts {
function typeHasStaticProperty(propName: __String, containingType: Type): boolean {
const prop = containingType.symbol && getPropertyOfType(getTypeOfSymbol(containingType.symbol), propName);
return prop !== undefined && !!prop.valueDeclaration && hasSyntacticModifier(prop.valueDeclaration, ModifierFlags.Static);
return prop !== undefined && !!prop.valueDeclaration && isStatic(prop.valueDeclaration);
}
function getSuggestedLibForNonExistentName(name: __String | Identifier) {
@@ -33328,16 +33372,16 @@ namespace ts {
}
}
else {
const isStatic = hasSyntacticModifier(member, ModifierFlags.Static);
const isStaticMember = isStatic(member);
const name = member.name;
if (!name) {
continue;
}
const isPrivate = isPrivateIdentifier(name);
const privateStaticFlags = isPrivate && isStatic ? DeclarationMeaning.PrivateStatic : 0;
const privateStaticFlags = isPrivate && isStaticMember ? DeclarationMeaning.PrivateStatic : 0;
const names =
isPrivate ? privateIdentifiers :
isStatic ? staticNames :
isStaticMember ? staticNames :
instanceNames;
const memberName = name && getPropertyNameForPropertyNameNode(name);
@@ -33407,8 +33451,8 @@ namespace ts {
function checkClassForStaticPropertyNameConflicts(node: ClassLikeDeclaration) {
for (const member of node.members) {
const memberNameNode = member.name;
const isStatic = hasSyntacticModifier(member, ModifierFlags.Static);
if (isStatic && memberNameNode) {
const isStaticMember = isStatic(member);
if (isStaticMember && memberNameNode) {
const memberName = getPropertyNameForPropertyNameNode(memberNameNode);
switch (memberName) {
case "name":
@@ -33590,7 +33634,7 @@ namespace ts {
return true;
}
return n.kind === SyntaxKind.PropertyDeclaration &&
!hasSyntacticModifier(n, ModifierFlags.Static) &&
!isStatic(n) &&
!!(n as PropertyDeclaration).initializer;
}
@@ -34075,13 +34119,13 @@ namespace ts {
)) {
const reportError =
(node.kind === SyntaxKind.MethodDeclaration || node.kind === SyntaxKind.MethodSignature) &&
hasSyntacticModifier(node, ModifierFlags.Static) !== hasSyntacticModifier(subsequentNode, ModifierFlags.Static);
isStatic(node) !== isStatic(subsequentNode);
// we can get here in two cases
// 1. mixed static and instance class members
// 2. something with the same name was defined before the set of overloads that prevents them from merging
// here we'll report error only for the first case since for second we should already report error in binder
if (reportError) {
const diagnostic = hasSyntacticModifier(node, ModifierFlags.Static) ? Diagnostics.Function_overload_must_be_static : Diagnostics.Function_overload_must_not_be_static;
const diagnostic = isStatic(node) ? Diagnostics.Function_overload_must_be_static : Diagnostics.Function_overload_must_not_be_static;
error(errorNode, diagnostic);
}
return;
@@ -37053,13 +37097,13 @@ namespace ts {
}
}
function checkIndexConstraints(type: Type, isStatic?: boolean) {
function checkIndexConstraints(type: Type, isStaticIndex?: boolean) {
const indexInfos = getIndexInfosOfType(type);
if (indexInfos.length === 0) {
return;
}
for (const prop of getPropertiesOfObjectType(type)) {
if (!(isStatic && prop.flags & SymbolFlags.Prototype)) {
if (!(isStaticIndex && prop.flags & SymbolFlags.Prototype)) {
checkIndexConstraintForProperty(type, prop, getLiteralTypeFromProperty(prop, TypeFlags.StringOrNumberLiteralOrUnique, /*includeNonPublic*/ true), getNonMissingTypeOfSymbol(prop));
}
}
@@ -37068,7 +37112,7 @@ namespace ts {
for (const member of typeDeclaration.members) {
// Only process instance properties with computed names here. Static properties cannot be in conflict with indexers,
// and properties with literal names were already checked.
if (!hasSyntacticModifier(member, ModifierFlags.Static) && !hasBindableName(member)) {
if (!isStatic(member) && !hasBindableName(member)) {
const symbol = getSymbolOfNode(member);
checkIndexConstraintForProperty(type, symbol, getTypeOfExpression((member as DynamicNamedDeclaration).name.expression), getNonMissingTypeOfSymbol(symbol));
}
@@ -37412,7 +37456,7 @@ namespace ts {
if (produceDiagnostics) {
checkIndexConstraints(type);
checkIndexConstraints(staticType, /*isStatic*/ true);
checkIndexConstraints(staticType, /*isStaticIndex*/ true);
checkTypeForDuplicateIndexSignatures(node);
checkPropertyInitialization(node);
}
@@ -37442,7 +37486,7 @@ namespace ts {
function checkClassMember(member: ClassElement | ParameterPropertyDeclaration, memberIsParameterProperty?: boolean) {
const hasOverride = hasOverrideModifier(member);
const hasStatic = hasStaticModifier(member);
const hasStatic = isStatic(member);
if (baseWithThis && (hasOverride || compilerOptions.noImplicitOverride)) {
const declaredProp = member.name && getSymbolAtLocation(member.name) || getSymbolAtLocation(member);
if (!declaredProp) {
@@ -37489,7 +37533,7 @@ namespace ts {
// iterate over all implemented properties and issue errors on each one which isn't compatible, rather than the class as a whole, if possible
let issuedMemberError = false;
for (const member of node.members) {
if (hasStaticModifier(member)) {
if (isStatic(member)) {
continue;
}
const declaredProp = member.name && getSymbolAtLocation(member.name) || getSymbolAtLocation(member);
@@ -37745,7 +37789,7 @@ namespace ts {
if (getEffectiveModifierFlags(member) & ModifierFlags.Ambient) {
continue;
}
if (isInstancePropertyWithoutInitializer(member)) {
if (!isStatic(member) && isPropertyWithoutInitializer(member)) {
const propName = (member as PropertyDeclaration).name;
if (isIdentifier(propName) || isPrivateIdentifier(propName)) {
const type = getTypeOfSymbol(getSymbolOfNode(member));
@@ -37759,13 +37803,30 @@ namespace ts {
}
}
function isInstancePropertyWithoutInitializer(node: Node) {
function isPropertyWithoutInitializer(node: Node) {
return node.kind === SyntaxKind.PropertyDeclaration &&
!hasSyntacticModifier(node, ModifierFlags.Static | ModifierFlags.Abstract) &&
!hasAbstractModifier(node) &&
!(node as PropertyDeclaration).exclamationToken &&
!(node as PropertyDeclaration).initializer;
}
function isPropertyInitializedInStaticBlocks(propName: Identifier | PrivateIdentifier, propType: Type, staticBlocks: readonly ClassStaticBlockDeclaration[], startPos: number, endPos: number) {
for (const staticBlock of staticBlocks) {
// static block must be within the provided range as they are evaluated in document order (unlike constructors)
if (staticBlock.pos >= startPos && staticBlock.pos <= endPos) {
const reference = factory.createPropertyAccessExpression(factory.createThis(), propName);
setParent(reference.expression, reference);
setParent(reference, staticBlock);
reference.flowNode = staticBlock.returnFlowNode;
const flowType = getFlowTypeOfReference(reference, propType, getOptionalType(propType));
if (!(getFalsyFlags(flowType) & TypeFlags.Undefined)) {
return true;
}
}
}
return false;
}
function isPropertyInitializedInConstructor(propName: Identifier | PrivateIdentifier, propType: Type, constructor: ConstructorDeclaration) {
const reference = factory.createPropertyAccessExpression(factory.createThis(), propName);
setParent(reference.expression, reference);
@@ -39177,7 +39238,7 @@ namespace ts {
}
const symbols = createSymbolTable();
let isStatic = false;
let isStaticSymbol = false;
populateSymbols();
@@ -39215,7 +39276,7 @@ namespace ts {
// add the type parameters into the symbol table
// (type parameters of classDeclaration/classExpression and interface are in member property of the symbol.
// Note: that the memberFlags come from previous iteration.
if (!isStatic) {
if (!isStaticSymbol) {
copySymbols(getMembersOfSymbol(getSymbolOfNode(location as ClassDeclaration | InterfaceDeclaration)), meaning & SymbolFlags.Type);
}
break;
@@ -39231,7 +39292,7 @@ namespace ts {
copySymbol(argumentsSymbol, meaning);
}
isStatic = hasSyntacticModifier(location, ModifierFlags.Static);
isStaticSymbol = isStatic(location);
location = location.parent;
}
@@ -39830,7 +39891,7 @@ namespace ts {
*/
function getParentTypeOfClassElement(node: ClassElement) {
const classSymbol = getSymbolOfNode(node.parent)!;
return hasSyntacticModifier(node, ModifierFlags.Static)
return isStatic(node)
? getTypeOfSymbol(classSymbol)
: getDeclaredTypeOfSymbol(classSymbol);
}
@@ -41874,8 +41935,8 @@ namespace ts {
break;
case SyntaxKind.PropertyDeclaration:
if (!hasSyntacticModifier(parent, ModifierFlags.Static) ||
!hasEffectiveModifier(parent, ModifierFlags.Readonly)) {
if (!isStatic(parent) ||
!hasEffectiveReadonlyModifier(parent)) {
return grammarErrorOnNode((parent as PropertyDeclaration).name, Diagnostics.A_property_of_a_class_whose_type_is_a_unique_symbol_type_must_be_both_static_and_readonly);
}
break;
@@ -42292,7 +42353,7 @@ namespace ts {
}
if (isPropertyDeclaration(node) && node.exclamationToken && (!isClassLike(node.parent) || !node.type || node.initializer ||
node.flags & NodeFlags.Ambient || hasSyntacticModifier(node, ModifierFlags.Static | ModifierFlags.Abstract))) {
node.flags & NodeFlags.Ambient || isStatic(node) || hasAbstractModifier(node))) {
const message = node.initializer
? Diagnostics.Declarations_with_initializers_cannot_also_have_definite_assignment_assertions
: !node.type
+8
View File
@@ -3344,6 +3344,14 @@
"category": "Error",
"code": 2815
},
"Cannot use 'this' in a static property initializer of a decorated class.": {
"category": "Error",
"code": 2816
},
"Property '{0}' has no initializer and is not definitely assigned in a class static block.": {
"category": "Error",
"code": 2817
},
"Import declaration '{0}' is using private name '{1}'.": {
"category": "Error",
+52 -2
View File
@@ -496,8 +496,11 @@ namespace ts {
createArraySliceCall,
createArrayConcatCall,
createObjectDefinePropertyCall,
createReflectGetCall,
createReflectSetCall,
createPropertyDescriptor,
createCallBinding,
createAssignmentTargetWrapper,
// Utilities
inlineExpressions,
@@ -998,8 +1001,10 @@ namespace ts {
case SyntaxKind.UndefinedKeyword: // `undefined` is an Identifier in the expression case.
transformFlags = TransformFlags.ContainsTypeScript;
break;
case SyntaxKind.StaticKeyword:
case SyntaxKind.SuperKeyword:
transformFlags = TransformFlags.ContainsES2015 | TransformFlags.ContainsLexicalSuper;
break;
case SyntaxKind.StaticKeyword:
transformFlags = TransformFlags.ContainsES2015;
break;
case SyntaxKind.ThisKeyword:
@@ -2624,7 +2629,7 @@ namespace ts {
propagateChildFlags(node.equalsGreaterThanToken) |
TransformFlags.ContainsES2015;
if (modifiersToFlags(node.modifiers) & ModifierFlags.Async) {
node.transformFlags |= TransformFlags.ContainsES2017;
node.transformFlags |= TransformFlags.ContainsES2017 | TransformFlags.ContainsLexicalThis;
}
return node;
}
@@ -5435,6 +5440,15 @@ namespace ts {
}
function createMethodCall(object: Expression, methodName: string | Identifier, argumentsList: readonly Expression[]) {
// Preserve the optionality of `object`.
if (isCallChain(object)) {
return createCallChain(
createPropertyAccessChain(object, /*questionDotToken*/ undefined, methodName),
/*questionDotToken*/ undefined,
/*typeArguments*/ undefined,
argumentsList
);
}
return createCallExpression(
createPropertyAccessExpression(object, methodName),
/*typeArguments*/ undefined,
@@ -5470,6 +5484,14 @@ namespace ts {
return createGlobalMethodCall("Object", "defineProperty", [target, asExpression(propertyName), attributes]);
}
function createReflectGetCall(target: Expression, propertyKey: Expression, receiver?: Expression): CallExpression {
return createGlobalMethodCall("Reflect", "get", receiver ? [target, propertyKey, receiver] : [target, propertyKey]);
}
function createReflectSetCall(target: Expression, propertyKey: Expression, value: Expression, receiver?: Expression): CallExpression {
return createGlobalMethodCall("Reflect", "set", receiver ? [target, propertyKey, value, receiver] : [target, propertyKey, value]);
}
function tryAddPropertyAssignment(properties: Push<PropertyAssignment>, propertyName: string, expression: Expression | undefined) {
if (expression) {
properties.push(createPropertyAssignment(propertyName, expression));
@@ -5645,6 +5667,34 @@ namespace ts {
return { target, thisArg };
}
function createAssignmentTargetWrapper(paramName: Identifier, expression: Expression): LeftHandSideExpression {
return createPropertyAccessExpression(
// Explicit parens required because of v8 regression (https://bugs.chromium.org/p/v8/issues/detail?id=9560)
createParenthesizedExpression(
createObjectLiteralExpression([
createSetAccessorDeclaration(
/*decorators*/ undefined,
/*modifiers*/ undefined,
"value",
[createParameterDeclaration(
/*decorators*/ undefined,
/*modifiers*/ undefined,
/*dotDotDotToken*/ undefined,
paramName,
/*questionToken*/ undefined,
/*type*/ undefined,
/*initializer*/ undefined
)],
createBlock([
createExpressionStatement(expression)
])
)
])
),
"value"
);
}
function inlineExpressions(expressions: readonly Expression[]) {
// Avoid deeply nested comma expressions as traversing them during emit can result in "Maximum call
// stack size exceeded" errors.
+61
View File
@@ -303,6 +303,67 @@ namespace ts {
}
}
/**
* Expand the read and increment/decrement operations a pre- or post-increment or pre- or post-decrement expression.
*
* ```ts
* // input
* <expression>++
* // output (if result is not discarded)
* var <temp>;
* (<temp> = <expression>, <resultVariable> = <temp>++, <temp>)
* // output (if result is discarded)
* var <temp>;
* (<temp> = <expression>, <temp>++, <temp>)
*
* // input
* ++<expression>
* // output (if result is not discarded)
* var <temp>;
* (<temp> = <expression>, <resultVariable> = ++<temp>)
* // output (if result is discarded)
* var <temp>;
* (<temp> = <expression>, ++<temp>)
* ```
*
* It is up to the caller to supply a temporary variable for `<resultVariable>` if one is needed.
* The temporary variable `<temp>` is injected so that `++` and `--` work uniformly with `number` and `bigint`.
* The result of the expression is always the final result of incrementing or decrementing the expression, so that it can be used for storage.
*
* @param factory {@link NodeFactory} used to create the expanded representation.
* @param node The original prefix or postfix unary node.
* @param expression The expression to use as the value to increment or decrement
* @param resultVariable A temporary variable in which to store the result. Pass `undefined` if the result is discarded, or if the value of `<temp>` is the expected result.
*/
export function expandPreOrPostfixIncrementOrDecrementExpression(factory: NodeFactory, node: PrefixUnaryExpression | PostfixUnaryExpression, expression: Expression, recordTempVariable: (node: Identifier) => void, resultVariable: Identifier | undefined) {
const operator = node.operator;
Debug.assert(operator === SyntaxKind.PlusPlusToken || operator === SyntaxKind.MinusMinusToken, "Expected 'node' to be a pre- or post-increment or pre- or post-decrement expression");
const temp = factory.createTempVariable(recordTempVariable);
expression = factory.createAssignment(temp, expression);
setTextRange(expression, node.operand);
let operation: Expression = isPrefixUnaryExpression(node) ?
factory.createPrefixUnaryExpression(operator, temp) :
factory.createPostfixUnaryExpression(temp, operator);
setTextRange(operation, node);
if (resultVariable) {
operation = factory.createAssignment(resultVariable, operation);
setTextRange(operation, node);
}
expression = factory.createComma(expression, operation);
setTextRange(expression, node);
if (isPostfixUnaryExpression(node)) {
expression = factory.createComma(expression, temp);
setTextRange(expression, node);
}
return expression;
}
/**
* Gets whether an identifier should only be referred to by its internal name.
*/
File diff suppressed because it is too large Load Diff
@@ -75,7 +75,7 @@ namespace ts {
}
function getAccessorNameVisibilityDiagnosticMessage(symbolAccessibilityResult: SymbolAccessibilityResult) {
if (hasSyntacticModifier(node, ModifierFlags.Static)) {
if (isStatic(node)) {
return symbolAccessibilityResult.errorModuleName ?
symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ?
Diagnostics.Public_static_property_0_of_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named :
@@ -106,7 +106,7 @@ namespace ts {
}
function getMethodNameVisibilityDiagnosticMessage(symbolAccessibilityResult: SymbolAccessibilityResult) {
if (hasSyntacticModifier(node, ModifierFlags.Static)) {
if (isStatic(node)) {
return symbolAccessibilityResult.errorModuleName ?
symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ?
Diagnostics.Public_static_method_0_of_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named :
@@ -173,7 +173,7 @@ namespace ts {
else if (node.kind === SyntaxKind.PropertyDeclaration || node.kind === SyntaxKind.PropertyAccessExpression || node.kind === SyntaxKind.PropertySignature ||
(node.kind === SyntaxKind.Parameter && hasSyntacticModifier(node.parent, ModifierFlags.Private))) {
// TODO(jfreeman): Deal with computed properties in error reporting.
if (hasSyntacticModifier(node, ModifierFlags.Static)) {
if (isStatic(node)) {
return symbolAccessibilityResult.errorModuleName ?
symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ?
Diagnostics.Public_static_property_0_of_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named :
@@ -210,7 +210,7 @@ namespace ts {
if (node.kind === SyntaxKind.SetAccessor) {
// Getters can infer the return type from the returned expression, but setters cannot, so the
// "_from_external_module_1_but_cannot_be_named" case cannot occur.
if (hasSyntacticModifier(node, ModifierFlags.Static)) {
if (isStatic(node)) {
diagnosticMessage = symbolAccessibilityResult.errorModuleName ?
Diagnostics.Parameter_type_of_public_static_setter_0_from_exported_class_has_or_is_using_name_1_from_private_module_2 :
Diagnostics.Parameter_type_of_public_static_setter_0_from_exported_class_has_or_is_using_private_name_1;
@@ -222,7 +222,7 @@ namespace ts {
}
}
else {
if (hasSyntacticModifier(node, ModifierFlags.Static)) {
if (isStatic(node)) {
diagnosticMessage = symbolAccessibilityResult.errorModuleName ?
symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ?
Diagnostics.Return_type_of_public_static_getter_0_from_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named :
@@ -270,7 +270,7 @@ namespace ts {
case SyntaxKind.MethodDeclaration:
case SyntaxKind.MethodSignature:
if (hasSyntacticModifier(node, ModifierFlags.Static)) {
if (isStatic(node)) {
diagnosticMessage = symbolAccessibilityResult.errorModuleName ?
symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ?
Diagnostics.Return_type_of_public_static_method_from_exported_class_has_or_is_using_name_0_from_external_module_1_but_cannot_be_named :
@@ -349,7 +349,7 @@ namespace ts {
case SyntaxKind.MethodDeclaration:
case SyntaxKind.MethodSignature:
if (hasSyntacticModifier(node.parent, ModifierFlags.Static)) {
if (isStatic(node.parent)) {
return symbolAccessibilityResult.errorModuleName ?
symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ?
Diagnostics.Parameter_0_of_public_static_method_from_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named :
@@ -417,7 +417,7 @@ namespace ts {
case SyntaxKind.MethodDeclaration:
case SyntaxKind.MethodSignature:
if (hasSyntacticModifier(node.parent, ModifierFlags.Static)) {
if (isStatic(node.parent)) {
diagnosticMessage = Diagnostics.Type_parameter_0_of_public_static_method_from_exported_class_has_or_is_using_private_name_1;
}
else if (node.parent.parent.kind === SyntaxKind.ClassDeclaration) {
+35 -14
View File
@@ -169,6 +169,8 @@ namespace ts {
ForStatement = 1 << 11, // Enclosing block-scoped container is a ForStatement
ForInOrForOfStatement = 1 << 12, // Enclosing block-scoped container is a ForInStatement or ForOfStatement
ConstructorWithCapturedSuper = 1 << 13, // Enclosed in a constructor that captures 'this' for use with 'super'
StaticInitializer = 1 << 14, // Enclosed in a static initializer
// NOTE: do not add more ancestor flags without also updating AncestorFactsMask below.
// NOTE: when adding a new ancestor flag, be sure to update the subtree flags below.
@@ -176,7 +178,7 @@ namespace ts {
// Ancestor masks
//
AncestorFactsMask = (ConstructorWithCapturedSuper << 1) - 1,
AncestorFactsMask = (StaticInitializer << 1) - 1,
// We are always in *some* kind of block scope, but only specific block-scope containers are
// top-level or Blocks.
@@ -189,7 +191,7 @@ namespace ts {
// Functions, methods, and accessors are both new lexical scopes and new block scopes.
FunctionIncludes = Function | TopLevel,
FunctionExcludes = BlockScopeExcludes & ~TopLevel | ArrowFunction | AsyncFunctionBody | CapturesThis | NonStaticClassElement | ConstructorWithCapturedSuper | IterationContainer,
FunctionExcludes = BlockScopeExcludes & ~TopLevel | ArrowFunction | AsyncFunctionBody | CapturesThis | NonStaticClassElement | ConstructorWithCapturedSuper | IterationContainer | StaticInitializer,
AsyncFunctionBodyIncludes = FunctionIncludes | AsyncFunctionBody,
AsyncFunctionBodyExcludes = FunctionExcludes & ~NonStaticClassElement,
@@ -225,12 +227,15 @@ namespace ts {
IterationStatementBlockIncludes = IterationStatementBlock,
IterationStatementBlockExcludes = BlockScopeExcludes,
StaticInitializerIncludes = FunctionIncludes | StaticInitializer,
StaticInitializerExcludes = FunctionExcludes,
//
// Subtree facts
//
NewTarget = 1 << 14, // Contains a 'new.target' meta-property
CapturedLexicalThis = 1 << 15, // Contains a lexical `this` reference captured by an arrow function.
NewTarget = 1 << 15, // Contains a 'new.target' meta-property
CapturedLexicalThis = 1 << 16, // Contains a lexical `this` reference captured by an arrow function.
//
// Subtree masks
@@ -377,6 +382,23 @@ namespace ts {
return shouldVisitNode(node) ? visitorWorker(node, /*expressionResultIsUnused*/ true) : node;
}
function classWrapperStatementVisitor(node: Node): VisitResult<Node> {
if (shouldVisitNode(node)) {
const original = getOriginalNode(node);
if (isPropertyDeclaration(original) && hasStaticModifier(original)) {
const ancestorFacts = enterSubtree(
HierarchyFacts.StaticInitializerExcludes,
HierarchyFacts.StaticInitializerIncludes
);
const result = visitorWorker(node, /*expressionResultIsUnused*/ false);
exitSubtree(ancestorFacts, HierarchyFacts.FunctionSubtreeExcludes, HierarchyFacts.None);
return result;
}
return visitorWorker(node, /*expressionResultIsUnused*/ false);
}
return node;
}
function callExpressionVisitor(node: Node): VisitResult<Node> {
if (node.kind === SyntaxKind.SuperKeyword) {
return visitSuperKeyword(/*isExpressionOfCall*/ true);
@@ -602,7 +624,7 @@ namespace ts {
}
function visitThisKeyword(node: Node): Node {
if (hierarchyFacts & HierarchyFacts.ArrowFunction) {
if (hierarchyFacts & HierarchyFacts.ArrowFunction && !(hierarchyFacts & HierarchyFacts.StaticInitializer)) {
hierarchyFacts |= HierarchyFacts.CapturedLexicalThis;
}
if (convertedLoopState) {
@@ -1750,7 +1772,7 @@ namespace ts {
* @param node An ArrowFunction node.
*/
function visitArrowFunction(node: ArrowFunction) {
if (node.transformFlags & TransformFlags.ContainsLexicalThis) {
if (node.transformFlags & TransformFlags.ContainsLexicalThis && !(hierarchyFacts & HierarchyFacts.StaticInitializer)) {
hierarchyFacts |= HierarchyFacts.CapturedLexicalThis;
}
@@ -1770,10 +1792,6 @@ namespace ts {
setOriginalNode(func, node);
setEmitFlags(func, EmitFlags.CapturesThis);
if (hierarchyFacts & HierarchyFacts.CapturedLexicalThis) {
enableSubstitutionsForCapturedThis();
}
// If an arrow function contains
exitSubtree(ancestorFacts, HierarchyFacts.ArrowFunctionSubtreeExcludes, HierarchyFacts.None);
@@ -1853,7 +1871,7 @@ namespace ts {
function transformFunctionLikeToExpression(node: FunctionLikeDeclaration, location: TextRange | undefined, name: Identifier | undefined, container: Node | undefined): FunctionExpression {
const savedConvertedLoopState = convertedLoopState;
convertedLoopState = undefined;
const ancestorFacts = container && isClassLike(container) && !hasSyntacticModifier(node, ModifierFlags.Static)
const ancestorFacts = container && isClassLike(container) && !isStatic(node)
? enterSubtree(HierarchyFacts.FunctionExcludes, HierarchyFacts.FunctionIncludes | HierarchyFacts.NonStaticClassElement)
: enterSubtree(HierarchyFacts.FunctionExcludes, HierarchyFacts.FunctionIncludes);
const parameters = visitParameterList(node.parameters, visitor, context);
@@ -3688,7 +3706,7 @@ namespace ts {
// visit the class body statements outside of any converted loop body.
const savedConvertedLoopState = convertedLoopState;
convertedLoopState = undefined;
const bodyStatements = visitNodes(body.statements, visitor, isStatement);
const bodyStatements = visitNodes(body.statements, classWrapperStatementVisitor, isStatement);
convertedLoopState = savedConvertedLoopState;
const classStatements = filter(bodyStatements, isVariableStatementWithInitializer);
@@ -3715,7 +3733,10 @@ namespace ts {
// return C;
// }())
//
const aliasAssignment = tryCast(initializer, isAssignmentExpression);
let aliasAssignment = tryCast(initializer, isAssignmentExpression);
if (!aliasAssignment && isBinaryExpression(initializer) && initializer.operatorToken.kind === SyntaxKind.CommaToken) {
aliasAssignment = tryCast(initializer.left, isAssignmentExpression);
}
// The underlying call (3) is another IIFE that may contain a '_super' argument.
const call = cast(aliasAssignment ? skipOuterExpressions(aliasAssignment.right) : initializer, isCallExpression);
@@ -4358,7 +4379,7 @@ namespace ts {
}
function getClassMemberPrefix(node: ClassExpression | ClassDeclaration, member: ClassElement) {
return hasSyntacticModifier(member, ModifierFlags.Static)
return isStatic(member)
? factory.getInternalName(node)
: factory.createPropertyAccessExpression(factory.getInternalName(node), "prototype");
}
+5 -5
View File
@@ -945,7 +945,7 @@ namespace ts {
* @param member The class member.
*/
function isStaticDecoratedClassElement(member: ClassElement, parent: ClassLikeDeclaration) {
return isDecoratedClassElement(member, /*isStatic*/ true, parent);
return isDecoratedClassElement(member, /*isStaticElement*/ true, parent);
}
/**
@@ -955,7 +955,7 @@ namespace ts {
* @param member The class member.
*/
function isInstanceDecoratedClassElement(member: ClassElement, parent: ClassLikeDeclaration) {
return isDecoratedClassElement(member, /*isStatic*/ false, parent);
return isDecoratedClassElement(member, /*isStaticElement*/ false, parent);
}
/**
@@ -964,9 +964,9 @@ namespace ts {
*
* @param member The class member.
*/
function isDecoratedClassElement(member: ClassElement, isStatic: boolean, parent: ClassLikeDeclaration) {
function isDecoratedClassElement(member: ClassElement, isStaticElement: boolean, parent: ClassLikeDeclaration) {
return nodeOrChildIsDecorated(member, parent)
&& isStatic === hasSyntacticModifier(member, ModifierFlags.Static);
&& isStaticElement === isStatic(member);
}
/**
@@ -3158,7 +3158,7 @@ namespace ts {
}
function getClassMemberPrefix(node: ClassExpression | ClassDeclaration, member: ClassElement) {
return hasSyntacticModifier(member, ModifierFlags.Static)
return isStatic(member)
? factory.getDeclarationName(node)
: getClassPrototype(node);
}
+1 -1
View File
@@ -385,6 +385,6 @@ namespace ts {
* @param member The class element node.
*/
export function isNonStaticMethodOrAccessorWithPrivateName(member: ClassElement): member is PrivateIdentifierMethodDeclaration | PrivateIdentifierAccessorDeclaration {
return !hasStaticModifier(member) && isMethodOrAccessor(member) && isPrivateIdentifier(member.name);
return !isStatic(member) && isMethodOrAccessor(member) && isPrivateIdentifier(member.name);
}
}
+28 -7
View File
@@ -1543,6 +1543,8 @@ namespace ts {
readonly body: Block;
/* @internal */ readonly decorators?: NodeArray<Decorator>; // Present for use with reporting a grammar error
/* @internal */ readonly modifier?: ModifiersArray; // Present for use with reporting a grammar error
/* @internal */ endFlowNode?: FlowNode;
/* @internal */ returnFlowNode?: FlowNode;
}
export interface TypeNode extends Node {
@@ -6632,7 +6634,7 @@ namespace ts {
ContainsDynamicImport = 1 << 22,
ContainsClassFields = 1 << 23,
ContainsPossibleTopLevelAwait = 1 << 24,
ContainsLexicalSuper = 1 << 25,
// Please leave this as 1 << 29.
// It is the maximum bit we can set before we outgrow the size of a v8 small integer (SMI) on an x86 system.
// It is a good reminder of how much room we have left
@@ -6660,12 +6662,12 @@ namespace ts {
PropertyAccessExcludes = OuterExpressionExcludes,
NodeExcludes = PropertyAccessExcludes,
ArrowFunctionExcludes = NodeExcludes | ContainsTypeScriptClassSyntax | ContainsBlockScopedBinding | ContainsYield | ContainsAwait | ContainsHoistedDeclarationOrCompletion | ContainsBindingPattern | ContainsObjectRestOrSpread | ContainsPossibleTopLevelAwait,
FunctionExcludes = NodeExcludes | ContainsTypeScriptClassSyntax | ContainsLexicalThis | ContainsBlockScopedBinding | ContainsYield | ContainsAwait | ContainsHoistedDeclarationOrCompletion | ContainsBindingPattern | ContainsObjectRestOrSpread | ContainsPossibleTopLevelAwait,
ConstructorExcludes = NodeExcludes | ContainsLexicalThis | ContainsBlockScopedBinding | ContainsYield | ContainsAwait | ContainsHoistedDeclarationOrCompletion | ContainsBindingPattern | ContainsObjectRestOrSpread | ContainsPossibleTopLevelAwait,
MethodOrAccessorExcludes = NodeExcludes | ContainsLexicalThis | ContainsBlockScopedBinding | ContainsYield | ContainsAwait | ContainsHoistedDeclarationOrCompletion | ContainsBindingPattern | ContainsObjectRestOrSpread,
PropertyExcludes = NodeExcludes | ContainsLexicalThis,
FunctionExcludes = NodeExcludes | ContainsTypeScriptClassSyntax | ContainsLexicalThis | ContainsLexicalSuper | ContainsBlockScopedBinding | ContainsYield | ContainsAwait | ContainsHoistedDeclarationOrCompletion | ContainsBindingPattern | ContainsObjectRestOrSpread | ContainsPossibleTopLevelAwait,
ConstructorExcludes = NodeExcludes | ContainsLexicalThis | ContainsLexicalSuper | ContainsBlockScopedBinding | ContainsYield | ContainsAwait | ContainsHoistedDeclarationOrCompletion | ContainsBindingPattern | ContainsObjectRestOrSpread | ContainsPossibleTopLevelAwait,
MethodOrAccessorExcludes = NodeExcludes | ContainsLexicalThis | ContainsLexicalSuper | ContainsBlockScopedBinding | ContainsYield | ContainsAwait | ContainsHoistedDeclarationOrCompletion | ContainsBindingPattern | ContainsObjectRestOrSpread,
PropertyExcludes = NodeExcludes | ContainsLexicalThis | ContainsLexicalSuper,
ClassExcludes = NodeExcludes | ContainsTypeScriptClassSyntax | ContainsComputedPropertyName,
ModuleExcludes = NodeExcludes | ContainsTypeScriptClassSyntax | ContainsLexicalThis | ContainsBlockScopedBinding | ContainsHoistedDeclarationOrCompletion | ContainsPossibleTopLevelAwait,
ModuleExcludes = NodeExcludes | ContainsTypeScriptClassSyntax | ContainsLexicalThis | ContainsLexicalSuper | ContainsBlockScopedBinding | ContainsHoistedDeclarationOrCompletion | ContainsPossibleTopLevelAwait,
TypeExcludes = ~ContainsTypeScript,
ObjectLiteralExcludes = NodeExcludes | ContainsTypeScriptClassSyntax | ContainsComputedPropertyName | ContainsObjectRestOrSpread,
ArrayLiteralOrCallOrNewExcludes = NodeExcludes | ContainsRestOrSpread,
@@ -6673,10 +6675,11 @@ namespace ts {
ParameterExcludes = NodeExcludes,
CatchClauseExcludes = NodeExcludes | ContainsObjectRestOrSpread,
BindingPatternExcludes = NodeExcludes | ContainsRestOrSpread,
ContainsLexicalThisOrSuper = ContainsLexicalThis | ContainsLexicalSuper,
// Propagating flags
// - Bitmasks for flags that should propagate from a child
PropertyNamePropagatingFlags = ContainsLexicalThis,
PropertyNamePropagatingFlags = ContainsLexicalThis | ContainsLexicalSuper,
// Masks
// - Additional bitmasks
@@ -7548,10 +7551,28 @@ namespace ts {
/* @internal */ createFunctionCallCall(target: Expression, thisArg: Expression, argumentsList: readonly Expression[]): CallExpression;
/* @internal */ createFunctionApplyCall(target: Expression, thisArg: Expression, argumentsExpression: Expression): CallExpression;
/* @internal */ createObjectDefinePropertyCall(target: Expression, propertyName: string | Expression, attributes: Expression): CallExpression;
/* @internal */ createReflectGetCall(target: Expression, propertyKey: Expression, receiver?: Expression): CallExpression;
/* @internal */ createReflectSetCall(target: Expression, propertyKey: Expression, value: Expression, receiver?: Expression): CallExpression;
/* @internal */ createPropertyDescriptor(attributes: PropertyDescriptorAttributes, singleLine?: boolean): ObjectLiteralExpression;
/* @internal */ createArraySliceCall(array: Expression, start?: number | Expression): CallExpression;
/* @internal */ createArrayConcatCall(array: Expression, values: readonly Expression[]): CallExpression;
/* @internal */ createCallBinding(expression: Expression, recordTempVariable: (temp: Identifier) => void, languageVersion?: ScriptTarget, cacheIdentifiers?: boolean): CallBinding;
/**
* Wraps an expression that cannot be an assignment target in an expression that can be.
*
* Given a `paramName` of `_a`:
* ```
* Reflect.set(obj, "x", _a)
* ```
* Becomes
* ```ts
* ({ set value(_a) { Reflect.set(obj, "x", _a); } }).value
* ```
*
* @param paramName
* @param expression
*/
/* @internal */ createAssignmentTargetWrapper(paramName: Identifier, expression: Expression): LeftHandSideExpression;
/* @internal */ inlineExpressions(expressions: readonly Expression[]): Expression;
/**
* Gets the internal name of a declaration. This is primarily used for declarations that can be
+7 -1
View File
@@ -1710,6 +1710,7 @@ namespace ts {
case SyntaxKind.Constructor:
case SyntaxKind.GetAccessor:
case SyntaxKind.SetAccessor:
case SyntaxKind.ClassStaticBlockDeclaration:
return node;
case SyntaxKind.Decorator:
// Decorators are always applied outside of the body of a class or method.
@@ -4404,7 +4405,7 @@ namespace ts {
else {
forEach(declarations, member => {
if (isAccessor(member)
&& hasSyntacticModifier(member, ModifierFlags.Static) === hasSyntacticModifier(accessor, ModifierFlags.Static)) {
&& isStatic(member) === isStatic(accessor)) {
const memberName = getPropertyNameForPropertyNameNode(member.name);
const accessorName = getPropertyNameForPropertyNameNode(accessor.name);
if (memberName === accessorName) {
@@ -4715,6 +4716,11 @@ namespace ts {
return !!getSelectedSyntacticModifierFlags(node, flags);
}
export function isStatic(node: Node) {
// https://tc39.es/ecma262/#sec-static-semantics-isstatic
return isClassElement(node) && hasStaticModifier(node) || isClassStaticBlockDeclaration(node);
}
export function hasStaticModifier(node: Node): boolean {
return hasSyntacticModifier(node, ModifierFlags.Static);
}
+12
View File
@@ -1425,6 +1425,18 @@ namespace ts {
return false;
}
/* @internal */
export function isObjectBindingOrAssignmentElement(node: Node): node is ObjectBindingOrAssignmentElement {
switch (node.kind) {
case SyntaxKind.BindingElement:
case SyntaxKind.PropertyAssignment: // AssignmentProperty
case SyntaxKind.ShorthandPropertyAssignment: // AssignmentProperty
case SyntaxKind.SpreadAssignment: // AssignmentRestProperty
return true;
}
return false;
}
/**
* Determines whether a node is an ArrayBindingOrAssignmentPattern
*/
+4 -1
View File
@@ -2313,6 +2313,9 @@ namespace ts.Completions {
break;
}
}
if (isClassStaticBlockDeclaration(classElement)) {
classElementModifierFlags |= ModifierFlags.Static;
}
// No member list for private methods
if (!(classElementModifierFlags & ModifierFlags.Private)) {
@@ -2766,7 +2769,7 @@ namespace ts.Completions {
}
// do not filter it out if the static presence doesnt match
if (hasEffectiveModifier(m, ModifierFlags.Static) !== !!(currentClassElementModifierFlags & ModifierFlags.Static)) {
if (isStatic(m) !== !!(currentClassElementModifierFlags & ModifierFlags.Static)) {
continue;
}
+6 -6
View File
@@ -1684,7 +1684,7 @@ namespace ts.FindAllReferences {
Debug.assert(classLike.name === referenceLocation);
const addRef = state.referenceAdder(search.symbol);
for (const member of classLike.members) {
if (!(isMethodOrAccessor(member) && hasSyntacticModifier(member, ModifierFlags.Static))) {
if (!(isMethodOrAccessor(member) && isStatic(member))) {
continue;
}
if (member.body) {
@@ -1917,7 +1917,7 @@ namespace ts.FindAllReferences {
// If we have a 'super' container, we must have an enclosing class.
// Now make sure the owning class is the same as the search-space
// and has the same static qualifier as the original 'super's owner.
return container && (ModifierFlags.Static & getSyntacticModifierFlags(container)) === staticFlag && container.parent.symbol === searchSpaceNode.symbol ? nodeEntry(node) : undefined;
return container && isStatic(container) === !!staticFlag && container.parent.symbol === searchSpaceNode.symbol ? nodeEntry(node) : undefined;
});
return [{ definition: { type: DefinitionKind.Symbol, symbol: searchSpaceNode.symbol }, references }];
@@ -1983,7 +1983,7 @@ namespace ts.FindAllReferences {
case SyntaxKind.ObjectLiteralExpression:
// Make sure the container belongs to the same class/object literals
// and has the appropriate static modifier from the original container.
return container.parent && searchSpaceNode.symbol === container.parent.symbol && (getSyntacticModifierFlags(container) & ModifierFlags.Static) === staticFlag;
return container.parent && searchSpaceNode.symbol === container.parent.symbol && isStatic(container) === !!staticFlag;
case SyntaxKind.SourceFile:
return container.kind === SyntaxKind.SourceFile && !isExternalModule(container as SourceFile) && !isParameterName(node);
}
@@ -2030,7 +2030,7 @@ namespace ts.FindAllReferences {
(sym, root, base) => {
// static method/property and instance method/property might have the same name. Only include static or only include instance.
if (base) {
if (isStatic(symbol) !== isStatic(base)) {
if (isStaticSymbol(symbol) !== isStaticSymbol(base)) {
base = undefined;
}
}
@@ -2196,7 +2196,7 @@ namespace ts.FindAllReferences {
readonly kind: NodeEntryKind | undefined;
}
function isStatic(symbol: Symbol): boolean {
function isStaticSymbol(symbol: Symbol): boolean {
if (!symbol.valueDeclaration) { return false; }
const modifierFlags = getEffectiveModifierFlags(symbol.valueDeclaration);
return !!(modifierFlags & ModifierFlags.Static);
@@ -2210,7 +2210,7 @@ namespace ts.FindAllReferences {
// check whether the symbol used to search itself is just the searched one.
if (baseSymbol) {
// static method/property and instance method/property might have the same name. Only check static or only check instance.
if (isStatic(referenceSymbol) !== isStatic(baseSymbol)) {
if (isStaticSymbol(referenceSymbol) !== isStaticSymbol(baseSymbol)) {
baseSymbol = undefined;
}
}
+1 -1
View File
@@ -627,7 +627,7 @@ namespace ts.NavigationBar {
case SyntaxKind.MethodDeclaration:
case SyntaxKind.GetAccessor:
case SyntaxKind.SetAccessor:
return hasSyntacticModifier(a, ModifierFlags.Static) === hasSyntacticModifier(b, ModifierFlags.Static);
return isStatic(a) === isStatic(b);
case SyntaxKind.ModuleDeclaration:
return areSameModule(a as ModuleDeclaration, b as ModuleDeclaration)
&& getFullyQualifiedModuleName(a as ModuleDeclaration) === getFullyQualifiedModuleName(b as ModuleDeclaration);
+2 -2
View File
@@ -398,7 +398,7 @@ namespace ts.refactor.extractSymbol {
let current: Node = nodeToCheck;
while (current !== containingClass) {
if (current.kind === SyntaxKind.PropertyDeclaration) {
if (hasSyntacticModifier(current, ModifierFlags.Static)) {
if (isStatic(current)) {
rangeFacts |= RangeFacts.InStaticRegion;
}
break;
@@ -411,7 +411,7 @@ namespace ts.refactor.extractSymbol {
break;
}
else if (current.kind === SyntaxKind.MethodDeclaration) {
if (hasSyntacticModifier(current, ModifierFlags.Static)) {
if (isStatic(current)) {
rangeFacts |= RangeFacts.InStaticRegion;
}
}