Introduce an object to store and manage diagnostics for different compiler components.

This commit is contained in:
Cyrus Najmabadi 2015-02-04 13:04:42 -08:00
parent de13648c9f
commit 35a6d0e68a
5 changed files with 118 additions and 34 deletions

View file

@ -104,8 +104,7 @@ module ts {
var nodeLinks: NodeLinks[] = [];
var potentialThisCollisions: Node[] = [];
var diagnostics: Diagnostic[] = [];
var diagnosticsModified: boolean = false;
var diagnostics = createDiagnosticCollection();
var primitiveTypeInfo: Map<{ type: Type; flags: TypeFlags }> = {
"string": {
@ -122,16 +121,11 @@ module ts {
}
};
function addDiagnostic(diagnostic: Diagnostic) {
diagnostics.push(diagnostic);
diagnosticsModified = true;
}
function error(location: Node, message: DiagnosticMessage, arg0?: any, arg1?: any, arg2?: any): void {
var diagnostic = location
? createDiagnosticForNode(location, message, arg0, arg1, arg2)
: createCompilerDiagnostic(message, arg0, arg1, arg2);
addDiagnostic(diagnostic);
diagnostics.add(diagnostic);
}
function createSymbol(flags: SymbolFlags, name: string): Symbol {
@ -3479,7 +3473,8 @@ module ts {
if (containingMessageChain) {
errorInfo = concatenateDiagnosticMessageChains(containingMessageChain, errorInfo);
}
addDiagnostic(createDiagnosticForNodeFromMessageChain(errorNode, errorInfo, host.getCompilerHost().getNewLine()));
diagnostics.add(createDiagnosticForNodeFromMessageChain(errorNode, errorInfo, host.getCompilerHost().getNewLine()));
}
return result !== Ternary.False;
@ -5705,9 +5700,9 @@ module ts {
return false;
}
else {
var diagnosticsCount = diagnostics.length;
var modificationCount = diagnostics.getModificationCount();
checkClassPropertyAccess(node, left, type, prop);
return diagnostics.length === diagnosticsCount
return diagnostics.getModificationCount() === modificationCount;
}
}
}
@ -8927,7 +8922,7 @@ module ts {
var errorInfo = chainDiagnosticMessages(undefined, Diagnostics.Named_properties_0_of_types_1_and_2_are_not_identical, prop.name, typeName1, typeName2);
errorInfo = chainDiagnosticMessages(errorInfo, Diagnostics.Interface_0_cannot_simultaneously_extend_types_1_and_2, typeToString(type), typeName1, typeName2);
addDiagnostic(createDiagnosticForNodeFromMessageChain(typeNode, errorInfo, host.getCompilerHost().getNewLine()));
diagnostics.add(createDiagnosticForNodeFromMessageChain(typeNode, errorInfo, host.getCompilerHost().getNewLine()));
}
}
}
@ -9578,30 +9573,19 @@ module ts {
}
}
function getSortedDiagnostics(): Diagnostic[]{
Debug.assert(produceDiagnostics, "diagnostics are available only in the full typecheck mode");
if (diagnosticsModified) {
diagnostics.sort(compareDiagnostics);
diagnostics = deduplicateSortedDiagnostics(diagnostics);
diagnosticsModified = false;
}
return diagnostics;
}
function getDiagnostics(sourceFile?: SourceFile): Diagnostic[] {
throwIfNonDiagnosticsProducing();
if (sourceFile) {
checkSourceFile(sourceFile);
return filter(getSortedDiagnostics(), d => d.file === sourceFile);
return diagnostics.getDiagnostics(sourceFile.fileName);
}
forEach(host.getSourceFiles(), checkSourceFile);
return getSortedDiagnostics();
return diagnostics.getDiagnostics();
}
function getGlobalDiagnostics(): Diagnostic[]{
throwIfNonDiagnosticsProducing();
return filter(getSortedDiagnostics(), d => !d.file);
return diagnostics.getGlobalDiagnostics();
}
function throwIfNonDiagnosticsProducing() {
@ -10234,7 +10218,7 @@ module ts {
// Bind all source files and propagate errors
forEach(host.getSourceFiles(), file => {
bindSourceFile(file);
forEach(file.semanticDiagnostics, addDiagnostic);
forEach(file.semanticDiagnostics, d => diagnostics.add(d));
});
// Initialize global symbol table
forEach(host.getSourceFiles(), file => {
@ -11035,14 +11019,14 @@ module ts {
if (!hasParseDiagnostics(sourceFile)) {
var scanner = createScanner(languageVersion, /*skipTrivia*/ true, sourceFile.text);
var start = scanToken(scanner, node.pos);
diagnostics.push(createFileDiagnostic(sourceFile, start, scanner.getTextPos() - start, message, arg0, arg1, arg2));
diagnostics.add(createFileDiagnostic(sourceFile, start, scanner.getTextPos() - start, message, arg0, arg1, arg2));
return true;
}
}
function grammarErrorAtPos(sourceFile: SourceFile, start: number, length: number, message: DiagnosticMessage, arg0?: any, arg1?: any, arg2?: any): boolean {
if (!hasParseDiagnostics(sourceFile)) {
diagnostics.push(createFileDiagnostic(sourceFile, start, length, message, arg0, arg1, arg2));
diagnostics.add(createFileDiagnostic(sourceFile, start, length, message, arg0, arg1, arg2));
return true;
}
}
@ -11052,7 +11036,7 @@ module ts {
if (!hasParseDiagnostics(sourceFile)) {
var span = getErrorSpanForNode(node);
var start = span.end > span.pos ? skipTrivia(sourceFile.text, span.pos) : span.pos;
diagnostics.push(createFileDiagnostic(sourceFile, start, span.end - start, message, arg0, arg1, arg2));
diagnostics.add(createFileDiagnostic(sourceFile, start, span.end - start, message, arg0, arg1, arg2));
return true;
}
}
@ -11186,7 +11170,7 @@ module ts {
if (!hasParseDiagnostics(sourceFile)) {
var scanner = createScanner(languageVersion, /*skipTrivia*/ true, sourceFile.text);
scanToken(scanner, node.pos);
diagnostics.push(createFileDiagnostic(sourceFile, scanner.getTextPos(), 0, message, arg0, arg1, arg2));
diagnostics.add(createFileDiagnostic(sourceFile, scanner.getTextPos(), 0, message, arg0, arg1, arg2));
return true;
}
}

View file

@ -358,10 +358,9 @@ module ts {
export function getSyntacticDiagnostics(sourceFile: SourceFile) {
if (!sourceFile.syntacticDiagnostics) {
// Don't bother doing any grammar checks if there are already parser errors.
// Otherwise we may end up with too many cascading errors.
sourceFile.syntacticDiagnostics = sourceFile.referenceDiagnostics.concat(sourceFile.parseDiagnostics);
}
return sourceFile.syntacticDiagnostics;
}

View file

@ -1678,4 +1678,24 @@ module ts {
span: TextSpan;
newLength: number;
}
// @internal
export interface DiagnosticCollection {
// Adds a diagnostic to this diagnostic collection.
add(diagnostic?: Diagnostic): void;
// Gets all the diagnostics that aren't associated with a file.
getGlobalDiagnostics(): Diagnostic[];
// If fileName is provided, gets all the diagnostics associated with that file name.
// Otherwise, returns all the diagnostics (global and file associated) in this colletion.
getDiagnostics(fileName?: string): Diagnostic[];
// Gets a count of how many times this collectoin has been modified. This value changes
// each time 'add' is called (regardless of whether or not an equivalent diagnostic was
// already in the collection). As such, it can be used as a simple way to tell if any
// operation caused diagnostics to be returned by storing and comparing the return value
// of this method before/after the operation is performed.
getModificationCount(): number;
}
}

View file

@ -1068,4 +1068,84 @@ module ts {
return createTextChangeRange(createTextSpanFromBounds(oldStartN, oldEndN), /*newLength: */newEndN - oldStartN);
}
// @internal
export function createDiagnosticCollection(): DiagnosticCollection {
var nonFileDiagnostics: Diagnostic[] = [];
var fileDiagnostics: Map<Diagnostic[]> = {};
var diagnosticsModified = false;
var modificationCount = 0;
return {
add,
getGlobalDiagnostics,
getDiagnostics,
getModificationCount
};
function getModificationCount() {
return modificationCount;
}
function add(diagnostic: Diagnostic): void {
var diagnostics: Diagnostic[];
if (diagnostic.file) {
diagnostics = fileDiagnostics[diagnostic.file.fileName];
if (!diagnostics) {
diagnostics = [];
fileDiagnostics[diagnostic.file.fileName] = diagnostics;
}
}
else {
diagnostics = nonFileDiagnostics;
}
diagnostics.push(diagnostic);
diagnosticsModified = true;
modificationCount++;
}
function getGlobalDiagnostics(): Diagnostic[] {
sortAndDeduplicate();
return nonFileDiagnostics;
}
function getDiagnostics(fileName?: string): Diagnostic[] {
sortAndDeduplicate();
if (fileName) {
return fileDiagnostics[fileName] || [];
}
var allDiagnostics: Diagnostic[] = [];
forEach(nonFileDiagnostics, d => { allDiagnostics.push(d) });
for (var key in fileDiagnostics) {
if (hasProperty(fileDiagnostics, key)) {
forEach(fileDiagnostics[key], d => { allDiagnostics.push(d) });
}
}
return sortAndDeplicateList(allDiagnostics);
}
function sortAndDeduplicate() {
if (!diagnosticsModified) {
return;
}
diagnosticsModified = false;
nonFileDiagnostics = sortAndDeplicateList(nonFileDiagnostics);
for (var key in fileDiagnostics) {
if (hasProperty(fileDiagnostics, key)) {
fileDiagnostics[key] = sortAndDeplicateList(fileDiagnostics[key]);
}
}
}
function sortAndDeplicateList(diagnostics: Diagnostic[]): Diagnostic[] {
return deduplicateSortedDiagnostics(diagnostics.sort(compareDiagnostics))
}
}
}

View file

@ -921,6 +921,7 @@ module Harness {
// Current directory is needed for rwcRunner to be able to use currentDirectory defined in json file
currentDirectory?: string) {
debugger;
options = options || { noResolve: false };
options.target = options.target || ts.ScriptTarget.ES3;
options.module = options.module || ts.ModuleKind.None;
@ -1074,7 +1075,7 @@ module Harness {
otherFiles.forEach(register);
var fileOutputs: GeneratedFile[] = [];
var programFiles = inputFiles.map(file => file.unitName);
var program = ts.createProgram(programFiles, options, createCompilerHost(inputFiles.concat(otherFiles),
(fn, contents, writeByteOrderMark) => fileOutputs.push({ fileName: fn, code: contents, writeByteOrderMark: writeByteOrderMark }),