-
Notifications
You must be signed in to change notification settings - Fork 7.6k
Allow findAllMatchingFunctionsInText to iterate over array-like objects (#1390) #2317
Conversation
function addFunctionEntry(funcEntry) { | ||
var endOffset = _getFunctionEndOffset(text, funcEntry.offsetStart); | ||
result.push({ | ||
name: key, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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 theallFunctions
object infindAllMatchingFunctionsInText
into an array-like object, and due to the length property it fails to iterate using$.each
.The fix substitutes the
$.each
for afor..in
loop.