From e650e8a6d408b0d9ad3e6ec98dbd78831c8ba4b6 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 17 Mar 2015 16:27:56 -0700 Subject: [PATCH] Add tests for javascript semantic dianostics. --- src/harness/fourslash.ts | 17 ++++++++++- src/services/services.ts | 22 ++++++++++---- src/services/shims.ts | 29 +++++++++++-------- tests/cases/fourslash/fourslash.ts | 4 +++ .../getJavaScriptSemanticDiagnostics1.ts | 15 ++++++++++ .../getJavaScriptSemanticDiagnostics2.ts | 15 ++++++++++ .../getJavaScriptSemanticDiagnostics3.ts | 15 ++++++++++ 7 files changed, 98 insertions(+), 19 deletions(-) create mode 100644 tests/cases/fourslash/getJavaScriptSemanticDiagnostics1.ts create mode 100644 tests/cases/fourslash/getJavaScriptSemanticDiagnostics2.ts create mode 100644 tests/cases/fourslash/getJavaScriptSemanticDiagnostics3.ts diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts index 95a320ac052..44927a7a49a 100644 --- a/src/harness/fourslash.ts +++ b/src/harness/fourslash.ts @@ -14,6 +14,7 @@ // /// +/// /// /// /// @@ -126,12 +127,13 @@ module FourSlash { outDir: 'outDir', sourceMap: 'sourceMap', sourceRoot: 'sourceRoot', + allowNonTsExtensions: 'allowNonTsExtensions', resolveReference: 'ResolveReference', // This flag is used to specify entry file for resolve file references. The flag is only allow once per test file }; // List of allowed metadata names var fileMetadataNames = [testOptMetadataNames.fileName, testOptMetadataNames.emitThisFile, testOptMetadataNames.resolveReference]; - var globalMetadataNames = [testOptMetadataNames.baselineFile, testOptMetadataNames.declaration, + var globalMetadataNames = [testOptMetadataNames.allowNonTsExtensions, testOptMetadataNames.baselineFile, testOptMetadataNames.declaration, testOptMetadataNames.mapRoot, testOptMetadataNames.module, testOptMetadataNames.out, testOptMetadataNames.outDir, testOptMetadataNames.sourceMap, testOptMetadataNames.sourceRoot] @@ -141,6 +143,9 @@ module FourSlash { for (var prop in globalOptions) { if (globalOptions.hasOwnProperty(prop)) { switch (prop) { + case testOptMetadataNames.allowNonTsExtensions: + settings.allowNonTsExtensions = true; + break; case testOptMetadataNames.declaration: settings.declaration = true; break; @@ -788,6 +793,16 @@ module FourSlash { return "\nActual " + name + ":\n\t" + actualValue + "\nExpected value:\n\t" + expectedValue; } + public getSemanticDiagnostics(expected: string) { + var diagnostics = this.languageService.getSemanticDiagnostics(this.activeFile.fileName); + var realized = ts.realizeDiagnostics(diagnostics, "\r\n"); + var actual = JSON.stringify(realized, null, " "); + if (actual !== expected) { + ts.sys.writeFile("c:\\temp\\out.txt", actual); + } + assert.equal(actual, expected); + } + public verifyQuickInfoString(negative: boolean, expectedText?: string, expectedDocumentation?: string) { [expectedText, expectedDocumentation].forEach(str => { if (str) { diff --git a/src/services/services.ts b/src/services/services.ts index 88a56a850cb..8715a171c8b 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -2420,12 +2420,10 @@ module ts { case SyntaxKind.ExportAssignment: diagnostics.push(createDiagnosticForNode(node, Diagnostics.export_can_only_be_used_in_TypeScript)); return; - case SyntaxKind.TypeParameter: - diagnostics.push(createDiagnosticForNode(node, Diagnostics.type_parameter_declarations_can_only_be_used_in_TypeScript)); - return; case SyntaxKind.ClassDeclaration: let classDeclaration = node; - if (checkModifiers(classDeclaration.modifiers)) { + if (checkModifiers(classDeclaration.modifiers) || + checkTypeParameters(classDeclaration.typeParameters)) { return; } break; @@ -2456,6 +2454,7 @@ module ts { case SyntaxKind.FunctionDeclaration: let functionDeclaration = node; if (checkModifiers(functionDeclaration.modifiers) || + checkTypeParameters(functionDeclaration.typeParameters) || checkTypeAnnotation(functionDeclaration.type)) { return; } @@ -2476,7 +2475,8 @@ module ts { case SyntaxKind.NewExpression: let expression = node; if (expression.typeArguments && expression.typeArguments.length > 0) { - diagnostics.push(createFileDiagnostic(sourceFile, expression.typeArguments.pos, expression.typeArguments.end, + let start = expression.typeArguments.pos; + diagnostics.push(createFileDiagnostic(sourceFile, start, expression.typeArguments.end - start, Diagnostics.type_arguments_can_only_be_used_in_TypeScript)); return; } @@ -2484,7 +2484,8 @@ module ts { case SyntaxKind.Parameter: let parameter = node; if (parameter.modifiers) { - diagnostics.push(createFileDiagnostic(sourceFile, parameter.modifiers.pos, parameter.modifiers.end, + let start = parameter.modifiers.pos; + diagnostics.push(createFileDiagnostic(sourceFile, start, parameter.modifiers.end - start, Diagnostics.parameter_modifiers_can_only_be_used_in_TypeScript)); return; } @@ -2511,6 +2512,15 @@ module ts { forEachChild(node, walk); } + function checkTypeParameters(typeParameters: NodeArray): boolean { + if (typeParameters) { + let start = typeParameters.pos; + diagnostics.push(createFileDiagnostic(sourceFile, start, typeParameters.end - start, Diagnostics.type_parameter_declarations_can_only_be_used_in_TypeScript)); + return true; + } + return false; + } + function checkTypeAnnotation(type: TypeNode): boolean { if (type) { diagnostics.push(createDiagnosticForNode(type, Diagnostics.types_can_only_be_used_in_TypeScript)); diff --git a/src/services/shims.ts b/src/services/shims.ts index fc47ff95280..f2082ee39cb 100644 --- a/src/services/shims.ts +++ b/src/services/shims.ts @@ -325,6 +325,22 @@ module ts { } } + /* @internal */ + export function realizeDiagnostics(diagnostics: Diagnostic[], newLine: string): { message: string; start: number; length: number; category: string; } []{ + return diagnostics.map(d => realizeDiagnostic(d, newLine)); + } + + function realizeDiagnostic(diagnostic: Diagnostic, newLine: string): { message: string; start: number; length: number; category: string; } { + return { + message: flattenDiagnosticMessageText(diagnostic.messageText, newLine), + start: diagnostic.start, + length: diagnostic.length, + /// TODO: no need for the tolowerCase call + category: DiagnosticCategory[diagnostic.category].toLowerCase(), + code: diagnostic.code + }; + } + class LanguageServiceShimObject extends ShimBase implements LanguageServiceShim { private logger: Logger; @@ -385,18 +401,7 @@ module ts { private realizeDiagnostics(diagnostics: Diagnostic[]): { message: string; start: number; length: number; category: string; }[]{ var newLine = this.getNewLine(); - return diagnostics.map(d => this.realizeDiagnostic(d, newLine)); - } - - private realizeDiagnostic(diagnostic: Diagnostic, newLine: string): { message: string; start: number; length: number; category: string; } { - return { - message: flattenDiagnosticMessageText(diagnostic.messageText, newLine), - start: diagnostic.start, - length: diagnostic.length, - /// TODO: no need for the tolowerCase call - category: DiagnosticCategory[diagnostic.category].toLowerCase(), - code: diagnostic.code - }; + return ts.realizeDiagnostics(diagnostics, newLine); } public getSyntacticClassifications(fileName: string, start: number, length: number): string { diff --git a/tests/cases/fourslash/fourslash.ts b/tests/cases/fourslash/fourslash.ts index 087c43786f0..8ade18fc200 100644 --- a/tests/cases/fourslash/fourslash.ts +++ b/tests/cases/fourslash/fourslash.ts @@ -439,6 +439,10 @@ module FourSlashInterface { displayParts: ts.SymbolDisplayPart[], documentation: ts.SymbolDisplayPart[]) { FourSlash.currentTestState.verifyQuickInfoDisplayParts(kind, kindModifiers, textSpan, displayParts, documentation); } + + public getSemanticDiagnostics(expected: string) { + FourSlash.currentTestState.getSemanticDiagnostics(expected); + } } export class edit { diff --git a/tests/cases/fourslash/getJavaScriptSemanticDiagnostics1.ts b/tests/cases/fourslash/getJavaScriptSemanticDiagnostics1.ts new file mode 100644 index 00000000000..e73b487347a --- /dev/null +++ b/tests/cases/fourslash/getJavaScriptSemanticDiagnostics1.ts @@ -0,0 +1,15 @@ +/// + +// @allowNonTsExtensions: true +// @Filename: a.tsjs +//// import a = b; + +verify.getSemanticDiagnostics(`[ + { + "message": "'import ... =' can only be used in TypeScript.", + "start": 0, + "length": 13, + "category": "error", + "code": 8002 + } +]`); \ No newline at end of file diff --git a/tests/cases/fourslash/getJavaScriptSemanticDiagnostics2.ts b/tests/cases/fourslash/getJavaScriptSemanticDiagnostics2.ts new file mode 100644 index 00000000000..e239577e5e4 --- /dev/null +++ b/tests/cases/fourslash/getJavaScriptSemanticDiagnostics2.ts @@ -0,0 +1,15 @@ +/// + +// @allowNonTsExtensions: true +// @Filename: a.tsjs +//// export = b; + +verify.getSemanticDiagnostics(`[ + { + "message": "'export=' can only be used in TypeScript.", + "start": 0, + "length": 11, + "category": "error", + "code": 8003 + } +]`); \ No newline at end of file diff --git a/tests/cases/fourslash/getJavaScriptSemanticDiagnostics3.ts b/tests/cases/fourslash/getJavaScriptSemanticDiagnostics3.ts new file mode 100644 index 00000000000..d74e97b36cc --- /dev/null +++ b/tests/cases/fourslash/getJavaScriptSemanticDiagnostics3.ts @@ -0,0 +1,15 @@ +/// + +// @allowNonTsExtensions: true +// @Filename: a.tsjs +//// class C; + +verify.getSemanticDiagnostics(`[ + { + "message": "'type parameter declarations' can only be used in TypeScript.", + "start": 8, + "length": 1, + "category": "error", + "code": 8004 + } +]`); \ No newline at end of file