Repository: vuejs/eslint-plugin-vue (js)

Issue:
no-use-v-if-with-v-for error
<!--
  Before posting the issue, please confirm that the problem you're getting
  is not related with your code editor configuration.
  To make sure it's not, run: yarn eslint src/your-file.vue
-->

**Tell us about your environment**	
* **ESLint version:** 6.8.0
* **eslint-plugin-vue version:** 6.2.1
* **Node version:**	v12.16.1

**Please show your full configuration:**
<!-- Paste content of your .eslintrc file -->
```json
{
    "root": true,
    "env": {
      "node": true,
      "es6": true
    },
    "extends": [
      "plugin:vue/essential",
      "@vue/prettier"
    ],
    "rules": {
      "no-console": 0,
      "max-len": [
        "error",
        {
          "code": 120,
          "ignoreComments": true
        }
      ],
      "prettier/prettier": [
        "warn",
        {
          "printWidth": 120,
          "tabWidth": 2,
          "bracketSpacing": false
        }
      ]
    },
    "parserOptions": {
      "parser": "babel-eslint"
    }
  }
```

**What did you do?**	
<!-- Please include the actual source code causing the issue. -->
As you can see I break the *no-use-v-if-with-v-for* rule, but instead to see an error, there is a execution error.
```vue
<template>
  <b-navbar-nav v-if="ready" align="center">
    <b-dropdown text="Menu"  lazy variant="lynk" size="sm">
      <!--b-dropdown-header>Dropdown header</b-dropdown-header-->
      <b-dropdown-item
        v-for="{path, name, hidden, icon, description} in userData.functions"
        v-if="!hidden"
        :key="path"
        :to="path"
      >
        <icon v-if="icon" :name="icon" /> {{ name || description || path }}
      </b-dropdown-item>
    </b-dropdown>
    <b-nav-item
      v-for="{path, name, inNav, icon, description} in userData.functions"
      v-if="inNav"
      :to="path"
      :key="path + 'Nav'"
    >
      <icon v-if="icon" :name="icon" scale="0.5" /> {{ name || description || path }}
    </b-nav-item>
  </b-navbar-nav>
</template>

<script>
import {createNamespacedHelpers} from "vuex";
const {mapState} = createNamespacedHelpers("auth");
export default {
  name: "ITDMenu",
  data() {
    return {};
  },
  computed: {
    ...mapState(["userData"]),
    ready() {
      return this?.userData?.functions?.some(el => !el.hidden);
    }
  }
};
</script>

```

**What did you expect to happen?**
I expect to see an error output.

