Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.
View | Details | Raw Unified | Return to bug 426930
Collapse All | Expand All

(-)a/bundles/org.eclipse.orion.client.javascript/web/javascript/finder.js (-2 / +2 lines)
Lines 71-77 Link Here
71
		 */
71
		 */
72
		findNode: function(offset, ast) {
72
		findNode: function(offset, ast) {
73
			var found = null;
73
			var found = null;
74
			if(offset != null && offset > -1 && ast) {
74
			if(offset !== null && offset > -1 && ast) {
75
				Estraverse.traverse(ast, {
75
				Estraverse.traverse(ast, {
76
					/**
76
					/**
77
					 * start visiting an AST node
77
					 * start visiting an AST node
Lines 103-109 Link Here
103
		 * @returns {Object} The AST token that starts at the given start offset
103
		 * @returns {Object} The AST token that starts at the given start offset
104
		 */
104
		 */
105
		findToken: function(offset, tokens) {
105
		findToken: function(offset, tokens) {
106
			if(offset != null && offset > -1 && tokens && tokens.length > 0) {
106
			if(offset !== null && offset > -1 && tokens && tokens.length > 0) {
107
				var min = 0,
107
				var min = 0,
108
					max = tokens.length-1,
108
					max = tokens.length-1,
109
					token, 
109
					token, 
(-)a/bundles/org.eclipse.orion.client.javascript/web/javascript/occurrences.js (-161 / +182 lines)
Lines 31-39 Link Here
31
		scopes: [],
31
		scopes: [],
32
		context: null,
32
		context: null,
33
		thisCheck: false,
33
		thisCheck: false,
34
		callExpressions: [],
35
		GENERAL: 1,
36
		FUNCTION: 2,
37
		
34
		
38
		/**
35
		/**
39
		 * @name enter
36
		 * @name enter
Lines 45-186 Link Here
45
		 * @returns The status if we should continue visiting
42
		 * @returns The status if we should continue visiting
46
		 */
43
		 */
47
		enter: function(node) {
44
		enter: function(node) {
48
			if (node.type === Estraverse.Syntax.Program){
45
			switch(node.type) {
49
				this.callExpressions = [];
46
				case Estraverse.Syntax.Program:
50
				this.occurrences = [];
47
					this.occurrences = [];
51
				this.scopes = [{range: node.range, occurrences: []}];
48
					this.scopes = [{range: node.range, occurrences: []}];
52
				this.defnode = null;
49
					this.defnode = null;
53
				this.defscope = null;
50
					this.defscope = null;
54
			} else if (this.thisCheck) {
51
					break;
55
				return this.enterThis(node);
52
				case Estraverse.Syntax.FunctionDeclaration:
56
			} else {
53
					this.checkId(node.id, true);
57
				switch(node.type) {
54
					//we want the parent scope for a declaration, otherwise we leave it right away
58
					case Estraverse.Syntax.FunctionDeclaration:
55
					this._enterScope(node);
59
						this.checkId(node.id, this.FUNCTION, true);
56
					if (node.params) {
60
						//we want the parent scope for a declaration, otherwise we leave it right away
57
						for (var i = 0; i < node.params.length; i++) {
61
						this.scopes.push({range: node.range, occurrences: []});
58
							if(this.checkId(node.params[i], true)) {
62
						if (node.params) {
59
								return Estraverse.VisitorOption.Skip;
63
							for (var i = 0; i < node.params.length; i++) {
64
								if(this.checkId(node.params[i], this.GENERAL, true)) {
65
									return Estraverse.VisitorOption.Skip;
66
								}
67
							}
60
							}
68
						}
61
						}
69
						break;
62
					}
70
					case Estraverse.Syntax.FunctionExpression:
63
					break;
71
						if (node.params) {
64
				case Estraverse.Syntax.FunctionExpression:
72
							this.scopes.push({range: node.range, occurrences: []});
65
					if (node.params) {
73
							for (var j = 0; j < node.params.length; j++) {
66
						if(this._enterScope(node)) {
74
								if(this.checkId(node.params[j], this.GENERAL, true)) {
67
							return Estraverse.VisitorOption.Skip;
75
									return Estraverse.VisitorOption.Skip;
68
						}
76
								}
69
						for (var j = 0; j < node.params.length; j++) {
70
							if(this.checkId(node.params[j], true)) {
71
								return Estraverse.VisitorOption.Skip;
77
							}
72
							}
78
						}
73
						}
79
						break;
74
					}
80
					case Estraverse.Syntax.AssignmentExpression:
75
					break;
81
						this.checkId(node.left);
76
				case Estraverse.Syntax.AssignmentExpression:
82
						this.checkId(node.right);
77
					this.checkId(node.left);
83
						break;
78
					this.checkId(node.right);
84
					case Estraverse.Syntax.ArrayExpression: 
79
					break;
85
						if (node.elements) {
80
				case Estraverse.Syntax.ArrayExpression: 
86
							for (var k = 0; k < node.elements.length; k++) {
81
					if (node.elements) {
87
								this.checkId(node.elements[k]);
82
						for (var k = 0; k < node.elements.length; k++) {
83
							this.checkId(node.elements[k]);
84
						}
85
					}
86
					break;
87
				case Estraverse.Syntax.MemberExpression:
88
					this.checkId(node.object);
89
					if (node.computed) { //computed = true for [], false for . notation
90
						this.checkId(node.property);
91
					}
92
					break;
93
				case Estraverse.Syntax.BinaryExpression:
94
					this.checkId(node.left);
95
					this.checkId(node.right);
96
					break;
97
				case Estraverse.Syntax.UnaryExpression:
98
					this.checkId(node.argument);
99
					break;
100
				case Estraverse.Syntax.IfStatement:
101
					this.checkId(node.test);
102
					break;
103
				case Estraverse.Syntax.SwitchStatement:
104
					this.checkId(node.discriminant);
105
					break;
106
				case Estraverse.Syntax.UpdateExpression:
107
					this.checkId(node.argument);
108
					break;
109
				case Estraverse.Syntax.ConditionalExpression:
110
					this.checkId(node.test);
111
					this.checkId(node.consequent);
112
					this.checkId(node.alternate);
113
					break;
114
				case Estraverse.Syntax.CallExpression:
115
					this.checkId(node.callee, false);
116
					if (node.arguments) {
117
						for (var l = 0; l < node.arguments.length; l++) {
118
							this.checkId(node.arguments[l]);
119
						}
120
					}
121
					break;
122
				case Estraverse.Syntax.ReturnStatement:
123
					this.checkId(node.argument);
124
					break;
125
				case Estraverse.Syntax.ObjectExpression:
126
					if(this._enterScope(node)) {
127
						return Estraverse.VisitorOption.Skip;
128
					}
129
					if(node.properties) {
130
						var len = node.properties.length;
131
						for (var m = 0; m < len; m++) {
132
							var prop = node.properties[m];
133
							if(this.thisCheck && prop.value && prop.value.type === Estraverse.Syntax.FunctionExpression) {
134
								//tag it 
135
								prop.value.isprop = true;
88
							}
136
							}
137
							this.checkId(prop.value);
89
						}
138
						}
90
						break;
139
					}
91
					case Estraverse.Syntax.MemberExpression:
140
					break;
92
						this.checkId(node.object);
141
				case Estraverse.Syntax.VariableDeclarator:
93
						if (node.computed) { //computed = true for [], false for . notation
142
					this.checkId(node.id, true);
94
							this.checkId(node.property);
143
					this.checkId(node.init);
144
					break;
145
				case Estraverse.Syntax.NewExpression:
146
					this.checkId(node.callee, false);
147
					break;
148
				case Estraverse.Syntax.LogicalExpression:
149
					this.checkId(node.left);
150
					this.checkId(node.right);
151
					break;
152
				case Estraverse.Syntax.ThisExpression:
153
					if(this.thisCheck) {
154
						var scope = this.scopes[this.scopes.length-1];
155
						scope.occurrences.push({
156
							start: node.range[0],
157
							end: node.range[1]
158
						});
159
						// if this node is the selected this we are in the right scope
160
						if (node.range[0] === this.context.node.range[0]){
161
							this.defscope = scope;
95
						}
162
						}
96
						break;
163
					}
97
					case Estraverse.Syntax.BinaryExpression:
164
					break;
98
						this.checkId(node.left);
99
						this.checkId(node.right);
100
						break;
101
					case Estraverse.Syntax.UnaryExpression:
102
						this.checkId(node.argument);
103
						break;
104
					case Estraverse.Syntax.IfStatement:
105
						this.checkId(node.test);
106
						break;
107
					case Estraverse.Syntax.SwitchStatement:
108
						this.checkId(node.discriminant);
109
						break;
110
					case Estraverse.Syntax.UpdateExpression:
111
						this.checkId(node.argument);
112
						break;
113
					case Estraverse.Syntax.ConditionalExpression:
114
						this.checkId(node.test);
115
						this.checkId(node.consequent);
116
						this.checkId(node.alternate);
117
						break;
118
					case Estraverse.Syntax.CallExpression:
119
						this.checkId(node.callee, this.FUNCTION, false);
120
						if (node.arguments) {
121
							for (var l = 0; l < node.arguments.length; l++) {
122
								this.checkId(node.arguments[l]);
123
							}
124
						}
125
						break;
126
					case Estraverse.Syntax.ReturnStatement:
127
						this.checkId(node.argument);
128
						break;
129
					case Estraverse.Syntax.ObjectExpression:
130
						if(node.properties) {
131
							var len = node.properties.length;
132
							for (var m = 0; m < len; m++) {
133
								this.checkId(node.properties[m].value);
134
							}
135
						}
136
						break;
137
					case Estraverse.Syntax.VariableDeclarator:
138
						this.checkId(node.id, this.GENERAL, true);
139
						this.checkId(node.init);
140
						break;
141
					case Estraverse.Syntax.NewExpression:
142
						this.checkId(node.callee, this.FUNCTION, false);
143
						break;
144
					case Estraverse.Syntax.LogicalExpression:
145
						this.checkId(node.left);
146
						this.checkId(node.right);
147
						break;
148
				}
149
			}
165
			}
150
		},
166
		},
151
		
167
		
152
		/**
168
		/**
153
		 * @name enterThis
169
		 * @description Enters and records the current scope onthe scope stack
154
		 * @description Callback from estraverse when a node is starting to be visited and we are searching for occurrences of 'this'
155
		 * @function
170
		 * @function
156
		 * @private
171
		 * @private
157
		 * @param {Object} node The AST node currently being visited
172
		 * @param {Object} node The AST node
158
		 * @returns The status if we should continue visiting
173
		 * @returns {Boolean} If we should skip visiting children of the scope node
159
		 */
174
		 */
160
		enterThis: function(node) {
175
		_enterScope: function(node) {
161
			// A function expression inside a call expression means a new scope for 'this'
176
			if(this.thisCheck) {
162
			if (node.type === Estraverse.Syntax.CallExpression){
177
				switch(node.type) {
163
				this.callExpressions.push(node);
178
					case Estraverse.Syntax.ObjectExpression:
164
			} else if (node.type === Estraverse.Syntax.FunctionExpression){
179
						this.scopes.push({range: node.range, occurrences: []});
165
				if (this.callExpressions.length > 0){
180
						if (this.defscope){
166
					this.scopes.push({range: node.range, occurrences: []});
181
							return true;
167
					// If the outer scope has the selected 'this' we can skip the inner scope
182
						}
168
					if (this.defscope){
183
						break;
169
						return Estraverse.VisitorOption.Skip;
184
					case Estraverse.Syntax.FunctionExpression:
170
					}
185
						if (!node.isprop){
171
				}
186
							this.scopes.push({range: node.range, occurrences: []});
172
			} else if (node.type === Estraverse.Syntax.ThisExpression){
187
							// If the outer scope has the selected 'this' we can skip the inner scope
173
				var scope = this.scopes[this.scopes.length-1];
188
							if (this.defscope){
174
				scope.occurrences.push({
189
								return true;
175
					start: node.range[0],
190
							}
176
					end: node.range[1]
191
						}
177
				});
192
						break;
178
				
179
				// if this node is the selected this we are in the right scope
180
				if (node.range === this.context.node.range){
181
					this.defscope = scope;
182
				}
193
				}
183
			}
194
			}
195
			else {
196
				switch(node.type) {
197
					case Estraverse.Syntax.FunctionDeclaration:
198
					case Estraverse.Syntax.FunctionExpression:
199
						this.scopes.push({range: node.range, occurrences: []});	
200
						break;
201
				}
202
			}
203
			return false;
184
		},
204
		},
185
		
205
		
186
		/**
206
		/**
Lines 193-245 Link Here
193
		 * @return The status if we should continue visiting
213
		 * @return The status if we should continue visiting
194
		 */
214
		 */
195
		leave: function(node) {
215
		leave: function(node) {
196
			if (this.context.node.type === Estraverse.Syntax.ThisExpression){
216
			if(this.thisCheck) {
197
				return this.leaveThis(node);
217
				switch(node.type) {
198
			} else {
218
					case Estraverse.Syntax.FunctionExpression:
199
				if (node.type === Estraverse.Syntax.FunctionDeclaration || 
219
						if(node.isprop) {
200
					node.type === Estraverse.Syntax.FunctionExpression ||
220
							delete node.isprop; //remove the tag
201
					node.type === Estraverse.Syntax.Program) {
221
							break;
202
					//if we leave the defining scope
203
					var scope = this.scopes.pop();
204
					if(this.defscope) {
205
						var len = scope.occurrences.length;
206
						for(var i = 0; i < len; i++) {
207
							this.occurrences.push(scope.occurrences[i]);
208
						}
222
						}
209
						if(this.defscope.range[0] === scope.range[0] && this.defscope.range[1] === scope.range[1]) {
223
						//FALL-THROUGH
210
							//we just popped out of the scope the word was defined in, we can quit
224
					case Estraverse.Syntax.ObjectExpression:
225
					case Estraverse.Syntax.Program:
226
						if(this._popScope()) {
227
							//we left an object closure, end
211
							return Estraverse.VisitorOption.Break;
228
							return Estraverse.VisitorOption.Break;
212
						}
229
						}
213
					}
230
						break;
231
				}
232
			}
233
			else {
234
				switch(node.type) {
235
					case Estraverse.Syntax.FunctionExpression:
236
					case Estraverse.Syntax.FunctionDeclaration:
237
					case Estraverse.Syntax.Program:
238
						if(this._popScope()) {
239
							return Estraverse.VisitorOption.Break;
240
						}
241
						break;
214
				}
242
				}
215
			}
243
			}
216
		},
244
		},
217
		
245
		
218
		/**
246
		/**
219
		 * @name leaveThis
247
		 * @description Pops the tip of the scope stack off, adds occurrences (if any) and returns if we should
220
		 * @description Callback when visitation of a node has completed and we are searching for occurrences of 'this'
248
		 * quit visiting
221
		 * @function
249
		 * @function
222
		 * @private
250
		 * @private
223
		 * @param {Object} node The AST node we are inspecting
251
		 * @returns {Boolean} If we should quit visiting
224
		 * @return The status if we should continue visiting
225
		 */
252
		 */
226
		leaveThis: function(node) {
253
		_popScope: function() {
227
			if (node.type === Estraverse.Syntax.CallExpression){
254
			var scope = this.scopes.pop();
228
				this.callExpressions.pop();
255
			if(this.defscope) {
229
			} else if ((this.callExpressions.length > 0 && node.type === Estraverse.Syntax.FunctionExpression) ||
256
				var len = scope.occurrences.length;
230
						node.type === Estraverse.Syntax.Program) {
257
				for(var i = 0; i < len; i++) {
231
				var scope = this.scopes.pop();
258
					this.occurrences.push(scope.occurrences[i]);
232
				if(this.defscope) {
259
				}
233
					var len = scope.occurrences.length;
260
				if(this.defscope.range[0] === scope.range[0] && this.defscope.range[1] === scope.range[1]) {
234
					for(var i = 0; i < len; i++) {
261
					//we just popped out of the scope the node was defined in, we can quit
235
						this.occurrences.push(scope.occurrences[i]);
262
					return true;
236
					}
237
					if(this.defscope.range[0] === scope.range[0] && this.defscope.range[1] === scope.range[1]) {
238
						//we just popped out of the scope the word was defined in, we can quit
239
						return Estraverse.VisitorOption.Break;
240
					}
241
				}
263
				}
242
			}
264
			}
265
			return false;
243
		},
266
		},
244
		
267
		
245
		/**
268
		/**
Lines 249-260 Link Here
249
		 * @private
272
		 * @private
250
		 * @memberof javascript.JavaScriptOccurrences.prototype
273
		 * @memberof javascript.JavaScriptOccurrences.prototype
251
		 * @param {Object} node The AST node we are inspecting
274
		 * @param {Object} node The AST node we are inspecting
252
		 * @param {Number} kind The kind of occurrence to consider
253
		 * @param {Boolean} candefine If the given node can define the word we are looking for
275
		 * @param {Boolean} candefine If the given node can define the word we are looking for
254
		 * @returns {Boolean} <code>true</code> if we should skip the next nodes, <code>false</code> otherwise
276
		 * @returns {Boolean} <code>true</code> if we should skip the next nodes, <code>false</code> otherwise
255
		 */
277
		 */
256
		checkId: function(node, kind, candefine) {
278
		checkId: function(node, candefine) {
257
			if (node && node.type === Estraverse.Syntax.Identifier) {
279
			if (!this.thisCheck && node && node.type === Estraverse.Syntax.Identifier) {
258
				if (node.name === this.context.word) {
280
				if (node.name === this.context.word) {
259
					var scope = this.scopes[this.scopes.length-1]; // Always will have at least the program scope
281
					var scope = this.scopes[this.scopes.length-1]; // Always will have at least the program scope
260
					if(candefine) {
282
					if(candefine) {
Lines 271-277 Link Here
271
						}
293
						}
272
						if(node.range[0] <= this.context.start && node.range[1] >= this.context.start) {
294
						if(node.range[0] <= this.context.start && node.range[1] >= this.context.start) {
273
							this.defnode = node.range;
295
							this.defnode = node.range;
274
							this.defnode.kind = !kind ? this.GENERAL : kind;
275
						}
296
						}
276
					}
297
					}
277
					scope.occurrences.push({
298
					scope.occurrences.push({
(-)a/bundles/org.eclipse.orion.client.javascript/web/js-tests/javascript/occurrencesTests.js (-2 / +146 lines)
Lines 601-611 Link Here
601
	 * Tests this usage in 2 objects
601
	 * Tests this usage in 2 objects
602
	 * @see https://bugs.eclipse.org/bugs/show_bug.cgi?id=424756
602
	 * @see https://bugs.eclipse.org/bugs/show_bug.cgi?id=424756
603
	 */
603
	 */
604
	Tests.test_thisUsageObjects = function() {
604
	Tests.test_thisUsageObjects1 = function() {
605
		editorContext.text = "var o1={v1: 'a', f1: function(){ if (this.v1){ this.v1++; }}}; var o2={v1: 'a', f1: function(){ if (this.v1){ this.v1++; }}};";
605
		editorContext.text = "var o1={v1: 'a', f1: function(){ if (this.v1){ this.v1++; }}}; var o2={v1: 'a', f1: function(){ if (this.v1){ this.v1++; }}};";
606
		return occurrences.computeOccurrences(editorContext, setContext(39, 39)).then(function(results) {
606
		return occurrences.computeOccurrences(editorContext, setContext(39, 39)).then(function(results) {
607
			try {
607
			try {
608
				assertOccurrences(results, [{start:37, end:41}, {start:47, end:51}, {start:100, end:104}, {start:110, end:114}]);
608
				assertOccurrences(results, [{start:37, end:41}, {start:47, end:51}]);
609
			}
610
			finally {
611
				tearDown();
612
			}
613
		});
614
	};
615
	
616
	/**
617
	 * Tests this usage in 2 objects
618
	 * @see https://bugs.eclipse.org/bugs/show_bug.cgi?id=424756
619
	 */
620
	Tests.test_thisUsageObjects2 = function() {
621
		editorContext.text = "var o1={v1: 'a', f1: function(){ if (this.v1){ this.v1++; }}}; var o2={v1: 'a', f1: function(){ if (this.v1){ this.v1++; }}};";
622
		return occurrences.computeOccurrences(editorContext, setContext(102, 102)).then(function(results) {
623
			try {
624
				assertOccurrences(results, [{start:100, end:104}, {start:110, end:114}]);
625
			}
626
			finally {
627
				tearDown();
628
			}
629
		});
630
	};
631
	
632
	/**
633
	 * Tests this usage in the root (global) scope of the file
634
	 * @see https://bugs.eclipse.org/bugs/show_bug.cgi?id=426930
635
	 */
636
	Tests.test_thisUsageGlobal1 = function() {
637
		editorContext.text = "function f1() {this.foo =1;};this.bar = 2;";
638
		return occurrences.computeOccurrences(editorContext, setContext(17, 17)).then(function(results) {
639
			try {
640
				assertOccurrences(results, [{start:15, end:19}, {start:29, end:33}]);
641
			}
642
			finally {
643
				tearDown();
644
			}
645
		});
646
	};
647
	
648
	/**
649
	 * Tests this usage in the root (global) scope of the file
650
	 * @see https://bugs.eclipse.org/bugs/show_bug.cgi?id=426930
651
	 */
652
	Tests.test_thisUsageGlobal2 = function() {
653
		editorContext.text = "function f1() {this.foo =1;};this.bar = 2;";
654
		return occurrences.computeOccurrences(editorContext, setContext(31, 31)).then(function(results) {
655
			try {
656
				assertOccurrences(results, [{start:15, end:19}, {start:29, end:33}]);
657
			}
658
			finally {
659
				tearDown();
660
			}
661
		});
662
	};
663
	
664
	/**
665
	 * Tests this usage in the root (global) scope of the file
666
	 * @see https://bugs.eclipse.org/bugs/show_bug.cgi?id=426930
667
	 */
668
	Tests.test_thisUsageGlobal3 = function() {
669
		editorContext.text = "function f1() {this.foo =1;function f2() {this.baz = 3;}};this.bar = 2;";
670
		return occurrences.computeOccurrences(editorContext, setContext(17, 17)).then(function(results) {
671
			try {
672
				assertOccurrences(results, [{start:15, end:19}, {start:42, end:46}, {start:58, end:62}]);
673
			}
674
			finally {
675
				tearDown();
676
			}
677
		});
678
	};
679
	
680
	/**
681
	 * Tests this usage in the root (global) scope of the file
682
	 * @see https://bugs.eclipse.org/bugs/show_bug.cgi?id=426930
683
	 */
684
	Tests.test_thisUsageGlobal4 = function() {
685
		editorContext.text = "function f1() {this.foo =1;function f2() {this.baz = 3;}};this.bar = 2;";
686
		return occurrences.computeOccurrences(editorContext, setContext(44, 44)).then(function(results) {
687
			try {
688
				assertOccurrences(results, [{start:15, end:19}, {start:42, end:46}, {start:58, end:62}]);
689
			}
690
			finally {
691
				tearDown();
692
			}
693
		});
694
	};
695
	
696
	/**
697
	 * Tests this usage in the root (global) scope of the file
698
	 * @see https://bugs.eclipse.org/bugs/show_bug.cgi?id=426930
699
	 */
700
	Tests.test_thisUsageGlobal3 = function() {
701
		editorContext.text = "function f1() {this.foo =1;function f2() {this.baz = 3;}};this.bar = 2;";
702
		return occurrences.computeOccurrences(editorContext, setContext(60, 60)).then(function(results) {
703
			try {
704
				assertOccurrences(results, [{start:15, end:19}, {start:42, end:46}, {start:58, end:62}]);
705
			}
706
			finally {
707
				tearDown();
708
			}
709
		});
710
	};
711
	
712
	/**
713
	 * Tests this usage in an object expression passed as a param
714
	 * @see https://bugs.eclipse.org/bugs/show_bug.cgi?id=426930
715
	 */
716
	Tests.test_thisUsageCallExpressionObject1 = function() {
717
		editorContext.text = "call({f1: function() {this.bool;},f2: function() {this.bool;},f3: function() {this.bool;}}this.end = true;";
718
		return occurrences.computeOccurrences(editorContext, setContext(24, 24)).then(function(results) {
719
			try {
720
				assertOccurrences(results, [{start:22, end:26}, {start:50, end:54}, {start:78, end:82}]);
721
			}
722
			finally {
723
				tearDown();
724
			}
725
		});
726
	};
727
	
728
	/**
729
	 * Tests this usage in an object expression passed as a param
730
	 * @see https://bugs.eclipse.org/bugs/show_bug.cgi?id=426930
731
	 */
732
	Tests.test_thisUsageCallExpressionObject2 = function() {
733
		editorContext.text = "call({f1: function() {this.bool;},f2: function() {this.bool;},f3: function() {this.bool;}}this.end = true;";
734
		return occurrences.computeOccurrences(editorContext, setContext(53, 53)).then(function(results) {
735
			try {
736
				assertOccurrences(results, [{start:22, end:26}, {start:50, end:54}, {start:78, end:82}]);
737
			}
738
			finally {
739
				tearDown();
740
			}
741
		});
742
	};
743
	
744
	/**
745
	 * Tests this usage in an object expression passed as a param
746
	 * @see https://bugs.eclipse.org/bugs/show_bug.cgi?id=426930
747
	 */
748
	Tests.test_thisUsageCallExpressionObject3 = function() {
749
		editorContext.text = "call({f1: function() {this.bool;},f2: function() {this.bool;},f3: function() {this.bool;}}this.end = true;";
750
		return occurrences.computeOccurrences(editorContext, setContext(81, 81)).then(function(results) {
751
			try {
752
				assertOccurrences(results, [{start:22, end:26}, {start:50, end:54}, {start:78, end:82}]);
609
			}
753
			}
610
			finally {
754
			finally {
611
				tearDown();
755
				tearDown();

Return to bug 426930