Repository: vuejs/vue
Pull request: fix merge strategy function of option props, methods, inject & computed

fix #6093 .
<!--
Please make sure to read the Pull Request Guidelines:
https://github.com/vuejs/vue/blob/dev/.github/CONTRIBUTING.md#pull-request-guidelines
-->

<!-- PULL REQUEST TEMPLATE -->
<!-- (Update "[ ]" to "[x]" to check a box) -->

**What kind of change does this PR introduce?** (check at least one)

- [x] Bugfix
- [ ] Feature
- [ ] Code style update
- [ ] Refactor
- [ ] Build-related changes
- [ ] Other, please describe:

**Does this PR introduce a breaking change?** (check one)

- [ ] Yes
- [x] No

If yes, please describe the impact and migration path for existing applications:

**The PR fulfills these requirements:**

- [x] It's submitted to the `dev` branch for v2.x (or to a previous version branch), _not_ the `master` branch
- [x] When resolving a specific issue, it's referenced in the PR's title (e.g. `fix #xxx[,#xxx]`, where "xxx" is the issue number)
- [x] All tests are passing: https://github.com/vuejs/vue/blob/dev/.github/CONTRIBUTING.md#development-setup
- [x] New/updated tests are included

**Other information:**
See [https://github.com/vuejs/vue/pull/6098#issuecomment-315296414](https://github.com/vuejs/vue/pull/6098#issuecomment-315296414)

Changed files:
filename: src/core/instance/inject.js
patch: @@ -1,7 +1,6 @@
 /* @flow */
 
 import { warn } from '../util/index'
-import { hasOwn } from 'shared/util'
 import { hasSymbol } from 'core/util/env'
 import { defineReactive, observerState } from '../observer/index'
 
@@ -56,7 +55,7 @@ export function resolveInject (inject: any, vm: Component): ?Object {
         }
         source = source.$parent
       }
-      if (process.env.NODE_ENV !== 'production' && !hasOwn(result, key)) {
+      if (process.env.NODE_ENV !== 'production' && !source) {
         warn(`Injection "${key}" not found`, vm)
       }
     }

filename: src/core/util/options.js
patch: @@ -201,11 +201,10 @@ strats.props =
 strats.methods =
 strats.inject =
 strats.computed = function (parentVal: ?Object, childVal: ?Object): ?Object {
-  if (!childVal) return Object.create(parentVal || null)
   if (!parentVal) return childVal
   const ret = Object.create(null)
   extend(ret, parentVal)
-  extend(ret, childVal)
+  if (childVal) extend(ret, childVal)
   return ret
 }
 strats.provide = mergeDataOrFn

filename: test/unit/features/options/inject.spec.js
patch: @@ -250,6 +250,68 @@ describe('Options provide/inject', () => {
     expect(injected).toEqual([1, false])
   })
 
+  it('should merge from mixins properly (objects)', () => {
+    const mixinA = { inject: { foo: 'foo' }}
+    const mixinB = { inject: { bar: 'bar' }}
+    const child = {
+      mixins: [mixinA, mixinB],
+      template: `<span/>`,
+      created () {
+        injected = [this.foo, this.bar]
+      }
+    }
+    new Vue({
+      provide: { foo: 'foo', bar: 'bar', baz: 'baz' },
+      render (h) {
+        return h(child)
+      }
+    }).$mount()
+
+    expect(injected).toEqual(['foo', 'bar'])
+  })
+
+  it('should merge from mixins properly (arrays)', () => {
+    const mixinA = { inject: ['foo'] }
+    const mixinB = { inject: ['bar'] }
+    const child = {
+      mixins: [mixinA, mixinB],
+      inject: ['baz'],
+      template: `<span/>`,
+      created () {
+        injected = [this.foo, this.bar, this.baz]
+      }
+    }
+    new Vue({
+      provide: { foo: 'foo', bar: 'bar', baz: 'baz' },
+      render (h) {
+        return h(child)
+      }
+    }).$mount()
+
+    expect(injected).toEqual(['foo', 'bar', 'baz'])
+  })
+
+  it('should merge from mixins properly (mix of objects and arrays)', () => {
+    const mixinA = { inject: { foo: 'foo' }}
+    const mixinB = { inject: ['bar'] }
+    const child = {
+      mixins: [mixinA, mixinB],
+      inject: { qux: 'baz' },
+      template: `<span/>`,
+      created () {
+        injected = [this.foo, this.bar, this.qux]
+      }
+    }
+    new Vue({
+      provide: { foo: 'foo', bar: 'bar', baz: 'baz' },
+      render (h) {
+        return h(child)
+      }
+    }).$mount()
+
+    expect(injected).toEqual(['foo', 'bar', 'baz'])
+  })
+
   it('should warn when injections has been modified', () => {
     const key = 'foo'
     const vm = new Vue({