diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 1eeeded5d36..06476d29fbe 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -773,48 +773,24 @@ namespace ts { function getJavaScriptSyntacticDiagnosticsForFile(sourceFile: SourceFile): Diagnostic[] { return runWithCancellationToken(() => { const diagnostics: Diagnostic[] = []; + let parent: Node = sourceFile; walk(sourceFile); return diagnostics; - function walk(node: Node): boolean { - if (!node) { - return false; - } + function walk(node: Node) { + // Return directly from the case if the given node doesnt want to visit each child + // Otherwise break to visit each child - switch (node.kind) { - case SyntaxKind.ImportEqualsDeclaration: - diagnostics.push(createDiagnosticForNode(node, Diagnostics.import_can_only_be_used_in_a_ts_file)); - return true; - case SyntaxKind.ExportAssignment: - if ((node).isExportEquals) { - diagnostics.push(createDiagnosticForNode(node, Diagnostics.export_can_only_be_used_in_a_ts_file)); - return true; + switch (parent.kind) { + case SyntaxKind.Parameter: + case SyntaxKind.PropertyDeclaration: + if ((parent).questionToken === node) { + diagnostics.push(createDiagnosticForNode(node, Diagnostics._0_can_only_be_used_in_a_ts_file, "?")); + return; } - break; - case SyntaxKind.ClassDeclaration: - let classDeclaration = node; - if (checkModifiers(classDeclaration.modifiers) || - checkTypeParameters(classDeclaration.typeParameters)) { - return true; - } - break; - case SyntaxKind.HeritageClause: - let heritageClause = node; - if (heritageClause.token === SyntaxKind.ImplementsKeyword) { - diagnostics.push(createDiagnosticForNode(node, Diagnostics.implements_clauses_can_only_be_used_in_a_ts_file)); - return true; - } - break; - case SyntaxKind.InterfaceDeclaration: - diagnostics.push(createDiagnosticForNode(node, Diagnostics.interface_declarations_can_only_be_used_in_a_ts_file)); - return true; - case SyntaxKind.ModuleDeclaration: - diagnostics.push(createDiagnosticForNode(node, Diagnostics.module_declarations_can_only_be_used_in_a_ts_file)); - return true; - case SyntaxKind.TypeAliasDeclaration: - diagnostics.push(createDiagnosticForNode(node, Diagnostics.type_aliases_can_only_be_used_in_a_ts_file)); - return true; + + // Pass through case SyntaxKind.MethodDeclaration: case SyntaxKind.MethodSignature: case SyntaxKind.Constructor: @@ -824,124 +800,141 @@ namespace ts { case SyntaxKind.FunctionDeclaration: case SyntaxKind.ArrowFunction: case SyntaxKind.FunctionDeclaration: - const functionDeclaration = node; - if (checkModifiers(functionDeclaration.modifiers) || - checkTypeParameters(functionDeclaration.typeParameters) || - checkTypeAnnotation(functionDeclaration.type)) { - return true; - } - break; - case SyntaxKind.VariableStatement: - const variableStatement = node; - if (checkModifiers(variableStatement.modifiers)) { - return true; - } - break; case SyntaxKind.VariableDeclaration: - const variableDeclaration = node; - if (checkTypeAnnotation(variableDeclaration.type)) { - return true; + // type annotation + if ((parent).type === node) { + diagnostics.push(createDiagnosticForNode(node, Diagnostics.types_can_only_be_used_in_a_ts_file)); + return; + } + } + + switch (node.kind) { + case SyntaxKind.ImportEqualsDeclaration: + diagnostics.push(createDiagnosticForNode(node, Diagnostics.import_can_only_be_used_in_a_ts_file)); + return; + case SyntaxKind.ExportAssignment: + if ((node).isExportEquals) { + diagnostics.push(createDiagnosticForNode(node, Diagnostics.export_can_only_be_used_in_a_ts_file)); + return; + } + break; + case SyntaxKind.HeritageClause: + let heritageClause = node; + if (heritageClause.token === SyntaxKind.ImplementsKeyword) { + diagnostics.push(createDiagnosticForNode(node, Diagnostics.implements_clauses_can_only_be_used_in_a_ts_file)); + return; + } + break; + case SyntaxKind.InterfaceDeclaration: + diagnostics.push(createDiagnosticForNode(node, Diagnostics.interface_declarations_can_only_be_used_in_a_ts_file)); + return; + case SyntaxKind.ModuleDeclaration: + diagnostics.push(createDiagnosticForNode(node, Diagnostics.module_declarations_can_only_be_used_in_a_ts_file)); + return; + case SyntaxKind.TypeAliasDeclaration: + diagnostics.push(createDiagnosticForNode(node, Diagnostics.type_aliases_can_only_be_used_in_a_ts_file)); + return; + case SyntaxKind.EnumDeclaration: + diagnostics.push(createDiagnosticForNode(node, Diagnostics.enum_declarations_can_only_be_used_in_a_ts_file)); + return; + case SyntaxKind.TypeAssertionExpression: + let typeAssertionExpression = node; + diagnostics.push(createDiagnosticForNode(typeAssertionExpression.type, Diagnostics.type_assertion_expressions_can_only_be_used_in_a_ts_file)); + return; + } + + const prevParent = parent; + parent = node; + forEachChild(node, walk, walkArray); + parent = prevParent; + } + + function walkArray(nodes: NodeArray) { + if (parent.decorators === nodes && !options.experimentalDecorators) { + diagnostics.push(createDiagnosticForNode(parent, Diagnostics.Experimental_support_for_decorators_is_a_feature_that_is_subject_to_change_in_a_future_release_Set_the_experimentalDecorators_option_to_remove_this_warning)); + } + + switch (parent.kind) { + case SyntaxKind.ClassDeclaration: + case SyntaxKind.MethodDeclaration: + case SyntaxKind.MethodSignature: + case SyntaxKind.Constructor: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + case SyntaxKind.FunctionExpression: + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.ArrowFunction: + case SyntaxKind.FunctionDeclaration: + // Check type parameters + if (nodes === (parent).typeParameters) { + diagnostics.push(createDiagnosticForNodeArray(nodes, Diagnostics.type_parameter_declarations_can_only_be_used_in_a_ts_file)); + return; + } + // pass through + case SyntaxKind.VariableStatement: + // Check modifiers + if (nodes === (parent).modifiers) { + return checkModifiers(>nodes); + } + break; + case SyntaxKind.PropertyDeclaration: + // Check modifiers of property declaration + if (nodes === (parent).modifiers) { + for (const modifier of >nodes) { + if (modifier.kind !== SyntaxKind.StaticKeyword) { + diagnostics.push(createDiagnosticForNode(modifier, Diagnostics._0_can_only_be_used_in_a_ts_file, tokenToString(modifier.kind))); + } + } + return; + } + break; + case SyntaxKind.Parameter: + // Check modifiers of parameter declaration + if (nodes === (parent).modifiers) { + diagnostics.push(createDiagnosticForNodeArray(nodes, Diagnostics.parameter_modifiers_can_only_be_used_in_a_ts_file)); + return; } break; case SyntaxKind.CallExpression: case SyntaxKind.NewExpression: - const expression = node; - if (expression.typeArguments && expression.typeArguments.length > 0) { - const start = expression.typeArguments.pos; - diagnostics.push(createFileDiagnostic(sourceFile, start, expression.typeArguments.end - start, - Diagnostics.type_arguments_can_only_be_used_in_a_ts_file)); - return true; + case SyntaxKind.ExpressionWithTypeArguments: + // Check type arguments + if (nodes === (parent).typeArguments) { + diagnostics.push(createDiagnosticForNodeArray(nodes, Diagnostics.type_arguments_can_only_be_used_in_a_ts_file)); + return; } break; - case SyntaxKind.Parameter: - const parameter = node; - if (parameter.modifiers) { - const start = parameter.modifiers.pos; - diagnostics.push(createFileDiagnostic(sourceFile, start, parameter.modifiers.end - start, - Diagnostics.parameter_modifiers_can_only_be_used_in_a_ts_file)); - return true; - } - if (parameter.questionToken) { - diagnostics.push(createDiagnosticForNode(parameter.questionToken, Diagnostics._0_can_only_be_used_in_a_ts_file, "?")); - return true; - } - if (parameter.type) { - diagnostics.push(createDiagnosticForNode(parameter.type, Diagnostics.types_can_only_be_used_in_a_ts_file)); - return true; - } - break; - case SyntaxKind.PropertyDeclaration: - const propertyDeclaration = node; - if (propertyDeclaration.modifiers) { - for (const modifier of propertyDeclaration.modifiers) { - if (modifier.kind !== SyntaxKind.StaticKeyword) { - diagnostics.push(createDiagnosticForNode(modifier, Diagnostics._0_can_only_be_used_in_a_ts_file, tokenToString(modifier.kind))); - return true; - } - } - } - if (checkTypeAnnotation((node).type)) { - return true; - } - break; - case SyntaxKind.EnumDeclaration: - diagnostics.push(createDiagnosticForNode(node, Diagnostics.enum_declarations_can_only_be_used_in_a_ts_file)); - return true; - case SyntaxKind.TypeAssertionExpression: - let typeAssertionExpression = node; - diagnostics.push(createDiagnosticForNode(typeAssertionExpression.type, Diagnostics.type_assertion_expressions_can_only_be_used_in_a_ts_file)); - return true; - case SyntaxKind.Decorator: - if (!options.experimentalDecorators) { - diagnostics.push(createDiagnosticForNode(node, Diagnostics.Experimental_support_for_decorators_is_a_feature_that_is_subject_to_change_in_a_future_release_Set_the_experimentalDecorators_option_to_remove_this_warning)); - } - return true; } - return forEachChild(node, walk); - } - - function checkTypeParameters(typeParameters: NodeArray): boolean { - if (typeParameters) { - const start = typeParameters.pos; - diagnostics.push(createFileDiagnostic(sourceFile, start, typeParameters.end - start, Diagnostics.type_parameter_declarations_can_only_be_used_in_a_ts_file)); - return true; + for (const node of nodes) { + walk(node); } - return false; } - function checkTypeAnnotation(type: TypeNode): boolean { - if (type) { - diagnostics.push(createDiagnosticForNode(type, Diagnostics.types_can_only_be_used_in_a_ts_file)); - return true; - } + function checkModifiers(modifiers: NodeArray) { + for (const modifier of modifiers) { + switch (modifier.kind) { + case SyntaxKind.PublicKeyword: + case SyntaxKind.PrivateKeyword: + case SyntaxKind.ProtectedKeyword: + case SyntaxKind.ReadonlyKeyword: + case SyntaxKind.DeclareKeyword: + diagnostics.push(createDiagnosticForNode(modifier, Diagnostics._0_can_only_be_used_in_a_ts_file, tokenToString(modifier.kind))); + break; - return false; - } - - function checkModifiers(modifiers: NodeArray): boolean { - if (modifiers) { - for (const modifier of modifiers) { - switch (modifier.kind) { - case SyntaxKind.PublicKeyword: - case SyntaxKind.PrivateKeyword: - case SyntaxKind.ProtectedKeyword: - case SyntaxKind.ReadonlyKeyword: - case SyntaxKind.DeclareKeyword: - diagnostics.push(createDiagnosticForNode(modifier, Diagnostics._0_can_only_be_used_in_a_ts_file, tokenToString(modifier.kind))); - return true; - - // These are all legal modifiers. - case SyntaxKind.StaticKeyword: - case SyntaxKind.ExportKeyword: - case SyntaxKind.ConstKeyword: - case SyntaxKind.DefaultKeyword: - case SyntaxKind.AbstractKeyword: - } + // These are all legal modifiers. + case SyntaxKind.StaticKeyword: + case SyntaxKind.ExportKeyword: + case SyntaxKind.ConstKeyword: + case SyntaxKind.DefaultKeyword: + case SyntaxKind.AbstractKeyword: } } + } - return false; + function createDiagnosticForNodeArray(nodes: NodeArray, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number): Diagnostic { + const start = nodes.pos; + return createFileDiagnostic(sourceFile, start, nodes.end - start, message, arg0, arg1, arg2); } // Since these are syntactic diagnostics, parent might not have been set diff --git a/tests/baselines/reference/decoratorInJsFile.errors.txt b/tests/baselines/reference/decoratorInJsFile.errors.txt new file mode 100644 index 00000000000..93bd5143b74 --- /dev/null +++ b/tests/baselines/reference/decoratorInJsFile.errors.txt @@ -0,0 +1,13 @@ +tests/cases/compiler/a.js(4,12): error TS8010: 'types' can only be used in a .ts file. + + +==== tests/cases/compiler/a.js (1 errors) ==== + + @SomeDecorator + class SomeClass { + foo(x: number) { + ~~~~~~ +!!! error TS8010: 'types' can only be used in a .ts file. + + } + } \ No newline at end of file diff --git a/tests/baselines/reference/decoratorInJsFile.symbols b/tests/baselines/reference/decoratorInJsFile.symbols deleted file mode 100644 index 1ad477095c1..00000000000 --- a/tests/baselines/reference/decoratorInJsFile.symbols +++ /dev/null @@ -1,12 +0,0 @@ -=== tests/cases/compiler/a.js === - -@SomeDecorator -class SomeClass { ->SomeClass : Symbol(SomeClass, Decl(a.js, 0, 0)) - - foo(x: number) { ->foo : Symbol(SomeClass.foo, Decl(a.js, 2, 17)) ->x : Symbol(x, Decl(a.js, 3, 8)) - - } -} diff --git a/tests/baselines/reference/decoratorInJsFile.types b/tests/baselines/reference/decoratorInJsFile.types deleted file mode 100644 index 49403979460..00000000000 --- a/tests/baselines/reference/decoratorInJsFile.types +++ /dev/null @@ -1,14 +0,0 @@ -=== tests/cases/compiler/a.js === - -@SomeDecorator ->SomeDecorator : any - -class SomeClass { ->SomeClass : SomeClass - - foo(x: number) { ->foo : (x: number) => void ->x : number - - } -} diff --git a/tests/baselines/reference/decoratorInJsFile1.errors.txt b/tests/baselines/reference/decoratorInJsFile1.errors.txt index a90aa922f96..f4422c0c2d9 100644 --- a/tests/baselines/reference/decoratorInJsFile1.errors.txt +++ b/tests/baselines/reference/decoratorInJsFile1.errors.txt @@ -1,13 +1,16 @@ -tests/cases/compiler/a.js(2,1): error TS1219: Experimental support for decorators is a feature that is subject to change in a future release. Set the 'experimentalDecorators' option to remove this warning. +tests/cases/compiler/a.js(3,7): error TS1219: Experimental support for decorators is a feature that is subject to change in a future release. Set the 'experimentalDecorators' option to remove this warning. +tests/cases/compiler/a.js(4,12): error TS8010: 'types' can only be used in a .ts file. -==== tests/cases/compiler/a.js (1 errors) ==== +==== tests/cases/compiler/a.js (2 errors) ==== @SomeDecorator - ~~~~~~~~~~~~~~ -!!! error TS1219: Experimental support for decorators is a feature that is subject to change in a future release. Set the 'experimentalDecorators' option to remove this warning. class SomeClass { + ~~~~~~~~~ +!!! error TS1219: Experimental support for decorators is a feature that is subject to change in a future release. Set the 'experimentalDecorators' option to remove this warning. foo(x: number) { + ~~~~~~ +!!! error TS8010: 'types' can only be used in a .ts file. } } \ No newline at end of file diff --git a/tests/cases/fourslash/server/getJavaScriptSyntacticDiagnostics02.ts b/tests/cases/fourslash/server/getJavaScriptSyntacticDiagnostics02.ts index dd9becad10b..a19d170217c 100644 --- a/tests/cases/fourslash/server/getJavaScriptSyntacticDiagnostics02.ts +++ b/tests/cases/fourslash/server/getJavaScriptSyntacticDiagnostics02.ts @@ -15,6 +15,13 @@ verify.getSyntacticDiagnostics(`[ "category": "error", "code": 8010 }, + { + "message": "\'types\' can only be used in a .ts file.", + "start": 52, + "length": 6, + "category": "error", + "code": 8010 + }, { "message": "Variable declaration expected.", "start": 67,