diff --git a/bundles/org.eclipse.orion.client.javascript/web/javascript/finder.js b/bundles/org.eclipse.orion.client.javascript/web/javascript/finder.js
index 5cd5352..6fa9134 100644
--- a/bundles/org.eclipse.orion.client.javascript/web/javascript/finder.js
+++ b/bundles/org.eclipse.orion.client.javascript/web/javascript/finder.js
@@ -30,6 +30,7 @@
scopes: [],
context: null,
thisCheck: false,
+ objectPropCheck: false,
/**
* @name enter
@@ -91,6 +92,8 @@
this.checkId(node.object);
if (node.computed) { //computed = true for [], false for . notation
this.checkId(node.property);
+ } else if (node.object.type === Estraverse.Syntax.ThisExpression){
+ this.checkId(node.property, false, true);
}
break;
case Estraverse.Syntax.BinaryExpression:
@@ -138,6 +141,7 @@
//tag it
prop.value.isprop = true;
}
+ this.checkId(prop.key, true, true);
this.checkId(prop.value);
}
}
@@ -214,16 +218,27 @@
}
break;
}
- }
- else {
- var kind = 'fe';
+ } else if (this.objectPropCheck){
+ switch(node.type) {
+ case Estraverse.Syntax.ObjectExpression:
+ this.scopes.push({range: node.range, occurrences: [], kind:'o'});
+ if (this.defscope){
+ return true;
+ }
+ break;
+ }
+ } else {
+ var kind;
switch(node.type) {
case Estraverse.Syntax.FunctionDeclaration:
kind = 'fd';
- //$FALL-THROUGH$
- case Estraverse.Syntax.FunctionExpression:
- this.scopes.push({range: node.range, occurrences: [], kind:kind});
break;
+ case Estraverse.Syntax.FunctionExpression:
+ kind = 'fe';
+ break;
+ }
+ if (kind){
+ this.scopes.push({range: node.range, occurrences: [], kind:kind});
}
}
return false;
@@ -255,8 +270,16 @@
}
break;
}
- }
- else {
+ } else if (this.objectPropCheck) {
+ switch(node.type){
+ case Estraverse.Syntax.ObjectExpression:
+ case Estraverse.Syntax.Program:
+ if(this._popScope()) {
+ return Estraverse.VisitorOption.Break;
+ }
+ break;
+ }
+ } else {
switch(node.type) {
case Estraverse.Syntax.FunctionExpression:
case Estraverse.Syntax.FunctionDeclaration:
@@ -278,8 +301,8 @@
*/
_popScope: function() {
var scope = this.scopes.pop();
- var len = scope.occurrences.length;
var i;
+ var len = scope.occurrences.length;
if(this.defscope) {
for(i = 0; i < len; i++) {
this.occurrences.push(scope.occurrences[i]);
@@ -303,30 +326,32 @@
* @param {Boolean} candefine If the given node can define the word we are looking for
* @returns {Boolean} true
if we should skip the next nodes, false
otherwise
*/
- checkId: function(node, candefine) {
- if (!this.thisCheck && node && node.type === Estraverse.Syntax.Identifier) {
- if (node.name === this.context.word) {
- var scope = this.scopes[this.scopes.length-1]; // Always will have at least the program scope
- if(candefine) {
- if(this.defscope) {
- // Re-defining, we want the last defining node previous to the selection, skip any future re-defines
- if(node.range[0] > this.context.start) {
- return true;
- } else {
- // Occurrences collected for the previous define are now invalid, fall through to mark this occurrence
- this.occurrences = [];
- scope.occurrences = [];
+ checkId: function(node, candefine, isObjectProp) {
+ if (!this.thisCheck && ((!isObjectProp && !this.objectPropCheck) || (isObjectProp && this.objectPropCheck))){
+ if (node && node.type === Estraverse.Syntax.Identifier) {
+ if (node.name === this.context.word) {
+ var scope = this.scopes[this.scopes.length-1]; // Always will have at least the program scope
+ if(candefine) {
+ if(this.defscope) {
+ // Re-defining, we want the last defining node previous to the selection, skip any future re-defines
+ if(node.range[0] > this.context.start) {
+ return true;
+ } else {
+ // Occurrences collected for the previous define are now invalid, fall through to mark this occurrence
+ this.occurrences = [];
+ scope.occurrences = [];
+ }
+ }
+ //does the scope enclose it?
+ if(scope && (scope.range[0] <= this.context.start) && (scope.range[1] >= this.context.end)) {
+ this.defscope = scope;
}
}
- //does the scope enclose it?
- if(scope && (scope.range[0] <= this.context.start) && (scope.range[1] >= this.context.end)) {
- this.defscope = scope;
- }
+ scope.occurrences.push({
+ start: node.range[0],
+ end: node.range[1]
+ });
}
- scope.occurrences.push({
- start: node.range[0],
- end: node.range[1]
- });
}
}
return false;
@@ -597,13 +622,13 @@
*/
findOccurrences: function(ast, ctxt) {
if(ast && ctxt) {
- var token = this._getToken(ctxt.selection.start, ast);
- if(!this._skip(token)) {
+ var node = this.findNode(ctxt.selection.start, ast, {parents: true});
+ if(!this._skip(node)) {
var context = {
start: ctxt.selection.start,
end: ctxt.selection.end,
- word: this._nameFromNode(token),
- token: token,
+ word: this._nameFromNode(node),
+ token: node,
};
var visitor = this._getVisitor(context);
Estraverse.traverse(ast, visitor);
@@ -617,18 +642,18 @@
* @description If we should skip marking occurrences
* @function
* @private
- * @param {Object} token The AST token
+ * @param {Object} node The AST node
* @returns {Boolean} True if we shoud skip computing occurrences
* @since 6.0
*/
- _skip: function(token) {
- if(!token) {
+ _skip: function(node) {
+ if(!node) {
return true;
}
- if(token.type === 'Keyword') { //$NON-NLS-0$
- return token.value !== 'this'; //$NON-NLS-0$
+ if(node.type === Estraverse.Syntax.ThisExpression) {
+ return false;
}
- return token.type !== Estraverse.Syntax.Identifier;
+ return node.type !== Estraverse.Syntax.Identifier;
},
/**
@@ -670,14 +695,14 @@
* @description Computes the node name to use while searching
* @function
* @private
- * @param {Object} token The AST token
+ * @param {Object} node The AST token
* @returns {String} The node name to use while seraching
* @since 6.0
*/
- _nameFromNode: function(token) {
- switch(token.type) {
- case Estraverse.Syntax.Identifier: return token.value;
- case 'Keyword': return 'this'; //$NON-NLS-0$ //$NON-NLS-1$
+ _nameFromNode: function(node) {
+ switch(node.type) {
+ case Estraverse.Syntax.Identifier: return node.name;
+ case Estraverse.Syntax.ThisExpression: return 'this'; //$NON-NLS-0$
}
},
@@ -697,7 +722,19 @@
this.visitor.enter = this.visitor.enter.bind(this.visitor);
this.visitor.leave = this.visitor.leave.bind(this.visitor);
}
- this.visitor.thisCheck = context.token && context.token.type === 'Keyword' && context.token.value === 'this'; //$NON-NLS-0$ //$NON-NLS-1$
+
+ // See if a 'this' keyword was selected
+ this.visitor.thisCheck = context.token && context.token.type === Estraverse.Syntax.ThisExpression;
+
+ // See if an object property key is selected (or a usage of an object property such as this.prop())
+ this.visitor.objectPropCheck = false;
+ var parent = context.token.parent ? context.token.parent : (context.token.parents && context.token.parents.length > 0 ? context.token.parents[context.token.parents.length-1] : null);
+ if (parent && parent.type === Estraverse.Syntax.Property){
+ this.visitor.objectPropCheck = context.token === parent.key;
+ } else if (parent && (parent.type === Estraverse.Syntax.MemberExpression && parent.object && parent.object.type === Estraverse.Syntax.ThisExpression)){
+ this.visitor.objectPropCheck = false;
+ }
+
this.visitor.context = context;
return this.visitor;
}
diff --git a/bundles/org.eclipse.orion.client.javascript/web/js-tests/javascript/occurrencesTests.js b/bundles/org.eclipse.orion.client.javascript/web/js-tests/javascript/occurrencesTests.js
index 92918a3..2d0a4de 100644
--- a/bundles/org.eclipse.orion.client.javascript/web/js-tests/javascript/occurrencesTests.js
+++ b/bundles/org.eclipse.orion.client.javascript/web/js-tests/javascript/occurrencesTests.js
@@ -1517,6 +1517,7 @@
}
});
});
+
/**
* Tests computing occurrences for do-while tests
* @see https://bugs.eclipse.org/bugs/show_bug.cgi?id=435941
@@ -1667,5 +1668,72 @@
}
});
});
+
+ /**
+ * Tests computing occurrences for object properties and references to them
+ * @see https://bugs.eclipse.org/bugs/show_bug.cgi?id=423083
+ */
+ it('test_object_properties_1A', function() {
+ editorContext.text = "Objects.mixin({ test1: function() {}, test2: function() { return this.test1(); } });";
+ return occurrences.computeOccurrences(editorContext, setContext(19, 19)).then(function(results) {
+ try {
+ assertOccurrences(results, [{start:16, end:21}, {start:70, end:75}]);
+ }
+ finally {
+ tearDown();
+ }
+ });
+ });
+
+ /**
+ * Tests computing occurrences for object properties and references to them
+ * @see https://bugs.eclipse.org/bugs/show_bug.cgi?id=423083
+ */
+ it('test_object_properties_1B', function() {
+ editorContext.text = "Objects.mixin({ test1: function() {}, test2: function() { return this.test1(); } });";
+ return occurrences.computeOccurrences(editorContext, setContext(71, 71)).then(function(results) {
+ try {
+ assertOccurrences(results, [{start:16, end:21}, {start:70, end:75}]);
+ }
+ finally {
+ tearDown();
+ }
+ });
+ });
+
+ /**
+ * Tests computing occurrences for object properties and references to them
+ * @see https://bugs.eclipse.org/bugs/show_bug.cgi?id=423083
+ */
+ it('test_object_properties_2A', function() {
+ editorContext.text = "var foo = { test1: function() {}, test2: function() { return this.test1(); } };";
+ return occurrences.computeOccurrences(editorContext, setContext(15, 15)).then(function(results) {
+ try {
+ assertOccurrences(results, [{start:12, end:17}, {start:66, end:71}]);
+ }
+ finally {
+ tearDown();
+ }
+ });
+ });
+
+ /**
+ * Tests computing occurrences for object properties and references to them
+ * @see https://bugs.eclipse.org/bugs/show_bug.cgi?id=423083
+ */
+ it('test_object_properties_2B', function() {
+ editorContext.text = "var foo = { test1: function() {}, test2: function() { return this.test1(); } };";
+ return occurrences.computeOccurrences(editorContext, setContext(66, 71)).then(function(results) {
+ try {
+ assertOccurrences(results, [{start:12, end:17}, {start:66, end:71}]);
+ }
+ finally {
+ tearDown();
+ }
+ });
+ });
+
+
+
});
});
\ No newline at end of file