Merge pull request #23834 from Microsoft/generateNamesEarlier

Pre-generate names ahead of time
This commit is contained in:
Ron Buckton
2018-05-02 17:51:37 -07:00
committed by GitHub
36 changed files with 3880 additions and 3776 deletions

View File

@@ -1378,6 +1378,8 @@ namespace ts {
}
function emitObjectLiteralExpression(node: ObjectLiteralExpression) {
forEach(node.properties, generateMemberNames);
const indentedFlag = getEmitFlags(node) & EmitFlags.Indented;
if (indentedFlag) {
increaseIndent();
@@ -1481,6 +1483,7 @@ namespace ts {
}
function emitFunctionExpression(node: FunctionExpression) {
generateNameIfNeeded(node.name);
emitFunctionDeclarationOrExpression(node);
}
@@ -1606,6 +1609,7 @@ namespace ts {
}
function emitClassExpression(node: ClassExpression) {
generateNameIfNeeded(node.name);
emitClassDeclarationOrExpression(node);
}
@@ -1911,6 +1915,9 @@ namespace ts {
}
pushNameGenerationScope(node);
forEach(node.parameters, generateNames);
generateNames(node.body);
emitSignatureHead(node);
if (onEmitNode) {
onEmitNode(EmitHint.Unspecified, body, emitBlockCallback);
@@ -2025,6 +2032,8 @@ namespace ts {
}
function emitClassDeclarationOrExpression(node: ClassDeclaration | ClassExpression) {
forEach(node.members, generateMemberNames);
emitDecorators(node, node.decorators);
emitModifiers(node, node.modifiers);
writeKeyword("class");
@@ -2113,6 +2122,7 @@ namespace ts {
function emitModuleBlock(node: ModuleBlock) {
pushNameGenerationScope(node);
forEach(node.statements, generateNames);
emitBlockStatements(node, /*forceSingleLine*/ isEmptyBlock(node));
popNameGenerationScope(node);
}
@@ -2516,6 +2526,7 @@ namespace ts {
function emitSourceFileWorker(node: SourceFile) {
const statements = node.statements;
pushNameGenerationScope(node);
forEach(node.statements, generateNames);
emitHelpers(node);
const index = findIndex(statements, statement => !isPrologueDirective(statement));
emitTripleSlashDirectivesIfNeeded(node);
@@ -3222,6 +3233,114 @@ namespace ts {
reservedNames.set(name, true);
}
function generateNames(node: Node | undefined) {
if (!node) return;
switch (node.kind) {
case SyntaxKind.Block:
forEach((<Block>node).statements, generateNames);
break;
case SyntaxKind.LabeledStatement:
case SyntaxKind.WithStatement:
case SyntaxKind.DoStatement:
case SyntaxKind.WhileStatement:
generateNames((<LabeledStatement | WithStatement | DoStatement | WhileStatement>node).statement);
break;
case SyntaxKind.IfStatement:
generateNames((<IfStatement>node).thenStatement);
generateNames((<IfStatement>node).elseStatement);
break;
case SyntaxKind.ForStatement:
case SyntaxKind.ForOfStatement:
case SyntaxKind.ForInStatement:
generateNames((<ForStatement | ForInOrOfStatement>node).initializer);
generateNames((<ForStatement | ForInOrOfStatement>node).statement);
break;
case SyntaxKind.SwitchStatement:
generateNames((<SwitchStatement>node).caseBlock);
break;
case SyntaxKind.CaseBlock:
forEach((<CaseBlock>node).clauses, generateNames);
break;
case SyntaxKind.CaseClause:
case SyntaxKind.DefaultClause:
forEach((<CaseOrDefaultClause>node).statements, generateNames);
break;
case SyntaxKind.TryStatement:
generateNames((<TryStatement>node).tryBlock);
generateNames((<TryStatement>node).catchClause);
generateNames((<TryStatement>node).finallyBlock);
break;
case SyntaxKind.CatchClause:
generateNames((<CatchClause>node).variableDeclaration);
generateNames((<CatchClause>node).block);
break;
case SyntaxKind.VariableStatement:
generateNames((<VariableStatement>node).declarationList);
break;
case SyntaxKind.VariableDeclarationList:
forEach((<VariableDeclarationList>node).declarations, generateNames);
break;
case SyntaxKind.VariableDeclaration:
case SyntaxKind.Parameter:
case SyntaxKind.BindingElement:
case SyntaxKind.ClassDeclaration:
generateNameIfNeeded((<NamedDeclaration>node).name);
break;
case SyntaxKind.FunctionDeclaration:
generateNameIfNeeded((<FunctionDeclaration>node).name);
if (getEmitFlags(node) & EmitFlags.ReuseTempVariableScope) {
forEach((<FunctionDeclaration>node).parameters, generateNames);
generateNames((<FunctionDeclaration>node).body);
}
break;
case SyntaxKind.ObjectBindingPattern:
case SyntaxKind.ArrayBindingPattern:
forEach((<BindingPattern>node).elements, generateNames);
break;
case SyntaxKind.ImportDeclaration:
generateNames((<ImportDeclaration>node).importClause);
break;
case SyntaxKind.ImportClause:
generateNameIfNeeded((<ImportClause>node).name);
generateNames((<ImportClause>node).namedBindings);
break;
case SyntaxKind.NamespaceImport:
generateNameIfNeeded((<NamespaceImport>node).name);
break;
case SyntaxKind.NamedImports:
forEach((<NamedImports>node).elements, generateNames);
break;
case SyntaxKind.ImportSpecifier:
generateNameIfNeeded((<ImportSpecifier>node).propertyName || (<ImportSpecifier>node).name);
break;
}
}
function generateMemberNames(node: Node | undefined) {
if (!node) return;
switch (node.kind) {
case SyntaxKind.PropertyAssignment:
case SyntaxKind.ShorthandPropertyAssignment:
case SyntaxKind.PropertyDeclaration:
case SyntaxKind.MethodDeclaration:
case SyntaxKind.GetAccessor:
case SyntaxKind.SetAccessor:
generateNameIfNeeded((<NamedDeclaration>node).name);
break;
}
}
function generateNameIfNeeded(name: DeclarationName | undefined) {
if (name) {
if (isGeneratedIdentifier(name)) {
generateName(name);
}
else if (isBindingPattern(name)) {
generateNames(name);
}
}
}
/**
* Generate the text for a generated identifier.
*/
@@ -3229,17 +3348,7 @@ namespace ts {
if ((name.autoGenerateFlags & GeneratedIdentifierFlags.KindMask) === GeneratedIdentifierFlags.Node) {
// Node names generate unique names based on their original node
// and are cached based on that node's id.
if (name.autoGenerateFlags & GeneratedIdentifierFlags.SkipNameGenerationScope) {
const savedTempFlags = tempFlags;
popNameGenerationScope(/*node*/ undefined);
const result = generateNameCached(getNodeForGeneratedName(name));
pushNameGenerationScope(/*node*/ undefined);
tempFlags = savedTempFlags;
return result;
}
else {
return generateNameCached(getNodeForGeneratedName(name));
}
return generateNameCached(getNodeForGeneratedName(name));
}
else {
// Auto, Loop, and Unique names are cached based on their unique

View File

@@ -188,16 +188,11 @@ namespace ts {
}
/** Create a unique name generated for a node. */
export function getGeneratedNameForNode(node: Node): Identifier;
/* @internal */ export function getGeneratedNameForNode(node: Node, shouldSkipNameGenerationScope?: boolean): Identifier; // tslint:disable-line unified-signatures
export function getGeneratedNameForNode(node: Node, shouldSkipNameGenerationScope?: boolean): Identifier {
export function getGeneratedNameForNode(node: Node): Identifier {
const name = createIdentifier("");
name.autoGenerateFlags = GeneratedIdentifierFlags.Node;
name.autoGenerateId = nextAutoGenerateId;
name.original = node;
if (shouldSkipNameGenerationScope) {
name.autoGenerateFlags |= GeneratedIdentifierFlags.SkipNameGenerationScope;
}
nextAutoGenerateId++;
return name;
}

View File

@@ -1248,7 +1248,7 @@ namespace ts {
function transformInitializedProperty(property: PropertyDeclaration, receiver: LeftHandSideExpression) {
// We generate a name here in order to reuse the value cached by the relocated computed name expression (which uses the same generated name)
const propertyName = isComputedPropertyName(property.name) && !isSimpleInlineableExpression(property.name.expression)
? updateComputedPropertyName(property.name, getGeneratedNameForNode(property.name, !hasModifier(property, ModifierFlags.Static)))
? updateComputedPropertyName(property.name, getGeneratedNameForNode(property.name))
: property.name;
const initializer = visitNode(property.initializer, visitor, isExpression);
const memberAccess = createMemberAccessForPropertyName(receiver, propertyName, /*location*/ propertyName);

View File

@@ -710,10 +710,9 @@ namespace ts {
KindMask = 7, // Mask to extract the kind of identifier from its flags.
// Flags
SkipNameGenerationScope = 1 << 3, // Should skip a name generation scope when generating the name for this identifier
ReservedInNestedScopes = 1 << 4, // Reserve the generated name in nested scopes
Optimistic = 1 << 5, // First instance won't use '_#' if there's no conflict
FileLevel = 1 << 6, // Use only the file identifiers list and not generated names to search for conflicts
ReservedInNestedScopes = 1 << 3, // Reserve the generated name in nested scopes
Optimistic = 1 << 4, // First instance won't use '_#' if there's no conflict
FileLevel = 1 << 5, // Use only the file identifiers list and not generated names to search for conflicts
}
export interface Identifier extends PrimaryExpression, Declaration {