| this.foo = this.foo + 1; // OK - outside of function. |
| |
| function f() { |
| this.foo = this.foo + 1; // OK - global |this|. |
| } |
| |
| /** |
| * @constructor |
| */ |
| function TypeOne() { |
| this.foo = this.foo + 1; // OK - object field in ctor. |
| |
| /** |
| * @this {TypeOne} |
| */ |
| function callbackOne() { |
| this.foo = this.foo + 1; // OK - @this declared. |
| |
| function badInnerCallback() { |
| this.foo = this.foo + 2; // ERROR - @this not declared. |
| } |
| } |
| |
| function badCallbackInCtor() { |
| this.foo = this.foo + 1; // ERROR - @this not declared. |
| } |
| } |
| |
| TypeOne.prototype = { |
| addListener: function(callback) |
| { |
| if (typeof callback !== "function") |
| throw "addListener: callback is not a function"; |
| if (this._listeners.length === 0) |
| extensionServer.sendRequest({ command: commands.Subscribe, type: this._type }); |
| this._listeners.push(callback); |
| extensionServer.registerHandler("notify-" + this._type, this._dispatch.bind(this)); |
| }, |
| |
| funcOne: function() { |
| this.foo = this.foo + 1; // OK - in method. |
| }, |
| |
| funcTwo: function() { |
| /** |
| * @this {TypeOne} |
| */ |
| function callback() { |
| this.foo = this.foo + 1; // OK - @this declared. |
| } |
| }, |
| |
| funcThree: function() { |
| function badCallbackInMethod() { |
| this.foo = this.foo + 1; // ERROR - @this not declared. |
| } |
| } |
| } |
| |
| |
| /** |
| * @constructor |
| */ |
| TypeTwo = function() { |
| this.bar = this.bar + 1; // OK - object field in ctor. |
| |
| /** |
| * @this {TypeTwo} |
| */ |
| function callbackOne() { |
| this.bar = this.bar + 1; // OK - @this declared. |
| |
| function badInnerCallback() { |
| this.bar = this.bar + 2; // ERROR - @this not declared. |
| } |
| } |
| |
| function badCallbackInCtor() { |
| this.bar = this.bar + 1; // ERROR - @this not declared. |
| } |
| } |
| |
| TypeTwo.prototype = { |
| funcOne: function() { |
| this.bar = this.bar + 1; // OK - in method. |
| }, |
| |
| funcTwo: function() { |
| /** |
| * @this {TypeTwo} |
| */ |
| function callback() { |
| this.bar = this.bar + 1; // OK - @this declared. |
| } |
| }, |
| |
| funcThree: function() { |
| function badCallbackInMethod() { |
| this.bar = this.bar + 1; // ERROR - @this not declared. |
| } |
| } |
| } |
| |
| /** |
| * @return {!Object} |
| */ |
| function returnConstructedObject() { |
| |
| /** |
| * @constructor |
| */ |
| TypeThree = function() { |
| this.bar = this.bar + 1; // OK - object field in ctor. |
| |
| /** |
| * @this {TypeThree} |
| */ |
| function callbackOne() { |
| this.bar = this.bar + 1; // OK - @this declared. |
| |
| function badInnerCallback() { |
| this.bar = this.bar + 2; // ERROR - @this not declared. |
| } |
| } |
| |
| function badCallbackInCtor() { |
| this.bar = this.bar + 1; // ERROR - @this not declared. |
| } |
| } |
| |
| TypeThree.prototype = { |
| funcOne: function() { |
| this.bar = this.bar + 1; // OK - in method. |
| }, |
| |
| funcTwo: function() { |
| /** |
| * @this {TypeThree} |
| */ |
| function callback() { |
| this.bar = this.bar + 1; // OK - @this declared. |
| } |
| }, |
| |
| funcThree: function() { |
| function badCallbackInMethod() { |
| this.bar = this.bar + 1; // ERROR - @this not declared. |
| } |
| |
| /** |
| * @this {TypeOne} |
| */ |
| function callbackNotReferencingThis() { |
| return 3; // ERROR - @this for a function not referencing |this|. |
| } |
| } |
| } |
| |
| return new TypeThree(); |
| } |
| |
| var object = { |
| /** |
| * @this {MyType} |
| */ |
| value: function() |
| { |
| this.foo = 1; // OK - @this annotated. |
| } |
| }; |
| |
| (function() { |
| var object = { |
| /** |
| * @this {MyType} |
| */ |
| value: function() |
| { |
| this.foo = 1; // OK - @this annotated. |
| } |
| }; |
| })(); |
| |
| /** |
| * @constructor |
| */ |
| var ReceiverTest = function() {} |
| |
| ReceiverTest.prototype = { |
| memberOne: function() { |
| var badMemberBinding1 = this.memberTwo.bind(null); // ERROR - Member not bound to |this| receiver. |
| var badMemberBinding2 = this.memberTwo.bind(bar); // ERROR - Member not bound to |this| receiver. |
| var goodMemberBinding = this.memberTwo.bind(this); |
| |
| /** @this {ReceiverTest} */ |
| function callbackWithThis() |
| { |
| this.memberTwo(); |
| } |
| |
| function callbackNoThis() |
| { |
| return 42; |
| } |
| |
| callbackWithThis.call(this); |
| callbackWithThis.call(foo); |
| callbackNoThis(); |
| callbackNoThis.call(null, 1); |
| callbackNoThis.apply(null, [2]); |
| callbackNoThis.bind(null, 1); |
| this.memberTwo(callbackWithThis.bind(this, 1)); |
| this.memberTwo(callbackWithThis.bind(foo, 1)); |
| this.memberTwo(callbackNoThis); |
| this.memberTwo(callbackNoThis.bind(null)); |
| |
| callbackWithThis(); // ERROR - No receiver. |
| callbackWithThis.call(); // ERROR - No receiver. |
| callbackWithThis.call(null); // ERROR - No receiver. |
| callbackWithThis.apply(); // ERROR - No receiver. |
| callbackWithThis.apply(null); // ERROR - No receiver. |
| callbackNoThis.call(this); // ERROR - Function has no @this annotation. |
| callbackNoThis.call(foo); // ERROR - Function has no @this annotation. |
| callbackNoThis.apply(this); // ERROR - Function has no @this annotation. |
| callbackNoThis.bind(this); // ERROR - Function has no @this annotation. |
| |
| this.memberTwo(callbackWithThis); // ERROR - Used as argument with no bound receiver. |
| this.memberTwo(callbackWithThis.bind(null, 2)); // ERROR - Used as argument with no bound receiver (null means "no receiver"). |
| this.memberTwo(callbackNoThis.bind(this)); // ERROR - Bound to a receiver but has no @this annotation. |
| this.memberTwo(callbackNoThis.bind(foo)); // ERROR - Bound to a receiver but has no @this annotation. |
| |
| // Callback receivers specified as arguments. |
| |
| array.forEach(callbackWithThis, this); |
| array.forEach(callbackNoThis); |
| |
| array.forEach(callbackWithThis); // ERROR - No receiver. |
| array.forEach(callbackNoThis, this); // ERROR - Receiver for callback with no @this annotation. |
| |
| var isMultiline = false; |
| |
| element.addEventListener("click", callbackNoThis); |
| element.addEventListener("click", callbackNoThis, true); |
| element.addEventListener("click", callbackNoThis, false); |
| element.addEventListener("click", callbackNoThis, isMultiline); // OK - ignored. |
| |
| element.addEventListener("click", callbackNoThis, this); // ERROR. |
| |
| element.addEventListener("click", callbackWithThis, this); |
| element.addEventListener("click", callbackWithThis, foo); // OK - ignored. |
| element.addEventListener("click", callbackWithThis, isMultiline); // OK - ignored. |
| |
| element.addEventListener("click", callbackWithThis, true); // ERROR. |
| element.addEventListener("click", callbackWithThis, false); // ERROR. |
| |
| // DevTools-specific. |
| |
| /** |
| * @suppressReceiverCheck |
| * @this {Object} |
| */ |
| function ignoredCallbackWithThis() |
| { |
| this.foo = 1; |
| } |
| object.callFunction(func, [], ignoredCallbackWithThis); // OK - ignored. |
| |
| function callbackReferencingThisNotAnnotated() |
| { |
| this.foo = 2; |
| } |
| this.memberTwo(callbackReferencingThisNotAnnotated.bind(this)); // OK - No @this annotation, but references |this|. |
| |
| /** |
| * @this {Object} |
| */ |
| function callbackNotReferencingThisAnnotated() |
| { |
| } |
| this.memberTwo(callbackNotReferencingThisAnnotated); // OK - Has @this annotation, but does not reference |this|. |
| }, |
| |
| memberTwo: function(arg) {} |
| } |
| |
| /** |
| * @constructor |
| */ |
| function ReceiverWithArrowsTest() |
| { |
| this._q = []; |
| } |
| |
| ReceiverWithArrowsTest.prototype = { |
| /** |
| * @param {string} s |
| */ |
| memberOne: function(s) |
| { |
| /** |
| * @param {string} a |
| * @this {C} |
| */ |
| function testArrowFunctionReferencingThis(a) |
| { |
| (x => this._q.push(x))(a); |
| } |
| |
| /** |
| * @param {string} a |
| * @this {C} |
| */ |
| function testNestedArrowFunctionReferencingThis(a) |
| { |
| (x => (y => this._q.push(y))(x))(a); |
| } |
| |
| /** |
| * @param {string} a |
| */ |
| function testArrowFunctionReferencingThisMissingAnnotation(a) |
| { |
| (x => this._q.push(x))(a); |
| } |
| |
| } |
| }; |