**What actually happened?**
If I fix the error, the linter starts working again:
```vue
<template>
  <b-navbar-nav v-if="ready" align="center">
    <b-dropdown text="Menu" lazy variant="lynk" size="sm">
      <b-dropdown-item v-for="{path, name, icon, description} in functionsMenu" :key="path" :to="path">
        <icon v-if="icon" :name="icon" /> {{ name || description || path }}
      </b-dropdown-item>
    </b-dropdown>
    <b-nav-item v-for="{path, name, icon, description} in functionsNav" :to="path" :key="path + 'Nav'">
      <icon v-if="icon" :name="icon" scale="0.5" /> {{ name || description || path }}
    </b-nav-item>
  </b-navbar-nav>
</template>

<script>
import {mapState} from "vuex";
export default {
  name: "ITDMenu",
  computed: {
    ...mapState("auth", ["userData"]),
    functionsMenu() {
      return this?.userData?.functions?.filter(el => !el.hidden) || [];
    },
    functionsNav() {
      return this?.userData?.functions?.filter(el => el.inNav) || [];
    },
    ready() {
      return this?.userData?.functions?.some(el => !el.hidden);
    }
  }
};
</script>
```
<!-- Please include the actual, raw output from ESLint. -->
the actual error is: 
```
± |develop U:270 ?:266 ✗| → yarn run eslint src/ITDMenu.vue                                                                                                                                                                                                                                                                                                                                    
TypeError: Cannot read property 'name' of undefined                                                                                                                                                                                                                                                                                                                                            
Occurred while linting /var/www/itdfw/dobleimpacto.itdmovil.cl/vue/src/ITDMenu.vue:26                                                                                                                                                                                                                                                                                                          
    at EventEmitter.VAttribute[directive=true][key.name.name='if'] (/var/www/itdfw/dobleimpacto.itdmovil.cl/vue/.yarn/$$virtual/eslint-plugin-vue-virtual-341ee9d370/6/home/jcmunoz/.yarn/berry/cache/eslint-plugin-vue-npm-6.2.1-a4fea6596b-2.zip/node_modules/eslint-plugin-vue/lib/rules/no-use-v-if-with-v-for.js:85:44)                                                                   
    at EventEmitter.emit (events.js:323:22)                                                                                                                                                                                                                                                                                                                                                    
    at NodeEventGenerator.applySelector (/var/www/itdfw/dobleimpacto.itdmovil.cl/vue/.yarn/$$virtual/vue-eslint-parser-virtual-63f41d2821/6/home/jcmunoz/.yarn/berry/cache/vue-eslint-parser-npm-7.0.0-d5f23305ab-2.zip/node_modules/vue-eslint-parser/index.js:3276:26)                                                                                                                       
    at NodeEventGenerator.applySelectors (/var/www/itdfw/dobleimpacto.itdmovil.cl/vue/.yarn/$$virtual/vue-eslint-parser-virtual-63f41d2821/6/home/jcmunoz/.yarn/berry/cache/vue-eslint-parser-npm-7.0.0-d5f23305ab-2.zip/node_modules/vue-eslint-parser/index.js:3290:22)                                                                                                                      
    at NodeEventGenerator.enterNode (/var/www/itdfw/dobleimpacto.itdmovil.cl/vue/.yarn/$$virtual/vue-eslint-parser-virtual-63f41d2821/6/home/jcmunoz/.yarn/berry/cache/vue-eslint-parser-npm-7.0.0-d5f23305ab-2.zip/node_modules/vue-eslint-parser/index.js:3298:14)                                                                                                                           
    at traverse (/var/www/itdfw/dobleimpacto.itdmovil.cl/vue/.yarn/$$virtual/vue-eslint-parser-virtual-63f41d2821/6/home/jcmunoz/.yarn/berry/cache/vue-eslint-parser-npm-7.0.0-d5f23305ab-2.zip/node_modules/vue-eslint-parser/index.js:113:13)                                                                                                                                                
    at traverse (/var/www/itdfw/dobleimpacto.itdmovil.cl/vue/.yarn/$$virtual/vue-eslint-parser-virtual-63f41d2821/6/home/jcmunoz/.yarn/berry/cache/vue-eslint-parser-npm-7.0.0-d5f23305ab-2.zip/node_modules/vue-eslint-parser/index.js:120:21)                                                                                                                                                
    at traverse (/var/www/itdfw/dobleimpacto.itdmovil.cl/vue/.yarn/$$virtual/vue-eslint-parser-virtual-63f41d2821/6/home/jcmunoz/.yarn/berry/cache/vue-eslint-parser-npm-7.0.0-d5f23305ab-2.zip/node_modules/vue-eslint-parser/index.js:125:13)                                                                                                                                                
    at traverse (/var/www/itdfw/dobleimpacto.itdmovil.cl/vue/.yarn/$$virtual/vue-eslint-parser-virtual-63f41d2821/6/home/jcmunoz/.yarn/berry/cache/vue-eslint-parser-npm-7.0.0-d5f23305ab-2.zip/node_modules/vue-eslint-parser/index.js:120:21)                                                                                                                                                
    at traverse (/var/www/itdfw/dobleimpacto.itdmovil.cl/vue/.yarn/$$virtual/vue-eslint-parser-virtual-63f41d2821/6/home/jcmunoz/.yarn/berry/cache/vue-eslint-parser-npm-7.0.0-d5f23305ab-2.zip/node_modules/vue-eslint-parser/index.js:120:21)  
```


Pull request:
Fixed no-use-v-if-with-v-for error when using destructuring for iteration or using iteration of expression
fixed #1069 

Patch:
diff --git a/lib/rules/no-use-v-if-with-v-for.js b/lib/rules/no-use-v-if-with-v-for.js
index 754086f7..70d72075 100644
--- a/lib/rules/no-use-v-if-with-v-for.js
+++ b/lib/rules/no-use-v-if-with-v-for.js
@@ -37,7 +37,7 @@ function getVForUsingIterationVar (vIf) {
       variable.kind === 'v-for'
     )
     if (targetVFor) {
-      return targetVFor.id.parent
+      return targetVFor
     }
   }
   return undefined
