@@ -651,6 +651,7 @@ import {
651
651
isNewExpression,
652
652
isNodeDescendantOf,
653
653
isNonNullAccess,
654
+ isNonNullExpression,
654
655
isNullishCoalesce,
655
656
isNumericLiteral,
656
657
isNumericLiteralName,
@@ -41572,8 +41573,82 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
41572
41573
}
41573
41574
}
41574
41575
41576
+ function checkGrammarDecorator(decorator: Decorator): boolean {
41577
+ const sourceFile = getSourceFileOfNode(decorator);
41578
+ if (!hasParseDiagnostics(sourceFile)) {
41579
+ let node: Expression = decorator.expression;
41580
+
41581
+ // DecoratorParenthesizedExpression :
41582
+ // `(` Expression `)`
41583
+
41584
+ if (isParenthesizedExpression(node)) {
41585
+ return false;
41586
+ }
41587
+
41588
+ let canHaveCallExpression = true;
41589
+ let errorNode: Node | undefined;
41590
+ while (true) {
41591
+ // Allow TS syntax such as non-null assertions and instantiation expressions
41592
+ if (isExpressionWithTypeArguments(node) || isNonNullExpression(node)) {
41593
+ node = node.expression;
41594
+ continue;
41595
+ }
41596
+
41597
+ // DecoratorCallExpression :
41598
+ // DecoratorMemberExpression Arguments
41599
+
41600
+ if (isCallExpression(node)) {
41601
+ if (!canHaveCallExpression) {
41602
+ errorNode = node;
41603
+ }
41604
+ if (node.questionDotToken) {
41605
+ // Even if we already have an error node, error at the `?.` token since it appears earlier.
41606
+ errorNode = node.questionDotToken;
41607
+ }
41608
+ node = node.expression;
41609
+ canHaveCallExpression = false;
41610
+ continue;
41611
+ }
41612
+
41613
+ // DecoratorMemberExpression :
41614
+ // IdentifierReference
41615
+ // DecoratorMemberExpression `.` IdentifierName
41616
+ // DecoratorMemberExpression `.` PrivateIdentifier
41617
+
41618
+ if (isPropertyAccessExpression(node)) {
41619
+ if (node.questionDotToken) {
41620
+ // Even if we already have an error node, error at the `?.` token since it appears earlier.
41621
+ errorNode = node.questionDotToken;
41622
+ }
41623
+ node = node.expression;
41624
+ canHaveCallExpression = false;
41625
+ continue;
41626
+ }
41627
+
41628
+ if (!isIdentifier(node)) {
41629
+ // Even if we already have an error node, error at this node since it appears earlier.
41630
+ errorNode = node;
41631
+ }
41632
+
41633
+ break;
41634
+ }
41635
+
41636
+ if (errorNode) {
41637
+ addRelatedInfo(
41638
+ error(decorator.expression, Diagnostics.Expression_must_be_enclosed_in_parentheses_to_be_used_as_a_decorator),
41639
+ createDiagnosticForNode(errorNode, Diagnostics.Invalid_syntax_in_decorator),
41640
+ );
41641
+ return true;
41642
+ }
41643
+ }
41644
+
41645
+ return false;
41646
+ }
41647
+
41575
41648
/** Check a decorator */
41576
41649
function checkDecorator(node: Decorator): void {
41650
+ checkGrammarDecorator(node);
41651
+
41577
41652
const signature = getResolvedSignature(node);
41578
41653
checkDeprecatedSignature(signature, node);
41579
41654
const returnType = getReturnTypeOfSignature(signature);
0 commit comments