From ba80a4c01b1086f6fd1202ebc9c262fc5f05b65b Mon Sep 17 00:00:00 2001 From: Yannick Croissant Date: Sun, 6 Jan 2019 21:21:25 +0100 Subject: [PATCH] [Fix] Detect components with return statement in switch/case Fixes #2118 --- lib/util/ast.js | 20 ++++++++++++++------ tests/lib/rules/no-unused-prop-types.js | 24 ++++++++++++++++++++++++ tests/lib/rules/prop-types.js | 19 +++++++++++++++++++ tests/lib/rules/require-default-props.js | 23 +++++++++++++++++++++++ 4 files changed, 80 insertions(+), 6 deletions(-) diff --git a/lib/util/ast.js b/lib/util/ast.js index 90d41a2d5b..530c889e7f 100644 --- a/lib/util/ast.js +++ b/lib/util/ast.js @@ -18,13 +18,21 @@ function findReturnStatement(node) { const bodyNodes = (node.value ? node.value.body.body : node.body.body); - let i = bodyNodes.length - 1; - for (; i >= 0; i--) { - if (bodyNodes[i].type === 'ReturnStatement') { - return bodyNodes[i]; + return (function loopNodes(nodes) { + let i = nodes.length - 1; + for (; i >= 0; i--) { + if (nodes[i].type === 'ReturnStatement') { + return nodes[i]; + } + if (nodes[i].type === 'SwitchStatement') { + let j = nodes[i].cases.length - 1; + for (; j >= 0; j--) { + return loopNodes(nodes[i].cases[j].consequent); + } + } } - } - return false; + return false; + }(bodyNodes)); } /** diff --git a/tests/lib/rules/no-unused-prop-types.js b/tests/lib/rules/no-unused-prop-types.js index 1483370ff0..17f95dc112 100644 --- a/tests/lib/rules/no-unused-prop-types.js +++ b/tests/lib/rules/no-unused-prop-types.js @@ -4961,6 +4961,30 @@ ruleTester.run('no-unused-prop-types', rule, { errors: [{ message: '\'person.lastname\' PropType is defined but prop is never used' }] + }, { + code: ` + import PropTypes from 'prop-types'; + import React from 'react'; + + const MyComponent= (props) => { + switch (props.usedProp) { + case 1: + return (
); + default: + return
; + } + }; + + MyComponent.propTypes = { + usedProp: PropTypes.string, + unUsedProp: PropTypes.string, + }; + + export default MyComponent; + `, + errors: [{ + message: '\'unUsedProp\' PropType is defined but prop is never used' + }] } /* , { diff --git a/tests/lib/rules/prop-types.js b/tests/lib/rules/prop-types.js index 70f1ac0807..b72f043abc 100644 --- a/tests/lib/rules/prop-types.js +++ b/tests/lib/rules/prop-types.js @@ -4334,6 +4334,25 @@ ruleTester.run('prop-types', rule, { errors: [{ message: '\'text\' is missing in props validation' }] + }, { + code: ` + import PropTypes from 'prop-types'; + import React from 'react'; + + const MyComponent = (props) => { + switch (props.usedProp) { + case 1: + return (
); + default: + return
; + } + }; + + export default MyComponent; + `, + errors: [{ + message: '\'usedProp\' is missing in props validation' + }] } ] }); diff --git a/tests/lib/rules/require-default-props.js b/tests/lib/rules/require-default-props.js index a7a40d6207..200986b81b 100644 --- a/tests/lib/rules/require-default-props.js +++ b/tests/lib/rules/require-default-props.js @@ -2199,6 +2199,29 @@ ruleTester.run('require-default-props', rule, { errors: [{ message: 'propType "name" is not required, but has no corresponding defaultProps declaration.' }] + }, { + code: ` + import PropTypes from 'prop-types'; + import React from 'react'; + + const MyComponent= (props) => { + switch (props.usedProp) { + case 1: + return (
); + default: + return
; + } + }; + + MyComponent.propTypes = { + usedProp: PropTypes.string, + }; + + export default MyComponent; + `, + errors: [{ + message: 'propType "usedProp" is not required, but has no corresponding defaultProps declaration.' + }] } ] });