diff --git a/packages/eslint-plugin/src/rules/explicit-function-return-type.ts b/packages/eslint-plugin/src/rules/explicit-function-return-type.ts index da3e7334b6a..b050578c189 100644 --- a/packages/eslint-plugin/src/rules/explicit-function-return-type.ts +++ b/packages/eslint-plugin/src/rules/explicit-function-return-type.ts @@ -1,6 +1,7 @@ import { TSESTree, AST_NODE_TYPES, + AST_TOKEN_TYPES, } from '@typescript-eslint/experimental-utils'; import * as util from '../util'; @@ -57,6 +58,53 @@ export default util.createRule({ }, ], create(context, [options]) { + const sourceCode = context.getSourceCode(); + + /** + * Returns start column position + * @param node + */ + function getLocStart( + node: + | TSESTree.ArrowFunctionExpression + | TSESTree.FunctionDeclaration + | TSESTree.FunctionExpression, + ): TSESTree.LineAndColumnData { + /* highlight method name */ + const parent = node.parent; + if ( + parent && + (parent.type === AST_NODE_TYPES.MethodDefinition || + (parent.type === AST_NODE_TYPES.Property && parent.method)) + ) { + return parent.loc.start; + } + + return node.loc.start; + } + + /** + * Returns end column position + * @param node + */ + function getLocEnd( + node: + | TSESTree.ArrowFunctionExpression + | TSESTree.FunctionDeclaration + | TSESTree.FunctionExpression, + ): TSESTree.LineAndColumnData { + /* highlight `=>` */ + if (node.type === AST_NODE_TYPES.ArrowFunctionExpression) { + return sourceCode.getTokenBefore( + node.body, + token => + token.type === AST_TOKEN_TYPES.Punctuator && token.value === '=>', + )!.loc.end; + } + + return sourceCode.getTokenBefore(node.body!)!.loc.end; + } + /** * Checks if a node is a constructor. * @param node The node to check @@ -258,6 +306,7 @@ export default util.createRule({ context.report({ node, + loc: { start: getLocStart(node), end: getLocEnd(node) }, messageId: 'missingReturnType', }); } diff --git a/packages/eslint-plugin/tests/rules/explicit-function-return-type.test.ts b/packages/eslint-plugin/tests/rules/explicit-function-return-type.test.ts index 942ed5ea2e8..0c67b903cee 100644 --- a/packages/eslint-plugin/tests/rules/explicit-function-return-type.test.ts +++ b/packages/eslint-plugin/tests/rules/explicit-function-return-type.test.ts @@ -327,15 +327,37 @@ const func = (value: number) => x as const; { filename: 'test.ts', code: ` +function test( + a: number, + b: number, +) { + return; +} + `, + errors: [ + { + messageId: 'missingReturnType', + line: 2, + endLine: 5, + column: 1, + endColumn: 2, + }, + ], + }, + { + filename: 'test.ts', + code: ` function test() { - return; + return; } `, errors: [ { messageId: 'missingReturnType', line: 2, + endLine: 2, column: 1, + endColumn: 16, }, ], }, @@ -343,14 +365,16 @@ function test() { filename: 'test.ts', code: ` var fn = function() { - return 1; + return 1; }; `, errors: [ { messageId: 'missingReturnType', line: 2, + endLine: 2, column: 10, + endColumn: 20, }, ], }, @@ -363,7 +387,9 @@ var arrowFn = () => 'test'; { messageId: 'missingReturnType', line: 2, + endLine: 2, column: 15, + endColumn: 20, }, ], }, @@ -380,23 +406,39 @@ class Test { return; } arrow = () => 'arrow'; + private method() { + return; + } } `, errors: [ { messageId: 'missingReturnType', line: 4, - column: 11, + endLine: 4, + column: 3, + endColumn: 13, }, { messageId: 'missingReturnType', line: 8, - column: 9, + endLine: 8, + column: 3, + endColumn: 11, }, { messageId: 'missingReturnType', line: 11, + endLine: 11, column: 11, + endColumn: 16, + }, + { + messageId: 'missingReturnType', + line: 12, + endLine: 12, + column: 3, + endColumn: 19, }, ], }, @@ -412,7 +454,9 @@ function test() { { messageId: 'missingReturnType', line: 2, + endLine: 2, column: 1, + endColumn: 16, }, ], }, @@ -424,7 +468,9 @@ function test() { { messageId: 'missingReturnType', line: 1, + endLine: 1, column: 13, + endColumn: 18, }, ], }, @@ -436,7 +482,9 @@ function test() { { messageId: 'missingReturnType', line: 1, + endLine: 1, column: 13, + endColumn: 23, }, ], }, @@ -448,7 +496,9 @@ function test() { { messageId: 'missingReturnType', line: 1, + endLine: 1, column: 16, + endColumn: 21, }, ], }, @@ -460,7 +510,9 @@ function test() { { messageId: 'missingReturnType', line: 1, + endLine: 1, column: 16, + endColumn: 26, }, ], }, @@ -472,7 +524,9 @@ function test() { { messageId: 'missingReturnType', line: 1, + endLine: 1, column: 15, + endColumn: 20, }, ], }, @@ -484,7 +538,9 @@ function test() { { messageId: 'missingReturnType', line: 1, + endLine: 1, column: 16, + endColumn: 26, }, ], }, @@ -497,6 +553,9 @@ function test() { { messageId: 'missingReturnType', line: 1, + endLine: 1, + column: 12, + endColumn: 17, }, ], }, @@ -513,6 +572,9 @@ const x = { { messageId: 'missingReturnType', line: 4, + endLine: 4, + column: 8, + endColumn: 13, }, ], }, @@ -529,6 +591,9 @@ const x: Foo = { { messageId: 'missingReturnType', line: 4, + endLine: 4, + column: 8, + endColumn: 13, }, ], }, @@ -540,7 +605,9 @@ const x: Foo = { { messageId: 'missingReturnType', line: 1, + endLine: 1, column: 7, + endColumn: 12, }, ], }, @@ -552,7 +619,9 @@ const x: Foo = { { messageId: 'missingReturnType', line: 1, + endLine: 1, column: 7, + endColumn: 18, }, ], }, @@ -564,7 +633,9 @@ const x: Foo = { { messageId: 'missingReturnType', line: 1, + endLine: 1, column: 16, + endColumn: 21, }, ], }, @@ -576,7 +647,9 @@ const x: Foo = { { messageId: 'missingReturnType', line: 1, + endLine: 1, column: 16, + endColumn: 27, }, ], }, @@ -588,7 +661,9 @@ const x: Foo = { { messageId: 'missingReturnType', line: 1, + endLine: 1, column: 24, + endColumn: 29, }, ], }, @@ -600,7 +675,9 @@ const x: Foo = { { messageId: 'missingReturnType', line: 1, + endLine: 1, column: 24, + endColumn: 35, }, ], }, @@ -623,7 +700,9 @@ function FunctionDeclaration() { { messageId: 'missingReturnType', line: 7, + endLine: 7, column: 11, + endColumn: 16, }, ], }, @@ -635,7 +714,9 @@ function FunctionDeclaration() { { messageId: 'missingReturnType', line: 1, + endLine: 1, column: 22, + endColumn: 27, }, ], }, @@ -659,22 +740,37 @@ foo(() => '') { messageId: 'missingReturnType', line: 3, + endLine: 3, + column: 5, + endColumn: 10, }, { messageId: 'missingReturnType', line: 4, + endLine: 4, + column: 5, + endColumn: 10, }, { messageId: 'missingReturnType', line: 5, + endLine: 5, + column: 5, + endColumn: 10, }, { messageId: 'missingReturnType', line: 6, + endLine: 6, + column: 5, + endColumn: 10, }, { messageId: 'missingReturnType', line: 7, + endLine: 7, + column: 5, + endColumn: 10, }, ], }, @@ -700,7 +796,9 @@ new Accumulator().accumulate(() => 1); { messageId: 'missingReturnType', line: 10, + endLine: 10, column: 30, + endColumn: 35, }, ], }, @@ -716,7 +814,9 @@ new Accumulator().accumulate(() => 1); { messageId: 'missingReturnType', line: 1, + endLine: 1, column: 2, + endColumn: 7, }, ], }, @@ -749,17 +849,23 @@ foo({ { messageId: 'missingReturnType', line: 4, - column: 7, + endLine: 4, + column: 3, + endColumn: 9, }, { messageId: 'missingReturnType', line: 9, + endLine: 9, column: 9, + endColumn: 20, }, { messageId: 'missingReturnType', line: 14, + endLine: 14, column: 9, + endColumn: 14, }, ], }, @@ -778,12 +884,16 @@ const func = (value: number) => ({ type: "X", value } as Action); { messageId: 'missingReturnType', line: 2, + endLine: 2, column: 14, + endColumn: 32, }, { messageId: 'missingReturnType', line: 3, + endLine: 3, column: 14, + endColumn: 32, }, ], }, @@ -801,7 +911,9 @@ const func = (value: number) => ({ type: "X", value } as const); { messageId: 'missingReturnType', line: 2, + endLine: 2, column: 14, + endColumn: 32, }, ], },