diff --git a/lib/rules/no-unused-prop-types.js b/lib/rules/no-unused-prop-types.js index be9054934c..aa70e176b4 100644 --- a/lib/rules/no-unused-prop-types.js +++ b/lib/rules/no-unused-prop-types.js @@ -635,7 +635,7 @@ module.exports = { break; } - components.set(node, { + components.set(component ? component.node : node, { usedPropTypes: usedPropTypes, ignorePropsValidation: ignorePropsValidation }); diff --git a/tests/lib/rules/no-unused-prop-types.js b/tests/lib/rules/no-unused-prop-types.js index 02a6032273..1678fe8b02 100644 --- a/tests/lib/rules/no-unused-prop-types.js +++ b/tests/lib/rules/no-unused-prop-types.js @@ -10,6 +10,7 @@ var rule = require('../../../lib/rules/no-unused-prop-types'); var RuleTester = require('eslint').RuleTester; +var assign = require('object.assign'); var parserOptions = { ecmaVersion: 6, @@ -1461,6 +1462,219 @@ ruleTester.run('no-unused-prop-types', rule, { '};' ].join('\n'), parserOptions: parserOptions + }, { + // Props used inside of an async class property + code: [ + 'export class Example extends Component {', + ' static propTypes = {', + ' foo: PropTypes.func,', + ' }', + ' classProperty = async () => {', + ' await this.props.foo();', + ' };', + '}' + ].join('\n'), + parser: 'babel-eslint' + }, { + // Multiple props used inside of an async class property + code: [ + 'export class Example extends Component {', + ' static propTypes = {', + ' foo: PropTypes.func,', + ' bar: PropTypes.func,', + ' baz: PropTypes.func,', + ' }', + ' classProperty = async () => {', + ' await this.props.foo();', + ' await this.props.bar();', + ' await this.props.baz();', + ' };', + '}' + ].join('\n'), + parser: 'babel-eslint' + }, { + // Destructured props inside of async class property + code: [ + 'export class Example extends Component {', + ' static propTypes = {', + ' foo: PropTypes.func,', + ' }', + ' classProperty = async () => {', + ' const { foo } = this.props;', + ' await foo();', + ' };', + '}' + ].join('\n'), + parser: 'babel-eslint' + }, { + // Multiple destructured props inside of async class property + code: [ + 'export class Example extends Component {', + ' static propTypes = {', + ' foo: PropTypes.func,', + ' bar: PropTypes.func,', + ' baz: PropTypes.func,', + ' }', + ' classProperty = async () => {', + ' const { foo, bar, baz } = this.props;', + ' await foo();', + ' await bar();', + ' await baz();', + ' };', + '}' + ].join('\n'), + parser: 'babel-eslint' + }, { + // Props used inside of an async class method + code: [ + 'export class Example extends Component {', + ' static propTypes = {', + ' foo: PropTypes.func,', + ' }', + ' async method() {', + ' await this.props.foo();', + ' };', + '}' + ].join('\n'), + parser: 'babel-eslint' + }, { + // Multiple props used inside of an async class method + code: [ + 'export class Example extends Component {', + ' static propTypes = {', + ' foo: PropTypes.func,', + ' bar: PropTypes.func,', + ' baz: PropTypes.func,', + ' }', + ' async method() {', + ' await this.props.foo();', + ' await this.props.bar();', + ' await this.props.baz();', + ' };', + '}' + ].join('\n'), + parser: 'babel-eslint' + }, { + // Destrucuted props inside of async class method + code: [ + 'export class Example extends Component {', + ' static propTypes = {', + ' foo: PropTypes.func,', + ' }', + ' async method() {', + ' const { foo } = this.props;', + ' await foo();', + ' };', + '}' + ].join('\n'), + parser: 'babel-eslint' + }, { + // Multiple destrucuted props inside of async class method + code: [ + 'export class Example extends Component {', + ' static propTypes = {', + ' foo: PropTypes.func,', + ' bar: PropTypes.func,', + ' baz: PropTypes.func,', + ' }', + ' async method() {', + ' const { foo, bar, baz } = this.props;', + ' await foo();', + ' await bar();', + ' await baz();', + ' };', + '}' + ].join('\n'), + parser: 'babel-eslint' + }, { + // factory functions that return async functions + code: [ + 'export class Example extends Component {', + ' static propTypes = {', + ' foo: PropTypes.func,', + ' bar: PropTypes.func,', + ' baz: PropTypes.func,', + ' }', + ' factory() {', + ' return async () => {', + ' await this.props.foo();', + ' await this.props.bar();', + ' await this.props.baz();', + ' };', + ' }', + '}' + ].join('\n'), + parser: 'babel-eslint' + }, { + // factory functions that return async functions + code: [ + 'export class Example extends Component {', + ' static propTypes = {', + ' foo: PropTypes.func,', + ' bar: PropTypes.func,', + ' baz: PropTypes.func,', + ' }', + ' factory() {', + ' return async function onSubmit() {', + ' await this.props.foo();', + ' await this.props.bar();', + ' await this.props.baz();', + ' };', + ' }', + '}' + ].join('\n'), + parser: 'babel-eslint' + }, { + // Multiple props used inside of an async method + code: [ + 'class Example extends Component {', + ' async method() {', + ' await this.props.foo();', + ' await this.props.bar();', + ' };', + '}', + 'Example.propTypes = {', + ' foo: PropTypes.func,', + ' bar: PropTypes.func,', + '}' + ].join('\n'), + parserOptions: assign({}, parserOptions, {ecmaVersion: 2017}) + }, { + // Multiple props used inside of an async function + code: [ + 'class Example extends Component {', + ' render() {', + ' async function onSubmit() {', + ' await this.props.foo();', + ' await this.props.bar();', + ' }', + ' return
', + ' };', + '}', + 'Example.propTypes = {', + ' foo: PropTypes.func,', + ' bar: PropTypes.func,', + '}' + ].join('\n'), + parserOptions: assign({}, parserOptions, {ecmaVersion: 2017}) + }, { + // Multiple props used inside of an async arrow function + code: [ + 'class Example extends Component {', + ' render() {', + ' const onSubmit = async () => {', + ' await this.props.foo();', + ' await this.props.bar();', + ' }', + ' return ', + ' };', + '}', + 'Example.propTypes = {', + ' foo: PropTypes.func,', + ' bar: PropTypes.func,', + '}' + ].join('\n'), + parserOptions: assign({}, parserOptions, {ecmaVersion: 2017}) } ], @@ -2438,6 +2652,170 @@ ruleTester.run('no-unused-prop-types', rule, { line: 3, column: 16 }] + }, { + // Multiple props used inside of an async class property + code: [ + 'export class Example extends Component {', + ' static propTypes = {', + ' foo: PropTypes.func,', + ' bar: PropTypes.func,', + ' baz: PropTypes.func,', + ' }', + ' classProperty = async () => {', + ' await this.props.foo();', + ' await this.props.bar();', + ' };', + '}' + ].join('\n'), + parser: 'babel-eslint', + errors: [{ + message: '\'baz\' PropType is defined but prop is never used' + }] + }, { + // Multiple destructured props inside of async class property + code: [ + 'export class Example extends Component {', + ' static propTypes = {', + ' foo: PropTypes.func,', + ' bar: PropTypes.func,', + ' baz: PropTypes.func,', + ' }', + ' classProperty = async () => {', + ' const { bar, baz } = this.props;', + ' await bar();', + ' await baz();', + ' };', + '}' + ].join('\n'), + parser: 'babel-eslint', + errors: [{ + message: '\'foo\' PropType is defined but prop is never used' + }] + }, { + // Multiple props used inside of an async class method + code: [ + 'export class Example extends Component {', + ' static propTypes = {', + ' foo: PropTypes.func,', + ' bar: PropTypes.func,', + ' baz: PropTypes.func,', + ' }', + ' async method() {', + ' await this.props.foo();', + ' await this.props.baz();', + ' };', + '}' + ].join('\n'), + parser: 'babel-eslint', + errors: [{ + message: '\'bar\' PropType is defined but prop is never used' + }] + }, { + // Multiple destrucuted props inside of async class method + code: [ + 'export class Example extends Component {', + ' static propTypes = {', + ' foo: PropTypes.func,', + ' bar: PropTypes.func,', + ' baz: PropTypes.func,', + ' }', + ' async method() {', + ' const { foo, bar } = this.props;', + ' await foo();', + ' await bar();', + ' };', + '}' + ].join('\n'), + parser: 'babel-eslint', + errors: [{ + message: '\'baz\' PropType is defined but prop is never used' + }] + }, { + // factory functions that return async functions + code: [ + 'export class Example extends Component {', + ' static propTypes = {', + ' foo: PropTypes.func,', + ' bar: PropTypes.func,', + ' baz: PropTypes.func,', + ' }', + ' factory() {', + ' return async () => {', + ' await this.props.foo();', + ' await this.props.bar();', + ' };', + ' }', + '}' + ].join('\n'), + parser: 'babel-eslint', + errors: [{ + message: '\'baz\' PropType is defined but prop is never used' + }] + }, { + // factory functions that return async functions + code: [ + 'export class Example extends Component {', + ' static propTypes = {', + ' foo: PropTypes.func,', + ' bar: PropTypes.func,', + ' baz: PropTypes.func,', + ' }', + ' factory() {', + ' return async function onSubmit() {', + ' await this.props.bar();', + ' await this.props.baz();', + ' };', + ' }', + '}' + ].join('\n'), + parser: 'babel-eslint', + errors: [{ + message: '\'foo\' PropType is defined but prop is never used' + }] + }, { + // Multiple props used inside of an async function + code: [ + 'class Example extends Component {', + ' render() {', + ' async function onSubmit() {', + ' await this.props.foo();', + ' await this.props.bar();', + ' }', + ' return ', + ' };', + '}', + 'Example.propTypes = {', + ' foo: PropTypes.func,', + ' bar: PropTypes.func,', + ' baz: PropTypes.func,', + '}' + ].join('\n'), + parserOptions: assign({}, parserOptions, {ecmaVersion: 2017}), + errors: [{ + message: '\'baz\' PropType is defined but prop is never used' + }] + }, { + // Multiple props used inside of an async arrow function + code: [ + 'class Example extends Component {', + ' render() {', + ' const onSubmit = async () => {', + ' await this.props.bar();', + ' await this.props.baz();', + ' }', + ' return ', + ' };', + '}', + 'Example.propTypes = {', + ' foo: PropTypes.func,', + ' bar: PropTypes.func,', + ' baz: PropTypes.func,', + '}' + ].join('\n'), + parserOptions: assign({}, parserOptions, {ecmaVersion: 2017}), + errors: [{ + message: '\'foo\' PropType is defined but prop is never used' + }] }/* , { // Enable this when the following issue is fixed // https://github.com/yannickcr/eslint-plugin-react/issues/296