From 5bab826c6b41af84d7f4a0ce7dbbef0a07159fee Mon Sep 17 00:00:00 2001 From: Yui T Date: Fri, 10 Apr 2015 14:23:54 -0700 Subject: [PATCH] Address issue with propertyAccessExpression and QualifiedName in TypeReference --- src/compiler/checker.ts | 130 +++++++++++++++++++++++++++++++--------- src/compiler/parser.ts | 6 +- src/compiler/types.ts | 4 +- 3 files changed, 107 insertions(+), 33 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index e103fbb8dbc..e75515cbb56 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -7954,7 +7954,7 @@ module ts { } function checkExpression(node: Expression, contextualMapper?: TypeMapper): Type { - checkGrammarExpressionInStrictMode(node); + checkGrammarIdentifierInStrictMode(node); return checkExpressionOrQualifiedName(node, contextualMapper); } @@ -8340,25 +8340,13 @@ module ts { } function checkTypeReferenceNode(node: TypeReferenceNode) { - // Check if the type reference is using strict mode keyword - // Example: - // class C { - // foo(x: public){} // Error. - // } - if (node.typeName.kind === SyntaxKind.Identifier) { - let typeName = node.typeName; - if (isReservedwordInStrictMode(typeName)) { - let nameText = declarationNameToString(typeName); - // TODO(yuisu): Fix this when external module becomes strict mode code; - reportStrictModeGrammarErrorInClassDeclaration(typeName, Diagnostics.Type_expected_0_is_a_reserved_word_in_strict_mode_Class_definitions_are_automatically_in_strict_mode, nameText) || - grammarErrorOnNode(typeName, Diagnostics.Type_expected_0_is_a_reserved_word_in_strict_mode, nameText); - } - } + checkGrammarTypeReferenceInStrictMode(node.typeName); return checkTypeReferenceOrHeritageClauseElement(node); } function checkHeritageClauseElement(node: HeritageClauseElement) { - checkGrammarExpressionInStrictMode(node.expression); + checkGrammarHeritageClauseElementInStrictMode(node.expression); + return checkTypeReferenceOrHeritageClauseElement(node); } @@ -10588,7 +10576,7 @@ module ts { // export { x, y } from "foo" forEach(node.exportClause.elements, checkExportSpecifier); - let inAmbientExternalModule = node.parent.kind === SyntaxKind.ModuleBlock && (node.parent.parent).name.kind === SyntaxKind.StringLiteral; + let inAmbientExternalModule = node.parent.kind === SyntaxKind.ModuleBlock && (node.parent.parent).name.kind === SyntaxKind.StringLiteral; if (node.parent.kind !== SyntaxKind.SourceFile && !inAmbientExternalModule) { error(node, Diagnostics.Export_declarations_are_not_permitted_in_an_internal_module); } @@ -11936,7 +11924,8 @@ module ts { // GRAMMAR CHECKING function isReservedwordInStrictMode(node: Identifier): boolean { - if ((node.parserContextFlags & ParserContextFlags.StrictMode) && node.originalSyntaxKind) { + // Check that originalStrictModeSyntaxKind is less than LastFurtureReservedWord to see if an Identifier is a strict-mode reserved word + if ((node.parserContextFlags & ParserContextFlags.StrictMode) && node.originalStrictModeSyntaxKind <= SyntaxKind.LastFutureReservedWord) { return true; } return false @@ -11959,7 +11948,7 @@ module ts { let nameBindings = impotClause.namedBindings; if (nameBindings.kind === SyntaxKind.NamespaceImport) { let name = (nameBindings).name; - if (name.originalSyntaxKind) { + if (name.originalStrictModeSyntaxKind) { let nameText = declarationNameToString(name); return grammarErrorOnNode(name, Diagnostics.Identifier_expected_0_is_a_reserved_word_in_strict_mode, nameText); } @@ -11968,7 +11957,7 @@ module ts { let reportError = false; for (let element of (nameBindings).elements) { let name = element.name; - if (name.originalSyntaxKind) { + if (name.originalStrictModeSyntaxKind) { let nameText = declarationNameToString(name); reportError = grammarErrorOnNode(name, Diagnostics.Identifier_expected_0_is_a_reserved_word_in_strict_mode, nameText); } @@ -11993,10 +11982,7 @@ module ts { case SyntaxKind.InterfaceDeclaration: case SyntaxKind.TypeAliasDeclaration: case SyntaxKind.EnumDeclaration: - // TODO(yuisu): fix this when having external moduel in strict mode - let reportError = reportStrictModeGrammarErrorInClassDeclaration(name, Diagnostics.Identifier_expected_0_is_a_reserved_word_in_strict_mode_Class_definitions_are_automatically_in_strict_mode, nameText) || - grammarErrorOnNode(name, Diagnostics.Identifier_expected_0_is_a_reserved_word_in_strict_mode, nameText); - return reportError ? reportError : false; + return checkGrammarIdentifierInStrictMode(name); case SyntaxKind.ClassDeclaration: // Report an error if the class declaration uses strict-mode reserved word. @@ -12008,17 +11994,105 @@ module ts { return grammarErrorOnNode(name, Diagnostics.Identifier_expected_0_is_a_reserved_word_in_strict_mode, nameText); case SyntaxKind.ImportEqualsDeclaration: - // TODO(yuisu): fix this when having external moduel in strict mode + // TODO(yuisu): fix this when having external module in strict mode return grammarErrorOnNode(name, Diagnostics.Identifier_expected_0_is_a_reserved_word_in_strict_mode, nameText); } } return false; } - function checkGrammarExpressionInStrictMode(node: Expression): boolean { - if (node.kind === SyntaxKind.Identifier && isReservedwordInStrictMode(node)) { + function checkGrammarTypeReferenceInStrictMode(typeName: Identifier | QualifiedName) { + // Check if the type reference is using strict mode keyword + // Example: + // class C { + // foo(x: public){} // Error. + // } + if (typeName.kind === SyntaxKind.Identifier) { + checkGrammarTypeNameInStrictMode(typeName); + } + // Report an error for each identifier in QualifiedName + // Example: + // foo (x: public.private.bar) // Error at public, private + // foo (x: public.private.package) // Error at public, private, package + else if (typeName.kind === SyntaxKind.QualifiedName) { + let partOfTypeName = typeName; + + // Keep traverse from right to left in QualifiedName and report an error at each one + // Stop when the next left is not longer a QualifiedName, then it must be the first component + // in QualifiedName and must be an Identifier. + // Example: + // x1: public.private.package // Error at public, private + while (partOfTypeName && partOfTypeName.kind === SyntaxKind.QualifiedName) { + let name = (partOfTypeName).right; + checkGrammarTypeNameInStrictMode(name); + partOfTypeName = (partOfTypeName).left; + } + + // Report and error at the component in QualifiedName which must be an identifier. + // Example: + // x1: public.private.package // Error at package + checkGrammarTypeNameInStrictMode(partOfTypeName); + } + } + + // This function will report an error for every identifier in property access expression + // whether it violates strict mode reserved words. + // Example: + // public.B // error at public + // public.private.A // error at public and private + // public.private.package // error at public and private and package + function checkGrammarHeritageClauseElementInStrictMode(expression: Expression) { + // Example: + // class C extends public // error at public + if (expression && expression.kind === SyntaxKind.Identifier) { + return checkGrammarIdentifierInStrictMode(expression); + } + else if (expression && expression.kind === SyntaxKind.PropertyAccessExpression) { + let propertyAccessExp = expression; + + // Keep traverse from right to left in propertyAccessExpression and report an error at each name + // in the PropertyAccessExpression. + // Stop when expression is no longer a propertyAccessExpression, then it must be the first + // expression in PropertyAccessExpression and must be an Identifier. + // Example: + // public.private.package // error at package, private + while (propertyAccessExp && propertyAccessExp.kind === SyntaxKind.PropertyAccessExpression) { + checkGrammarIdentifierInStrictMode(propertyAccessExp.name); + propertyAccessExp = propertyAccessExp.expression; + } + + // Report an error at the first expression in PropertyAccessExpression + // Example: + // public.private.package // error at public + checkGrammarIdentifierInStrictMode(propertyAccessExp); + } + + } + + // The function takes an identifier itself or an expression which has SyntaxKind.Identifier. + function checkGrammarIdentifierInStrictMode(node: Expression | Identifier, nameText?: string): boolean { + if (node && node.kind === SyntaxKind.Identifier && isReservedwordInStrictMode(node)) { + if (!nameText) { + nameText = declarationNameToString(node); + } + + // TODO (yuisu): Fix when module is a strict mode + let errorReport = reportStrictModeGrammarErrorInClassDeclaration(node, Diagnostics.Identifier_expected_0_is_a_reserved_word_in_strict_mode_Class_definitions_are_automatically_in_strict_mode, nameText)|| + grammarErrorOnNode(node, Diagnostics.Identifier_expected_0_is_a_reserved_word_in_strict_mode, nameText); + return errorReport; + } + return false; + } + + // The function takes an identifier when uses as a typeName in TypeReferenceNode + function checkGrammarTypeNameInStrictMode(node: Identifier): boolean { + if (node && node.kind === SyntaxKind.Identifier && isReservedwordInStrictMode(node)) { let nameText = declarationNameToString(node); - return grammarErrorOnNode(node, Diagnostics.Identifier_expected_0_is_a_reserved_word_in_strict_mode, nameText); + + // TODO (yuisu): Fix when module is a strict mode + let errorReport = reportStrictModeGrammarErrorInClassDeclaration(node, Diagnostics.Type_expected_0_is_a_reserved_word_in_strict_mode_Class_definitions_are_automatically_in_strict_mode, nameText) || + grammarErrorOnNode(node, Diagnostics.Type_expected_0_is_a_reserved_word_in_strict_mode, nameText); + return errorReport; } return false; } diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 200c36bea51..a8a3dfbe8d9 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -1487,9 +1487,9 @@ module ts { if (isIdentifier) { let node = createNode(SyntaxKind.Identifier); - // Store original token kind so we can report appropriate error later in type checker - if (token >= SyntaxKind.FirstReservedWord && token <= SyntaxKind.LastFutureReservedWord) { - node.originalSyntaxKind = token; + // Store original token kind if it is not just an Identifier so we can report appropriate error later in type checker + if (token !== SyntaxKind.Identifier) { + node.originalStrictModeSyntaxKind = token; } node.text = internIdentifier(scanner.getTokenValue()); nextToken(); diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 27e38ff7178..b436ad115f6 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -386,8 +386,8 @@ module ts { } export interface Identifier extends PrimaryExpression { - text: string; // Text of identifier (with escapes converted to characters) - originalSyntaxKind?: SyntaxKind; // original syntaxKind which get set so that we can report an error later + text: string; // Text of identifier (with escapes converted to characters) + originalStrictModeSyntaxKind?: SyntaxKind; // Original syntaxKind which get set so that we can report an error later } export interface QualifiedName extends Node {