Merge pull request #31480 from andrewbranch/bug/25487

Fix invalid JSXExpressions having identifier-ish things in their trivia, improve error messages for comma expressions in JSX
This commit is contained in:
Andrew Branch
2019-06-26 10:13:42 -07:00
committed by GitHub
17 changed files with 111 additions and 47 deletions
+7
View File
@@ -20033,6 +20033,7 @@ namespace ts {
}
function checkJsxExpression(node: JsxExpression, checkMode?: CheckMode) {
checkGrammarJsxExpression(node);
if (node.expression) {
const type = checkExpression(node.expression, checkMode);
if (node.dotDotDotToken && type !== anyType && !isArrayType(type)) {
@@ -31912,6 +31913,12 @@ namespace ts {
}
}
function checkGrammarJsxExpression(node: JsxExpression) {
if (node.expression && isCommaSequence(node.expression)) {
return grammarErrorOnNode(node.expression, Diagnostics.JSX_expressions_may_not_use_the_comma_operator_Did_you_mean_to_write_an_array);
}
}
function checkGrammarForInOrForOfStatement(forInOrOfStatement: ForInOrOfStatement): boolean {
if (checkGrammarStatementInAmbientContext(forInOrOfStatement)) {
return true;
+4
View File
@@ -5009,5 +5009,9 @@
"Classes may not have a field named 'constructor'.": {
"category": "Error",
"code": 18006
},
"JSX expressions may not use the comma operator. Did you mean to write an array?": {
"category": "Error",
"code": 18007
}
}
+7 -3
View File
@@ -4430,14 +4430,18 @@ namespace ts {
if (token() !== SyntaxKind.CloseBraceToken) {
node.dotDotDotToken = parseOptionalToken(SyntaxKind.DotDotDotToken);
node.expression = parseAssignmentExpressionOrHigher();
// Only an AssignmentExpression is valid here per the JSX spec,
// but we can unambiguously parse a comma sequence and provide
// a better error message in grammar checking.
node.expression = parseExpression();
}
if (inExpressionContext) {
parseExpected(SyntaxKind.CloseBraceToken);
}
else {
parseExpected(SyntaxKind.CloseBraceToken, /*message*/ undefined, /*shouldAdvance*/ false);
scanJsxText();
if (parseExpected(SyntaxKind.CloseBraceToken, /*message*/ undefined, /*shouldAdvance*/ false)) {
scanJsxText();
}
}
return finishNode(node);
+19
View File
@@ -583,6 +583,21 @@ namespace FourSlash {
});
}
public verifyErrorExistsAtRange(range: Range, code: number, expectedMessage?: string) {
const span = ts.createTextSpanFromRange(range);
const hasMatchingError = ts.some(
this.getDiagnostics(range.fileName),
({ code, messageText, start, length }) =>
code === code &&
(!expectedMessage || expectedMessage === messageText) &&
ts.isNumber(start) && ts.isNumber(length) &&
ts.textSpansEqual(span, { start, length }));
if (!hasMatchingError) {
this.raiseError(`No error with code ${code} found at provided range.`);
}
}
public verifyNumberOfErrorsInCurrentFile(expected: number) {
const errors = this.getDiagnostics(this.activeFile.fileName);
const actual = errors.length;
@@ -4009,6 +4024,10 @@ namespace FourSlashInterface {
this.state.verifyNoErrors();
}
public errorExistsAtRange(range: FourSlash.Range, code: number, message?: string) {
this.state.verifyErrorExistsAtRange(range, code, message);
}
public numberOfErrorsInCurrentFile(expected: number) {
this.state.verifyNumberOfErrorsInCurrentFile(expected);
}