From de9c459d5e38dbe0c0475ddd81543d017987ba98 Mon Sep 17 00:00:00 2001 From: Andy Date: Wed, 4 Oct 2017 12:20:58 -0700 Subject: [PATCH] Clean up code in getModifierOccurrences (#18948) --- src/compiler/core.ts | 2 + src/services/documentHighlights.ts | 114 ++++++++++++----------------- 2 files changed, 47 insertions(+), 69 deletions(-) diff --git a/src/compiler/core.ts b/src/compiler/core.ts index c912cfa6b53..45a4a04b6ab 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -247,6 +247,8 @@ namespace ts { } /** Works like Array.prototype.find, returning `undefined` if no element satisfying the predicate is found. */ + export function find(array: ReadonlyArray, predicate: (element: T, index: number) => element is U): U | undefined; + export function find(array: ReadonlyArray, predicate: (element: T, index: number) => boolean): T | undefined; export function find(array: ReadonlyArray, predicate: (element: T, index: number) => boolean): T | undefined { for (let i = 0; i < array.length; i++) { const value = array[i]; diff --git a/src/services/documentHighlights.ts b/src/services/documentHighlights.ts index bb64ee32685..4f11e33c638 100644 --- a/src/services/documentHighlights.ts +++ b/src/services/documentHighlights.ts @@ -265,40 +265,23 @@ namespace ts.DocumentHighlights { } function getModifierOccurrences(modifier: SyntaxKind, declaration: Node): Node[] { - const container = declaration.parent; - // Make sure we only highlight the keyword when it makes sense to do so. - if (isAccessibilityModifier(modifier)) { - if (!(container.kind === SyntaxKind.ClassDeclaration || - container.kind === SyntaxKind.ClassExpression || - (declaration.kind === SyntaxKind.Parameter && hasKind(container, SyntaxKind.Constructor)))) { - return undefined; - } - } - else if (modifier === SyntaxKind.StaticKeyword) { - if (!(container.kind === SyntaxKind.ClassDeclaration || container.kind === SyntaxKind.ClassExpression)) { - return undefined; - } - } - else if (modifier === SyntaxKind.ExportKeyword || modifier === SyntaxKind.DeclareKeyword) { - if (!(container.kind === SyntaxKind.ModuleBlock || container.kind === SyntaxKind.SourceFile)) { - return undefined; - } - } - else if (modifier === SyntaxKind.AbstractKeyword) { - if (!(container.kind === SyntaxKind.ClassDeclaration || declaration.kind === SyntaxKind.ClassDeclaration)) { - return undefined; - } - } - else { - // unsupported modifier + if (!isLegalModifier(modifier, declaration)) { return undefined; } - const keywords: Node[] = []; - const modifierFlag: ModifierFlags = getFlagFromModifier(modifier); + const modifierFlag = modifierToFlag(modifier); + return mapDefined(getNodesToSearchForModifier(declaration, modifierFlag), node => { + if (getModifierFlags(node) & modifierFlag) { + const mod = find(node.modifiers, m => m.kind === modifier); + Debug.assert(!!mod); + return mod; + } + }); + } - let nodes: ReadonlyArray; + function getNodesToSearchForModifier(declaration: Node, modifierFlag: ModifierFlags): ReadonlyArray { + const container = declaration.parent; switch (container.kind) { case SyntaxKind.ModuleBlock: case SyntaxKind.SourceFile: @@ -307,65 +290,58 @@ namespace ts.DocumentHighlights { case SyntaxKind.DefaultClause: // Container is either a class declaration or the declaration is a classDeclaration if (modifierFlag & ModifierFlags.Abstract) { - nodes = [...(declaration).members, declaration]; + return [...(declaration).members, declaration]; } else { - nodes = (container).statements; + return (container).statements; } - break; case SyntaxKind.Constructor: - nodes = [...(container).parameters, ...(container.parent).members]; - break; + return [...(container).parameters, ...(container.parent).members]; case SyntaxKind.ClassDeclaration: case SyntaxKind.ClassExpression: - nodes = (container).members; + const nodes = (container).members; // If we're an accessibility modifier, we're in an instance member and should search // the constructor's parameter list for instance members as well. if (modifierFlag & ModifierFlags.AccessibilityModifier) { - const constructor = forEach((container).members, member => { - return member.kind === SyntaxKind.Constructor && member; - }); - + const constructor = find((container).members, isConstructorDeclaration); if (constructor) { - nodes = [...nodes, ...constructor.parameters]; + return [...nodes, ...constructor.parameters]; } } else if (modifierFlag & ModifierFlags.Abstract) { - nodes = [...nodes, container]; + return [...nodes, container]; } - break; + return nodes; default: Debug.fail("Invalid container kind."); } + } - forEach(nodes, node => { - if (getModifierFlags(node) & modifierFlag) { - forEach(node.modifiers, child => pushKeywordIf(keywords, child, modifier)); - } - }); - - return keywords; - - function getFlagFromModifier(modifier: SyntaxKind) { - switch (modifier) { - case SyntaxKind.PublicKeyword: - return ModifierFlags.Public; - case SyntaxKind.PrivateKeyword: - return ModifierFlags.Private; - case SyntaxKind.ProtectedKeyword: - return ModifierFlags.Protected; - case SyntaxKind.StaticKeyword: - return ModifierFlags.Static; - case SyntaxKind.ExportKeyword: - return ModifierFlags.Export; - case SyntaxKind.DeclareKeyword: - return ModifierFlags.Ambient; - case SyntaxKind.AbstractKeyword: - return ModifierFlags.Abstract; - default: - Debug.fail(); - } + function isLegalModifier(modifier: SyntaxKind, declaration: Node): boolean { + const container = declaration.parent; + switch (modifier) { + case SyntaxKind.PrivateKeyword: + case SyntaxKind.ProtectedKeyword: + case SyntaxKind.PublicKeyword: + switch (container.kind) { + case SyntaxKind.ClassDeclaration: + case SyntaxKind.ClassExpression: + return true; + case SyntaxKind.Constructor: + return declaration.kind === SyntaxKind.Parameter; + default: + return false; + } + case SyntaxKind.StaticKeyword: + return container.kind === SyntaxKind.ClassDeclaration || container.kind === SyntaxKind.ClassExpression; + case SyntaxKind.ExportKeyword: + case SyntaxKind.DeclareKeyword: + return container.kind === SyntaxKind.ModuleBlock || container.kind === SyntaxKind.SourceFile; + case SyntaxKind.AbstractKeyword: + return container.kind === SyntaxKind.ClassDeclaration || declaration.kind === SyntaxKind.ClassDeclaration; + default: + return false; } }