Put semantically relevant tokens in the tree.

This commit is contained in:
Cyrus Najmabadi
2014-12-01 22:03:41 -08:00
parent 8ad4a0a5b8
commit db89584a86
25 changed files with 175 additions and 151 deletions
+32 -14
View File
@@ -756,7 +756,7 @@ module ts {
//
// x is an optional parameter, but it is a required property.
return propertySymbol.valueDeclaration &&
propertySymbol.valueDeclaration.flags & NodeFlags.QuestionMark &&
hasQuestionToken(propertySymbol.valueDeclaration) &&
propertySymbol.valueDeclaration.kind !== SyntaxKind.Parameter;
}
@@ -1441,7 +1441,7 @@ module ts {
writePunctuation(writer, SyntaxKind.DotDotDotToken);
}
appendSymbolNameOnly(p, writer);
if (p.valueDeclaration.flags & NodeFlags.QuestionMark || (<VariableDeclaration>p.valueDeclaration).initializer) {
if (hasQuestionToken(p.valueDeclaration) || (<VariableDeclaration>p.valueDeclaration).initializer) {
writePunctuation(writer, SyntaxKind.QuestionToken);
}
writePunctuation(writer, SyntaxKind.ColonToken);
@@ -2527,7 +2527,7 @@ module ts {
hasStringLiterals = true;
}
if (minArgumentCount < 0) {
if (param.initializer || param.flags & NodeFlags.QuestionMark || param.dotDotDotToken) {
if (param.initializer || param.questionToken || param.dotDotDotToken) {
minArgumentCount = i;
}
}
@@ -7020,20 +7020,23 @@ module ts {
return;
}
function getCanonicalOverload(overloads: Declaration[], implementation: FunctionLikeDeclaration) {
// Consider the canonical set of flags to be the flags of the bodyDeclaration or the first declaration
// Error on all deviations from this canonical set of flags
// The caveat is that if some overloads are defined in lib.d.ts, we don't want to
// report the errors on those. To achieve this, we will say that the implementation is
// the canonical signature only if it is in the same container as the first overload
var implementationSharesContainerWithFirstOverload = implementation !== undefined && implementation.parent === overloads[0].parent;
return implementationSharesContainerWithFirstOverload ? implementation : overloads[0];
}
function checkFlagAgreementBetweenOverloads(overloads: Declaration[], implementation: FunctionLikeDeclaration, flagsToCheck: NodeFlags, someOverloadFlags: NodeFlags, allOverloadFlags: NodeFlags): void {
// Error if some overloads have a flag that is not shared by all overloads. To find the
// deviations, we XOR someOverloadFlags with allOverloadFlags
var someButNotAllOverloadFlags = someOverloadFlags ^ allOverloadFlags;
if (someButNotAllOverloadFlags !== 0) {
// Consider the canonical set of flags to be the flags of the bodyDeclaration or the first declaration
// Error on all deviations from this canonical set of flags
// The caveat is that if some overloads are defined in lib.d.ts, we don't want to
// report the errors on those. To achieve this, we will say that the implementation is
// the canonical signature only if it is in the same container as the first overload
var implementationSharesContainerWithFirstOverload = implementation !== undefined && implementation.parent === overloads[0].parent;
var canonicalFlags = implementationSharesContainerWithFirstOverload
? getEffectiveDeclarationFlags(implementation, flagsToCheck)
: getEffectiveDeclarationFlags(overloads[0], flagsToCheck);
var canonicalFlags = getEffectiveDeclarationFlags(getCanonicalOverload(overloads, implementation), flagsToCheck);
forEach(overloads, o => {
var deviation = getEffectiveDeclarationFlags(o, flagsToCheck) ^ canonicalFlags;
if (deviation & NodeFlags.Export) {
@@ -7045,16 +7048,27 @@ module ts {
else if (deviation & (NodeFlags.Private | NodeFlags.Protected)) {
error(o.name, Diagnostics.Overload_signatures_must_all_be_public_private_or_protected);
}
else if (deviation & NodeFlags.QuestionMark) {
});
}
}
function checkQuestionTokenAgreementBetweenOverloads(overloads: Declaration[], implementation: FunctionLikeDeclaration, someHaveQuestionToken: boolean, allHaveQuestionToken: boolean): void {
if (someHaveQuestionToken !== allHaveQuestionToken) {
var canonicalHasQuestionToken = hasQuestionToken(getCanonicalOverload(overloads, implementation));
forEach(overloads, o => {
var deviation = hasQuestionToken(o) !== canonicalHasQuestionToken;
if (deviation) {
error(o.name, Diagnostics.Overload_signatures_must_all_be_optional_or_required);
}
});
}
}
var flagsToCheck: NodeFlags = NodeFlags.Export | NodeFlags.Ambient | NodeFlags.Private | NodeFlags.Protected | NodeFlags.QuestionMark;
var flagsToCheck: NodeFlags = NodeFlags.Export | NodeFlags.Ambient | NodeFlags.Private | NodeFlags.Protected;
var someNodeFlags: NodeFlags = 0;
var allNodeFlags = flagsToCheck;
var someHaveQuestionToken = false;
var allHaveQuestionToken = true;
var hasOverloads = false;
var bodyDeclaration: FunctionLikeDeclaration;
var lastSeenNonAmbientDeclaration: FunctionLikeDeclaration;
@@ -7128,6 +7142,8 @@ module ts {
var currentNodeFlags = getEffectiveDeclarationFlags(node, flagsToCheck);
someNodeFlags |= currentNodeFlags;
allNodeFlags &= currentNodeFlags;
someHaveQuestionToken = someHaveQuestionToken || hasQuestionToken(node);
allHaveQuestionToken = allHaveQuestionToken && hasQuestionToken(node);
if (node.body && bodyDeclaration) {
if (isConstructor) {
@@ -7176,6 +7192,8 @@ module ts {
if (hasOverloads) {
checkFlagAgreementBetweenOverloads(declarations, bodyDeclaration, flagsToCheck, someNodeFlags, allNodeFlags);
checkQuestionTokenAgreementBetweenOverloads(declarations, bodyDeclaration, someHaveQuestionToken, allHaveQuestionToken);
if (bodyDeclaration) {
var signatures = getSignaturesOfSymbol(symbol);
var bodySignature = getSignatureFromDeclaration(bodyDeclaration);
+3 -3
View File
@@ -943,7 +943,7 @@ module ts {
if (node.kind !== SyntaxKind.VariableDeclaration || resolver.isDeclarationVisible(node)) {
writeTextOfNode(currentSourceFile, node.name);
// If optional property emit ?
if (node.kind === SyntaxKind.Property && (node.flags & NodeFlags.QuestionMark)) {
if (node.kind === SyntaxKind.Property && hasQuestionToken(node)) {
write("?");
}
if (node.kind === SyntaxKind.Property && node.parent.kind === SyntaxKind.TypeLiteral) {
@@ -1124,7 +1124,7 @@ module ts {
}
else {
writeTextOfNode(currentSourceFile, node.name);
if (node.flags & NodeFlags.QuestionMark) {
if (hasQuestionToken(node)) {
write("?");
}
}
@@ -1256,7 +1256,7 @@ module ts {
write("...");
}
writeTextOfNode(currentSourceFile, node.name);
if (node.initializer || (node.flags & NodeFlags.QuestionMark)) {
if (node.initializer || hasQuestionToken(node)) {
write("?");
}
decreaseIndent();
+57 -54
View File
@@ -219,6 +219,7 @@ module ts {
return children(node.modifiers) ||
child((<ParameterDeclaration>node).dotDotDotToken) ||
child((<ParameterDeclaration>node).name) ||
child((<ParameterDeclaration>node).questionToken) ||
child((<ParameterDeclaration>node).type) ||
child((<ParameterDeclaration>node).initializer);
case SyntaxKind.Property:
@@ -226,6 +227,7 @@ module ts {
case SyntaxKind.ShorthandPropertyAssignment:
return children(node.modifiers) ||
child((<PropertyDeclaration>node).name) ||
child((<PropertyDeclaration>node).questionToken) ||
child((<PropertyDeclaration>node).type) ||
child((<PropertyDeclaration>node).initializer);
case SyntaxKind.FunctionType:
@@ -246,6 +248,7 @@ module ts {
case SyntaxKind.ArrowFunction:
return children(node.modifiers) ||
child((<FunctionLikeDeclaration>node).name) ||
child((<FunctionLikeDeclaration>node).questionToken) ||
children((<FunctionLikeDeclaration>node).typeParameters) ||
children((<FunctionLikeDeclaration>node).parameters) ||
child((<FunctionLikeDeclaration>node).type) ||
@@ -626,6 +629,23 @@ module ts {
return node && node.kind === SyntaxKind.Parameter && (<ParameterDeclaration>node).dotDotDotToken !== undefined;
}
export function hasQuestionToken(node: Node) {
if (node) {
switch (node.kind) {
case SyntaxKind.Parameter:
return (<ParameterDeclaration>node).questionToken !== undefined;
case SyntaxKind.Method:
return (<MethodDeclaration>node).questionToken !== undefined;
case SyntaxKind.ShorthandPropertyAssignment:
case SyntaxKind.PropertyAssignment:
case SyntaxKind.Property:
return (<PropertyDeclaration>node).questionToken !== undefined;
}
}
return false;
}
export function hasRestParameters(s: SignatureDeclaration): boolean {
return s.parameters.length > 0 && s.parameters[s.parameters.length - 1].dotDotDotToken !== undefined;
}
@@ -1853,9 +1873,7 @@ module ts {
nextToken();
}
if (parseOptional(SyntaxKind.QuestionToken)) {
node.flags |= NodeFlags.QuestionMark;
}
node.questionToken = token === SyntaxKind.QuestionToken ? parseTokenNode() : undefined;
node.type = parseParameterType();
node.initializer = inGeneratorParameterContext()
? doOutsideOfYieldContext(parseParameterInitializer)
@@ -2020,15 +2038,12 @@ module ts {
function parsePropertyOrMethod(): Declaration {
var fullStart = scanner.getStartPos();
var name = parsePropertyName();
var flags = 0;
if (parseOptional(SyntaxKind.QuestionToken)) {
flags = NodeFlags.QuestionMark;
}
var questionToken = token === SyntaxKind.QuestionToken ? parseTokenNode() : undefined;
if (token === SyntaxKind.OpenParenToken || token === SyntaxKind.LessThanToken) {
var method = <MethodDeclaration>createNode(SyntaxKind.Method, fullStart);
method.name = name;
method.flags = flags;
method.questionToken = questionToken;
// Method signatues don't exist in expression contexts. So they have neither
// [Yield] nor [GeneratorParameter]
@@ -2040,7 +2055,7 @@ module ts {
else {
var property = <PropertyDeclaration>createNode(SyntaxKind.Property, fullStart);
property.name = name;
property.flags = flags;
property.questionToken = questionToken;
property.type = parseTypeAnnotation();
parseSemicolon();
return finishNode(property);
@@ -3125,28 +3140,24 @@ module ts {
return finishNode(node);
}
var flags: NodeFlags = 0;
// Disallowing of optional property assignments happens in the grammar checker.
if (token === SyntaxKind.QuestionToken) {
flags |= NodeFlags.QuestionMark;
nextToken();
}
var questionToken = token === SyntaxKind.QuestionToken ? parseTokenNode() : undefined;
// Parse to check if it is short-hand property assignment or normal property assignment
if ((token === SyntaxKind.CommaToken || token === SyntaxKind.CloseBraceToken) && tokenIsIdentifier) {
node = <ShortHandPropertyDeclaration>createNode(SyntaxKind.ShorthandPropertyAssignment, nodePos);
node.name = propertyName;
var shorthandDeclaration = <ShortHandPropertyDeclaration>createNode(SyntaxKind.ShorthandPropertyAssignment, nodePos);
shorthandDeclaration.name = <Identifier>propertyName;
shorthandDeclaration.questionToken = questionToken;
return finishNode(shorthandDeclaration);
}
else {
node = <PropertyDeclaration>createNode(SyntaxKind.PropertyAssignment, nodePos);
node.name = propertyName;
var propertyDeclaration = <PropertyDeclaration>createNode(SyntaxKind.PropertyAssignment, nodePos);
propertyDeclaration.name = propertyName;
propertyDeclaration.questionToken = questionToken;
parseExpected(SyntaxKind.ColonToken);
(<PropertyDeclaration>node).initializer = allowInAnd(parseAssignmentExpressionOrHigher);
propertyDeclaration.initializer = allowInAnd(parseAssignmentExpressionOrHigher);
return finishNode(propertyDeclaration);
}
node.flags = flags;
return finishNode(node);
}
function parseObjectLiteralMember(): Declaration {
@@ -3671,23 +3682,18 @@ module ts {
}
function parsePropertyMemberDeclaration(fullStart: number, modifiers: ModifiersArray): ClassElement {
var flags = modifiers ? modifiers.flags : 0;
var asteriskToken = parseOptionalToken(SyntaxKind.AsteriskToken);
var name = parsePropertyName();
if (parseOptional(SyntaxKind.QuestionToken)) {
// Note: this is not legal as per the grammar. But we allow it in the parser and
// report an error in the grammar checker.
flags |= NodeFlags.QuestionMark;
}
// Note: this is not legal as per the grammar. But we allow it in the parser and
// report an error in the grammar checker.
var questionToken = token === SyntaxKind.QuestionToken ? parseTokenNode() : undefined;
if (asteriskToken || token === SyntaxKind.OpenParenToken || token === SyntaxKind.LessThanToken) {
var method = <MethodDeclaration>createNode(SyntaxKind.Method, fullStart);
setModifiers(method, modifiers);
if (flags) {
method.flags = flags;
}
method.asteriskToken = asteriskToken;
method.name = name;
method.questionToken = questionToken;
fillSignature(SyntaxKind.CallSignature, SyntaxKind.ColonToken, /* returnTokenRequired */ false, /*yieldAndGeneratorParameterContext:*/ !!asteriskToken, method);
method.body = parseFunctionBlockOrSemicolon(!!asteriskToken);
return finishNode(method);
@@ -3695,10 +3701,8 @@ module ts {
else {
var property = <PropertyDeclaration>createNode(SyntaxKind.Property, fullStart);
setModifiers(property, modifiers);
if (flags) {
property.flags = flags;
}
property.name = name;
property.questionToken = questionToken;
property.type = parseTypeAnnotation();
property.initializer = allowInAnd(() => parseInitializer(/*inParameter*/ false));
parseSemicolon();
@@ -4820,13 +4824,13 @@ module ts {
}
}
else if (parameter.dotDotDotToken) {
return grammarErrorOnNode(parameter.name, Diagnostics.An_index_signature_cannot_have_a_rest_parameter);
return grammarErrorOnNode(parameter.dotDotDotToken, Diagnostics.An_index_signature_cannot_have_a_rest_parameter);
}
else if (parameter.flags & NodeFlags.Modifier) {
return grammarErrorOnNode(parameter.name, Diagnostics.An_index_signature_parameter_cannot_have_an_accessibility_modifier);
}
else if (parameter.flags & NodeFlags.QuestionMark) {
return grammarErrorOnNode(parameter.name, Diagnostics.An_index_signature_parameter_cannot_have_a_question_mark);
else if (parameter.questionToken) {
return grammarErrorOnNode(parameter.questionToken, Diagnostics.An_index_signature_parameter_cannot_have_a_question_mark);
}
else if (parameter.initializer) {
return grammarErrorOnNode(parameter.name, Diagnostics.An_index_signature_parameter_cannot_have_an_initializer);
@@ -4878,7 +4882,7 @@ module ts {
return true;
}
if (node.parent.kind === SyntaxKind.ClassDeclaration) {
if (checkForInvalidQuestionMark(node, Diagnostics.A_class_member_cannot_be_declared_optional)) {
if (checkForInvalidQuestionMark(node, node.questionToken, Diagnostics.A_class_member_cannot_be_declared_optional)) {
return true;
}
// Technically, computed properties in ambient contexts is disallowed
@@ -5178,21 +5182,21 @@ module ts {
var parameter = parameters[i];
if (parameter.dotDotDotToken) {
if (i !== (parameterCount - 1)) {
return grammarErrorOnNode(parameter.name, Diagnostics.A_rest_parameter_must_be_last_in_a_parameter_list);
return grammarErrorOnNode(parameter.dotDotDotToken, Diagnostics.A_rest_parameter_must_be_last_in_a_parameter_list);
}
if (parameter.flags & NodeFlags.QuestionMark) {
return grammarErrorOnNode(parameter.name, Diagnostics.A_rest_parameter_cannot_be_optional);
if (parameter.questionToken) {
return grammarErrorOnNode(parameter.questionToken, Diagnostics.A_rest_parameter_cannot_be_optional);
}
if (parameter.initializer) {
return grammarErrorOnNode(parameter.name, Diagnostics.A_rest_parameter_cannot_have_an_initializer);
}
}
else if (parameter.flags & NodeFlags.QuestionMark || parameter.initializer) {
else if (parameter.questionToken || parameter.initializer) {
seenOptionalParameter = true;
if (parameter.flags & NodeFlags.QuestionMark && parameter.initializer) {
if (parameter.questionToken && parameter.initializer) {
return grammarErrorOnNode(parameter.name, Diagnostics.Parameter_cannot_have_question_mark_and_initializer);
}
}
@@ -5226,7 +5230,7 @@ module ts {
function checkProperty(node: PropertyDeclaration) {
if (node.parent.kind === SyntaxKind.ClassDeclaration) {
if (checkForInvalidQuestionMark(node, Diagnostics.A_class_member_cannot_be_declared_optional) ||
if (checkForInvalidQuestionMark(node, node.questionToken, Diagnostics.A_class_member_cannot_be_declared_optional) ||
checkForDisallowedComputedProperty(node.name, Diagnostics.Computed_property_names_are_not_allowed_in_class_property_declarations)) {
return true;
}
@@ -5267,13 +5271,12 @@ module ts {
}
function checkPropertyAssignment(node: PropertyDeclaration) {
return checkForInvalidQuestionMark(node, Diagnostics.An_object_member_cannot_be_declared_optional);
return checkForInvalidQuestionMark(node, node.questionToken, Diagnostics.An_object_member_cannot_be_declared_optional);
}
function checkForInvalidQuestionMark(node: Declaration, message: DiagnosticMessage) {
if (node.flags & NodeFlags.QuestionMark) {
var pos = skipTrivia(sourceText, node.name.end);
return grammarErrorAtPos(pos, "?".length, message);
function checkForInvalidQuestionMark(node: Declaration, questionToken: Node, message: DiagnosticMessage) {
if (questionToken) {
return grammarErrorOnNode(questionToken, message);
}
}
@@ -5315,13 +5318,13 @@ module ts {
else {
var parameter = accessor.parameters[0];
if (parameter.dotDotDotToken) {
return grammarErrorOnNode(accessor.name, Diagnostics.A_set_accessor_cannot_have_rest_parameter);
return grammarErrorOnNode(parameter.dotDotDotToken, Diagnostics.A_set_accessor_cannot_have_rest_parameter);
}
else if (parameter.flags & NodeFlags.Modifier) {
return grammarErrorOnNode(accessor.name, Diagnostics.A_parameter_property_is_only_allowed_in_a_constructor_implementation);
}
else if (parameter.flags & NodeFlags.QuestionMark) {
return grammarErrorOnNode(accessor.name, Diagnostics.A_set_accessor_cannot_have_an_optional_parameter);
else if (parameter.questionToken) {
return grammarErrorOnNode(parameter.questionToken, Diagnostics.A_set_accessor_cannot_have_an_optional_parameter);
}
else if (parameter.initializer) {
return grammarErrorOnNode(accessor.name, Diagnostics.A_set_accessor_parameter_cannot_have_an_initializer);
@@ -5368,7 +5371,7 @@ module ts {
}
function checkShorthandPropertyAssignment(node: ShortHandPropertyDeclaration): boolean {
return checkForInvalidQuestionMark(node, Diagnostics.An_object_member_cannot_be_declared_optional);
return checkForInvalidQuestionMark(node, node.questionToken, Diagnostics.An_object_member_cannot_be_declared_optional);
}
function checkSwitchStatement(node: SwitchStatement) {
+4 -1
View File
@@ -272,7 +272,6 @@ module ts {
export const enum NodeFlags {
Export = 0x00000001, // Declarations
Ambient = 0x00000002, // Declarations
QuestionMark = 0x00000004, // Parameter/Property/Method
Public = 0x00000010, // Property/Method
Private = 0x00000020, // Property/Method
Protected = 0x00000040, // Property/Method
@@ -370,11 +369,13 @@ module ts {
export interface ParameterDeclaration extends Declaration {
dotDotDotToken?: Node;
name: Identifier;
questionToken?: Node;
type?: TypeNode | StringLiteralExpression;
initializer?: Expression;
}
export interface PropertyDeclaration extends Declaration, ClassElement {
questionToken?: Node;
type?: TypeNode;
initializer?: Expression;
}
@@ -384,6 +385,7 @@ module ts {
export interface ShortHandPropertyDeclaration extends Declaration {
name: Identifier;
questionToken?: Node;
}
/**
@@ -398,6 +400,7 @@ module ts {
_functionLikeDeclarationBrand: any;
asteriskToken?: Node;
questionToken?: Node;
body?: Block | Expression;
}
+1 -1
View File
@@ -524,7 +524,7 @@ module ts.SignatureHelp {
var displayParts = mapToDisplayParts(writer =>
typeInfoResolver.getSymbolDisplayBuilder().buildParameterDisplay(parameter, writer, invocation));
var isOptional = !!(parameter.valueDeclaration.flags & NodeFlags.QuestionMark);
var isOptional = hasQuestionToken(parameter.valueDeclaration);
return {
name: parameter.name,