From c30ee34016f46eb30324516eb4661ce23a9e5740 Mon Sep 17 00:00:00 2001 From: dcode Date: Sun, 26 Jan 2020 00:39:42 +0100 Subject: [PATCH] Extend pedantic diagnostics --- src/compiler.ts | 27 +++++++++++++++++++++++---- src/diagnosticMessages.generated.ts | 4 ++++ src/diagnosticMessages.json | 2 ++ src/diagnostics.ts | 29 +++++++++++++++++++++++++++++ tests/compiler/instanceof.ts | 2 +- 5 files changed, 59 insertions(+), 5 deletions(-) diff --git a/src/compiler.ts b/src/compiler.ts index b0bc725588..1289e70476 100644 --- a/src/compiler.ts +++ b/src/compiler.ts @@ -428,7 +428,7 @@ export class Compiler extends DiagnosticEmitter { if (cyclicClasses.size) { if (options.pedantic) { for (let classInstance of cyclicClasses) { - this.info( + this.pedantic( DiagnosticCode.Type_0_is_cyclic_Module_will_include_deferred_garbage_collection, classInstance.identifierNode.range, classInstance.internalName ); @@ -504,7 +504,7 @@ export class Compiler extends DiagnosticEmitter { if (options.importTable) { module.addTableImport("0", "env", "table"); if (options.pedantic && options.willOptimize) { - this.warning( + this.pedantic( DiagnosticCode.Importing_the_table_disables_some_indirect_call_optimizations, null ); @@ -513,7 +513,7 @@ export class Compiler extends DiagnosticEmitter { if (options.exportTable) { module.addTableExport("0", ExportNames.table); if (options.pedantic && options.willOptimize) { - this.warning( + this.pedantic( DiagnosticCode.Exporting_the_table_disables_some_indirect_call_optimizations, null ); @@ -5532,6 +5532,12 @@ export class Compiler extends DiagnosticEmitter { assert(indexedSet.signature.parameterTypes.length == 2); // parser must guarantee this targetType = indexedSet.signature.parameterTypes[1]; // 2nd parameter is the element if (indexedSet.hasDecorator(DecoratorFlags.UNSAFE)) this.checkUnsafe(expression); + if (!isUnchecked && this.options.pedantic) { + this.pedantic( + DiagnosticCode.Indexed_access_may_involve_bounds_checking, + expression.range + ); + } break; } default: { @@ -7174,11 +7180,18 @@ export class Compiler extends DiagnosticEmitter { if (targetType.is(TypeFlags.REFERENCE)) { let classReference = targetType.classReference; if (classReference) { - let indexedGet = classReference.lookupOverload(OperatorKind.INDEXED_GET, this.currentFlow.is(FlowFlags.UNCHECKED_CONTEXT)); + let isUnchecked = this.currentFlow.is(FlowFlags.UNCHECKED_CONTEXT); + let indexedGet = classReference.lookupOverload(OperatorKind.INDEXED_GET, isUnchecked); if (indexedGet) { let thisArg = this.compileExpression(targetExpression, classReference.type, Constraints.CONV_IMPLICIT ); + if (!isUnchecked && this.options.pedantic) { + this.pedantic( + DiagnosticCode.Indexed_access_may_involve_bounds_checking, + expression.range + ); + } return this.compileCallDirect(indexedGet, [ expression.elementExpression ], expression, thisArg, constraints); @@ -7625,6 +7638,12 @@ export class Compiler extends DiagnosticEmitter { ], expression) ); flow.freeTempLocal(temp); + if (this.options.pedantic) { + this.pedantic( + DiagnosticCode.Expression_compiles_to_a_dynamic_check_at_runtime, + expression.range + ); + } return ret; } else { this.error( diff --git a/src/diagnosticMessages.generated.ts b/src/diagnosticMessages.generated.ts index 74974b3e94..7078c27a5b 100644 --- a/src/diagnosticMessages.generated.ts +++ b/src/diagnosticMessages.generated.ts @@ -40,6 +40,8 @@ export enum DiagnosticCode { Type_0_is_cyclic_Module_will_include_deferred_garbage_collection = 900, Importing_the_table_disables_some_indirect_call_optimizations = 901, Exporting_the_table_disables_some_indirect_call_optimizations = 902, + Expression_compiles_to_a_dynamic_check_at_runtime = 903, + Indexed_access_may_involve_bounds_checking = 904, Unterminated_string_literal = 1002, Identifier_expected = 1003, _0_expected = 1005, @@ -187,6 +189,8 @@ export function diagnosticCodeToString(code: DiagnosticCode): string { case 900: return "Type '{0}' is cyclic. Module will include deferred garbage collection."; case 901: return "Importing the table disables some indirect call optimizations."; case 902: return "Exporting the table disables some indirect call optimizations."; + case 903: return "Expression compiles to a dynamic check at runtime."; + case 904: return "Indexed access may involve bounds checking."; case 1002: return "Unterminated string literal."; case 1003: return "Identifier expected."; case 1005: return "'{0}' expected."; diff --git a/src/diagnosticMessages.json b/src/diagnosticMessages.json index fdfb03676b..de8c842aaa 100644 --- a/src/diagnosticMessages.json +++ b/src/diagnosticMessages.json @@ -34,6 +34,8 @@ "Type '{0}' is cyclic. Module will include deferred garbage collection.": 900, "Importing the table disables some indirect call optimizations.": 901, "Exporting the table disables some indirect call optimizations.": 902, + "Expression compiles to a dynamic check at runtime.": 903, + "Indexed access may involve bounds checking.": 904, "Unterminated string literal.": 1002, "Identifier expected.": 1003, diff --git a/src/diagnostics.ts b/src/diagnostics.ts index dac05c2907..22579be4f2 100644 --- a/src/diagnostics.ts +++ b/src/diagnostics.ts @@ -24,6 +24,8 @@ export { /** Indicates the category of a {@link DiagnosticMessage}. */ export enum DiagnosticCategory { + /** Overly pedantic message. */ + PEDANTIC, /** Informatory message. */ INFO, /** Warning message. */ @@ -35,6 +37,7 @@ export enum DiagnosticCategory { /** Returns the string representation of the specified diagnostic category. */ export function diagnosticCategoryToString(category: DiagnosticCategory): string { switch (category) { + case DiagnosticCategory.PEDANTIC: return "PEDANTIC"; case DiagnosticCategory.INFO: return "INFO"; case DiagnosticCategory.WARNING: return "WARNING"; case DiagnosticCategory.ERROR: return "ERROR"; @@ -51,12 +54,15 @@ export const COLOR_BLUE: string = "\u001b[96m"; export const COLOR_YELLOW: string = "\u001b[93m"; /** ANSI escape sequence for red foreground. */ export const COLOR_RED: string = "\u001b[91m"; +/** ANSI escape sequence for magenta foreground. */ +export const COLOR_MAGENTA: string = "\u001b[95m"; /** ANSI escape sequence to reset the foreground color. */ export const COLOR_RESET: string = "\u001b[0m"; /** Returns the ANSI escape sequence for the specified category. */ export function diagnosticCategoryToColor(category: DiagnosticCategory): string { switch (category) { + case DiagnosticCategory.PEDANTIC: return COLOR_MAGENTA; case DiagnosticCategory.INFO: return COLOR_BLUE; case DiagnosticCategory.WARNING: return COLOR_YELLOW; case DiagnosticCategory.ERROR: return COLOR_RED; @@ -275,6 +281,29 @@ export abstract class DiagnosticEmitter { // console.log(new Error("stack").stack); } + /** Emits an overly pedantic diagnostic message. */ + pedantic( + code: DiagnosticCode, + range: Range | null, + arg0: string | null = null, + arg1: string | null = null, + arg2: string | null = null + ): void { + this.emitDiagnostic(code, DiagnosticCategory.PEDANTIC, range, null, arg0, arg1, arg2); + } + + /** Emits an overly pedantic diagnostic message with a related range. */ + pedanticRelated( + code: DiagnosticCode, + range: Range, + relatedRange: Range, + arg0: string | null = null, + arg1: string | null = null, + arg2: string | null = null + ): void { + this.emitDiagnostic(code, DiagnosticCategory.PEDANTIC, range, relatedRange, arg0, arg1, arg2); + } + /** Emits an informatory diagnostic message. */ info( code: DiagnosticCode, diff --git a/tests/compiler/instanceof.ts b/tests/compiler/instanceof.ts index b5b103294e..2cff1b0bc4 100644 --- a/tests/compiler/instanceof.ts +++ b/tests/compiler/instanceof.ts @@ -15,7 +15,7 @@ assert(!(I instanceof A)); assert(!(f instanceof A)); assert(!(F instanceof A)); -// assert(!(a instanceof B)); // dynamic upcast, checked in runtime/instanceof +// assert(!(a instanceof B)); // dynamic upcast, checked in rt/instanceof assert( b instanceof B ); assert(!(i instanceof B)); assert(!(I instanceof B));