Files
Konstantin Shcheglov 0349520b98 DeCo. Migrate everything to new AST.
No more flag, always parse into the new AST, always visit new AST nodes,
always return them as child entities, parent-child structure reflects
the new AST.

So, use `namePart` and `body` where possible. Deprecate previous
properties.

This is still de jure a breaking change, because `parent` of deprecated
properties changes. De facto this required very few changes in google3.

Once this CL lands, I will publish `analyzer 10.0.0`, migrate everything
to new properties, delete deprecated properties, and publish `analyzer
11.0.0`.

Maybe deprecate `NamedCompilationUnitMember.name` and migrate to
subclass specific `name` or `namePart` properties before publishing
`analyzer 10.0.0`. This part is not breaking per se.

* Deprecations in `ClassDeclaration`:
  * Properties `leftBracket`, `members`, `rightBracket` are deprecated, use `body` instead.
  * Properties `name`, `typeParameters` are deprecated, use `namePart` instead.
* Deprecations in `EnumDeclaration`:
  * Properties `leftBracket`, `constants`, `members`, `rightBracket` are deprecated, use `body` instead.
  * Properties `name`, `typeParameters` are deprecated, use `namePart` instead.
* Deprecations in `ExtensionDeclaration`:
  * Properties `leftBracket`, `members`, `rightBracket` are deprecated, use `body` instead.
* Deprecations in `ExtensionTypeDeclaration`:
  * Properties `leftBracket`, `constants`, `members`, `rightBracket` are deprecated, use `body` instead.
  * Properties `constKeyword`, `name`, `representation`, `typeParameters` are deprecated,
    use `primaryConstructor` instead.
* **Breaking Change:** While the deprecated members mentioned  above still exist in the AST,
  their parent nodes have changed. This means that code  relying on specific parent-child
  relationships for these nodes might break.

Bug: https://github.com/dart-lang/sdk/issues/61701
Change-Id: Ic48104da8b029c9b454bbd2336574b7823025565
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/461841
Reviewed-by: Johnni Winther <johnniwinther@google.com>
Reviewed-by: Samuel Rawlins <srawlins@google.com>
Reviewed-by: Paul Berry <paulberry@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
2025-11-17 08:57:36 -08:00

223 lines
8.4 KiB
Dart

