diff --git a/lib/rules/no-unused-prop-types.js b/lib/rules/no-unused-prop-types.js index be9054934c..744f211c96 100644 --- a/lib/rules/no-unused-prop-types.js +++ b/lib/rules/no-unused-prop-types.js @@ -18,6 +18,7 @@ var annotations = require('../util/annotations'); // ------------------------------------------------------------------------------ var DIRECT_PROPS_REGEX = /^props\s*(\.|\[)/; +var DIRECT_NEXT_PROPS_REGEX = /^nextProps\s*(\.|\[)/; // ------------------------------------------------------------------------------ // Rule Definition @@ -77,6 +78,24 @@ module.exports = { return value; } + /** + * Check if we are in a class constructor + * @return {boolean} true if we are in a class constructor, false if not + **/ + function inComponentWillReceiveProps() { + var scope = context.getScope(); + while (scope) { + if ( + scope.block && scope.block.parent && + scope.block.parent.key && scope.block.parent.key.name === 'componentWillReceiveProps' + ) { + return true; + } + scope = scope.upper; + } + return false; + } + /** * Checks if we are using a prop * @param {ASTNode} node The AST node being checked. @@ -88,7 +107,8 @@ module.exports = { node.object.type === 'ThisExpression' && node.property.name === 'props' ); var isStatelessFunctionUsage = node.object.name === 'props'; - return isClassUsage || isStatelessFunctionUsage; + var isNextPropsUsage = node.object.name === 'nextProps' && inComponentWillReceiveProps(); + return isClassUsage || isStatelessFunctionUsage || isNextPropsUsage; } /** @@ -491,12 +511,17 @@ module.exports = { */ function getPropertyName(node) { var isDirectProp = DIRECT_PROPS_REGEX.test(sourceCode.getText(node)); + var isDirectNextProp = DIRECT_NEXT_PROPS_REGEX.test(sourceCode.getText(node)); var isInClassComponent = utils.getParentES6Component() || utils.getParentES5Component(); var isNotInConstructor = !inConstructor(node); - if (isDirectProp && isInClassComponent && isNotInConstructor) { + var isNotInComponentWillReceiveProps = !inComponentWillReceiveProps(); + if ((isDirectProp || isDirectNextProp) + && isInClassComponent + && isNotInConstructor + && isNotInComponentWillReceiveProps) { return void 0; } - if (!isDirectProp) { + if (!isDirectProp && !isDirectNextProp) { node = node.parent; } var property = node.property; diff --git a/tests/lib/rules/no-unused-prop-types.js b/tests/lib/rules/no-unused-prop-types.js index 02a6032273..8611e10d70 100644 --- a/tests/lib/rules/no-unused-prop-types.js +++ b/tests/lib/rules/no-unused-prop-types.js @@ -1461,6 +1461,22 @@ ruleTester.run('no-unused-prop-types', rule, { '};' ].join('\n'), parserOptions: parserOptions + }, { + code: [ + 'class Hello extends Component {', + ' componentWillReceiveProps (nextProps) {', + ' if (nextProps.foo) {', + ' doSomething(this.props.bar);', + ' }', + ' }', + '}', + + 'Hello.propTypes = {', + ' foo: PropTypes.bool,', + ' bar: PropTypes.bool', + '};' + ].join('\n'), + parserOptions: parserOptions } ],