diff --git a/lib/jsdoc/augment.js b/lib/jsdoc/augment.js index adef306b..570682a7 100644 --- a/lib/jsdoc/augment.js +++ b/lib/jsdoc/augment.js @@ -73,6 +73,7 @@ function getMembers(longname, docs) { function getAdditions(doclets, docs, documented) { var doop = require('jsdoc/util/doop'); + var additionIndexes; var additions = []; var doc; var parents; @@ -87,6 +88,8 @@ function getAdditions(doclets, docs, documented) { doc = doclets[i]; parents = doc.augments; if (parents && doc.kind === 'class') { + // reset the lookup table of added doclet indexes by longname + additionIndexes = {}; for (var j = 0, jj = parents.length; j < jj; j++) { members = getMembers(parents[j], docs); for (var k = 0, kk = members.length; k < kk; k++) { @@ -97,6 +100,8 @@ function getAdditions(doclets, docs, documented) { } member.inherited = true; + // TODO: this will fail on longnames like: MyClass#"quoted#Longname" + // and nested instance members like: MyClass#MyOtherClass#myMethod member.memberof = doc.longname; parts = member.longname.split('#'); parts[0] = doc.longname; @@ -105,7 +110,20 @@ function getAdditions(doclets, docs, documented) { // add the ancestor's docs, unless the descendant both a) overrides the // ancestor and b) documents the override if ( !hasOwnProp.call(documented, member.longname) ) { - additions.push(member); + // We add only one doclet per longname. If you inherit from two classes that + // both use the same method name, you get docs for one method rather than + // two. Last one wins; if you write `@extends Class1 @extends Class2`, and + // both classes have the instance method `myMethod`, you get the `myMethod` + // docs from Class2. + if (typeof additionIndexes[member.longname] !== 'undefined') { + // replace the existing doclet + additions[additionIndexes[member.longname]] = member; + } + else { + // add the doclet to the array, and track its index + additions.push(member); + additionIndexes[member.longname] = additions.length - 1; + } } } } diff --git a/test/fixtures/augmentstag5.js b/test/fixtures/augmentstag5.js new file mode 100644 index 00000000..dca225f1 --- /dev/null +++ b/test/fixtures/augmentstag5.js @@ -0,0 +1,36 @@ +/** @class */ +'use strict'; + +function Base0() {} + +Base0.prototype = /** @lends Base0# */ { + /** Description for {@link Base0#methodOfBaseCommon}. */ + methodOfBaseCommon: function() {}, + + /** Description for {@link Base0#methodOfBase0}. */ + methodOfBase0: function() {} +}; + +/** @class */ +function Base1() {} + +Base1.prototype = /** @lends Base1# */ { + /** Description for {@link Base1#methodOfBaseCommon}. */ + methodOfBaseCommon: function() {}, + + /** Description for {@link Base1#methodOfBase1}. */ + methodOfBase1: function() {} +}; + +/** + * @class + * @augments Base0 + * @augments Base1 + */ +function Class() {} + +Class.prototype = Object.create(Base0.prototype); + +Object.getOwnPropertyNames(Base1.prototype).forEach(function (prop) { + Object.defineProperty(Class.prototype, prop, Object.getOwnPropertyDescriptor(Base1.prototype, prop)); +}); diff --git a/test/specs/tags/augmentstag.js b/test/specs/tags/augmentstag.js index eaf90bb5..882ac21a 100644 --- a/test/specs/tags/augmentstag.js +++ b/test/specs/tags/augmentstag.js @@ -1,9 +1,12 @@ -/*global describe: true, expect: true, it: true, jasmine: true */ - describe("@augments tag", function() { +/*global describe, expect, it, jasmine */ +'use strict'; + + describe('@augments tag', function() { var docSet = jasmine.getDocSetFromFile('test/fixtures/augmentstag.js'); var docSet2 = jasmine.getDocSetFromFile('test/fixtures/augmentstag2.js'); var docSet3 = jasmine.getDocSetFromFile('test/fixtures/augmentstag3.js'); var docSet4 = jasmine.getDocSetFromFile('test/fixtures/augmentstag4.js'); + var docSet5 = jasmine.getDocSetFromFile('test/fixtures/augmentstag5.js'); it('When a symbol has an @augments tag, the doclet has a augments property that includes that value.', function() { var bar = docSet.getByLongname('Bar')[0]; @@ -128,4 +131,12 @@ expect(derivedMethod1.undocumented).not.toBe(true); expect(derivedMethod1.description).toBe(baseMethod1.description); }); + + it('When a symbol inherits two methods that would both have the same longname, the last one wins', function() { + var base1CommonMethod = docSet5.getByLongname('Base1#methodOfBaseCommon')[0]; + var classCommonMethod = docSet5.getByLongname('Class#methodOfBaseCommon'); + + expect(classCommonMethod.length).toBe(1); + expect(classCommonMethod[0].description).toBe(base1CommonMethod.description); + }); });