diff --git a/src/services/navigationBar.ts b/src/services/navigationBar.ts index ab7c4327bb..03d2aec13c 100644 --- a/src/services/navigationBar.ts +++ b/src/services/navigationBar.ts @@ -631,28 +631,50 @@ namespace ts.NavigationBar { } function getFunctionOrClassName(node: FunctionExpression | FunctionDeclaration | ArrowFunction | ClassLikeDeclaration): string { + const { parent } = node; if (node.name && getFullWidth(node.name) > 0) { return declarationNameToString(node.name); } // See if it is a var initializer. If so, use the var name. - else if (node.parent.kind === SyntaxKind.VariableDeclaration) { - return declarationNameToString((node.parent as VariableDeclaration).name); + else if (isVariableDeclaration(parent)) { + return declarationNameToString(parent.name); } // See if it is of the form " = function(){...}". If so, use the text from the left-hand side. - else if (node.parent.kind === SyntaxKind.BinaryExpression && - (node.parent as BinaryExpression).operatorToken.kind === SyntaxKind.EqualsToken) { - return nodeText((node.parent as BinaryExpression).left).replace(whiteSpaceRegex, ""); + else if (isBinaryExpression(parent) && parent.operatorToken.kind === SyntaxKind.EqualsToken) { + return nodeText(parent.left).replace(whiteSpaceRegex, ""); } // See if it is a property assignment, and if so use the property name - else if (node.parent.kind === SyntaxKind.PropertyAssignment && (node.parent as PropertyAssignment).name) { - return nodeText((node.parent as PropertyAssignment).name); + else if (isPropertyAssignment(parent)) { + return nodeText(parent.name); } // Default exports are named "default" else if (getModifierFlags(node) & ModifierFlags.Default) { return "default"; } + else if (isClassLike(node)) { + return ""; + } + else if (isCallExpression(parent)) { + const name = getCalledExpressionName(parent.expression); + if (name !== undefined) { + const args = mapDefined(parent.arguments, a => isStringLiteral(a) ? a.getText(curSourceFile) : undefined).join(", "); + return `${name}(${args}) callback`; + } + } + return ""; + } + + function getCalledExpressionName(expr: Expression): string | undefined { + if (isIdentifier(expr)) { + return expr.text; + } + else if (isPropertyAccessExpression(expr)) { + const left = getCalledExpressionName(expr.expression); + const right = expr.name.text; + return left === undefined ? right : `${left}.${right}`; + } else { - return isClassLike(node) ? "" : ""; + return undefined; } } diff --git a/tests/cases/fourslash/navigationBarAnonymousClassAndFunctionExpressions.ts b/tests/cases/fourslash/navigationBarAnonymousClassAndFunctionExpressions.ts index c0753bc715..23fe81fe48 100644 --- a/tests/cases/fourslash/navigationBarAnonymousClassAndFunctionExpressions.ts +++ b/tests/cases/fourslash/navigationBarAnonymousClassAndFunctionExpressions.ts @@ -18,6 +18,8 @@ //// // These will only show up as childItems. //// function z() {} //// console.log(function() {}) +//// describe("this", 'function', () => {}); +//// [].map(() => {}); ////}) ////(function classes() { //// // Classes show up in top-level regardless of whether they have names or inner declarations. @@ -71,7 +73,15 @@ verify.navigationTree({ "kind": "function", "childItems": [ { - "text": "", + "text": "console.log() callback", + "kind": "function" + }, + { + "text": `describe("this", 'function') callback`, + "kind": "function" + }, + { + "text": `map() callback`, "kind": "function" }, { @@ -185,7 +195,15 @@ verify.navigationBar([ "kind": "function", "childItems": [ { - "text": "", + "text": "console.log() callback", + "kind": "function" + }, + { + "text": `describe("this", 'function') callback`, + "kind": "function" + }, + { + "text": `map() callback`, "kind": "function" }, {