Allow findAllMatchingFunctionsInText to iterate over array-like objects (#1390)#2317
Allow findAllMatchingFunctionsInText to iterate over array-like objects (#1390)#2317dangoor merged 3 commits intoadobe:masterfrom jbalsas:fix-1390
Conversation
There was a problem hiding this comment.
Using key like that seems dangerous but JSLint complains about creating functions inside loops otherwise. Is there a better way to do it?
There was a problem hiding this comment.
Creating functions in a loop is certainly legal JavaScript, so I thought I'd Google to see what the Crockford-approved approach is. I was not let down
|
Your fix worked fine for me when I fired it up (thanks!) As someone looking at this code for the first time, I found "key" to be not very descriptive (same goes for index in the original code). A little renaming and Crockford-approved function creating yielded this: /**
* Finds all instances of the specified functionName in "text".
* Returns an Array of Objects with start and end properties.
*
* @param text {!String} JS text to search
* @param searchName {!String} function name to search for
* @return {Array.<{offset:number, functionName:string}>}
* Array of objects containing the start offset for each matched function name.
*/
function findAllMatchingFunctionsInText(text, searchName) {
var allFunctions = _findAllFunctionsInText(text);
var result = [];
var lines = text.split("\n");
var functionName;
function makeAddFunction(functionName) {
return function (funcEntry) {
var endOffset = _getFunctionEndOffset(text, funcEntry.offsetStart);
result.push({
name: functionName,
lineStart: StringUtils.offsetToLineNum(lines, funcEntry.offsetStart),
lineEnd: StringUtils.offsetToLineNum(lines, endOffset)
});
};
}
for (functionName in allFunctions) {
if (allFunctions.hasOwnProperty(functionName)) {
if (functionName === searchName || searchName === "*") {
var addFunctionEntry = makeAddFunction(functionName);
allFunctions[functionName].forEach(addFunctionEntry);
}
}
}
return result;
}How does that look to you? (or anyone else reading this, for that matter?) |
|
@dangoor That does look better, thanks! I'll try to add your suggestions and push the changes later today. BTW, congrats, and welcome! ;) |
|
Thanks! |
|
Changes pushed! |
|
Are there any other places this bug could occur? It seems like $.each() is unsafe for iterating general string->* maps anywhere because of this API "feature." I see a bunch of other places where we use $.each() on objects and thus could conceivably get bit by this: QuickOpen.multiFieldSort(), PreferenceStorage.setAllValues(), FileIndexManager, and PerfUtils. Maybe we should have a shared utility function for enumerating object keys, and fix all these places at once? (There's already a CollectionUtils module where we could put it). |
|
I considered it, but wasn't sure how much you'd want to refactor the existing calls... What would you expect for this? I guess, while we're at it, we'll cover several cases from #1098, so we could check whatever's missing after it. |
|
@dangoor @peterflynn I've refactored the loop into I've checked, and there are plenty of references to |
|
Sorry for the delay in getting back to you here. I like this revision, thanks for making the adjustments. I'll be merging this soon. I made a couple of tweaks to the final landing. The most notable is that I swapped the arguments passed to the callback of CollectionUtils.forEach (it's now value, key). I thought this would be good for two reasons:
(other than that, I added a change to the test suite that demonstrates the bug in #1390, though the JSUtils tests all pass with this code change) |
This is a possible fix for #1390 where no results appear in the Go to Definition dialog.
The root cause is that in this case, there is a
.prototype.length = function ()which turns theallFunctionsobject infindAllMatchingFunctionsInTextinto an array-like object, and due to the length property it fails to iterate using$.each.The fix substitutes the
$.eachfor afor..inloop.