Skip to content

Commit a3916ff

Browse files
Merge pull request microsoft#3476 from Microsoft/classificationPerf2
Don't bother trying to semantically classify names that could never be typenames.
2 parents e675383 + 804b976 commit a3916ff

File tree

4 files changed

+48
-5
lines changed

4 files changed

+48
-5
lines changed

src/compiler/binder.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,10 +90,12 @@ namespace ts {
9090
let lastContainer: Node;
9191
let symbolCount = 0;
9292
let Symbol = objectAllocator.getSymbolConstructor();
93+
let classifiableNames: Map<string> = {};
9394

9495
if (!file.locals) {
9596
bind(file);
9697
file.symbolCount = symbolCount;
98+
file.classifiableNames = classifiableNames;
9799
}
98100

99101
return;
@@ -194,6 +196,11 @@ namespace ts {
194196
symbol = hasProperty(symbolTable, name)
195197
? symbolTable[name]
196198
: (symbolTable[name] = createSymbol(SymbolFlags.None, name));
199+
200+
if (name && (includes & SymbolFlags.Classifiable)) {
201+
classifiableNames[name] = name;
202+
}
203+
197204
if (symbol.flags & excludes) {
198205
if (node.name) {
199206
node.name.parent = node;

src/compiler/program.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ namespace ts {
148148
let commonSourceDirectory: string;
149149
let diagnosticsProducingTypeChecker: TypeChecker;
150150
let noDiagnosticsTypeChecker: TypeChecker;
151+
let classifiableNames: Map<string>;
151152

152153
let start = new Date().getTime();
153154

@@ -172,6 +173,7 @@ namespace ts {
172173
getDeclarationDiagnostics,
173174
getCompilerOptionsDiagnostics,
174175
getTypeChecker,
176+
getClassifiableNames,
175177
getDiagnosticsProducingTypeChecker,
176178
getCommonSourceDirectory: () => commonSourceDirectory,
177179
emit,
@@ -183,6 +185,20 @@ namespace ts {
183185
};
184186
return program;
185187

188+
function getClassifiableNames() {
189+
if (!classifiableNames) {
190+
// Initialize a checker so that all our files are bound.
191+
getTypeChecker();
192+
classifiableNames = {};
193+
194+
for (let sourceFile of files) {
195+
copyMap(sourceFile.classifiableNames, classifiableNames);
196+
}
197+
}
198+
199+
return classifiableNames;
200+
}
201+
186202
function getEmitHost(writeFileCallback?: WriteFileCallback): EmitHost {
187203
return {
188204
getCanonicalFileName: fileName => host.getCanonicalFileName(fileName),

src/compiler/types.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1172,6 +1172,8 @@ namespace ts {
11721172
// Stores a line map for the file.
11731173
// This field should never be used directly to obtain line map, use getLineMap function instead.
11741174
/* @internal */ lineMap: number[];
1175+
1176+
/* @internal */ classifiableNames?: Map<string>;
11751177
}
11761178

11771179
export interface ScriptReferenceHost {
@@ -1223,6 +1225,8 @@ namespace ts {
12231225
// language service).
12241226
/* @internal */ getDiagnosticsProducingTypeChecker(): TypeChecker;
12251227

1228+
/* @internal */ getClassifiableNames(): Map<string>;
1229+
12261230
/* @internal */ getNodeCount(): number;
12271231
/* @internal */ getIdentifierCount(): number;
12281232
/* @internal */ getSymbolCount(): number;
@@ -1519,6 +1523,11 @@ namespace ts {
15191523

15201524
PropertyOrAccessor = Property | Accessor,
15211525
Export = ExportNamespace | ExportType | ExportValue,
1526+
1527+
/* @internal */
1528+
// The set of things we consider semantically classifiable. Used to speed up the LS during
1529+
// classification.
1530+
Classifiable = Class | Enum | TypeAlias | Interface | TypeParameter | Module,
15221531
}
15231532

15241533
export interface Symbol {

src/services/services.ts

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5992,6 +5992,7 @@ namespace ts {
59925992
let typeChecker = program.getTypeChecker();
59935993

59945994
let result: number[] = [];
5995+
let classifiableNames = program.getClassifiableNames();
59955996
processNode(sourceFile);
59965997

59975998
return { spans: result, endOfLineState: EndOfLineState.None };
@@ -6004,6 +6005,9 @@ namespace ts {
60046005

60056006
function classifySymbol(symbol: Symbol, meaningAtPosition: SemanticMeaning): ClassificationType {
60066007
let flags = symbol.getFlags();
6008+
if ((flags & SymbolFlags.Classifiable) === SymbolFlags.None) {
6009+
return;
6010+
}
60076011

60086012
if (flags & SymbolFlags.Class) {
60096013
return ClassificationType.className;
@@ -6048,11 +6052,18 @@ namespace ts {
60486052
// Only walk into nodes that intersect the requested span.
60496053
if (node && textSpanIntersectsWith(span, node.getFullStart(), node.getFullWidth())) {
60506054
if (node.kind === SyntaxKind.Identifier && !nodeIsMissing(node)) {
6051-
let symbol = typeChecker.getSymbolAtLocation(node);
6052-
if (symbol) {
6053-
let type = classifySymbol(symbol, getMeaningFromLocation(node));
6054-
if (type) {
6055-
pushClassification(node.getStart(), node.getWidth(), type);
6055+
let identifier = <Identifier>node;
6056+
6057+
// Only bother calling into the typechecker if this is an identifier that
6058+
// could possibly resolve to a type name. This makes classification run
6059+
// in a third of the time it would normally take.
6060+
if (classifiableNames[identifier.text]) {
6061+
let symbol = typeChecker.getSymbolAtLocation(node);
6062+
if (symbol) {
6063+
let type = classifySymbol(symbol, getMeaningFromLocation(node));
6064+
if (type) {
6065+
pushClassification(node.getStart(), node.getWidth(), type);
6066+
}
60566067
}
60576068
}
60586069
}

0 commit comments

Comments
 (0)