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:
CyrusNajmabadi 2015-06-12 13:14:08 -07:00
commit a3916ffb50
4 changed files with 48 additions and 5 deletions

View file

@ -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;

View file

@ -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),

View file

@ -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 {

View file

@ -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,11 +6052,18 @@ 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 symbol = typeChecker.getSymbolAtLocation(node); let identifier = <Identifier>node;
if (symbol) {
let type = classifySymbol(symbol, getMeaningFromLocation(node)); // Only bother calling into the typechecker if this is an identifier that
if (type) { // could possibly resolve to a type name. This makes classification run
pushClassification(node.getStart(), node.getWidth(), type); // in a third of the time it would normally take.
if (classifiableNames[identifier.text]) {
let symbol = typeChecker.getSymbolAtLocation(node);
if (symbol) {
let type = classifySymbol(symbol, getMeaningFromLocation(node));
if (type) {
pushClassification(node.getStart(), node.getWidth(), type);
}
} }
} }
} }