Skip to content

Commit 369f784

Browse files
Merge pull request microsoft#1939 from Microsoft/diagnosticsOrganization
Compiler API cleanup.
2 parents b14a46b + d20d20a commit 369f784

File tree

90 files changed

+4092
-1363
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

90 files changed

+4092
-1363
lines changed

src/compiler/binder.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
/// <reference path="parser.ts"/>
22

33
module ts {
4+
/* @internal */ export var bindTime = 0;
5+
46
export const enum ModuleInstanceState {
57
NonInstantiated = 0,
68
Instantiated = 1,
@@ -60,8 +62,13 @@ module ts {
6062
return declaration.name && declaration.name.kind === SyntaxKind.ComputedPropertyName;
6163
}
6264

63-
export function bindSourceFile(file: SourceFile) {
65+
export function bindSourceFile(file: SourceFile): void {
66+
var start = new Date().getTime();
67+
bindSourceFileWorker(file);
68+
bindTime += new Date().getTime() - start;
69+
}
6470

71+
function bindSourceFileWorker(file: SourceFile): void {
6572
var parent: Node;
6673
var container: Node;
6774
var blockScopeContainer: Node;
@@ -136,9 +143,9 @@ module ts {
136143
: Diagnostics.Duplicate_identifier_0;
137144

138145
forEach(symbol.declarations, declaration => {
139-
file.semanticDiagnostics.push(createDiagnosticForNode(declaration.name, message, getDisplayName(declaration)));
146+
file.bindDiagnostics.push(createDiagnosticForNode(declaration.name, message, getDisplayName(declaration)));
140147
});
141-
file.semanticDiagnostics.push(createDiagnosticForNode(node.name, message, getDisplayName(node)));
148+
file.bindDiagnostics.push(createDiagnosticForNode(node.name, message, getDisplayName(node)));
142149

143150
symbol = createSymbol(0, name);
144151
}
@@ -159,7 +166,7 @@ module ts {
159166
if (node.name) {
160167
node.name.parent = node;
161168
}
162-
file.semanticDiagnostics.push(createDiagnosticForNode(symbol.exports[prototypeSymbol.name].declarations[0],
169+
file.bindDiagnostics.push(createDiagnosticForNode(symbol.exports[prototypeSymbol.name].declarations[0],
163170
Diagnostics.Duplicate_identifier_0, prototypeSymbol.name));
164171
}
165172
symbol.exports[prototypeSymbol.name] = prototypeSymbol;

src/compiler/checker.ts

Lines changed: 40 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ module ts {
55
var nextNodeId = 1;
66
var nextMergeId = 1;
77

8+
/* @internal */ export var checkTime = 0;
9+
810
export function createTypeChecker(host: TypeCheckerHost, produceDiagnostics: boolean): TypeChecker {
911
var Symbol = objectAllocator.getSymbolConstructor();
1012
var Type = objectAllocator.getTypeConstructor();
@@ -48,12 +50,12 @@ module ts {
4850
getContextualType,
4951
getFullyQualifiedName,
5052
getResolvedSignature,
51-
getEnumMemberValue,
53+
getConstantValue,
5254
isValidPropertyAccess,
5355
getSignatureFromDeclaration,
5456
isImplementationOfOverload,
5557
getAliasedSymbol: resolveImport,
56-
getEmitResolver: () => emitResolver,
58+
getEmitResolver,
5759
};
5860

5961
var undefinedSymbol = createSymbol(SymbolFlags.Property | SymbolFlags.Transient, "undefined");
@@ -104,8 +106,7 @@ module ts {
104106
var nodeLinks: NodeLinks[] = [];
105107
var potentialThisCollisions: Node[] = [];
106108

107-
var diagnostics: Diagnostic[] = [];
108-
var diagnosticsModified: boolean = false;
109+
var diagnostics = createDiagnosticCollection();
109110

110111
var primitiveTypeInfo: Map<{ type: Type; flags: TypeFlags }> = {
111112
"string": {
@@ -122,16 +123,18 @@ module ts {
122123
}
123124
};
124125

125-
function addDiagnostic(diagnostic: Diagnostic) {
126-
diagnostics.push(diagnostic);
127-
diagnosticsModified = true;
126+
function getEmitResolver(sourceFile?: SourceFile) {
127+
// Ensure we have all the type information in place for this file so that all the
128+
// emitter questions of this resolver will return the right information.
129+
getDiagnostics(sourceFile);
130+
return emitResolver;
128131
}
129132

130133
function error(location: Node, message: DiagnosticMessage, arg0?: any, arg1?: any, arg2?: any): void {
131134
var diagnostic = location
132135
? createDiagnosticForNode(location, message, arg0, arg1, arg2)
133136
: createCompilerDiagnostic(message, arg0, arg1, arg2);
134-
addDiagnostic(diagnostic);
137+
diagnostics.add(diagnostic);
135138
}
136139

137140
function createSymbol(flags: SymbolFlags, name: string): Symbol {
@@ -3479,7 +3482,8 @@ module ts {
34793482
if (containingMessageChain) {
34803483
errorInfo = concatenateDiagnosticMessageChains(containingMessageChain, errorInfo);
34813484
}
3482-
addDiagnostic(createDiagnosticForNodeFromMessageChain(errorNode, errorInfo, host.getCompilerHost().getNewLine()));
3485+
3486+
diagnostics.add(createDiagnosticForNodeFromMessageChain(errorNode, errorInfo));
34833487
}
34843488
return result !== Ternary.False;
34853489

@@ -5705,9 +5709,9 @@ module ts {
57055709
return false;
57065710
}
57075711
else {
5708-
var diagnosticsCount = diagnostics.length;
5712+
var modificationCount = diagnostics.getModificationCount();
57095713
checkClassPropertyAccess(node, left, type, prop);
5710-
return diagnostics.length === diagnosticsCount
5714+
return diagnostics.getModificationCount() === modificationCount;
57115715
}
57125716
}
57135717
}
@@ -8927,7 +8931,7 @@ module ts {
89278931

89288932
var errorInfo = chainDiagnosticMessages(undefined, Diagnostics.Named_properties_0_of_types_1_and_2_are_not_identical, prop.name, typeName1, typeName2);
89298933
errorInfo = chainDiagnosticMessages(errorInfo, Diagnostics.Interface_0_cannot_simultaneously_extend_types_1_and_2, typeToString(type), typeName1, typeName2);
8930-
addDiagnostic(createDiagnosticForNodeFromMessageChain(typeNode, errorInfo, host.getCompilerHost().getNewLine()));
8934+
diagnostics.add(createDiagnosticForNodeFromMessageChain(typeNode, errorInfo));
89318935
}
89328936
}
89338937
}
@@ -9542,8 +9546,14 @@ module ts {
95429546
}
95439547
}
95449548

9545-
// Fully type check a source file and collect the relevant diagnostics.
95469549
function checkSourceFile(node: SourceFile) {
9550+
var start = new Date().getTime();
9551+
checkSourceFileWorker(node);
9552+
checkTime += new Date().getTime() - start;
9553+
}
9554+
9555+
// Fully type check a source file and collect the relevant diagnostics.
9556+
function checkSourceFileWorker(node: SourceFile) {
95479557
var links = getNodeLinks(node);
95489558
if (!(links.flags & NodeCheckFlags.TypeChecked)) {
95499559
// Grammar checking
@@ -9578,30 +9588,19 @@ module ts {
95789588
}
95799589
}
95809590

9581-
function getSortedDiagnostics(): Diagnostic[]{
9582-
Debug.assert(produceDiagnostics, "diagnostics are available only in the full typecheck mode");
9583-
9584-
if (diagnosticsModified) {
9585-
diagnostics.sort(compareDiagnostics);
9586-
diagnostics = deduplicateSortedDiagnostics(diagnostics);
9587-
diagnosticsModified = false;
9588-
}
9589-
return diagnostics;
9590-
}
9591-
95929591
function getDiagnostics(sourceFile?: SourceFile): Diagnostic[] {
95939592
throwIfNonDiagnosticsProducing();
95949593
if (sourceFile) {
95959594
checkSourceFile(sourceFile);
9596-
return filter(getSortedDiagnostics(), d => d.file === sourceFile);
9595+
return diagnostics.getDiagnostics(sourceFile.fileName);
95979596
}
95989597
forEach(host.getSourceFiles(), checkSourceFile);
9599-
return getSortedDiagnostics();
9598+
return diagnostics.getDiagnostics();
96009599
}
96019600

9602-
function getGlobalDiagnostics(): Diagnostic[]{
9601+
function getGlobalDiagnostics(): Diagnostic[] {
96039602
throwIfNonDiagnosticsProducing();
9604-
return filter(getSortedDiagnostics(), d => !d.file);
9603+
return diagnostics.getGlobalDiagnostics();
96059604
}
96069605

96079606
function throwIfNonDiagnosticsProducing() {
@@ -9625,7 +9624,7 @@ module ts {
96259624
return false;
96269625
}
96279626

9628-
function getSymbolsInScope(location: Node, meaning: SymbolFlags): Symbol[]{
9627+
function getSymbolsInScope(location: Node, meaning: SymbolFlags): Symbol[] {
96299628
var symbols: SymbolTable = {};
96309629
var memberFlags: NodeFlags = 0;
96319630
function copySymbol(symbol: Symbol, meaning: SymbolFlags) {
@@ -10011,7 +10010,7 @@ module ts {
1001110010
return getNamedMembers(propsByName);
1001210011
}
1001310012

10014-
function getRootSymbols(symbol: Symbol): Symbol[]{
10013+
function getRootSymbols(symbol: Symbol): Symbol[] {
1001510014
if (symbol.flags & SymbolFlags.UnionProperty) {
1001610015
var symbols: Symbol[] = [];
1001710016
var name = symbol.name;
@@ -10119,11 +10118,6 @@ module ts {
1011910118
return isImportResolvedToValue(getSymbolOfNode(node));
1012010119
}
1012110120

10122-
function hasSemanticDiagnostics(sourceFile?: SourceFile) {
10123-
// Return true if there is any semantic error in a file or globally
10124-
return getDiagnostics(sourceFile).length > 0 || getGlobalDiagnostics().length > 0;
10125-
}
10126-
1012710121
function isImportResolvedToValue(symbol: Symbol): boolean {
1012810122
var target = resolveImport(symbol);
1012910123
// const enums and modules that contain only const enums are not considered values from the emit perespective
@@ -10177,7 +10171,11 @@ module ts {
1017710171
return getNodeLinks(node).enumMemberValue;
1017810172
}
1017910173

10180-
function getConstantValue(node: PropertyAccessExpression | ElementAccessExpression): number {
10174+
function getConstantValue(node: EnumMember | PropertyAccessExpression | ElementAccessExpression): number {
10175+
if (node.kind === SyntaxKind.EnumMember) {
10176+
return getEnumMemberValue(<EnumMember>node);
10177+
}
10178+
1018110179
var symbol = getNodeLinks(node).resolvedSymbol;
1018210180
if (symbol && (symbol.flags & SymbolFlags.EnumMember)) {
1018310181
var declaration = symbol.valueDeclaration;
@@ -10216,9 +10214,7 @@ module ts {
1021610214
getExportAssignmentName,
1021710215
isReferencedImportDeclaration,
1021810216
getNodeCheckFlags,
10219-
getEnumMemberValue,
1022010217
isTopLevelValueImportWithEntityName,
10221-
hasSemanticDiagnostics,
1022210218
isDeclarationVisible,
1022310219
isImplementationOfOverload,
1022410220
writeTypeOfDeclaration,
@@ -10234,14 +10230,15 @@ module ts {
1023410230
// Bind all source files and propagate errors
1023510231
forEach(host.getSourceFiles(), file => {
1023610232
bindSourceFile(file);
10237-
forEach(file.semanticDiagnostics, addDiagnostic);
1023810233
});
10234+
1023910235
// Initialize global symbol table
1024010236
forEach(host.getSourceFiles(), file => {
1024110237
if (!isExternalModule(file)) {
1024210238
extendSymbolTable(globals, file.locals);
1024310239
}
1024410240
});
10241+
1024510242
// Initialize special symbols
1024610243
getSymbolLinks(undefinedSymbol).type = undefinedType;
1024710244
getSymbolLinks(argumentsSymbol).type = getGlobalType("IArguments");
@@ -11035,14 +11032,14 @@ module ts {
1103511032
if (!hasParseDiagnostics(sourceFile)) {
1103611033
var scanner = createScanner(languageVersion, /*skipTrivia*/ true, sourceFile.text);
1103711034
var start = scanToken(scanner, node.pos);
11038-
diagnostics.push(createFileDiagnostic(sourceFile, start, scanner.getTextPos() - start, message, arg0, arg1, arg2));
11035+
diagnostics.add(createFileDiagnostic(sourceFile, start, scanner.getTextPos() - start, message, arg0, arg1, arg2));
1103911036
return true;
1104011037
}
1104111038
}
1104211039

1104311040
function grammarErrorAtPos(sourceFile: SourceFile, start: number, length: number, message: DiagnosticMessage, arg0?: any, arg1?: any, arg2?: any): boolean {
1104411041
if (!hasParseDiagnostics(sourceFile)) {
11045-
diagnostics.push(createFileDiagnostic(sourceFile, start, length, message, arg0, arg1, arg2));
11042+
diagnostics.add(createFileDiagnostic(sourceFile, start, length, message, arg0, arg1, arg2));
1104611043
return true;
1104711044
}
1104811045
}
@@ -11052,7 +11049,7 @@ module ts {
1105211049
if (!hasParseDiagnostics(sourceFile)) {
1105311050
var span = getErrorSpanForNode(node);
1105411051
var start = span.end > span.pos ? skipTrivia(sourceFile.text, span.pos) : span.pos;
11055-
diagnostics.push(createFileDiagnostic(sourceFile, start, span.end - start, message, arg0, arg1, arg2));
11052+
diagnostics.add(createFileDiagnostic(sourceFile, start, span.end - start, message, arg0, arg1, arg2));
1105611053
return true;
1105711054
}
1105811055
}
@@ -11186,7 +11183,7 @@ module ts {
1118611183
if (!hasParseDiagnostics(sourceFile)) {
1118711184
var scanner = createScanner(languageVersion, /*skipTrivia*/ true, sourceFile.text);
1118811185
scanToken(scanner, node.pos);
11189-
diagnostics.push(createFileDiagnostic(sourceFile, scanner.getTextPos(), 0, message, arg0, arg1, arg2));
11186+
diagnostics.add(createFileDiagnostic(sourceFile, scanner.getTextPos(), 0, message, arg0, arg1, arg2));
1119011187
return true;
1119111188
}
1119211189
}

src/compiler/core.ts

Lines changed: 37 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,12 @@ module ts {
118118
return result;
119119
}
120120

121+
export function addRange<T>(to: T[], from: T[]): void {
122+
for (var i = 0, n = from.length; i < n; i++) {
123+
to.push(from[i]);
124+
}
125+
}
126+
121127
/**
122128
* Returns the last element of an array if non-empty, undefined otherwise.
123129
*/
@@ -325,38 +331,6 @@ module ts {
325331
return headChain;
326332
}
327333

328-
export function flattenDiagnosticChain(file: SourceFile, start: number, length: number, diagnosticChain: DiagnosticMessageChain, newLine: string): Diagnostic {
329-
Debug.assert(start >= 0, "start must be non-negative, is " + start);
330-
Debug.assert(length >= 0, "length must be non-negative, is " + length);
331-
332-
var code = diagnosticChain.code;
333-
var category = diagnosticChain.category;
334-
var messageText = "";
335-
336-
var indent = 0;
337-
while (diagnosticChain) {
338-
if (indent) {
339-
messageText += newLine;
340-
341-
for (var i = 0; i < indent; i++) {
342-
messageText += " ";
343-
}
344-
}
345-
messageText += diagnosticChain.messageText;
346-
indent++;
347-
diagnosticChain = diagnosticChain.next;
348-
}
349-
350-
return {
351-
file,
352-
start,
353-
length,
354-
code,
355-
category,
356-
messageText
357-
};
358-
}
359-
360334
export function compareValues<T>(a: T, b: T): Comparison {
361335
if (a === b) return Comparison.EqualTo;
362336
if (a === undefined) return Comparison.LessThan;
@@ -368,13 +342,41 @@ module ts {
368342
return diagnostic.file ? diagnostic.file.fileName : undefined;
369343
}
370344

371-
export function compareDiagnostics(d1: Diagnostic, d2: Diagnostic): number {
345+
export function compareDiagnostics(d1: Diagnostic, d2: Diagnostic): Comparison {
372346
return compareValues(getDiagnosticFileName(d1), getDiagnosticFileName(d2)) ||
373347
compareValues(d1.start, d2.start) ||
374348
compareValues(d1.length, d2.length) ||
375349
compareValues(d1.code, d2.code) ||
376-
compareValues(d1.messageText, d2.messageText) ||
377-
0;
350+
compareMessageText(d1.messageText, d2.messageText) ||
351+
Comparison.EqualTo;
352+
}
353+
354+
function compareMessageText(text1: string | DiagnosticMessageChain, text2: string | DiagnosticMessageChain): Comparison {
355+
while (text1 && text2) {
356+
// We still have both chains.
357+
var string1 = typeof text1 === "string" ? text1 : text1.messageText;
358+
var string2 = typeof text2 === "string" ? text2 : text2.messageText;
359+
360+
var res = compareValues(string1, string2);
361+
if (res) {
362+
return res;
363+
}
364+
365+
text1 = typeof text1 === "string" ? undefined : text1.next;
366+
text2 = typeof text2 === "string" ? undefined : text2.next;
367+
}
368+
369+
if (!text1 && !text2) {
370+
// if the chains are done, then these messages are the same.
371+
return Comparison.EqualTo;
372+
}
373+
374+
// We still have one chain remaining. The shorter chain should come first.
375+
return text1 ? Comparison.GreaterThan : Comparison.LessThan;
376+
}
377+
378+
export function sortAndDeduplicateDiagnostics(diagnostics: Diagnostic[]): Diagnostic[]{
379+
return deduplicateSortedDiagnostics(diagnostics.sort(compareDiagnostics));
378380
}
379381

380382
export function deduplicateSortedDiagnostics(diagnostics: Diagnostic[]): Diagnostic[] {

0 commit comments

Comments
 (0)