@@ -76,13 +76,20 @@ module.exports = {
         if (utils.hasDirective(element, 'for')) {
           if (isUsingIterationVar(node)) {
             if (!allowUsingIterationVar) {
-              const vFor = getVForUsingIterationVar(node)
+              const vForVar = getVForUsingIterationVar(node)
+
+              let targetVForExpr = vForVar.id.parent
+              while (targetVForExpr.type !== 'VForExpression') {
+                targetVForExpr = targetVForExpr.parent
+              }
+              const iteratorNode = targetVForExpr.right
               context.report({
                 node,
                 loc: node.loc,
-                message: "The '{{iteratorName}}' variable inside 'v-for' directive should be replaced with a computed property that returns filtered array instead. You should not mix 'v-for' with 'v-if'.",
+                message: "The '{{iteratorName}}' {{kind}} inside 'v-for' directive should be replaced with a computed property that returns filtered array instead. You should not mix 'v-for' with 'v-if'.",
                 data: {
-                  iteratorName: vFor.right.name
+                  iteratorName: iteratorNode.type === 'Identifier' ? iteratorNode.name : context.getSourceCode().getText(iteratorNode),
+                  kind: iteratorNode.type === 'Identifier' ? 'variable' : 'expression'
                 }
               })
             }


Test patch:
diff --git a/tests/lib/rules/no-use-v-if-with-v-for.js b/tests/lib/rules/no-use-v-if-with-v-for.js
index a47e858a..c8bcda78 100644
--- a/tests/lib/rules/no-use-v-if-with-v-for.js
+++ b/tests/lib/rules/no-use-v-if-with-v-for.js
@@ -73,6 +73,55 @@ tester.run('no-use-v-if-with-v-for', rule, {
           </ul>
         </template>
       `
+    },
+    {
+      filename: 'test.vue',
+      code: '<template><div><div v-for="{x} in list" v-if="x"></div></div></template>',
+      options: [{ allowUsingIterationVar: true }]
+    },
+    {
+      filename: 'test.vue',
+      code: '<template><div><div v-for="{x,y,z} in list" v-if="y.foo"></div></div></template>',
+      options: [{ allowUsingIterationVar: true }]
+    },
+    {
+      filename: 'test.vue',
+      code: '<template><div><div v-for="({x,y,z},i) in list" v-if="i%2==0"></div></div></template>',
+      options: [{ allowUsingIterationVar: true }]
+    },
+    {
+      filename: 'test.vue',
+      code: '<template><div v-if="shown"><div v-for="({x,y,z},i) in list"></div></div></template>'
+    },
+    {
+      filename: 'test.vue',
+      code: `
+        <template>
+          <ul>
+            <li
+              v-for="{user} in activeUsers"
+              :key="user.id"
+            >
+              {{ user.name }}
+            <li>
+          </ul>
+        </template>
+      `
+    },
+    {
+      filename: 'test.vue',
+      code: `
+        <template>
+          <ul v-if="shouldShowUsers">
+            <li
+              v-for="{user} in users"
+              :key="user.id"
+            >
+              {{ user.name }}
+            <li>
+          </ul>
+        </template>
+      `
     }
   ],
   invalid: [
@@ -139,6 +188,70 @@ tester.run('no-use-v-if-with-v-for', rule, {
         message: "This 'v-if' should be moved to the wrapper element.",
         line: 6
       }]
+    },
+    {
+      filename: 'test.vue',
+      code: '<template><div><div v-for="{x,y,z} in list" v-if="z.isActive"></div></div></template>',
+      errors: [{
+        message: "The 'list' variable inside 'v-for' directive should be replaced with a computed property that returns filtered array instead. You should not mix 'v-for' with 'v-if'.",
+        line: 1
+      }]
+    },
+    {
+      filename: 'test.vue',
+      code: `
+        <template>
+          <ul>
+            <li
+              v-for="{foo, bar, user} in users"
+              v-if="user.isActive"
+              :key="user.id"
+            >
+              {{ user.name }}
+            <li>
+          </ul>
+        </template>
+      `,
+      errors: [{
+        message: "The 'users' variable inside 'v-for' directive should be replaced with a computed property that returns filtered array instead. You should not mix 'v-for' with 'v-if'.",
+        line: 6
+      }]
+    },
+    {
+      filename: 'test.vue',
+      code: `
+        <template>
+          <ul>
+            <li
+              v-for="{foo, bar, user} in users"
+              v-if="shouldShowUsers"
+              :key="user.id"
+            >
+              {{ user.name }}
+            <li>
+          </ul>
+        </template>
+      `,
+      errors: [{
+        message: "This 'v-if' should be moved to the wrapper element.",
+        line: 6
+      }]
+    },
+    {
+      filename: 'test.vue',
+      code: '<template><div><div v-for="{x} in list()" v-if="x.isActive"></div></div></template>',
+      errors: [{
+        message: "The 'list()' expression inside 'v-for' directive should be replaced with a computed property that returns filtered array instead. You should not mix 'v-for' with 'v-if'.",
+        line: 1
+      }]
+    },
+    {
+      filename: 'test.vue',
+      code: '<template><div><div v-for="i in 5" v-if="i"></div></div></template>',
+      errors: [{
+        message: "The '5' expression inside 'v-for' directive should be replaced with a computed property that returns filtered array instead. You should not mix 'v-for' with 'v-if'.",
+        line: 1
+      }]
     }
   ]
 })