// Copyright (c) 2013, 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/ast/ast.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/dart/element/type_provider.dart';
import 'package:analyzer/source/source.dart';
import 'package:analyzer/src/dart/element/type.dart';
import 'package:test/test.dart';
/// The type of an assertion which asserts properties of [T]s.
typedef Asserter<T> = void Function(T type);
/// The type of a function which given an [S], builds an assertion over [T]s.
typedef AsserterBuilder<S, T> = Asserter<T> Function(S arg);
/// The type of a function which given an [S0] and an S1, builds an assertion
/// over [T]s.
typedef AsserterBuilder2<S0, S1, T> = Asserter<T> Function(S0 arg0, S1 arg1);
/// The type of a function which given an [R] returns an [AsserterBuilder] over
/// [S]s and [T]s. That is, it returns a function which given an [S], returns
/// a function over [T]s.
typedef AsserterBuilderBuilder<R, S, T> = AsserterBuilder<S, T> Function(R arg);
class AstFinder {
/// Return the declaration of the class with the given [className] in the
/// given compilation [unit].
static ClassDeclaration getClass(CompilationUnit unit, String className) {
NodeList<CompilationUnitMember> unitMembers = unit.declarations;
for (CompilationUnitMember unitMember in unitMembers) {
if (unitMember is ClassDeclaration &&
unitMember.namePart.typeName.lexeme == className) {
return unitMember;
}
}
Source source = unit.declaredFragment!.source;
fail('No class named $className in $source');
}
/// Return the declaration of the constructor with the given [constructorName]
/// in the class with the given [className] in the given compilation [unit].
/// If constructorName is null, return the default constructor;
static ConstructorDeclaration getConstructorInClass(
CompilationUnit unit,
String className,
String? constructorName,
) {
ClassDeclaration unitMember = getClass(unit, className);
var classBody = unitMember.body as BlockClassBody;
NodeList<ClassMember> classMembers = classBody.members;
for (ClassMember classMember in classMembers) {
if (classMember is ConstructorDeclaration) {
if (classMember.name?.lexeme == constructorName) {
return classMember;
}
}
}
fail('No constructor named $constructorName in $className');
}
/// Return the declaration of the field with the given [fieldName] in the
/// class with the given [className] in the given compilation [unit].
static VariableDeclaration getFieldInClass(
CompilationUnit unit,
String className,
String fieldName,
) {
ClassDeclaration unitMember = getClass(unit, className);
var classBody = unitMember.body as BlockClassBody;
NodeList<ClassMember> classMembers = classBody.members;
for (ClassMember classMember in classMembers) {
if (classMember is FieldDeclaration) {
NodeList<VariableDeclaration> fields = classMember.fields.variables;
for (VariableDeclaration field in fields) {
if (field.name.lexeme == fieldName) {
return field;
}
}
}
}
fail('No field named $fieldName in $className');
}
/// Return the declaration of the method with the given [methodName] in the
/// class with the given [className] in the given compilation [unit].
static MethodDeclaration getMethodInClass(
CompilationUnit unit,
String className,
String methodName,
) {
ClassDeclaration unitMember = getClass(unit, className);
var classBody = unitMember.body as BlockClassBody;
NodeList<ClassMember> classMembers = classBody.members;
for (ClassMember classMember in classMembers) {
if (classMember is MethodDeclaration) {
if (classMember.name.lexeme == methodName) {
return classMember;
}
}
}
fail('No method named $methodName in $className');
}
/// Return the statements in the body of the top-level function with the given
/// [functionName] in the given compilation [unit].
static List<Statement> getStatementsInTopLevelFunction(
CompilationUnit unit,
String functionName,
) {
FunctionDeclaration function = getTopLevelFunction(unit, functionName);
var body = function.functionExpression.body as BlockFunctionBody;
return body.block.statements;
}
/// Return the declaration of the top-level function with the given
/// [functionName] in the given compilation [unit].
static FunctionDeclaration getTopLevelFunction(
CompilationUnit unit,
String functionName,
) {
NodeList<CompilationUnitMember> unitMembers = unit.declarations;
for (CompilationUnitMember unitMember in unitMembers) {
if (unitMember is FunctionDeclaration) {
if (unitMember.name.lexeme == functionName) {
return unitMember;
}
}
}
fail('No toplevel function named $functionName found');
}
}
/// Class for compositionally building up assertions on types
class TypeAssertions {
// TODO(leafp): Make these matchers.
// https://pub.dev/documentation/matcher/latest/matcher/Matcher-class.html
/// Provides primitive types for basic type assertions.
final TypeProvider _typeProvider;
TypeAssertions(this._typeProvider);
/// Primitive assertion for the dynamic type.
Asserter<DartType> get isDynamic => isType(_typeProvider.dynamicType);
/// Primitive assertion for the int type.
Asserter<DartType> get isInt => isType(_typeProvider.intType);
/// Primitive assertion for the dynamic type.
Asserter<DartType> get isInvalidType => isType(InvalidTypeImpl.instance);
/// Primitive assertion for the list type.
Asserter<DartType> get isList => hasElement(_typeProvider.listElement);
/// Primitive assertion for the map type.
Asserter<DartType> get isMap => hasElement(_typeProvider.mapElement);
/// Primitive assertion for the Never type.
Asserter<DartType> get isNever => isType(_typeProvider.neverType);
/// Primitive assertion for the Null type.
Asserter<DartType> get isNull => isType(_typeProvider.nullType);
/// Primitive assertion for the num type.
Asserter<DartType> get isNum => isType(_typeProvider.numType);
/// Primitive assertion for the Object type.
Asserter<DartType> get isObject => isType(_typeProvider.objectType);
/// Primitive assertion for the string type.
Asserter<DartType> get isString => isType(_typeProvider.stringType);
/// Assert that a type has the element that is equal to the [expected].
Asserter<DartType> hasElement(Element expected) =>
(DartType type) => expect(expected, (type as InterfaceType).element);
/// Given assertions for the argument and return types, produce an
/// assertion over unary function types.
Asserter<DartType> isFunction2Of(
Asserter<DartType> argType,
Asserter<DartType> returnType,
) => (DartType type) {
FunctionType fType = type as FunctionType;
argType(fType.normalParameterTypes[0]);
returnType(fType.returnType);
};
/// Given an assertion for the base type and assertions over the type
/// parameters, produce an assertion over instantiations.
AsserterBuilder<List<Asserter<DartType>>, DartType> isInstantiationOf(
Asserter<DartType> baseAssert,
) =>
(List<Asserter<DartType>> argAsserts) => (DartType type) {
InterfaceType t = type as InterfaceType;
baseAssert(t);
List<DartType> typeArguments = t.typeArguments;
expect(typeArguments, hasLength(argAsserts.length));
for (int i = 0; i < typeArguments.length; i++) {
argAsserts[i](typeArguments[i]);
}
};
/// Assert that a type is the List type, and that the given assertion holds
/// over the type parameter.
Asserter<InterfaceType> isListOf(Asserter<DartType> argAssert) =>
isInstantiationOf(isList)([argAssert]);
/// Assert that a type is the Map type, and that the given assertions hold
/// over the type parameters.
Asserter<InterfaceType> isMapOf(
Asserter<DartType> argAssert0,
Asserter<DartType> argAssert1,
) => isInstantiationOf(isMap)([argAssert0, argAssert1]);
/// Assert that a type is equal to the [expected].
Asserter<DartType> isType(DartType expected) => (DartType t) {
expect(t, expected);
};
}