-
Notifications
You must be signed in to change notification settings - Fork 12.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Share code between getCompletionsAtPosition and getCompletionEntryDetails. #2475
Changes from 3 commits
bce9b5a
a1cbfdf
66b3fae
2af1b92
eed6f0d
c459bb7
4802b4b
a5bd919
8d55fe0
614b106
63278ca
e26c260
69ff9b3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10547,62 +10547,102 @@ module ts { | |
return false; | ||
} | ||
|
||
function getSymbolsInScope(location: Node, meaning: SymbolFlags): Symbol[] { | ||
function getSymbolsInScope(location: Node, meaning: SymbolFlags, predicate?: (symbol: Symbol) => boolean): Symbol[] { | ||
let symbols: SymbolTable = {}; | ||
let memberFlags: NodeFlags = 0; | ||
function copySymbol(symbol: Symbol, meaning: SymbolFlags) { | ||
|
||
if (isInsideWithStatementBody(location)) { | ||
// We cannot answer semantic questions within a with block, do not proceed any further | ||
return []; | ||
} | ||
|
||
populateSymbols(); | ||
|
||
return mapToArray(symbols); | ||
|
||
function populateSymbols() { | ||
while (location) { | ||
if (location.locals && !isGlobalSourceFile(location)) { | ||
if (copySymbols(location.locals, meaning)) { | ||
return; | ||
} | ||
} | ||
switch (location.kind) { | ||
case SyntaxKind.SourceFile: | ||
if (!isExternalModule(<SourceFile>location)) { | ||
break; | ||
} | ||
case SyntaxKind.ModuleDeclaration: | ||
if (copySymbols(getSymbolOfNode(location).exports, meaning & SymbolFlags.ModuleMember)) { | ||
return; | ||
} | ||
break; | ||
case SyntaxKind.EnumDeclaration: | ||
if (copySymbols(getSymbolOfNode(location).exports, meaning & SymbolFlags.EnumMember)) { | ||
return; | ||
} | ||
break; | ||
case SyntaxKind.ClassDeclaration: | ||
case SyntaxKind.InterfaceDeclaration: | ||
if (!(memberFlags & NodeFlags.Static)) { | ||
if (copySymbols(getSymbolOfNode(location).members, meaning & SymbolFlags.Type)) { | ||
return; | ||
} | ||
} | ||
break; | ||
case SyntaxKind.FunctionExpression: | ||
if ((<FunctionExpression>location).name) { | ||
if (copySymbol(location.symbol, meaning)) { | ||
return; | ||
} | ||
} | ||
break; | ||
} | ||
memberFlags = location.flags; | ||
location = location.parent; | ||
} | ||
if (copySymbols(globals, meaning)) { | ||
return; | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this Note that I don't mean parallelism in the computing context, I mean it as a literary device in which components of a text are constructed in a similar manner. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it was to keep things consistent. |
||
} | ||
|
||
// Returns 'true' if we should stop processing symbols. | ||
function copySymbol(symbol: Symbol, meaning: SymbolFlags): boolean { | ||
if (symbol.flags & meaning) { | ||
let id = symbol.name; | ||
if (!isReservedMemberName(id) && !hasProperty(symbols, id)) { | ||
symbols[id] = symbol; | ||
if (predicate) { | ||
// If we were supplied a predicate function, then check if this symbol | ||
// matches with it. If so, we're done and can immediately return. | ||
// Otherwise, just ignore this symbol and keep going. | ||
if (predicate(symbol)) { | ||
symbols[id] = symbol; | ||
return true; | ||
} | ||
} | ||
else { | ||
// If no predicate was supplied, then just add the symbol as is. | ||
symbols[id] = symbol; | ||
} | ||
} | ||
} | ||
|
||
return false; | ||
} | ||
function copySymbols(source: SymbolTable, meaning: SymbolFlags) { | ||
|
||
function copySymbols(source: SymbolTable, meaning: SymbolFlags): boolean { | ||
if (meaning) { | ||
for (let id in source) { | ||
if (hasProperty(source, id)) { | ||
copySymbol(source[id], meaning); | ||
if (copySymbol(source[id], meaning)) { | ||
return true; | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
if (isInsideWithStatementBody(location)) { | ||
// We cannot answer semantic questions within a with block, do not proceed any further | ||
return []; | ||
} | ||
|
||
while (location) { | ||
if (location.locals && !isGlobalSourceFile(location)) { | ||
copySymbols(location.locals, meaning); | ||
} | ||
switch (location.kind) { | ||
case SyntaxKind.SourceFile: | ||
if (!isExternalModule(<SourceFile>location)) break; | ||
case SyntaxKind.ModuleDeclaration: | ||
copySymbols(getSymbolOfNode(location).exports, meaning & SymbolFlags.ModuleMember); | ||
break; | ||
case SyntaxKind.EnumDeclaration: | ||
copySymbols(getSymbolOfNode(location).exports, meaning & SymbolFlags.EnumMember); | ||
break; | ||
case SyntaxKind.ClassDeclaration: | ||
case SyntaxKind.InterfaceDeclaration: | ||
if (!(memberFlags & NodeFlags.Static)) { | ||
copySymbols(getSymbolOfNode(location).members, meaning & SymbolFlags.Type); | ||
} | ||
break; | ||
case SyntaxKind.FunctionExpression: | ||
if ((<FunctionExpression>location).name) { | ||
copySymbol(location.symbol, meaning); | ||
} | ||
break; | ||
} | ||
memberFlags = location.flags; | ||
location = location.parent; | ||
return false; | ||
} | ||
copySymbols(globals, meaning); | ||
return mapToArray(symbols); | ||
} | ||
|
||
function isTypeDeclarationName(name: Node): boolean { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1092,7 +1092,10 @@ module ts { | |
getSignaturesOfType(type: Type, kind: SignatureKind): Signature[]; | ||
getIndexTypeOfType(type: Type, kind: IndexKind): Type; | ||
getReturnTypeOfSignature(signature: Signature): Type; | ||
getSymbolsInScope(location: Node, meaning: SymbolFlags): Symbol[]; | ||
|
||
// If 'predicate' is supplied, then only the first symbol in scope matching the predicate | ||
// will be returned. Otherwise, all symbols in scope will be returned. | ||
getSymbolsInScope(location: Node, meaning: SymbolFlags, predicate?: (symbol: Symbol) => boolean): Symbol[]; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Now that I see it, you can just use this comment. |
||
getSymbolAtLocation(node: Node): Symbol; | ||
getShorthandAssignmentValueSymbol(location: Node): Symbol; | ||
getTypeAtLocation(node: Node): Type; | ||
|
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.
Consider adding some variation of the following comment:
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.
I'm somewhat ambivalent about the name
predicate
. But I don't care that much.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.
What would you prefer?
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.
i do not think you need the predicate. I think this is an optimization that does not buy us much on the general case. do you have perf numbers before and after the fix?
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.
I only measured after the fix. The time to get the details was in the low number of MS. Effectively, all the time was spent in the Roslyn delay timer, as well as just presenting the item. Computing of the item was effectively nothing. (This wasn't true for "Diagnostics". but that's a known issue where we end up building up a massive display string for that special type).
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.
then does the predicate buy us any measurable perf improvements?
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.
Looking at the numbers, it appears to save a few ms (4-5) for global completion lists. I think that does make it worth it. My concern is arond a project with several large d.ts files (like WinRT, etc.) With all the tens of thousands of symbols, it would be nice to not have to go get all of them again since we only want one.
But, i'll defer to you here. I think it would be fine to remove the predicate.