Merge pull request #3476 from Microsoft/classificationPerf2
Don't bother trying to semantically classify names that could never be typenames.
This commit is contained in:
commit
a3916ffb50
4 changed files with 48 additions and 5 deletions
|
@ -90,10 +90,12 @@ namespace ts {
|
||||||
let lastContainer: Node;
|
let lastContainer: Node;
|
||||||
let symbolCount = 0;
|
let symbolCount = 0;
|
||||||
let Symbol = objectAllocator.getSymbolConstructor();
|
let Symbol = objectAllocator.getSymbolConstructor();
|
||||||
|
let classifiableNames: Map<string> = {};
|
||||||
|
|
||||||
if (!file.locals) {
|
if (!file.locals) {
|
||||||
bind(file);
|
bind(file);
|
||||||
file.symbolCount = symbolCount;
|
file.symbolCount = symbolCount;
|
||||||
|
file.classifiableNames = classifiableNames;
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
@ -194,6 +196,11 @@ namespace ts {
|
||||||
symbol = hasProperty(symbolTable, name)
|
symbol = hasProperty(symbolTable, name)
|
||||||
? symbolTable[name]
|
? symbolTable[name]
|
||||||
: (symbolTable[name] = createSymbol(SymbolFlags.None, name));
|
: (symbolTable[name] = createSymbol(SymbolFlags.None, name));
|
||||||
|
|
||||||
|
if (name && (includes & SymbolFlags.Classifiable)) {
|
||||||
|
classifiableNames[name] = name;
|
||||||
|
}
|
||||||
|
|
||||||
if (symbol.flags & excludes) {
|
if (symbol.flags & excludes) {
|
||||||
if (node.name) {
|
if (node.name) {
|
||||||
node.name.parent = node;
|
node.name.parent = node;
|
||||||
|
|
|
@ -148,6 +148,7 @@ namespace ts {
|
||||||
let commonSourceDirectory: string;
|
let commonSourceDirectory: string;
|
||||||
let diagnosticsProducingTypeChecker: TypeChecker;
|
let diagnosticsProducingTypeChecker: TypeChecker;
|
||||||
let noDiagnosticsTypeChecker: TypeChecker;
|
let noDiagnosticsTypeChecker: TypeChecker;
|
||||||
|
let classifiableNames: Map<string>;
|
||||||
|
|
||||||
let start = new Date().getTime();
|
let start = new Date().getTime();
|
||||||
|
|
||||||
|
@ -172,6 +173,7 @@ namespace ts {
|
||||||
getDeclarationDiagnostics,
|
getDeclarationDiagnostics,
|
||||||
getCompilerOptionsDiagnostics,
|
getCompilerOptionsDiagnostics,
|
||||||
getTypeChecker,
|
getTypeChecker,
|
||||||
|
getClassifiableNames,
|
||||||
getDiagnosticsProducingTypeChecker,
|
getDiagnosticsProducingTypeChecker,
|
||||||
getCommonSourceDirectory: () => commonSourceDirectory,
|
getCommonSourceDirectory: () => commonSourceDirectory,
|
||||||
emit,
|
emit,
|
||||||
|
@ -183,6 +185,20 @@ namespace ts {
|
||||||
};
|
};
|
||||||
return program;
|
return program;
|
||||||
|
|
||||||
|
function getClassifiableNames() {
|
||||||
|
if (!classifiableNames) {
|
||||||
|
// Initialize a checker so that all our files are bound.
|
||||||
|
getTypeChecker();
|
||||||
|
classifiableNames = {};
|
||||||
|
|
||||||
|
for (let sourceFile of files) {
|
||||||
|
copyMap(sourceFile.classifiableNames, classifiableNames);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return classifiableNames;
|
||||||
|
}
|
||||||
|
|
||||||
function getEmitHost(writeFileCallback?: WriteFileCallback): EmitHost {
|
function getEmitHost(writeFileCallback?: WriteFileCallback): EmitHost {
|
||||||
return {
|
return {
|
||||||
getCanonicalFileName: fileName => host.getCanonicalFileName(fileName),
|
getCanonicalFileName: fileName => host.getCanonicalFileName(fileName),
|
||||||
|
|
|
@ -1172,6 +1172,8 @@ namespace ts {
|
||||||
// Stores a line map for the file.
|
// Stores a line map for the file.
|
||||||
// This field should never be used directly to obtain line map, use getLineMap function instead.
|
// This field should never be used directly to obtain line map, use getLineMap function instead.
|
||||||
/* @internal */ lineMap: number[];
|
/* @internal */ lineMap: number[];
|
||||||
|
|
||||||
|
/* @internal */ classifiableNames?: Map<string>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ScriptReferenceHost {
|
export interface ScriptReferenceHost {
|
||||||
|
@ -1223,6 +1225,8 @@ namespace ts {
|
||||||
// language service).
|
// language service).
|
||||||
/* @internal */ getDiagnosticsProducingTypeChecker(): TypeChecker;
|
/* @internal */ getDiagnosticsProducingTypeChecker(): TypeChecker;
|
||||||
|
|
||||||
|
/* @internal */ getClassifiableNames(): Map<string>;
|
||||||
|
|
||||||
/* @internal */ getNodeCount(): number;
|
/* @internal */ getNodeCount(): number;
|
||||||
/* @internal */ getIdentifierCount(): number;
|
/* @internal */ getIdentifierCount(): number;
|
||||||
/* @internal */ getSymbolCount(): number;
|
/* @internal */ getSymbolCount(): number;
|
||||||
|
@ -1519,6 +1523,11 @@ namespace ts {
|
||||||
|
|
||||||
PropertyOrAccessor = Property | Accessor,
|
PropertyOrAccessor = Property | Accessor,
|
||||||
Export = ExportNamespace | ExportType | ExportValue,
|
Export = ExportNamespace | ExportType | ExportValue,
|
||||||
|
|
||||||
|
/* @internal */
|
||||||
|
// The set of things we consider semantically classifiable. Used to speed up the LS during
|
||||||
|
// classification.
|
||||||
|
Classifiable = Class | Enum | TypeAlias | Interface | TypeParameter | Module,
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Symbol {
|
export interface Symbol {
|
||||||
|
|
|
@ -5992,6 +5992,7 @@ namespace ts {
|
||||||
let typeChecker = program.getTypeChecker();
|
let typeChecker = program.getTypeChecker();
|
||||||
|
|
||||||
let result: number[] = [];
|
let result: number[] = [];
|
||||||
|
let classifiableNames = program.getClassifiableNames();
|
||||||
processNode(sourceFile);
|
processNode(sourceFile);
|
||||||
|
|
||||||
return { spans: result, endOfLineState: EndOfLineState.None };
|
return { spans: result, endOfLineState: EndOfLineState.None };
|
||||||
|
@ -6004,6 +6005,9 @@ namespace ts {
|
||||||
|
|
||||||
function classifySymbol(symbol: Symbol, meaningAtPosition: SemanticMeaning): ClassificationType {
|
function classifySymbol(symbol: Symbol, meaningAtPosition: SemanticMeaning): ClassificationType {
|
||||||
let flags = symbol.getFlags();
|
let flags = symbol.getFlags();
|
||||||
|
if ((flags & SymbolFlags.Classifiable) === SymbolFlags.None) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (flags & SymbolFlags.Class) {
|
if (flags & SymbolFlags.Class) {
|
||||||
return ClassificationType.className;
|
return ClassificationType.className;
|
||||||
|
@ -6048,6 +6052,12 @@ namespace ts {
|
||||||
// Only walk into nodes that intersect the requested span.
|
// Only walk into nodes that intersect the requested span.
|
||||||
if (node && textSpanIntersectsWith(span, node.getFullStart(), node.getFullWidth())) {
|
if (node && textSpanIntersectsWith(span, node.getFullStart(), node.getFullWidth())) {
|
||||||
if (node.kind === SyntaxKind.Identifier && !nodeIsMissing(node)) {
|
if (node.kind === SyntaxKind.Identifier && !nodeIsMissing(node)) {
|
||||||
|
let identifier = <Identifier>node;
|
||||||
|
|
||||||
|
// Only bother calling into the typechecker if this is an identifier that
|
||||||
|
// could possibly resolve to a type name. This makes classification run
|
||||||
|
// in a third of the time it would normally take.
|
||||||
|
if (classifiableNames[identifier.text]) {
|
||||||
let symbol = typeChecker.getSymbolAtLocation(node);
|
let symbol = typeChecker.getSymbolAtLocation(node);
|
||||||
if (symbol) {
|
if (symbol) {
|
||||||
let type = classifySymbol(symbol, getMeaningFromLocation(node));
|
let type = classifySymbol(symbol, getMeaningFromLocation(node));
|
||||||
|
@ -6056,6 +6066,7 @@ namespace ts {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
forEachChild(node, processNode);
|
forEachChild(node, processNode);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue