Files
sdk/pkg/analyzer/test/generated/complex_parser_test.dart
T
FMorschel 240eda5647 [analyzer] Migrates to contexMessages from analyzer_testing package
This also includes some small refactorings for parameter names to start using the diagnostic wording instead of error. As well as a small change to `contextMessage` and related to use a list of `Pattern`s instead of a single `String` for better matching.

In future CLs, the TODOs added in this one will be addressed so we can fully migrate this. Added them because of the size of the CL.

Bug: https://github.com/dart-lang/sdk/issues/61557
Change-Id: I5557668a1baed98faff977255c9f22e0d9d96008
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/452180
Commit-Queue: Paul Berry <paulberry@google.com>
Auto-Submit: Felipe Morschel <git@fmorschel.dev>
Reviewed-by: Paul Berry <paulberry@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
2025-10-20 13:37:00 -07:00

620 lines
24 KiB
Dart

// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
/// @docImport 'simple_parser_test.dart';
library;
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/error/error.dart';
import 'package:analyzer/src/dart/scanner/scanner.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
import '../util/ast_type_matchers.dart';
import 'parser_test_base.dart';
main() {
defineReflectiveSuite(() {
defineReflectiveTests(ComplexParserTest);
});
}
/// The class `ComplexParserTest` defines parser tests that test the parsing of
/// more complex code fragments or the interactions between multiple parsing
/// methods. For example, tests to ensure that the precedence of operations is
/// being handled correctly should be defined in this class.
///
/// Simpler tests should be defined in the class [SimpleParserTest].
@reflectiveTest
class ComplexParserTest extends FastaParserTestCase {
void test_additiveExpression_normal() {
var expression = parseExpression("x + y - z") as BinaryExpression;
expect(expression.leftOperand, isBinaryExpression);
}
void test_additiveExpression_noSpaces() {
var expression = parseExpression("i+1") as BinaryExpression;
expect(expression.leftOperand, isSimpleIdentifier);
expect(expression.rightOperand, isIntegerLiteral);
}
void test_additiveExpression_precedence_multiplicative_left() {
var expression = parseExpression("x * y + z") as BinaryExpression;
expect(expression.leftOperand, isBinaryExpression);
}
void test_additiveExpression_precedence_multiplicative_left_withSuper() {
var expression = parseExpression("super * y - z") as BinaryExpression;
expect(expression.leftOperand, isBinaryExpression);
}
void test_additiveExpression_precedence_multiplicative_right() {
var expression = parseExpression("x + y * z") as BinaryExpression;
expect(expression.rightOperand, isBinaryExpression);
}
void test_additiveExpression_super() {
var expression = parseExpression("super + y - z") as BinaryExpression;
expect(expression.leftOperand, isBinaryExpression);
}
void test_assignableExpression_arguments_normal_chain() {
var propertyAccess1 = parseExpression("a(b)(c).d(e).f") as PropertyAccess;
expect(propertyAccess1.propertyName.name, "f");
//
// a(b)(c).d(e)
//
var invocation2 = propertyAccess1.target as MethodInvocation;
expect(invocation2.methodName.name, "d");
expect(invocation2.typeArguments, isNull);
ArgumentList argumentList2 = invocation2.argumentList;
expect(argumentList2, isNotNull);
expect(argumentList2.arguments, hasLength(1));
//
// a(b)(c)
//
var invocation3 = invocation2.target as FunctionExpressionInvocation;
expect(invocation3.typeArguments, isNull);
ArgumentList argumentList3 = invocation3.argumentList;
expect(argumentList3, isNotNull);
expect(argumentList3.arguments, hasLength(1));
//
// a(b)
//
var invocation4 = invocation3.function as MethodInvocation;
expect(invocation4.methodName.name, "a");
expect(invocation4.typeArguments, isNull);
ArgumentList argumentList4 = invocation4.argumentList;
expect(argumentList4, isNotNull);
expect(argumentList4.arguments, hasLength(1));
}
void test_assignableExpression_arguments_normal_chain_typeArguments() {
_validate_assignableExpression_arguments_normal_chain_typeArguments(
"a<E>(b)<F>(c).d<G>(e).f",
);
}
void test_assignmentExpression_compound() {
var expression = parseExpression("x = y = 0") as AssignmentExpression;
expect(expression.leftHandSide, isSimpleIdentifier);
expect(expression.rightHandSide, isAssignmentExpression);
}
void test_assignmentExpression_indexExpression() {
var expression = parseExpression("x[1] = 0") as AssignmentExpression;
expect(expression.leftHandSide, isIndexExpression);
expect(expression.rightHandSide, isIntegerLiteral);
}
void test_assignmentExpression_prefixedIdentifier() {
var expression = parseExpression("x.y = 0") as AssignmentExpression;
expect(expression.leftHandSide, isPrefixedIdentifier);
expect(expression.rightHandSide, isIntegerLiteral);
}
void test_assignmentExpression_propertyAccess() {
var expression = parseExpression("super.y = 0") as AssignmentExpression;
expect(expression.leftHandSide, isPropertyAccess);
expect(expression.rightHandSide, isIntegerLiteral);
}
void test_binary_operator_written_out_expression() {
var expression =
parseExpression(
'x xor y',
diagnostics: [
expectedError(ParserErrorCode.binaryOperatorWrittenOut, 2, 3),
],
)
as BinaryExpression;
var lhs = expression.leftOperand as SimpleIdentifier;
expect(lhs.name, 'x');
expect(expression.operator.lexeme, '^');
var rhs = expression.rightOperand as SimpleIdentifier;
expect(rhs.name, 'y');
}
void test_binary_operator_written_out_expression_logical() {
var expression =
parseExpression(
'x > 0 and y > 1',
diagnostics: [
expectedError(ParserErrorCode.binaryOperatorWrittenOut, 6, 3),
],
)
as BinaryExpression;
var lhs = expression.leftOperand as BinaryExpression;
expect((lhs.leftOperand as SimpleIdentifier).name, 'x');
expect(lhs.operator.lexeme, '>');
expect((lhs.rightOperand as IntegerLiteral).value, 0);
expect(expression.operator.lexeme, '&&');
var rhs = expression.rightOperand as BinaryExpression;
expect((rhs.leftOperand as SimpleIdentifier).name, 'y');
expect(rhs.operator.lexeme, '>');
expect((rhs.rightOperand as IntegerLiteral).value, 1);
}
void test_bitwiseAndExpression_normal() {
var expression = parseExpression("x & y & z") as BinaryExpression;
expect(expression.leftOperand, isBinaryExpression);
}
void test_bitwiseAndExpression_precedence_equality_left() {
var expression = parseExpression("x == y && z") as BinaryExpression;
expect(expression.leftOperand, isBinaryExpression);
}
void test_bitwiseAndExpression_precedence_equality_right() {
var expression = parseExpression("x && y == z") as BinaryExpression;
expect(expression.rightOperand, isBinaryExpression);
}
void test_bitwiseAndExpression_super() {
var expression = parseExpression("super & y & z") as BinaryExpression;
expect(expression.leftOperand, isBinaryExpression);
}
void test_bitwiseOrExpression_normal() {
var expression = parseExpression("x | y | z") as BinaryExpression;
expect(expression.leftOperand, isBinaryExpression);
}
void test_bitwiseOrExpression_precedence_xor_left() {
var expression = parseExpression("x ^ y | z") as BinaryExpression;
expect(expression.leftOperand, isBinaryExpression);
}
void test_bitwiseOrExpression_precedence_xor_right() {
var expression = parseExpression("x | y ^ z") as BinaryExpression;
expect(expression.rightOperand, isBinaryExpression);
}
void test_bitwiseOrExpression_super() {
var expression = parseExpression("super | y | z") as BinaryExpression;
expect(expression.leftOperand, isBinaryExpression);
}
void test_bitwiseXorExpression_normal() {
var expression = parseExpression("x ^ y ^ z") as BinaryExpression;
expect(expression.leftOperand, isBinaryExpression);
}
void test_bitwiseXorExpression_precedence_and_left() {
var expression = parseExpression("x & y ^ z") as BinaryExpression;
expect(expression.leftOperand, isBinaryExpression);
}
void test_bitwiseXorExpression_precedence_and_right() {
var expression = parseExpression("x ^ y & z") as BinaryExpression;
expect(expression.rightOperand, isBinaryExpression);
}
void test_bitwiseXorExpression_super() {
var expression = parseExpression("super ^ y ^ z") as BinaryExpression;
expect(expression.leftOperand, isBinaryExpression);
}
void test_cascade_withAssignment() {
var cascade =
parseExpression("new Map()..[3] = 4 ..[0] = 11") as CascadeExpression;
Expression target = cascade.target;
for (Expression section in cascade.cascadeSections) {
expect(section, isAssignmentExpression);
Expression lhs = (section as AssignmentExpression).leftHandSide;
expect(lhs, isIndexExpression);
IndexExpression index = lhs as IndexExpression;
expect(index.isCascaded, isTrue);
expect(index.realTarget, same(target));
}
}
void test_conditionalExpression_precedence_ifNullExpression() {
var expression = parseExpression('a ?? b ? y : z') as ConditionalExpression;
expect(expression.condition, isBinaryExpression);
}
void test_conditionalExpression_precedence_logicalOrExpression() {
var expression = parseExpression("a | b ? y : z") as ConditionalExpression;
expect(expression.condition, isBinaryExpression);
}
void test_conditionalExpression_precedence_nullableType_as() {
var statement =
parseStatement('x as bool ? (x + y) : z;') as ExpressionStatement;
var expression = statement.expression as ConditionalExpression;
Expression condition = expression.condition;
expect(condition, isAsExpression);
Expression thenExpression = expression.thenExpression;
expect(thenExpression, isParenthesizedExpression);
Expression elseExpression = expression.elseExpression;
expect(elseExpression, isSimpleIdentifier);
}
void test_conditionalExpression_precedence_nullableType_as2() {
var statement =
parseStatement('x as bool? ? (x + y) : z;') as ExpressionStatement;
var expression = statement.expression as ConditionalExpression;
var asExpression = expression.condition as AsExpression;
var type = asExpression.type as NamedType;
expect(type.question!.lexeme, '?');
Expression thenExpression = expression.thenExpression;
expect(thenExpression, isParenthesizedExpression);
Expression elseExpression = expression.elseExpression;
expect(elseExpression, isSimpleIdentifier);
assertNoErrors();
}
void test_conditionalExpression_precedence_nullableType_as3() {
var statement =
parseStatement('(x as bool?) ? (x + y) : z;') as ExpressionStatement;
var expression = statement.expression as ConditionalExpression;
var condition = expression.condition as ParenthesizedExpression;
var asExpression = condition.expression as AsExpression;
var type = asExpression.type as NamedType;
expect(type.question!.lexeme, '?');
Expression thenExpression = expression.thenExpression;
expect(thenExpression, isParenthesizedExpression);
Expression elseExpression = expression.elseExpression;
expect(elseExpression, isSimpleIdentifier);
assertNoErrors();
}
void test_conditionalExpression_precedence_nullableType_is() {
var statement =
parseStatement('x is String ? (x + y) : z;') as ExpressionStatement;
var expression = statement.expression as ConditionalExpression;
Expression condition = expression.condition;
expect(condition, isIsExpression);
Expression thenExpression = expression.thenExpression;
expect(thenExpression, isParenthesizedExpression);
Expression elseExpression = expression.elseExpression;
expect(elseExpression, isSimpleIdentifier);
}
void test_conditionalExpression_precedence_nullableType_is2() {
var statement =
parseStatement('x is String? ? (x + y) : z;') as ExpressionStatement;
var expression = statement.expression as ConditionalExpression;
var isExpression = expression.condition as IsExpression;
var type = isExpression.type as NamedType;
expect(type.question!.lexeme, '?');
Expression thenExpression = expression.thenExpression;
expect(thenExpression, isParenthesizedExpression);
Expression elseExpression = expression.elseExpression;
expect(elseExpression, isSimpleIdentifier);
assertNoErrors();
}
void test_conditionalExpression_precedence_nullableType_is3() {
var statement =
parseStatement('(x is String?) ? (x + y) : z;') as ExpressionStatement;
var expression = statement.expression as ConditionalExpression;
var condition = expression.condition as ParenthesizedExpression;
var isExpression = condition.expression as IsExpression;
var type = isExpression.type as NamedType;
expect(type.question!.lexeme, '?');
Expression thenExpression = expression.thenExpression;
expect(thenExpression, isParenthesizedExpression);
Expression elseExpression = expression.elseExpression;
expect(elseExpression, isSimpleIdentifier);
assertNoErrors();
}
void test_conditionalExpression_precedence_nullableTypeWithTypeArg1_is() {
var statement =
parseStatement('x is String<S> ? (x + y) : z;') as ExpressionStatement;
var expression = statement.expression as ConditionalExpression;
Expression condition = expression.condition;
expect(condition, TypeMatcher<IsExpression>());
Expression thenExpression = expression.thenExpression;
expect(thenExpression, TypeMatcher<ParenthesizedExpression>());
Expression elseExpression = expression.elseExpression;
expect(elseExpression, TypeMatcher<SimpleIdentifier>());
}
void test_conditionalExpression_precedence_nullableTypeWithTypeArg1GFT_is() {
var statement =
parseStatement('x is String<S> Function() ? (x + y) : z;')
as ExpressionStatement;
var expression = statement.expression as ConditionalExpression;
Expression condition = expression.condition;
expect(condition, TypeMatcher<IsExpression>());
Expression thenExpression = expression.thenExpression;
expect(thenExpression, TypeMatcher<ParenthesizedExpression>());
Expression elseExpression = expression.elseExpression;
expect(elseExpression, TypeMatcher<SimpleIdentifier>());
}
void test_conditionalExpression_precedence_nullableTypeWithTypeArg2_is() {
var statement =
parseStatement('x is String<S,T> ? (x + y) : z;')
as ExpressionStatement;
var expression = statement.expression as ConditionalExpression;
Expression condition = expression.condition;
expect(condition, TypeMatcher<IsExpression>());
Expression thenExpression = expression.thenExpression;
expect(thenExpression, TypeMatcher<ParenthesizedExpression>());
Expression elseExpression = expression.elseExpression;
expect(elseExpression, TypeMatcher<SimpleIdentifier>());
}
void test_conditionalExpression_precedence_prefixedNullableType_is() {
var statement =
parseStatement('x is p.A ? (x + y) : z;') as ExpressionStatement;
var expression = statement.expression as ConditionalExpression;
var condition = expression.condition;
expect(condition, TypeMatcher<IsExpression>());
Expression thenExpression = expression.thenExpression;
expect(thenExpression, TypeMatcher<ParenthesizedExpression>());
Expression elseExpression = expression.elseExpression;
expect(elseExpression, TypeMatcher<SimpleIdentifier>());
}
void test_conditionalExpression_precedence_withAssignment() {
var statement =
parseStatement('b ? c = true : g();') as ExpressionStatement;
var expression = statement.expression as ConditionalExpression;
expect(expression.condition, TypeMatcher<SimpleIdentifier>());
expect(expression.thenExpression, TypeMatcher<AssignmentExpression>());
}
void test_conditionalExpression_precedence_withAssignment2() {
var statement =
parseStatement('b.x ? c = true : g();') as ExpressionStatement;
var expression = statement.expression as ConditionalExpression;
expect(expression.condition, TypeMatcher<PrefixedIdentifier>());
expect(expression.thenExpression, TypeMatcher<AssignmentExpression>());
}
void test_conditionalExpression_prefixedValue() {
var statement = parseStatement('a.b ? y : z;') as ExpressionStatement;
var expression = statement.expression as ConditionalExpression;
expect(expression.condition, TypeMatcher<PrefixedIdentifier>());
expect(expression.thenExpression, TypeMatcher<SimpleIdentifier>());
}
void test_conditionalExpression_prefixedValue2() {
var statement = parseStatement('a.b ? x.y : z;') as ExpressionStatement;
var expression = statement.expression as ConditionalExpression;
expect(expression.condition, TypeMatcher<PrefixedIdentifier>());
expect(expression.thenExpression, TypeMatcher<PrefixedIdentifier>());
}
void test_constructor_initializer_withParenthesizedExpression() {
CompilationUnit unit = parseCompilationUnit(r'''
class C {
C() :
this.a = (b == null ? c : d) {
}
}''');
NodeList<CompilationUnitMember> declarations = unit.declarations;
expect(declarations, hasLength(1));
}
void test_equalityExpression_normal() {
var expression =
parseExpression(
"x == y != z",
codes: [ParserErrorCode.equalityCannotBeEqualityOperand],
)
as BinaryExpression;
expect(expression.leftOperand, isBinaryExpression);
}
void test_equalityExpression_precedence_relational_left() {
var expression = parseExpression("x is y == z") as BinaryExpression;
expect(expression.leftOperand, isIsExpression);
}
void test_equalityExpression_precedence_relational_right() {
var expression = parseExpression("x == y is z") as BinaryExpression;
expect(expression.rightOperand, isIsExpression);
}
void test_equalityExpression_super() {
var expression =
parseExpression(
"super == y != z",
codes: [ParserErrorCode.equalityCannotBeEqualityOperand],
)
as BinaryExpression;
expect(expression.leftOperand, isBinaryExpression);
}
void test_ifNullExpression() {
var expression = parseExpression('x ?? y ?? z') as BinaryExpression;
expect(expression.leftOperand, isBinaryExpression);
}
void test_ifNullExpression_precedence_logicalOr_left() {
var expression = parseExpression('x || y ?? z') as BinaryExpression;
expect(expression.leftOperand, isBinaryExpression);
}
void test_ifNullExpression_precedence_logicalOr_right() {
var expression = parseExpression('x ?? y || z') as BinaryExpression;
expect(expression.rightOperand, isBinaryExpression);
}
void test_logicalAndExpression() {
var expression = parseExpression("x && y && z") as BinaryExpression;
expect(expression.leftOperand, isBinaryExpression);
}
void test_logicalAndExpression_precedence_bitwiseOr_left() {
var expression = parseExpression("x | y < z") as BinaryExpression;
expect(expression.leftOperand, isBinaryExpression);
}
void test_logicalAndExpression_precedence_bitwiseOr_right() {
var expression = parseExpression("x < y | z") as BinaryExpression;
expect(expression.rightOperand, isBinaryExpression);
}
void test_logicalAndExpressionStatement() {
// Assert that `<` and `>` are not interpreted as type arguments.
var statement = parseStatement("C<T && T>U;") as ExpressionStatement;
var expression = statement.expression as BinaryExpression;
expect(expression.leftOperand, isBinaryExpression);
}
void test_logicalOrExpression() {
var expression = parseExpression("x || y || z") as BinaryExpression;
expect(expression.leftOperand, isBinaryExpression);
}
void test_logicalOrExpression_precedence_logicalAnd_left() {
var expression = parseExpression("x && y || z") as BinaryExpression;
expect(expression.leftOperand, isBinaryExpression);
}
void test_logicalOrExpression_precedence_logicalAnd_right() {
var expression = parseExpression("x || y && z") as BinaryExpression;
expect(expression.rightOperand, isBinaryExpression);
}
void test_methodInvocation1() {
// Assert that `<` and `>` are not interpreted as type arguments.
var statement = parseStatement("f(a < b, c > 3);") as ExpressionStatement;
assertNoErrors();
var method = statement.expression as MethodInvocation;
expect(method.argumentList.arguments, hasLength(2));
}
void test_methodInvocation2() {
// Assert that `<` and `>` are not interpreted as type arguments.
var statement = parseStatement("f(a < b, c >> 3);") as ExpressionStatement;
assertNoErrors();
var method = statement.expression as MethodInvocation;
expect(method.argumentList.arguments, hasLength(2));
}
void test_methodInvocation3() {
// Assert that `<` and `>` are not interpreted as type arguments.
var statement =
parseStatement("f(a < b, c < d >> 3);") as ExpressionStatement;
assertNoErrors();
var method = statement.expression as MethodInvocation;
expect(method.argumentList.arguments, hasLength(2));
}
void test_multipleLabels_statement() {
var statement = parseStatement("a: b: c: return x;") as LabeledStatement;
expect(statement.labels, hasLength(3));
expect(statement.statement, isReturnStatement);
}
void test_multiplicativeExpression_normal() {
var expression = parseExpression("x * y / z") as BinaryExpression;
expect(expression.leftOperand, isBinaryExpression);
}
void test_multiplicativeExpression_precedence_unary_left() {
var expression = parseExpression("-x * y") as BinaryExpression;
expect(expression.leftOperand, isPrefixExpression);
}
void test_multiplicativeExpression_precedence_unary_right() {
var expression = parseExpression("x * -y") as BinaryExpression;
expect(expression.rightOperand, isPrefixExpression);
}
void test_multiplicativeExpression_super() {
var expression = parseExpression("super * y / z") as BinaryExpression;
expect(expression.leftOperand, isBinaryExpression);
}
void test_relationalExpression_precedence_shift_right() {
var expression = parseExpression("x << y is z") as IsExpression;
expect(expression.expression, isBinaryExpression);
}
void test_shiftExpression_normal() {
var expression = parseExpression("x >> 4 << 3") as BinaryExpression;
expect(expression.leftOperand, isBinaryExpression);
}
void test_shiftExpression_precedence_additive_left() {
var expression = parseExpression("x + y << z") as BinaryExpression;
expect(expression.leftOperand, isBinaryExpression);
}
void test_shiftExpression_precedence_additive_right() {
var expression = parseExpression("x << y + z") as BinaryExpression;
expect(expression.rightOperand, isBinaryExpression);
}
void test_shiftExpression_super() {
var expression = parseExpression("super >> 4 << 3") as BinaryExpression;
expect(expression.leftOperand, isBinaryExpression);
}
void test_topLevelFunction_nestedGenericFunction() {
parseCompilationUnit('''
void f() {
void g<T>() {
}
}
''');
}
void _validate_assignableExpression_arguments_normal_chain_typeArguments(
String code, [
List<DiagnosticCode> codes = const <DiagnosticCode>[],
]) {
var propertyAccess1 = parseExpression(code, codes: codes) as PropertyAccess;
expect(propertyAccess1.propertyName.name, "f");
//
// a<E>(b)<F>(c).d<G>(e)
//
var invocation2 = propertyAccess1.target as MethodInvocation;
expect(invocation2.methodName.name, "d");
expect(invocation2.typeArguments, isNotNull);
ArgumentList argumentList2 = invocation2.argumentList;
expect(argumentList2, isNotNull);
expect(argumentList2.arguments, hasLength(1));
//
// a<E>(b)<F>(c)
//
var invocation3 = invocation2.target as FunctionExpressionInvocation;
expect(invocation3.typeArguments, isNotNull);
ArgumentList argumentList3 = invocation3.argumentList;
expect(argumentList3, isNotNull);
expect(argumentList3.arguments, hasLength(1));
//
// a(b)
//
var invocation4 = invocation3.function as MethodInvocation;
expect(invocation4.methodName.name, "a");
expect(invocation4.typeArguments, isNotNull);
ArgumentList argumentList4 = invocation4.argumentList;
expect(argumentList4, isNotNull);
expect(argumentList4.arguments, hasLength(1));
}
}