Files
sdk/pkg/analyzer/test/generated/invalid_code_test.dart
T
Konstantin Shcheglov fc7c531253 CQ. Remove result state from ResolutionTest.
Stop storing the most recently resolved unit in ResolutionTest. Make
test helpers operate on explicit result objects instead, so each
assertion uses the diagnostics, type provider, type system, and
inheritance manager from the result it is checking.

This makes the tests less order-dependent and easier to reason about. A
test can now resolve more than one file or unit without later assertions
implicitly depending on whichever result happened to be stored last. It
also makes helper APIs more local: the data needed by an assertion is
passed directly, rather than recovered from mutable test state.

Update tests to keep the returned result when they need access to the
resolved AST or result-derived utilities. Add convenience accessors on
the result wrappers to preserve common lookup patterns without
reintroducing shared mutable state.

Change-Id: Ib45c52f8fd104b668f9fdd1ec6b1442927cd7e61
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/505920
Reviewed-by: Paul Berry <paulberry@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
2026-05-22 13:05:47 -07:00

480 lines
10 KiB
Dart

// Copyright (c) 2017, 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.
import 'package:analyzer/dart/element/nullability_suffix.dart';
import 'package:analyzer/src/diagnostic/diagnostic.dart' as diag;
import 'package:test_reflective_loader/test_reflective_loader.dart';
import '../src/dart/resolution/context_collection_resolution.dart';
main() {
defineReflectiveSuite(() {
defineReflectiveTests(InvalidCodeTest);
});
}
/// Tests for various end-to-end cases when invalid code caused exceptions
/// in one or another Analyzer subsystem. We are not interested not in specific
/// errors generated, but we want to make sure that there is at least one,
/// and analysis finishes without exceptions.
@reflectiveTest
class InvalidCodeTest extends PubPackageResolutionTest {
// TODO(srawlins): Use null safety in test cases.
// https://github.com/dart-lang/sdk/issues/44666
test_const_AwaitExpression() async {
await _assertCanBeAnalyzed(r'''
const a = await b();
''');
}
test_const_ForPartsWithExpression() async {
await _assertCanBeAnalyzed(r'''
@A([for (;;) 0])
void f() {}
''');
}
/// This code results in a method with the empty name, and the default
/// constructor, which also has the empty name. The `Map` in `f` initializer
/// references the empty name.
test_constructorAndMethodNameCollision() async {
await _assertCanBeAnalyzed('''
class C {
var f = { : };
@ ();
}
''');
}
test_constructorDeclaration_named_missingName() async {
await _assertCanBeAnalyzed('''
class C {
C.();
}
''');
}
test_constructorDeclaration_named_missingName_factory() async {
await _assertCanBeAnalyzed('''
class C {
factory C.();
}
''');
}
test_duplicateName_class_enum() async {
await _assertCanBeAnalyzed('''
class A<T> {
void foo(B b) {
b.bar(this);
}
}
class B {
void bar(A a) {}
}
enum A {
a, b, c
}
''');
}
test_extensionOverrideInAnnotationContext() async {
await _assertCanBeAnalyzed('''
class R {
const R(int x);
}
@R(E(null).f())
extension E on Object {
int f() => 0;
}
''');
}
test_extensionOverrideInAnnotationContext_importedWithPrefix() async {
newFile('$testPackageLibPath/a.dart', r'''
extension E on Object {
int f() => 0;
}
''');
await _assertCanBeAnalyzed('''
import 'a.dart' as prefix;
class A {
const A(int x);
}
@R(prefix.E(null).f())
void g() {}
}
''');
}
test_extensionOverrideInConstContext() async {
await _assertCanBeAnalyzed('''
extension E on Object {
int f() => 0;
}
const e = E(null).f();
''');
}
test_fieldFormalParameter_annotation_localFunction() async {
await _assertCanBeAnalyzed(r'''
void main() {
void foo(@deprecated this.bar) {}
}
''');
}
test_functionExpression_emptyBody() async {
await _assertCanBeAnalyzed(r'''
var v = <T>();
''');
}
test_functionExpressionInvocation_mustBeNullShortingTerminated() async {
// It looks like MethodInvocation, but because `8` is not SimpleIdentifier,
// we parse it as FunctionExpressionInvocation.
await _assertCanBeAnalyzed(r'''
var v = a?.8(b);
''');
}
test_fuzz_01() async {
var result = await _assertCanBeAnalyzed(r'''
typedef F = void Function(bool, int a(double b));
''');
var alias = result.findElement.typeAlias('F');
assertType(
alias.instantiate(
typeArguments: const [],
nullabilitySuffix: NullabilitySuffix.none,
),
'void Function(bool, int Function(double))',
);
}
test_fuzz_02() async {
await _assertCanBeAnalyzed(r'''
class G<class G{d
''');
}
test_fuzz_03() async {
await _assertCanBeAnalyzed('''
class{const():super.{n
''');
}
test_fuzz_04() async {
await _assertCanBeAnalyzed('''
f({a: ({b = 0}) {}}) {}
''');
}
test_fuzz_05() async {
// Here 'v' is used as both the local variable name, and its type.
// This triggers "reference before declaration" diagnostics.
// It attempts to ask the enclosing unit element for "v".
// Every (not library or unit) element must have the enclosing unit.
await _assertCanBeAnalyzed('''
f({a = [for (v v in [])]}) {}
''');
}
test_fuzz_06() async {
await _assertCanBeAnalyzed(r'''
class C {
int f;
set f() {}
}
''');
}
test_fuzz_07() async {
// typedef v(<T extends T>(e
await _assertCanBeAnalyzed(r'''
typedef F(a<TT extends TT>(e));
''');
}
test_fuzz_08() async {
// class{const v
// v=((){try catch
// When we resolve initializers of typed constant variables,
// we should build locale elements.
await _assertCanBeAnalyzed(r'''
class C {
const Object v = () { var a = 0; };
}
''');
}
test_fuzz_09() async {
var result = await _assertCanBeAnalyzed(r'''
typedef void F(int a, this.b);
''');
var alias = result.findElement.typeAlias('F');
assertType(
alias.instantiate(
typeArguments: const [],
nullabilitySuffix: NullabilitySuffix.none,
),
'void Function(int, dynamic)',
);
}
test_fuzz_10() async {
await _assertCanBeAnalyzed(r'''
void f<@A(() { Function() v; }) T>() {}
''');
}
test_fuzz_12() async {
// This code crashed with summary2 because usually AST reader is lazy,
// so we did not read metadata `@b` for `c`. But default values must be
// read fully.
// Fixed 2020-11-12.
await _assertCanBeAnalyzed(r'''
void f({a = [for (@b c = 0;;)]}) {}
''');
}
test_fuzz_13() async {
// `x is int` promotes the type of `x` to `S extends int`, and the
// underlying element is `TypeParameterMember`, which by itself is
// questionable. But this is not a valid constant anyway, so we should
// not even try to serialize it.
await _assertCanBeAnalyzed(r'''
const v = [<S extends num>(S x) => x is int ? x : 0];
''');
}
test_fuzz_14() async {
// This crashed because parser produces `ConstructorDeclaration`.
// So, we try to create `ConstructorElement` for it, and it wants
// `ClassElement` as the enclosing element. But we have `ExtensionElement`.
await _assertCanBeAnalyzed(r'''
extension E {
factory S() {}
}
''');
}
test_fuzz_15() async {
// `@A` is not a valid annotation, it is missing arguments.
// There was a bug that we did not check for arguments being missing.
await _assertCanBeAnalyzed(r'''
class A<T> {}
@A
class B {}
''');
}
test_fuzz_16() async {
// The default constructor of `A` does not have formal parameters.
// But we give it arguments.
// There was a bug that we did not check for this mismatch.
await _assertCanBeAnalyzed(r'''
class A<T> {}
@A(0)
class B {}
''');
}
test_fuzz_38091() async {
// https://github.com/dart-lang/sdk/issues/38091
// this caused an infinite loop in parser recovery
await _assertCanBeAnalyzed(r'c(=k(<)>');
}
test_fuzz_38506() async {
// https://github.com/dart-lang/sdk/issues/38506
// We have only one LibraryElement to get resolved annotations.
// Leave annotations node of other LibraryDirective(s) unresolved.
await _assertCanBeAnalyzed(r'''
library c;
@foo
library c;
''');
}
test_fuzz_38878() async {
// We should not attempt to resolve `super` in annotations.
await _assertCanBeAnalyzed(r'''
class C {
@A(super.f())
f(int x) {}
}
''');
}
test_fuzz_38953() async {
// When we enter a directive, we should stop using the element walker
// of the unit, just like when we enter a method body. Even though using
// interpolation is not allowed in any directives.
await _assertCanBeAnalyzed(r'''
import '${[for(var v = 0;;) v]}';
export '${[for(var v = 0;;) v]}';
part '${[for(var v = 0;;) v]}';
''');
}
test_genericFunction_asTypeArgument_ofUnresolvedClass() async {
await _assertCanBeAnalyzed(r'''
C<int Function()> c;
''');
}
test_inAnnotation_noFlow_labeledStatement() async {
await _assertCanBeAnalyzed('''
@A(() { label: })
typedef F = void Function();
''');
}
test_inDefaultValue_noFlow_ifExpression() async {
await _assertCanBeAnalyzed('''
typedef void F({a = [if (true) 0]});
''');
}
test_inDefaultValue_noFlow_ifStatement() async {
await _assertCanBeAnalyzed('''
typedef void F([a = () { if (true) 0; }]);
''');
}
test_invalid_unicode() async {
await assertErrorsInCode('\uFFFD', [error(diag.encoding, 0, 1)]);
}
test_invalidPart_withPart() async {
await _assertCanBeAnalyzed('''
part of a;
part 'test.dart';
''');
}
test_issue_40837() async {
await _assertCanBeAnalyzed('''
class A {
const A(_);
}
@A(() => 0)
class B {}
''');
}
test_issue_48688() async {
// During parsing we recover as `<synthetic>.bar.baz()`.
// So, we have a synthetic empty identifier.
// There was a bug - we considered it a reference to the unnamed extension.
await _assertCanBeAnalyzed(r'''
void f() {
final foo.bar.baz();
}
extension on int {}
''');
}
test_issue_52363() async {
await _assertCanBeAnalyzed(r'''
class A {
const a = (var b,) = (0,);
}
''');
}
test_issue_52432() async {
await _assertCanBeAnalyzed(r'''
void f() {
void g([super.foo]) {}
}
''');
}
test_keywordInConstructorInitializer_assert() async {
await _assertCanBeAnalyzed('''
class C {
C() : assert = 0;
}
''');
}
test_keywordInConstructorInitializer_null() async {
await _assertCanBeAnalyzed('''
class C {
C() : null = 0;
}
''');
}
test_keywordInConstructorInitializer_super() async {
await _assertCanBeAnalyzed('''
class C {
C() : super = 0;
}
''');
}
test_keywordInConstructorInitializer_this() async {
await _assertCanBeAnalyzed('''
class C {
C() : this = 0;
}
''');
}
test_libraryAfterImport() async {
await _assertCanBeAnalyzed(r'''
import 'dart:async';
@foo
library my;
''');
}
test_localFunction_defaultFieldFormalParameter_metadata() async {
await _assertCanBeAnalyzed(r'''
const my = 0;
void foo() {
// ignore:unused_element
void bar({@my this.x}) {}
}
''');
}
test_syntheticImportPrefix() async {
await _assertCanBeAnalyzed('''
import 'dart:math' as;
''');
}
test_typeBeforeAnnotation() async {
await _assertCanBeAnalyzed('''
class A {
const A([x]);
}
class B {
dynamic @A(const A()) x;
}
''');
}
Future<TestResolvedUnitResult> _assertCanBeAnalyzed(String text) async {
var result = await resolveTestCode(text);
assertHasTestErrors(result);
return result;
}
}