blob: e08cf2e9288ceec573a47952aa1cec6e47e403a4 [file] [log] [blame]
// Copyright (c) 2016, 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.
library fasta.outline_builder;
import 'package:_fe_analyzer_shared/src/parser/parser.dart'
show
Assert,
ConstructorReferenceContext,
DeclarationHeaderKind,
DeclarationKind,
FormalParameterKind,
IdentifierContext,
MemberKind,
lengthOfSpan,
optional;
import 'package:_fe_analyzer_shared/src/parser/quote.dart' show unescapeString;
import 'package:_fe_analyzer_shared/src/parser/stack_listener.dart'
show FixedNullableList, NullValues, ParserRecovery;
import 'package:_fe_analyzer_shared/src/scanner/scanner.dart' show Token;
import 'package:_fe_analyzer_shared/src/type_inference/type_analyzer_operations.dart'
show Variance;
import 'package:_fe_analyzer_shared/src/util/link.dart';
import 'package:_fe_analyzer_shared/src/util/value_kind.dart';
import 'package:kernel/ast.dart'
show AsyncMarker, InvalidType, Nullability, ProcedureKind, TreeNode;
import '../api_prototype/experimental_flags.dart';
import '../base/combinator.dart' show CombinatorBuilder;
import '../base/configuration.dart' show Configuration;
import '../base/identifiers.dart'
show Identifier, OperatorIdentifier, SimpleIdentifier, flattenName;
import '../base/ignored_parser_errors.dart' show isIgnoredParserError;
import '../base/messages.dart';
import '../base/modifier.dart'
show
Augment,
Const,
Covariant,
External,
Final,
Modifier,
Static,
Var,
abstractMask,
augmentMask,
constMask,
covariantMask,
externalMask,
lateMask,
requiredMask,
staticMask;
import '../builder/constructor_reference_builder.dart';
import '../builder/declaration_builders.dart';
import '../builder/fixed_type_builder.dart';
import '../builder/formal_parameter_builder.dart';
import '../builder/invalid_type_builder.dart';
import '../builder/library_builder.dart';
import '../builder/metadata_builder.dart';
import '../builder/mixin_application_builder.dart';
import '../builder/named_type_builder.dart';
import '../builder/nullability_builder.dart';
import '../builder/omitted_type_builder.dart';
import '../builder/record_type_builder.dart';
import '../builder/type_builder.dart';
import '../base/operator.dart' show Operator;
import '../base/problems.dart' show unhandled;
import '../base/uris.dart';
import '../kernel/utils.dart';
import 'builder_factory.dart';
import 'offset_map.dart';
import 'source_enum_builder.dart';
import 'stack_listener_impl.dart';
import 'type_parameter_scope_builder.dart';
import 'value_kinds.dart';
enum MethodBody {
Abstract,
Regular,
RedirectingFactoryBody,
}
/// Enum for the context in which declarations occur.
///
/// This is used to determine whether instance type variables access is allowed.
enum DeclarationContext {
/// In the context of the enclosing library.
///
/// This is used for library, import, export, part, and part of declarations
/// in libraries and parts, as well as annotations on top level declarations.
Library,
/// In a typedef declaration
///
/// This excludes annotations on the typedef declaration itself, which are
/// seen in the [Library] context.
Typedef,
/// In an enum declaration
///
/// This excludes annotations on the enum declaration itself, which are seen
/// in the [Library] context.
Enum,
/// In a top level method declaration.
///
/// This includes return type of the declaration but excludes annotations on
/// the method declaration itself, which are seen in the [Library] context.
TopLevelMethod,
/// In a top level field declaration.
///
/// This includes type of the declaration but excludes annotations on the
/// field declaration itself, which are seen in the [Library] context.
TopLevelField,
/// In a `class Name<TypeParams>` or `mixin Name<TypeParams>` prefix of a
/// class declaration `class Name<TypeParams> ... { ... }`, mixin declaration
/// `mixin Name<TypeParams> ... { ... }` or named mixin application
/// `class Name<TypeParams> = ...;`.
///
/// This is replaced by [Class], [Mixin] or [NamedMixinApplication] after the
/// type parameters have been parsed.
ClassOrMixinOrNamedMixinApplication,
/// In a named mixin application.
///
/// This excludes type parameters declared on the named mixin application,
/// which are seen in the [ClassOrMixinOrNamedMixinApplication] context,
/// and annotations on the named mixin application itself, which are seen in
/// the [Library] context.
NamedMixinApplication,
/// In a class declaration before the class body.
///
/// This excludes type parameters declared on the class declaration, which are
/// seen in the [ClassOrMixinOrNamedMixinApplication] context, and annotations
/// on the class declaration itself, which are seen in the [Library] context.
Class,
/// In a class declaration body.
///
/// This includes annotations on class member declarations.
ClassBody,
/// In a generative constructor declaration inside a class declaration.
///
/// This excludes annotations on the constructor declaration itself, which
/// are seen in the [ClassBody] context.
ClassConstructor,
/// In a factory constructor declaration inside a class declaration.
///
/// This excludes annotations on the constructor declaration itself, which
/// are seen in the [ClassBody] context.
ClassFactory,
/// In an instance method declaration inside a class declaration.
///
/// This includes return type of the declaration but excludes annotations on
/// the method declaration itself, which are seen in the [ClassBody] context.
ClassInstanceMethod,
/// In an instance field declaration inside a class declaration.
///
/// This includes type of the declaration but excludes annotations on the
/// field declaration itself, which are seen in the [ClassBody] context.
ClassInstanceField,
/// In a static method declaration inside a class declaration.
///
/// This includes return type of the declaration but excludes annotations on
/// the method declaration itself, which are seen in the [ClassBody] context.
ClassStaticMethod,
/// In a static field declaration inside a class declaration.
///
/// This includes type of the declaration but excludes annotations on the
/// field declaration itself, which are seen in the [ClassBody] context.
ClassStaticField,
/// In a mixin declaration before the mixin body.
///
/// This excludes type parameters declared on the mixin declaration, which are
/// seen in the [ClassOrMixinOrNamedMixinApplication] context, and annotations
/// on the mixin declaration itself, which are seen in the [Library] context.
Mixin,
/// In a mixin declaration body.
///
/// This includes annotations on mixin member declarations.
MixinBody,
/// In a generative constructor declaration inside a mixin declaration. This
/// is an error case.
///
/// This excludes annotations on the constructor declaration itself, which
/// are seen in the [MixinBody] context.
MixinConstructor,
/// In a factory constructor declaration inside a mixin declaration. This is
/// an error case.
///
/// This excludes annotations on the constructor declaration itself, which
/// are seen in the [MixinBody] context.
MixinFactory,
/// In an instance method declaration inside a mixin declaration.
///
/// This includes return type of the declaration but excludes annotations on
/// the method declaration itself, which are seen in the [MixinBody] context.
MixinInstanceMethod,
/// In an instance field declaration inside a mixin declaration.
///
/// This includes type of the declaration but excludes annotations on the
/// field declaration itself, which are seen in the [MixinBody] context.
MixinInstanceField,
/// In a static method declaration inside a mixin declaration.
///
/// This includes return type of the declaration but excludes annotations on
/// the method declaration itself, which are seen in the [MixinBody] context.
MixinStaticMethod,
/// In a static field declaration inside a mixin declaration.
///
/// This includes type of the declaration but excludes annotations on the
/// field declaration itself, which are seen in the [MixinBody] context.
MixinStaticField,
/// In an extension declaration before the extension body.
///
/// This includes type parameters declared on the extension declaration but
/// excludes annotations on the extension declaration itself, which are seen
/// in the [Library] context.
ExtensionOrExtensionType,
/// In an extension declaration before the extension body.
///
/// This includes type parameters declared on the extension declaration but
/// excludes annotations on the extension declaration itself, which are seen
/// in the [Library] context.
Extension,
/// In a extension declaration body.
///
/// This includes annotations on extension member declarations.
ExtensionBody,
/// In a generative constructor declaration inside an extension declaration.
/// This is an error case.
///
/// This excludes annotations on the constructor declaration itself, which
/// are seen in the [ExtensionBody] context.
ExtensionConstructor,
/// In a factory constructor declaration inside an extension declaration. This
/// is an error case.
///
/// This excludes annotations on the constructor declaration itself, which
/// are seen in the [ExtensionBody] context.
ExtensionFactory,
/// In an instance method declaration inside an extension declaration.
///
/// This includes return type of the declaration but excludes annotations on
/// the method declaration itself, which are seen in the [ExtensionBody]
/// context.
ExtensionInstanceMethod,
/// In a non-external instance field declaration inside an extension
/// declaration. This is an error case.
///
/// This includes type of the declaration but excludes annotations on the
/// field declaration itself, which are seen in the [ExtensionBody] context.
ExtensionInstanceField,
/// In an external instance field declaration inside an extension declaration.
///
/// This includes type of the declaration but excludes annotations on the
/// field declaration itself, which are seen in the [ExtensionBody] context.
ExtensionExternalInstanceField,
/// In a static method declaration inside an extension declaration.
///
/// This includes return type of the declaration but excludes annotations on
/// the method declaration itself, which are seen in the [ExtensionBody]
/// context.
ExtensionStaticMethod,
/// In a static field declaration inside an extension declaration.
///
/// This includes type of the declaration but excludes annotations on the
/// field declaration itself, which are seen in the [ExtensionBody] context.
ExtensionStaticField,
/// In an extension type declaration before the extension type body.
///
/// This includes type parameters declared on the extension type declaration
/// but excludes annotations on the extension type declaration itself, which
/// are seen in the [Library] context.
ExtensionType,
/// In a extension type declaration body.
///
/// This includes annotations on extension type member declarations.
ExtensionTypeBody,
/// In a generative constructor declaration inside an extension type
/// declaration.
///
/// This excludes annotations on the constructor declaration itself, which
/// are seen in the [ExtensionTypeBody] context.
ExtensionTypeConstructor,
/// In a factory constructor declaration inside an extension type declaration.
///
/// This excludes annotations on the constructor declaration itself, which
/// are seen in the [ExtensionTypeBody] context.
ExtensionTypeFactory,
/// In an instance method declaration inside an extension type declaration.
///
/// This includes return type of the declaration but excludes annotations on
/// the method declaration itself, which are seen in the [ExtensionTypeBody]
/// context.
ExtensionTypeInstanceMethod,
/// In an instance field declaration inside an extension type declaration.
/// This is an error case.
///
/// This includes type of the declaration but excludes annotations on the
/// field declaration itself, which are seen in the [ExtensionTypeBody]
/// context.
ExtensionTypeInstanceField,
/// In a static method declaration inside an extension type declaration.
///
/// This includes return type of the declaration but excludes annotations on
/// the method declaration itself, which are seen in the [ExtensionTypeBody]
/// context.
ExtensionTypeStaticMethod,
/// In a static field declaration inside an extension type declaration.
///
/// This includes type of the declaration but excludes annotations on the
/// field declaration itself, which are seen in the [ExtensionTypeBody]
/// context.
ExtensionTypeStaticField,
/// In a generative constructor declaration inside an enum declaration.
EnumConstructor,
/// In a static method declaration inside an enum declaration.
EnumStaticMethod,
/// In a static field declaration inside an enum declaration.
EnumStaticField,
/// In an instance method declaration inside an enum declaration.
EnumInstanceMethod,
/// In an instance field declaration inside an enum declaration.
EnumInstanceField,
/// In a factory constructor declaration inside an enum declaration. This
/// is an error case.
///
/// This excludes annotations on the constructor declaration itself, which
/// are seen in the [EnumBody] context.
EnumFactory,
/// In an enum declaration body.
///
/// This includes annotations on extension member declarations.
EnumBody,
}
extension on DeclarationContext {
InstanceTypeVariableAccessState get instanceTypeVariableAccessState {
switch (this) {
case DeclarationContext.Library:
case DeclarationContext.Typedef:
case DeclarationContext.TopLevelMethod:
case DeclarationContext.TopLevelField:
return InstanceTypeVariableAccessState.Unexpected;
case DeclarationContext.ClassOrMixinOrNamedMixinApplication:
case DeclarationContext.NamedMixinApplication:
case DeclarationContext.Class:
case DeclarationContext.ClassConstructor:
case DeclarationContext.ClassFactory:
case DeclarationContext.ClassInstanceMethod:
case DeclarationContext.ClassInstanceField:
case DeclarationContext.Enum:
case DeclarationContext.EnumConstructor:
case DeclarationContext.EnumInstanceField:
case DeclarationContext.EnumInstanceMethod:
case DeclarationContext.Mixin:
case DeclarationContext.MixinInstanceMethod:
case DeclarationContext.MixinInstanceField:
case DeclarationContext.ExtensionOrExtensionType:
case DeclarationContext.Extension:
case DeclarationContext.ExtensionInstanceMethod:
case DeclarationContext.ExtensionExternalInstanceField:
case DeclarationContext.ExtensionType:
case DeclarationContext.ExtensionTypeConstructor:
case DeclarationContext.ExtensionTypeFactory:
case DeclarationContext.ExtensionTypeInstanceMethod:
case DeclarationContext.ExtensionTypeInstanceField:
return InstanceTypeVariableAccessState.Allowed;
case DeclarationContext.ClassBody:
case DeclarationContext.ClassStaticMethod:
case DeclarationContext.ClassStaticField:
case DeclarationContext.EnumStaticField:
case DeclarationContext.EnumStaticMethod:
case DeclarationContext.EnumBody:
case DeclarationContext.MixinBody:
case DeclarationContext.MixinStaticMethod:
case DeclarationContext.MixinStaticField:
case DeclarationContext.ExtensionBody:
case DeclarationContext.ExtensionStaticMethod:
case DeclarationContext.ExtensionStaticField:
case DeclarationContext.ExtensionTypeBody:
case DeclarationContext.ExtensionTypeStaticMethod:
case DeclarationContext.ExtensionTypeStaticField:
return InstanceTypeVariableAccessState.Disallowed;
case DeclarationContext.MixinConstructor:
case DeclarationContext.MixinFactory:
case DeclarationContext.ExtensionConstructor:
case DeclarationContext.ExtensionFactory:
case DeclarationContext.ExtensionInstanceField:
case DeclarationContext.EnumFactory:
return InstanceTypeVariableAccessState.Invalid;
}
}
/// Returns the kind of type variable created in the current context.
TypeVariableKind get typeVariableKind {
switch (this) {
case DeclarationContext.Class:
case DeclarationContext.ClassOrMixinOrNamedMixinApplication:
case DeclarationContext.Mixin:
case DeclarationContext.NamedMixinApplication:
return TypeVariableKind.classMixinOrEnum;
case DeclarationContext.ExtensionOrExtensionType:
case DeclarationContext.Extension:
case DeclarationContext.ExtensionBody:
case DeclarationContext.ExtensionType:
case DeclarationContext.ExtensionTypeBody:
return TypeVariableKind.extensionOrExtensionType;
case DeclarationContext.ClassBody:
case DeclarationContext.ClassConstructor:
case DeclarationContext.ClassFactory:
case DeclarationContext.ClassInstanceField:
case DeclarationContext.ClassInstanceMethod:
case DeclarationContext.ClassStaticField:
case DeclarationContext.ClassStaticMethod:
case DeclarationContext.Enum:
case DeclarationContext.EnumBody:
case DeclarationContext.EnumConstructor:
case DeclarationContext.EnumFactory:
case DeclarationContext.EnumInstanceField:
case DeclarationContext.EnumInstanceMethod:
case DeclarationContext.EnumStaticField:
case DeclarationContext.EnumStaticMethod:
case DeclarationContext.ExtensionConstructor:
case DeclarationContext.ExtensionExternalInstanceField:
case DeclarationContext.ExtensionFactory:
case DeclarationContext.ExtensionInstanceField:
case DeclarationContext.ExtensionInstanceMethod:
case DeclarationContext.ExtensionStaticField:
case DeclarationContext.ExtensionStaticMethod:
case DeclarationContext.ExtensionTypeConstructor:
case DeclarationContext.ExtensionTypeFactory:
case DeclarationContext.ExtensionTypeInstanceField:
case DeclarationContext.ExtensionTypeInstanceMethod:
case DeclarationContext.ExtensionTypeStaticField:
case DeclarationContext.ExtensionTypeStaticMethod:
case DeclarationContext.Library:
case DeclarationContext.MixinBody:
case DeclarationContext.MixinConstructor:
case DeclarationContext.MixinFactory:
case DeclarationContext.MixinInstanceField:
case DeclarationContext.MixinInstanceMethod:
case DeclarationContext.MixinStaticField:
case DeclarationContext.MixinStaticMethod:
case DeclarationContext.TopLevelField:
case DeclarationContext.TopLevelMethod:
case DeclarationContext.Typedef:
return TypeVariableKind.function;
}
}
}
class OutlineBuilder extends StackListenerImpl {
final SourceCompilationUnit _compilationUnit;
final BuilderFactory _builderFactory;
final bool enableNative;
bool inAbstractOrSealedClass = false;
bool inConstructor = false;
bool inConstructorName = false;
int importIndex = 0;
String? nativeMethodName;
Link<DeclarationContext> _declarationContext = const Link();
/// Level of nesting of function-type type parameters
///
/// For instance, `X` is at nesting level 1, and `Y` is at nesting level 2 in
/// the following:
///
/// method() {
/// Function<X>(Function<Y extends X>(Y))? f;
/// }
///
/// For simplicity, non-generic functions are considered generic functions
/// with 0 type parameters.
int _structuralParameterDepthLevel = 0;
/// True if a type of a formal parameter is currently compiled
///
/// This variable is needed to distinguish between the type of a formal
/// parameter and its initializer because in those two regions of code the
/// type variables should be interpreted differently: as structural and
/// nominal correspondingly.
bool _insideOfFormalParameterType = false;
bool get inFunctionType =>
_structuralParameterDepthLevel > 0 || _insideOfFormalParameterType;
OffsetMap _offsetMap;
OutlineBuilder(this._compilationUnit, this._builderFactory, this._offsetMap)
: enableNative = _compilationUnit.loader.target.backendTarget
.enableNative(_compilationUnit.importUri);
@override
LibraryFeatures get libraryFeatures => _compilationUnit.libraryFeatures;
@override
bool get isDartLibrary => _compilationUnit.isDartLibrary;
@override
Message reportFeatureNotEnabled(
LibraryFeature feature, int charOffset, int length) {
return _compilationUnit.reportFeatureNotEnabled(
feature, uri, charOffset, length);
}
DeclarationContext get declarationContext => _declarationContext.head;
void pushDeclarationContext(DeclarationContext value) {
_declarationContext = _declarationContext.prepend(value);
}
void popDeclarationContext([DeclarationContext? expectedContext]) {
assert(
expectedContext == null || expectedContext == declarationContext,
// Coverage-ignore(suite): Not run.
"Unexpected declaration context: "
"Expected $expectedContext, actual $declarationContext.");
_declarationContext = _declarationContext.tail!;
}
@override
Uri get uri => _compilationUnit.fileUri;
int popCharOffset() => pop() as int;
List<String>? popIdentifierList(int count) {
assert(checkState(
null, repeatedKind(ValueKinds.IdentifierOrParserRecovery, count)));
if (count == 0) return null;
List<String> list = new List<String>.filled(count, /* dummyValue = */ '');
bool isParserRecovery = false;
for (int i = count - 1; i >= 0; i--) {
Object? identifier = pop();
if (identifier is ParserRecovery) {
isParserRecovery = true;
} else {
list[i] = (identifier as Identifier).name;
}
}
return isParserRecovery ? null : list;
}
@override
void beginCompilationUnit(Token token) {
pushDeclarationContext(DeclarationContext.Library);
}
@override
void endCompilationUnit(int count, Token token) {
popDeclarationContext(DeclarationContext.Library);
_builderFactory.checkStacks();
super.endCompilationUnit(count, token);
}
@override
void endMetadata(Token beginToken, Token? periodBeforeName, Token endToken) {
debugEvent("endMetadata");
assert(checkState(beginToken, [
/* arguments */ ValueKinds.ArgumentsTokenOrNull,
if (periodBeforeName != null) /* constructor name */
ValueKinds.IdentifierOrParserRecovery,
/* type arguments */ ValueKinds.TypeArgumentsOrNull,
/* prefix or constructor */ ValueKinds.IdentifierOrParserRecovery,
]));
pop(NullValues.Arguments); // arguments
if (periodBeforeName != null) {
pop(); // constructor name
}
pop(NullValues.TypeArguments); // type arguments
Object? sentinel = pop(); // prefix or constructor
push(sentinel is ParserRecovery
? sentinel
: new MetadataBuilder(beginToken));
}
@override
void endMetadataStar(int count) {
debugEvent("MetadataStar");
push(const FixedNullableList<MetadataBuilder>()
.popNonNullable(stack, count, dummyMetadataBuilder) ??
NullValues.Metadata);
}
@override
void handleInvalidTopLevelDeclaration(Token endToken) {
debugEvent("InvalidTopLevelDeclaration");
pop(); // metadata star
}
@override
void endHide(Token hideKeyword) {
debugEvent("endHide");
assert(checkState(hideKeyword, [
ValueKinds.NameListOrParserRecovery,
]));
Object? names = pop();
if (names is ParserRecovery) {
// Coverage-ignore-block(suite): Not run.
push(names);
} else {
push(new CombinatorBuilder.hide(names as Iterable<String>,
hideKeyword.charOffset, _compilationUnit.fileUri));
}
}
@override
void endShow(Token showKeyword) {
debugEvent("Show");
Object? names = pop();
if (names is ParserRecovery) {
// Coverage-ignore-block(suite): Not run.
push(names);
} else {
push(new CombinatorBuilder.show(names as Iterable<String>,
showKeyword.charOffset, _compilationUnit.fileUri));
}
}
@override
void endCombinators(int count) {
debugEvent("Combinators");
push(const FixedNullableList<CombinatorBuilder>()
.popNonNullable(stack, count, dummyCombinator) ??
NullValues.Combinators);
}
@override
void endExport(Token exportKeyword, Token semicolon) {
debugEvent("endExport");
assert(checkState(exportKeyword, [
/* show / hide combinators */ ValueKinds.CombinatorListOrNull,
/* configurations */ ValueKinds.ConfigurationListOrNull,
/* uri offset */ ValueKinds.Integer,
/* uri */ ValueKinds.Name,
/* metadata */ ValueKinds.MetadataListOrNull,
]));
List<CombinatorBuilder>? combinators =
pop(NullValues.Combinators) as List<CombinatorBuilder>?;
List<Configuration>? configurations =
pop(NullValues.ConditionalUris) as List<Configuration>?;
int uriOffset = popCharOffset();
String uri = pop() as String;
List<MetadataBuilder>? metadata = pop() as List<MetadataBuilder>?;
_builderFactory.addExport(_offsetMap, exportKeyword, metadata, uri,
configurations, combinators, exportKeyword.charOffset, uriOffset);
checkEmpty(exportKeyword.charOffset);
}
@override
void handleImportPrefix(Token? deferredKeyword, Token? asKeyword) {
debugEvent("handleImportPrefix");
if (asKeyword == null) {
// If asKeyword is null, then no prefix has been pushed on the stack.
// Push a placeholder indicating that there is no prefix.
push(NullValues.Prefix);
}
push(deferredKeyword != null);
}
@override
void endImport(Token importKeyword, Token? augmentToken, Token? semicolon) {
debugEvent("endImport");
assert(checkState(importKeyword, [
/* show / hide combinators */ ValueKinds.CombinatorListOrNull,
/* is deferred */ ValueKinds.Bool,
/* prefix */ ValueKinds.PrefixOrParserRecoveryOrNull,
/* configurations */ ValueKinds.ConfigurationListOrNull,
/* uri offset */ ValueKinds.Integer,
/* uri */ ValueKinds.Name,
/* metadata */ ValueKinds.MetadataListOrNull,
]));
List<CombinatorBuilder>? combinators =
pop(NullValues.Combinators) as List<CombinatorBuilder>?;
bool isDeferred = pop() as bool;
Object? prefix = pop(NullValues.Prefix);
List<Configuration>? configurations =
pop(NullValues.ConditionalUris) as List<Configuration>?;
int uriOffset = popCharOffset();
String uri =
pop() as String; // For a conditional import, this is the default URI.
List<MetadataBuilder>? metadata =
pop(NullValues.Metadata) as List<MetadataBuilder>?;
checkEmpty(importKeyword.charOffset);
if (prefix is! Identifier?) {
assert(
prefix is ParserRecovery,
// Coverage-ignore(suite): Not run.
"Unexpected prefix $prefix (${prefix.runtimeType}).");
return;
}
if (augmentToken != null) {
if (reportIfNotEnabled(libraryFeatures.macros, augmentToken.charOffset,
augmentToken.length)) {
augmentToken = null;
}
}
bool isAugmentationImport = augmentToken != null;
_builderFactory.addImport(
offsetMap: _offsetMap,
importKeyword: importKeyword,
metadata: metadata,
isAugmentationImport: isAugmentationImport,
uri: uri,
configurations: configurations,
prefix: prefix?.name,
combinators: combinators,
deferred: isDeferred,
charOffset: importKeyword.charOffset,
prefixCharOffset: prefix?.nameOffset ?? TreeNode.noOffset,
uriOffset: uriOffset,
importIndex: importIndex++);
}
@override
void endConditionalUris(int count) {
debugEvent("endConditionalUris");
push(const FixedNullableList<Configuration>()
.popNonNullable(stack, count, dummyConfiguration) ??
NullValues.ConditionalUris);
}
@override
void endConditionalUri(Token ifKeyword, Token leftParen, Token? equalSign) {
debugEvent("EndConditionalUri");
int charOffset = popCharOffset();
String uri = pop() as String;
if (equalSign != null) {
// Coverage-ignore-block(suite): Not run.
popCharOffset();
}
String condition = popIfNotNull(equalSign) as String? ?? "true";
Object? dottedName = pop();
if (dottedName is ParserRecovery) {
// Coverage-ignore-block(suite): Not run.
push(dottedName);
} else {
push(new Configuration(charOffset, dottedName as String, condition, uri));
}
}
@override
void handleDottedName(int count, Token firstIdentifier) {
debugEvent("DottedName");
assert(checkState(firstIdentifier,
repeatedKind(ValueKinds.IdentifierOrParserRecovery, count)));
List<String>? names = popIdentifierList(count);
if (names == null) {
// Coverage-ignore-block(suite): Not run.
push(new ParserRecovery(firstIdentifier.charOffset));
} else {
push(names.join('.'));
}
}
@override
void handleRecoverImport(Token? semicolon) {
debugEvent("handleRecoverImport");
assert(checkState(semicolon, [
/* show / hide combinators */ ValueKinds.CombinatorListOrNull,
/* is deferred */ ValueKinds.Bool,
/* prefix */ ValueKinds.PrefixOrParserRecoveryOrNull,
/* configurations */ ValueKinds.ConfigurationListOrNull,
]));
pop(NullValues.Combinators); // combinators
pop(NullValues.Deferred); // deferredKeyword
pop(NullValues.Prefix); // prefix
pop(NullValues.ConditionalUris); // conditionalUris
}
@override
void endPart(Token partKeyword, Token semicolon) {
debugEvent("endPart");
assert(checkState(partKeyword, [
/* uri string */ ValueKinds.ConfigurationListOrNull,
/* offset */ ValueKinds.Integer,
/* uri string */ ValueKinds.String,
/* metadata */ ValueKinds.MetadataListOrNull,
]));
pop(); // configurations
int charOffset = popCharOffset();
String uri = pop() as String;
List<MetadataBuilder>? metadata = pop() as List<MetadataBuilder>?;
_builderFactory.addPart(_offsetMap, partKeyword, metadata, uri, charOffset);
checkEmpty(partKeyword.charOffset);
}
@override
void handleOperatorName(Token operatorKeyword, Token token) {
debugEvent("handleOperatorName");
push(new OperatorIdentifier(token));
}
@override
// Coverage-ignore(suite): Not run.
void handleInvalidOperatorName(Token operatorKeyword, Token token) {
debugEvent("handleInvalidOperatorName");
push(new SimpleIdentifier(token));
}
@override
void handleIdentifier(Token token, IdentifierContext context) {
debugEvent("handleIdentifier");
if (context == IdentifierContext.enumValueDeclaration) {
List<MetadataBuilder>? metadata = pop() as List<MetadataBuilder>?;
if (token.isSynthetic) {
push(new ParserRecovery(token.charOffset));
} else {
push(new EnumConstantInfo(metadata, token.lexeme, token.charOffset));
}
} else {
if (!token.isSynthetic) {
push(new SimpleIdentifier(token));
} else {
// This comes from a synthetic token which is inserted by the parser in
// an attempt to recover. This almost always means that the parser has
// gotten very confused and we need to ignore the results.
push(new ParserRecovery(token.charOffset));
}
}
if (inConstructor && context == IdentifierContext.methodDeclaration) {
inConstructorName = true;
}
}
@override
void handleStringPart(Token token) {
debugEvent("StringPart");
// Ignore string parts - report error later.
}
@override
void endLiteralString(int interpolationCount, Token endToken) {
debugEvent("endLiteralString");
if (interpolationCount == 0) {
Token token = pop() as Token;
push(unescapeString(token.lexeme, token, this));
push(token.charOffset);
} else {
Token beginToken = pop() as Token;
int charOffset = beginToken.charOffset;
push("${MALFORMED_URI_SCHEME}:bad${charOffset}");
push(charOffset);
// Point to dollar sign
int interpolationOffset = charOffset + beginToken.lexeme.length;
addProblem(messageInterpolationInUri, interpolationOffset, 1);
}
}
@override
void handleNativeClause(Token nativeToken, bool hasName) {
debugEvent("NativeClause");
if (hasName) {
// Pop the native clause which in this case is a StringLiteral.
pop(); // Char offset.
Object? name = pop();
if (name is ParserRecovery) {
// Coverage-ignore-block(suite): Not run.
nativeMethodName = '';
} else {
nativeMethodName = name as String; // String.
}
} else {
nativeMethodName = '';
}
}
@override
// Coverage-ignore(suite): Not run.
void handleStringJuxtaposition(Token startToken, int literalCount) {
debugEvent("StringJuxtaposition");
List<String> list =
new List<String>.filled(literalCount, /* dummyValue = */ '');
int charOffset = -1;
for (int i = literalCount - 1; i >= 0; i--) {
charOffset = popCharOffset();
list[i] = pop() as String;
}
push(list.join(""));
push(charOffset);
}
@override
void handleIdentifierList(int count) {
debugEvent("endIdentifierList");
assert(checkState(
null, repeatedKind(ValueKinds.IdentifierOrParserRecovery, count)));
push(popIdentifierList(count) ??
// Coverage-ignore(suite): Not run.
(count == 0 ? NullValues.IdentifierList : new ParserRecovery(-1)));
}
@override
void handleQualified(Token period) {
assert(checkState(period, [
/*suffix*/ ValueKinds.IdentifierOrParserRecovery,
/*prefix*/ ValueKinds.IdentifierOrParserRecovery,
]));
debugEvent("handleQualified");
Object? suffix = pop();
Object prefix = pop()!;
if (prefix is! Identifier) {
// Coverage-ignore-block(suite): Not run.
assert(prefix is ParserRecovery,
"Unexpected prefix $prefix (${prefix.runtimeType})");
push(prefix);
} else if (suffix is! SimpleIdentifier) {
assert(
suffix is ParserRecovery,
// Coverage-ignore(suite): Not run.
"Unexpected suffix $suffix (${suffix.runtimeType})");
push(suffix);
} else {
push(suffix.withIdentifierQualifier(prefix));
}
}
@override
void endLibraryName(Token libraryKeyword, Token semicolon, bool hasName) {
debugEvent("endLibraryName");
assert(checkState(libraryKeyword, [
if (hasName) ValueKinds.IdentifierOrParserRecovery,
ValueKinds.MetadataListOrNull,
]));
Object? name = null;
if (hasName) {
name = pop();
}
String? libraryName;
List<MetadataBuilder>? metadata = pop() as List<MetadataBuilder>?;
if (name != null && name is! ParserRecovery) {
libraryName =
flattenName(name as Identifier, offsetForToken(libraryKeyword), uri);
} else {
reportIfNotEnabled(
libraryFeatures.unnamedLibraries, semicolon.charOffset, noLength);
}
_builderFactory.addLibraryDirective(
libraryName: libraryName, metadata: metadata, isAugment: false);
}
@override
// Coverage-ignore(suite): Not run.
void endLibraryAugmentation(
Token augmentKeyword, Token libraryKeyword, Token semicolon) {
debugEvent("endLibraryAugmentation");
assert(checkState(libraryKeyword, [
/* uri offset */ ValueKinds.Integer,
/* uri string */ ValueKinds.String,
/* metadata */ ValueKinds.MetadataListOrNull,
]));
// TODO(johnniwinther): Pass uri to [libraryBuilder] and verify it.
pop() as int;
pop() as String;
List<MetadataBuilder>? metadata = pop() as List<MetadataBuilder>?;
_builderFactory.addLibraryDirective(
libraryName: null, metadata: metadata, isAugment: true);
}
@override
void beginClassOrMixinOrNamedMixinApplicationPrelude(Token token) {
debugEvent("beginClassOrNamedMixinApplicationPrelude");
pushDeclarationContext(
DeclarationContext.ClassOrMixinOrNamedMixinApplication);
_builderFactory.beginClassOrNamedMixinApplicationHeader();
}
@override
void beginClassDeclaration(
Token begin,
Token? abstractToken,
Token? macroToken,
Token? sealedToken,
Token? baseToken,
Token? interfaceToken,
Token? finalToken,
Token? augmentToken,
Token? mixinToken,
Token name) {
debugEvent("beginClassDeclaration");
popDeclarationContext(
DeclarationContext.ClassOrMixinOrNamedMixinApplication);
pushDeclarationContext(DeclarationContext.Class);
List<NominalVariableBuilder>? typeVariables =
pop() as List<NominalVariableBuilder>?;
push(typeVariables ?? NullValues.NominalVariables);
if (macroToken != null) {
if (reportIfNotEnabled(
libraryFeatures.macros, macroToken.charOffset, macroToken.length)) {
macroToken = null;
}
}
if (sealedToken != null) {
if (reportIfNotEnabled(libraryFeatures.sealedClass,
sealedToken.charOffset, sealedToken.length)) {
sealedToken = null;
}
}
if (baseToken != null) {
if (reportIfNotEnabled(libraryFeatures.classModifiers,
baseToken.charOffset, baseToken.length)) {
baseToken = null;
}
}
if (interfaceToken != null) {
if (reportIfNotEnabled(libraryFeatures.classModifiers,
interfaceToken.charOffset, interfaceToken.length)) {
interfaceToken = null;
}
}
if (finalToken != null) {
if (reportIfNotEnabled(libraryFeatures.classModifiers,
finalToken.charOffset, finalToken.length)) {
finalToken = null;
}
}
if (mixinToken != null) {
if (reportIfNotEnabled(libraryFeatures.classModifiers,
mixinToken.charOffset, mixinToken.length)) {
mixinToken = null;
}
}
_builderFactory.beginClassDeclaration(
name.lexeme, name.charOffset, typeVariables);
_builderFactory.beginIndexedContainer(name.lexeme,
isExtensionTypeDeclaration: false);
inAbstractOrSealedClass = abstractToken != null || sealedToken != null;
push(abstractToken != null ? abstractMask : 0);
push(macroToken ?? NullValues.Token);
push(sealedToken ?? NullValues.Token);
push(baseToken ?? NullValues.Token);
push(interfaceToken ?? NullValues.Token);
push(finalToken ?? NullValues.Token);
push(augmentToken ?? NullValues.Token);
push(mixinToken ?? NullValues.Token);
}
@override
void beginMixinDeclaration(Token beginToken, Token? augmentToken,
Token? baseToken, Token mixinKeyword, Token name) {
debugEvent("beginMixinDeclaration");
popDeclarationContext(
DeclarationContext.ClassOrMixinOrNamedMixinApplication);
pushDeclarationContext(DeclarationContext.Mixin);
List<NominalVariableBuilder>? typeVariables =
pop() as List<NominalVariableBuilder>?;
if (baseToken != null) {
if (reportIfNotEnabled(libraryFeatures.classModifiers,
baseToken.charOffset, baseToken.length)) {
baseToken = null;
}
}
push(augmentToken ?? NullValues.Token);
push(baseToken ?? NullValues.Token);
push(typeVariables ?? NullValues.NominalVariables);
_builderFactory.beginMixinDeclaration(
name.lexeme, name.charOffset, typeVariables);
_builderFactory.beginIndexedContainer(name.lexeme,
isExtensionTypeDeclaration: false);
}
@override
void beginClassOrMixinOrExtensionBody(DeclarationKind kind, Token token) {
DeclarationContext declarationContext;
switch (kind) {
case DeclarationKind.TopLevel:
// Coverage-ignore(suite): Not run.
throw new UnsupportedError('Unexpected top level body.');
case DeclarationKind.Class:
declarationContext = DeclarationContext.ClassBody;
_builderFactory.beginClassBody();
break;
case DeclarationKind.Mixin:
declarationContext = DeclarationContext.MixinBody;
_builderFactory.beginMixinBody();
break;
case DeclarationKind.Extension:
declarationContext = DeclarationContext.ExtensionBody;
assert(checkState(token, [
unionOfKinds([ValueKinds.ParserRecovery, ValueKinds.TypeBuilder])
]));
Object? extensionThisType = peek();
// TODO(johnniwinther): Supply an invalid type as the extension on type.
_builderFactory.beginExtensionBody(
extensionThisType is TypeBuilder ? extensionThisType : null);
break;
case DeclarationKind.ExtensionType:
declarationContext = DeclarationContext.ExtensionTypeBody;
_builderFactory.beginExtensionTypeBody();
break;
// Coverage-ignore(suite): Not run.
case DeclarationKind.Enum:
declarationContext = DeclarationContext.Enum;
// [BuilderFactory.beginEnumBody] is called in [handleEnumHeader].
break;
}
pushDeclarationContext(declarationContext);
debugEvent("beginClassOrMixinBody");
}
@override
void beginNamedMixinApplication(
Token begin,
Token? abstractToken,
Token? macroToken,
Token? sealedToken,
Token? baseToken,
Token? interfaceToken,
Token? finalToken,
Token? augmentToken,
Token? mixinToken,
Token name) {
debugEvent("beginNamedMixinApplication");
popDeclarationContext(
DeclarationContext.ClassOrMixinOrNamedMixinApplication);
pushDeclarationContext(DeclarationContext.NamedMixinApplication);
List<NominalVariableBuilder>? typeVariables =
pop() as List<NominalVariableBuilder>?;
push(typeVariables ?? NullValues.NominalVariables);
_builderFactory.beginNamedMixinApplication(
name.lexeme, name.charOffset, typeVariables);
push(abstractToken != null ? abstractMask : 0);
if (macroToken != null) {
if (reportIfNotEnabled(
libraryFeatures.macros, macroToken.charOffset, macroToken.length)) {
macroToken = null;
}
}
if (sealedToken != null) {
if (reportIfNotEnabled(libraryFeatures.sealedClass,
sealedToken.charOffset, sealedToken.length)) {
sealedToken = null;
}
}
if (baseToken != null) {
if (reportIfNotEnabled(libraryFeatures.classModifiers,
baseToken.charOffset, baseToken.length)) {
baseToken = null;
}
}
if (interfaceToken != null) {
if (reportIfNotEnabled(libraryFeatures.classModifiers,
interfaceToken.charOffset, interfaceToken.length)) {
interfaceToken = null;
}
}
if (finalToken != null) {
if (reportIfNotEnabled(libraryFeatures.classModifiers,
finalToken.charOffset, finalToken.length)) {
finalToken = null;
}
}
if (mixinToken != null) {
if (reportIfNotEnabled(libraryFeatures.classModifiers,
mixinToken.charOffset, mixinToken.length)) {
mixinToken = null;
}
}
push(macroToken ?? NullValues.Token);
push(sealedToken ?? NullValues.Token);
push(baseToken ?? NullValues.Token);
push(interfaceToken ?? NullValues.Token);
push(finalToken ?? NullValues.Token);
push(augmentToken ?? NullValues.Token);
push(mixinToken ?? NullValues.Token);
}
@override
void handleImplements(Token? implementsKeyword, int interfacesCount) {
debugEvent("Implements");
push(const FixedNullableList<TypeBuilder>()
.popNonNullable(stack, interfacesCount, dummyTypeBuilder) ??
NullValues.TypeBuilderList);
if (implementsKeyword != null &&
declarationContext == DeclarationContext.Enum) {
reportIfNotEnabled(libraryFeatures.enhancedEnums,
implementsKeyword.charOffset, implementsKeyword.length);
}
}
@override
void handleRecoverDeclarationHeader(DeclarationHeaderKind kind) {
debugEvent("handleRecoverClassHeader");
assert(checkState(null, [
/* interfaces */ ValueKinds.TypeBuilderListOrNull,
/* mixins */ unionOfKinds([
ValueKinds.MixinApplicationBuilderOrNull,
ValueKinds.ParserRecovery,
]),
/* supertype offset */ ValueKinds.Integer,
/* supertype */ unionOfKinds([
ValueKinds.TypeBuilderOrNull,
ValueKinds.ParserRecovery,
]),
]));
// TODO(jensj): Possibly use these instead... E.g. "class A extend B {}"
// will get here (because it's 'extends' with an 's') and discard the B...
// Also Analyzer actually merges the information meaning that the two could
// give different errors (if, say, one later assigns
// A to a variable of type B).
pop(NullValues.TypeBuilderList); // Interfaces.
pop(NullValues.MixinApplicationBuilder); // Mixin applications.
pop(); // Supertype offset.
pop(NullValues.TypeBuilder); // Supertype.
}
@override
void handleRecoverMixinHeader() {
debugEvent("handleRecoverMixinHeader");
// TODO(jensj): Possibly use these instead...
// See also handleRecoverClassHeader
pop(NullValues.TypeBuilderList); // Interfaces.
pop(NullValues.TypeBuilderList); // Supertype constraints.
}
@override
void handleClassExtends(Token? extendsKeyword, int typeCount) {
debugEvent("handleClassExtends");
while (typeCount > 1) {
pop();
typeCount--;
}
push(extendsKeyword?.charOffset ?? -1);
}
@override
void handleMixinOn(Token? onKeyword, int typeCount) {
debugEvent("handleMixinOn");
push(const FixedNullableList<TypeBuilder>()
.popNonNullable(stack, typeCount, dummyTypeBuilder) ??
new ParserRecovery(offsetForToken(onKeyword)));
}
@override
void endClassDeclaration(Token beginToken, Token endToken) {
debugEvent("endClassDeclaration");
assert(checkState(beginToken, [
/* interfaces */ ValueKinds.TypeBuilderListOrNull,
/* mixins */ unionOfKinds([
ValueKinds.MixinApplicationBuilderOrNull,
ValueKinds.ParserRecovery,
]),
/* supertype offset */ ValueKinds.Integer,
/* supertype */ unionOfKinds([
ValueKinds.TypeBuilderOrNull,
ValueKinds.ParserRecovery,
]),
/* mixin token */ ValueKinds.TokenOrNull,
/* augment token */ ValueKinds.TokenOrNull,
/* final token */ ValueKinds.TokenOrNull,
/* interface token */ ValueKinds.TokenOrNull,
/* base token */ ValueKinds.TokenOrNull,
/* sealed token */ ValueKinds.TokenOrNull,
/* macro token */ ValueKinds.TokenOrNull,
/* modifiers */ ValueKinds.Integer,
/* type variables */ ValueKinds.NominalVariableListOrNull,
/* name */ ValueKinds.IdentifierOrParserRecovery,
/* metadata */ ValueKinds.MetadataListOrNull,
]));
List<TypeBuilder>? interfaces =
pop(NullValues.TypeBuilderList) as List<TypeBuilder>?;
MixinApplicationBuilder? mixinApplication =
nullIfParserRecovery(pop(NullValues.MixinApplicationBuilder))
as MixinApplicationBuilder?;
int supertypeOffset = popCharOffset();
TypeBuilder? supertype = nullIfParserRecovery(pop()) as TypeBuilder?;
Token? mixinToken = pop(NullValues.Token) as Token?;
Token? augmentToken = pop(NullValues.Token) as Token?;
Token? finalToken = pop(NullValues.Token) as Token?;
Token? interfaceToken = pop(NullValues.Token) as Token?;
Token? baseToken = pop(NullValues.Token) as Token?;
Token? sealedToken = pop(NullValues.Token) as Token?;
Token? macroToken = pop(NullValues.Token) as Token?;
int modifiers = pop() as int;
List<NominalVariableBuilder>? typeVariables =
pop() as List<NominalVariableBuilder>?;
Object? name = pop();
if (typeVariables != null && mixinApplication != null) {
mixinApplication.typeVariables = typeVariables;
}
List<MetadataBuilder>? metadata = pop() as List<MetadataBuilder>?;
inAbstractOrSealedClass = false;
checkEmpty(beginToken.charOffset);
if (name is ParserRecovery) {
// Coverage-ignore-block(suite): Not run.
_builderFactory.endClassDeclarationForParserRecovery(typeVariables);
} else {
Identifier identifier = name as Identifier;
final int startCharOffset =
metadata == null ? beginToken.charOffset : metadata.first.charOffset;
String classNameForErrors = identifier.name;
if (supertype != null) {
if (supertype.nullabilityBuilder.build() == Nullability.nullable) {
_compilationUnit.addProblem(
templateNullableSuperclassError
.withArguments(supertype.fullNameForErrors),
identifier.nameOffset,
classNameForErrors.length,
uri);
}
}
if (mixinApplication != null) {
List<TypeBuilder>? mixins = mixinApplication.mixins;
for (TypeBuilder mixin in mixins) {
if (mixin.nullabilityBuilder.build() == Nullability.nullable) {
_compilationUnit.addProblem(
templateNullableMixinError
.withArguments(mixin.fullNameForErrors),
identifier.nameOffset,
classNameForErrors.length,
uri);
}
}
}
if (interfaces != null) {
for (TypeBuilder interface in interfaces) {
if (interface.nullabilityBuilder.build() == Nullability.nullable) {
_compilationUnit.addProblem(
templateNullableInterfaceError
.withArguments(interface.fullNameForErrors),
identifier.nameOffset,
classNameForErrors.length,
uri);
}
}
}
if (sealedToken != null) {
modifiers |= abstractMask;
}
_builderFactory.addClass(
_offsetMap,
metadata,
modifiers,
identifier,
typeVariables,
supertype,
mixinApplication,
interfaces,
startCharOffset,
identifier.nameOffset,
endToken.charOffset,
supertypeOffset,
isMacro: macroToken != null,
isSealed: sealedToken != null,
isBase: baseToken != null,
isInterface: interfaceToken != null,
isFinal: finalToken != null,
isAugmentation: augmentToken != null,
isMixinClass: mixinToken != null);
}
_builderFactory.endIndexedContainer();
popDeclarationContext(DeclarationContext.Class);
}
Object? nullIfParserRecovery(Object? node) {
return node is ParserRecovery ? null : node;
}
@override
void endMixinDeclaration(Token beginToken, Token endToken) {
debugEvent("endMixinDeclaration");
assert(checkState(beginToken, [
/* interfaces */ ValueKinds.TypeBuilderListOrNull,
/* supertypeConstraints */ unionOfKinds([
ValueKinds.TypeBuilderListOrNull,
ValueKinds.ParserRecovery,
]),
/* type variables */ ValueKinds.NominalVariableListOrNull,
/* base token */ ValueKinds.TokenOrNull,
/* augment token */ ValueKinds.TokenOrNull,
/* name */ ValueKinds.IdentifierOrParserRecovery,
/* metadata */ ValueKinds.MetadataListOrNull,
]));
List<TypeBuilder>? interfaces =
pop(NullValues.TypeBuilderList) as List<TypeBuilder>?;
List<TypeBuilder>? supertypeConstraints =
nullIfParserRecovery(pop()) as List<TypeBuilder>?;
List<NominalVariableBuilder>? typeVariables =
pop(NullValues.NominalVariables) as List<NominalVariableBuilder>?;
Token? baseToken = pop(NullValues.Token) as Token?;
Token? augmentToken = pop(NullValues.Token) as Token?;
Object? name = pop();
List<MetadataBuilder>? metadata =
pop(NullValues.Metadata) as List<MetadataBuilder>?;
checkEmpty(beginToken.charOffset);
if (name is ParserRecovery) {
// Coverage-ignore-block(suite): Not run.
_builderFactory.endMixinDeclarationForParserRecovery(typeVariables);
} else {
Identifier identifier = name as Identifier;
int startOffset = metadata == null
? beginToken.charOffset
:
// Coverage-ignore(suite): Not run.
metadata.first.charOffset;
String classNameForErrors = identifier.name;
if (supertypeConstraints != null) {
for (TypeBuilder supertype in supertypeConstraints) {
if (supertype.nullabilityBuilder.build() == Nullability.nullable) {
_compilationUnit.addProblem(
templateNullableSuperclassError
.withArguments(supertype.fullNameForErrors),
identifier.nameOffset,
classNameForErrors.length,
uri);
}
}
}
if (interfaces != null) {
for (TypeBuilder interface in interfaces) {
if (interface.nullabilityBuilder.build() == Nullability.nullable) {
_compilationUnit.addProblem(
templateNullableInterfaceError
.withArguments(interface.fullNameForErrors),
identifier.nameOffset,
classNameForErrors.length,
uri);
}
}
}
_builderFactory.addMixinDeclaration(
_offsetMap,
metadata,
identifier,
typeVariables,
supertypeConstraints,
interfaces,
startOffset,
identifier.nameOffset,
endToken.charOffset,
-1,
isBase: baseToken != null,
isAugmentation: augmentToken != null);
}
_builderFactory.endIndexedContainer();
popDeclarationContext(DeclarationContext.Mixin);
}
@override
void beginExtensionDeclarationPrelude(Token extensionKeyword) {
assert(checkState(extensionKeyword, [ValueKinds.MetadataListOrNull]));
debugEvent("beginExtensionDeclaration");
pushDeclarationContext(DeclarationContext.ExtensionOrExtensionType);
_builderFactory.beginExtensionOrExtensionTypeHeader();
}
@override
void beginExtensionDeclaration(
Token? augmentToken, Token extensionKeyword, Token? nameToken) {
assert(checkState(extensionKeyword,
[ValueKinds.NominalVariableListOrNull, ValueKinds.MetadataListOrNull]));
debugEvent("beginExtensionDeclaration");
popDeclarationContext(DeclarationContext.ExtensionOrExtensionType);
pushDeclarationContext(DeclarationContext.Extension);
List<NominalVariableBuilder>? typeVariables =
pop() as List<NominalVariableBuilder>?;
int offset = nameToken?.charOffset ?? extensionKeyword.charOffset;
push(nameToken != null
? new SimpleIdentifier(nameToken)
: NullValues.Identifier);
push(typeVariables ?? NullValues.NominalVariables);
_builderFactory.beginExtensionDeclaration(
nameToken?.lexeme, offset, typeVariables);
}
@override
void endExtensionDeclaration(Token beginToken, Token extensionKeyword,
Token? onKeyword, Token endToken) {
assert(checkState(extensionKeyword, [
unionOfKinds([ValueKinds.ParserRecovery, ValueKinds.TypeBuilder]),
ValueKinds.NominalVariableListOrNull,
ValueKinds.IdentifierOrNull,
ValueKinds.MetadataListOrNull
]));
debugEvent("endExtensionDeclaration");
Object? onType = pop();
if (onType is ParserRecovery) {
ParserRecovery parserRecovery = onType;
onType = new FixedTypeBuilderImpl(
const InvalidType(), uri, parserRecovery.charOffset);
}
List<NominalVariableBuilder>? typeVariables =
pop(NullValues.NominalVariables) as List<NominalVariableBuilder>?;
Identifier? name = pop(NullValues.Identifier) as Identifier?;
int nameOffset = name?.nameOffset ?? extensionKeyword.charOffset;
List<MetadataBuilder>? metadata =
pop(NullValues.Metadata) as List<MetadataBuilder>?;
checkEmpty(extensionKeyword.charOffset);
int startOffset = metadata == null
? extensionKeyword.charOffset
: metadata.first.charOffset;
_builderFactory.addExtensionDeclaration(
_offsetMap,
beginToken,
metadata,
// TODO(johnniwinther): Support modifiers on extensions?
0,
name,
typeVariables,
onType as TypeBuilder,
startOffset,
nameOffset,
endToken.charOffset);
popDeclarationContext(DeclarationContext.Extension);
}
@override
void beginExtensionTypeDeclaration(
Token? augmentToken, Token extensionKeyword, Token nameToken) {
assert(checkState(extensionKeyword,
[ValueKinds.NominalVariableListOrNull, ValueKinds.MetadataListOrNull]));
debugEvent("beginExtensionTypeDeclaration");
popDeclarationContext(DeclarationContext.ExtensionOrExtensionType);
pushDeclarationContext(DeclarationContext.ExtensionType);
List<NominalVariableBuilder>? typeVariables =
pop() as List<NominalVariableBuilder>?;
String name = nameToken.lexeme;
int offset = nameToken.charOffset;
push(new SimpleIdentifier(nameToken));
push(typeVariables ?? NullValues.NominalVariables);
_builderFactory.beginExtensionTypeDeclaration(name, offset, typeVariables);
_builderFactory.beginIndexedContainer(name,
isExtensionTypeDeclaration: true);
}
@override
void endExtensionTypeDeclaration(Token beginToken, Token? augmentToken,
Token extensionKeyword, Token typeKeyword, Token endToken) {
assert(checkState(extensionKeyword, [
ValueKinds.TypeBuilderListOrNull,
ValueKinds.NominalVariableListOrNull,
ValueKinds.Identifier,
ValueKinds.MetadataListOrNull,
]));
reportIfNotEnabled(libraryFeatures.inlineClass, typeKeyword.charOffset,
typeKeyword.length);
List<TypeBuilder>? interfaces =
pop(NullValues.TypeBuilderList) as List<TypeBuilder>?;
List<NominalVariableBuilder>? typeVariables =
pop(NullValues.NominalVariables) as List<NominalVariableBuilder>?;
Identifier identifier = pop() as Identifier;
List<MetadataBuilder>? metadata =
pop(NullValues.Metadata) as List<MetadataBuilder>?;
checkEmpty(extensionKeyword.charOffset);
reportIfNotEnabled(libraryFeatures.inlineClass,
extensionKeyword.next!.charOffset, extensionKeyword.next!.length);
int startOffset = metadata == null
? extensionKeyword.charOffset
: metadata.first.charOffset;
_builderFactory.addExtensionTypeDeclaration(
_offsetMap,
metadata,
// TODO(johnniwinther): Support modifiers on extension types?
0,
identifier,
typeVariables,
interfaces,
startOffset,
endToken.charOffset);
_builderFactory.endIndexedContainer();
popDeclarationContext(DeclarationContext.ExtensionType);
}
@override
void beginPrimaryConstructor(Token beginToken) {}
@override
void endPrimaryConstructor(
Token beginToken, Token? constKeyword, bool hasConstructorName) {
assert(checkState(beginToken, [
ValueKinds.FormalListOrNull,
/* formals offset */ ValueKinds.Integer,
if (hasConstructorName) ValueKinds.IdentifierOrParserRecovery,
]));
List<FormalParameterBuilder>? formals =
pop(NullValues.FormalParameters) as List<FormalParameterBuilder>?;
int charOffset = pop() as int; // Pop formals char offset
String constructorName = '';
if (hasConstructorName) {
// TODO(johnniwinther): Handle [ParserRecovery].
Identifier identifier = pop() as Identifier;
charOffset = identifier.nameOffset;
constructorName = identifier.name;
}
bool inExtensionType =
declarationContext == DeclarationContext.ExtensionType;
if (formals != null) {
int requiredPositionalCount = 0;
int? firstNamedParameterOffset;
int? firstOptionalPositionalParameterOffset;
for (int i = 0; i < formals.length; i++) {
FormalParameterBuilder formal = formals[i];
if (inExtensionType) {
TypeBuilder type = formal.type;
if (type is FunctionTypeBuilder &&
type.hasFunctionFormalParameterSyntax) {
_compilationUnit.addProblem(
// ignore: lines_longer_than_80_chars
messageExtensionTypePrimaryConstructorFunctionFormalParameterSyntax,
formal.charOffset,
formal.name.length,
formal.fileUri);
}
if (type is ImplicitTypeBuilder) {
_compilationUnit.addProblem(messageExpectedRepresentationType,
formal.charOffset, formal.name.length, formal.fileUri);
formal.type =
new InvalidTypeBuilderImpl(formal.fileUri, formal.charOffset);
}
if (Modifier.maskContainsActualModifiers(
// 'covariant' is reported in the parser.
Modifier.removeCovariantMask(
// 'required' is reported in the parser.
Modifier.removeRequiredMask(formal.modifiers)))) {
_compilationUnit.addProblem(messageRepresentationFieldModifier,
formal.charOffset, formal.name.length, formal.fileUri);
}
if (formal.isInitializingFormal) {
_compilationUnit.addProblem(
messageExtensionTypePrimaryConstructorWithInitializingFormal,
formal.charOffset,
formal.name.length,
formal.fileUri);
}
}
if (formal.isPositional) {
if (formal.isOptionalPositional) {
firstOptionalPositionalParameterOffset = formal.charOffset;
} else {
requiredPositionalCount++;
}
}
if (formal.isNamed) {
firstNamedParameterOffset = formal.charOffset;
}
_builderFactory.addPrimaryConstructorField(
// TODO(johnniwinther): Support annotations on annotations on fields
// defined through a primary constructor. This is not needed for
// extension types where the field is not part of the AST but will
// be needed when primary constructors are generally supported.
metadata: null,
type: formal.type,
name: formal.name,
charOffset: formal.charOffset);
formals[i] = formal.forPrimaryConstructor(_builderFactory);
}
if (inExtensionType) {
if (firstOptionalPositionalParameterOffset != null) {
_compilationUnit.addProblem(
messageOptionalParametersInExtensionTypeDeclaration,
firstOptionalPositionalParameterOffset,
1,
uri);
} else if (firstNamedParameterOffset != null) {
_compilationUnit.addProblem(
messageNamedParametersInExtensionTypeDeclaration,
firstNamedParameterOffset,
1,
uri);
} else if (requiredPositionalCount == 0) {
_compilationUnit.addProblem(
messageExpectedRepresentationField, charOffset, 1, uri);
} else if (formals.length > 1) {
_compilationUnit.addProblem(
messageMultipleRepresentationFields, charOffset, 1, uri);
}
}
}
_builderFactory.addPrimaryConstructor(
offsetMap: _offsetMap,
beginToken: beginToken,
constructorName: constructorName == "new" ? "" : constructorName,
charOffset: charOffset,
formals: formals,
isConst: constKeyword != null);
}
ProcedureKind computeProcedureKind(Token? token) {
if (token == null) return ProcedureKind.Method;
if (optional("get", token)) return ProcedureKind.Getter;
if (optional("set", token)) return ProcedureKind.Setter;
return unhandled(
token.lexeme, "computeProcedureKind", token.charOffset, uri);
}
@override
void beginTopLevelMethod(
Token lastConsumed, Token? augmentToken, Token? externalToken) {
pushDeclarationContext(DeclarationContext.TopLevelMethod);
_builderFactory.beginTopLevelMethod();
int modifiers = 0;
if (augmentToken != null) {
modifiers |= augmentMask;
}
if (externalToken != null) {
modifiers |= externalMask;
}
push(modifiers);
}
@override
void endTopLevelMethod(Token beginToken, Token? getOrSet, Token endToken) {
debugEvent("endTopLevelMethod");
assert(checkState(beginToken, [
ValueKinds.MethodBody,
ValueKinds.AsyncMarker,
ValueKinds.FormalListOrNull,
/* formalsOffset */ ValueKinds.Integer,
ValueKinds.NominalVariableListOrNull,
ValueKinds.IdentifierOrParserRecovery,
ValueKinds.TypeBuilderOrNull,
/* modifiers */ ValueKinds.Integer,
ValueKinds.MetadataListOrNull,
]));
MethodBody kind = pop() as MethodBody;
AsyncMarker asyncModifier = pop() as AsyncMarker;
List<FormalParameterBuilder>? formals =
pop() as List<FormalParameterBuilder>?;
int formalsOffset = popCharOffset();
List<NominalVariableBuilder>? typeVariables =
pop() as List<NominalVariableBuilder>?;
Object? identifier = pop();
TypeBuilder? returnType = pop() as TypeBuilder?;
bool isAbstract = kind == MethodBody.Abstract;
if (getOrSet != null && optional("set", getOrSet)) {
if (formals == null || formals.length != 1) {
// This isn't abstract as we'll add an error-recovery node in
// [BodyBuilder.finishFunction].
isAbstract = false;
}
if (returnType != null && !returnType.isVoidType) {
addProblem(messageNonVoidReturnSetter, beginToken.charOffset, noLength);
// Use implicit void as recovery.
returnType = null;
}
}
int modifiers = pop() as int;
modifiers = Modifier.addAbstractMask(modifiers, isAbstract: isAbstract);
if (nativeMethodName != null) {
modifiers |= externalMask;
}
List<MetadataBuilder>? metadata = pop() as List<MetadataBuilder>?;
checkEmpty(beginToken.charOffset);
if (identifier is Identifier) {
_builderFactory.endTopLevelMethod();
final int startCharOffset =
metadata == null ? beginToken.charOffset : metadata.first.charOffset;
_builderFactory.addProcedure(
_offsetMap,
metadata,
modifiers,
returnType,
identifier,
identifier.name,
typeVariables,
formals,
computeProcedureKind(getOrSet),
startCharOffset,
identifier.nameOffset,
formalsOffset,
endToken.charOffset,
nativeMethodName,
asyncModifier,
isInstanceMember: false,
isExtensionMember: false,
isExtensionTypeMember: false);
nativeMethodName = null;
} else {
_builderFactory.endTopLevelMethodForParserRecovery(typeVariables);
}
popDeclarationContext(DeclarationContext.TopLevelMethod);
}
@override
// Coverage-ignore(suite): Not run.
void handleNativeFunctionBody(Token nativeToken, Token semicolon) {
debugEvent("NativeFunctionBody");
if (nativeMethodName != null) {
push(MethodBody.Regular);
} else {
push(MethodBody.Abstract);
}
}
@override
// Coverage-ignore(suite): Not run.
void handleNativeFunctionBodyIgnored(Token nativeToken, Token semicolon) {
debugEvent("NativeFunctionBodyIgnored");
}
@override
void handleNativeFunctionBodySkipped(Token nativeToken, Token semicolon) {
if (!enableNative) {
super.handleRecoverableError(
messageExpectedBlockToSkip, nativeToken, nativeToken);
}
push(MethodBody.Regular);
}
@override
void handleNoFunctionBody(Token token) {
debugEvent("NoFunctionBody");
if (nativeMethodName != null) {
// Coverage-ignore-block(suite): Not run.
push(MethodBody.Regular);
} else {
push(MethodBody.Abstract);
}
}
@override
void handleFunctionBodySkipped(Token token, bool isExpressionBody) {
debugEvent("handleFunctionBodySkipped");
push(MethodBody.Regular);
}
@override
void beginMethod(
DeclarationKind declarationKind,
Token? augmentToken,
Token? externalToken,
Token? staticToken,
Token? covariantToken,
Token? varFinalOrConst,
Token? getOrSet,
Token name) {
inConstructor =
name.lexeme == _builderFactory.currentTypeParameterScopeBuilder.name &&
getOrSet == null;
DeclarationContext declarationContext;
switch (declarationKind) {
case DeclarationKind.TopLevel:
// Coverage-ignore(suite): Not run.
assert(
false,
"Expected top level method to be handled by "
"`beginTopLevelMethod`.");
declarationContext = DeclarationContext.TopLevelMethod;
break;
case DeclarationKind.Class:
if (inConstructor) {
declarationContext = DeclarationContext.ClassConstructor;
} else if (staticToken != null) {
declarationContext = DeclarationContext.ClassStaticMethod;
} else {
declarationContext = DeclarationContext.ClassInstanceMethod;
}
break;
case DeclarationKind.Mixin:
if (inConstructor) {
declarationContext = DeclarationContext.MixinConstructor;
} else if (staticToken != null) {
declarationContext = DeclarationContext.MixinStaticMethod;
} else {
declarationContext = DeclarationContext.MixinInstanceMethod;
}
break;
case DeclarationKind.Extension:
if (inConstructor) {
declarationContext = DeclarationContext.ExtensionConstructor;
} else if (staticToken != null) {
declarationContext = DeclarationContext.ExtensionStaticMethod;
} else {
declarationContext = DeclarationContext.ExtensionInstanceMethod;
}
break;
case DeclarationKind.ExtensionType:
if (inConstructor) {
declarationContext = DeclarationContext.ExtensionTypeConstructor;
} else if (staticToken != null) {
declarationContext = DeclarationContext.ExtensionTypeStaticMethod;
} else {
declarationContext = DeclarationContext.ExtensionTypeInstanceMethod;
}
break;
case DeclarationKind.Enum:
if (inConstructor) {
declarationContext = DeclarationContext.EnumConstructor;
} else if (staticToken != null) {
declarationContext = DeclarationContext.EnumStaticMethod;
} else {
declarationContext = DeclarationContext.EnumInstanceMethod;
}
}
pushDeclarationContext(declarationContext);
List<Modifier>? modifiers;
if (augmentToken != null) {
modifiers ??= <Modifier>[];
modifiers.add(Augment);
}
if (externalToken != null) {
modifiers ??= <Modifier>[];
modifiers.add(External);
}
if (staticToken != null) {
if (!inConstructor) {
modifiers ??= <Modifier>[];
modifiers.add(Static);
}
}
if (covariantToken != null) {
// Coverage-ignore-block(suite): Not run.
modifiers ??= <Modifier>[];
modifiers.add(Covariant);
}
if (varFinalOrConst != null) {
String lexeme = varFinalOrConst.lexeme;
if (identical('var', lexeme)) {
// Coverage-ignore-block(suite): Not run.
modifiers ??= <Modifier>[];
modifiers.add(Var);
} else if (identical('final', lexeme)) {
// Coverage-ignore-block(suite): Not run.
modifiers ??= <Modifier>[];
modifiers.add(Final);
} else {
modifiers ??= <Modifier>[];
modifiers.add(Const);
}
}
push(varFinalOrConst?.charOffset ?? -1);
push(modifiers ?? NullValues.Modifiers);
if (inConstructor) {
_builderFactory.beginConstructor();
} else if (staticToken != null) {
_builderFactory.beginStaticMethod();
} else {
_builderFactory.beginInstanceMethod();
}
}
@override
void endClassMethod(Token? getOrSet, Token beginToken, Token beginParam,
Token? beginInitializers, Token endToken) {
debugEvent("endClassMethod");
_endClassMethod(getOrSet, beginToken, beginParam, beginInitializers,
endToken, _MethodKind.classMethod);
}
@override
void endClassConstructor(Token? getOrSet, Token beginToken, Token beginParam,
Token? beginInitializers, Token endToken) {
debugEvent("endClassConstructor");
_endClassMethod(getOrSet, beginToken, beginParam, beginInitializers,
endToken, _MethodKind.classConstructor);
}
@override
void endMixinMethod(Token? getOrSet, Token beginToken, Token beginParam,
Token? beginInitializers, Token endToken) {
debugEvent("endMixinMethod");
_endClassMethod(getOrSet, beginToken, beginParam, beginInitializers,
endToken, _MethodKind.mixinMethod);
}
@override
void endExtensionMethod(Token? getOrSet, Token beginToken, Token beginParam,
Token? beginInitializers, Token endToken) {
debugEvent("endExtensionMethod");
_endClassMethod(getOrSet, beginToken, beginParam, beginInitializers,
endToken, _MethodKind.extensionMethod);
}
@override
void endExtensionTypeMethod(Token? getOrSet, Token beginToken,
Token beginParam, Token? beginInitializers, Token endToken) {
debugEvent("endExtensionTypeMethod");
_endClassMethod(getOrSet, beginToken, beginParam, beginInitializers,
endToken, _MethodKind.extensionTypeMethod);
}
@override
void endMixinConstructor(Token? getOrSet, Token beginToken, Token beginParam,
Token? beginInitializers, Token endToken) {
debugEvent("endMixinConstructor");
_endClassMethod(getOrSet, beginToken, beginParam, beginInitializers,
endToken, _MethodKind.mixinConstructor);
}
@override
void endExtensionConstructor(Token? getOrSet, Token beginToken,
Token beginParam, Token? beginInitializers, Token endToken) {
debugEvent("endExtensionConstructor");
_endClassMethod(getOrSet, beginToken, beginParam, beginInitializers,
endToken, _MethodKind.extensionConstructor);
}
@override
void endExtensionTypeConstructor(Token? getOrSet, Token beginToken,
Token beginParam, Token? beginInitializers, Token endToken) {
debugEvent("endExtensionTypeConstructor");
_endClassMethod(getOrSet, beginToken, beginParam, beginInitializers,
endToken, _MethodKind.extensionTypeConstructor);
}
void _endClassMethod(Token? getOrSet, Token beginToken, Token beginParam,
Token? beginInitializers, Token endToken, _MethodKind methodKind) {
assert(checkState(beginToken, [ValueKinds.MethodBody]));
MethodBody bodyKind = pop() as MethodBody;
if (bodyKind == MethodBody.RedirectingFactoryBody) {
// This will cause an error later.
pop();
}
assert(checkState(beginToken, [
ValueKinds.AsyncModifier,
ValueKinds.FormalListOrNull,
ValueKinds.Integer, // formals offset
ValueKinds.NominalVariableListOrNull,
ValueKinds.IdentifierOrParserRecovery,
ValueKinds.TypeBuilderOrNull,
ValueKinds.ModifiersOrNull,
ValueKinds.Integer, // var/final/const offset
ValueKinds.MetadataListOrNull,
]));
AsyncMarker asyncModifier = pop() as AsyncMarker;
List<FormalParameterBuilder>? formals =
pop() as List<FormalParameterBuilder>?;
int formalsOffset = popCharOffset();
List<NominalVariableBuilder>? typeVariables =
pop() as List<NominalVariableBuilder>?;
Object? identifier = pop();
TypeBuilder? returnType = pop() as TypeBuilder?;
int modifiers = Modifier.toMask(pop() as List<Modifier>?);
int varFinalOrConstOffset = popCharOffset();
List<MetadataBuilder>? metadata = pop() as List<MetadataBuilder>?;
if (identifier is! Identifier) {
assert(
identifier is ParserRecovery,
// Coverage-ignore(suite): Not run.
"Unexpected identifier $identifier (${identifier.runtimeType})");
if (inConstructor) {
_builderFactory.endConstructorForParserRecovery(typeVariables);
} else if ((modifiers & staticMask) != 0) {
// Coverage-ignore-block(suite): Not run.
_builderFactory.endStaticMethodForParserRecovery(typeVariables);
} else {
_builderFactory.endInstanceMethodForParserRecovery(typeVariables);
}
nativeMethodName = null;
inConstructor = false;
popDeclarationContext();
return;
}
Operator? operator = identifier.operator;
// TODO(johnniwinther): Find a uniform way to compute this.
bool hasNoFormals = formals == null;
if (Operator.subtract == operator && hasNoFormals) {
operator = Operator.unaryMinus;
}
String name;
ProcedureKind? kind;
int charOffset = identifier.qualifierOffset;
if (operator != null) {
name = operator.text;
kind = ProcedureKind.Operator;
int requiredArgumentCount = operator.requiredArgumentCount;
if ((formals?.length ?? 0) != requiredArgumentCount) {
Template<Message Function(String name)> template;
switch (requiredArgumentCount) {
case 0:
template = templateOperatorParameterMismatch0;
break;
case 1:
if (Operator.subtract == operator) {
template = templateOperatorMinusParameterMismatch;
} else {
template = templateOperatorParameterMismatch1;
}
break;
case 2:
template = templateOperatorParameterMismatch2;
break;
// Coverage-ignore(suite): Not run.
default:
unhandled("$requiredArgumentCount", "operatorRequiredArgumentCount",
identifier.nameOffset, uri);
}
addProblem(template.withArguments(name), charOffset, name.length);
} else {
if (formals != null) {
for (FormalParameterBuilder formal in formals) {
if (!formal.isRequiredPositional) {
addProblem(messageOperatorWithOptionalFormals, formal.charOffset,
formal.name.length);
}
}
}
}
if (typeVariables != null) {
NominalVariableBuilder typeVariableBuilder = typeVariables.first;
addProblem(messageOperatorWithTypeParameters,
typeVariableBuilder.charOffset, typeVariableBuilder.name.length);
}
} else {
name = identifier.name;
kind = computeProcedureKind(getOrSet);
}
bool isAbstract = bodyKind == MethodBody.Abstract;
if (isAbstract) {
// An error has been reported if this wasn't already sync.
asyncModifier = AsyncMarker.Sync;
}
if (getOrSet != null && optional("set", getOrSet)) {
if (formals == null || formals.length != 1) {
// This isn't abstract as we'll add an error-recovery node in
// [BodyBuilder.finishFunction].
isAbstract = false;
}
if (returnType != null && !returnType.isVoidType) {
addProblem(
messageNonVoidReturnSetter,
returnType.charOffset ?? // Coverage-ignore(suite): Not run.
beginToken.charOffset,
noLength);
// Use implicit void as recovery.
returnType = null;
}
}
if (operator == Operator.indexSet &&
returnType != null &&
!returnType.isVoidType) {
addProblem(
messageNonVoidReturnOperator,
returnType.charOffset ?? // Coverage-ignore(suite): Not run.
beginToken.offset,
noLength);
// Use implicit void as recovery.
returnType = null;
}
modifiers = Modifier.addAbstractMask(modifiers, isAbstract: isAbstract);
if (nativeMethodName != null) {
modifiers |= externalMask;
}
bool isConst = (modifiers & constMask) != 0;
bool isStatic = (modifiers & staticMask) != 0;
bool isConstructor = switch (methodKind) {
_MethodKind.classConstructor => true,
_MethodKind.mixinConstructor => true,
_MethodKind.extensionConstructor => true,
_MethodKind.extensionTypeConstructor => true,
_MethodKind.enumConstructor => true,
_MethodKind.classMethod => false,
_MethodKind.mixinMethod => false,
_MethodKind.extensionMethod => false,
_MethodKind.extensionTypeMethod => false,
_MethodKind.enumMethod => false,
};
if (isConstructor) {
if (isConst &&
bodyKind != MethodBody.Abstract &&
!libraryFeatures.constFunctions.isEnabled) {
addProblem(messageConstConstructorWithBody, varFinalOrConstOffset, 5);
modifiers &= ~constMask;
}
if (returnType != null) {
addProblem(
messageConstructorWithReturnType,
returnType.charOffset ?? // Coverage-ignore(suite): Not run.
beginToken.offset,
noLength);
returnType = null;
}
} else {
if (isConst) {
// Coverage-ignore-block(suite): Not run.
// TODO(danrubel): consider removing this
// because it is an error to have a const method.
modifiers &= ~constMask;
}
}
int startCharOffset =
metadata == null ? beginToken.charOffset : metadata.first.charOffset;
int endCharOffset = endToken.charOffset;
bool forAbstractClassOrMixin =
inAbstractOrSealedClass || methodKind == _MethodKind.mixinConstructor;
bool isExtensionMember = methodKind == _MethodKind.extensionMethod;
bool isExtensionTypeMember = methodKind == _MethodKind.extensionTypeMethod;
_builderFactory.addClassMethod(
offsetMap: _offsetMap,
metadata: metadata,
identifier: identifier,
name: name,
returnType: returnType,
formals: formals,
typeVariables: typeVariables,
beginInitializers: beginInitializers,
startCharOffset: startCharOffset,
endCharOffset: endCharOffset,
charOffset: charOffset,
formalsOffset: formalsOffset,
modifiers: modifiers,
inConstructor: inConstructor,
isStatic: isStatic,
isConstructor: isConstructor,
isExtensionMember: isExtensionMember,
isExtensionTypeMember: isExtensionTypeMember,
forAbstractClassOrMixin: forAbstractClassOrMixin,
asyncModifier: asyncModifier,
nativeMethodName: nativeMethodName,
kind: kind);
nativeMethodName = null;
inConstructor = false;
popDeclarationContext();
}
@override
void handleNamedMixinApplicationWithClause(Token withKeyword) {
debugEvent("NamedMixinApplicationWithClause");
assert(checkState(withKeyword, [
/* mixins */ unionOfKinds([
ValueKinds.ParserRecovery,
ValueKinds.TypeBuilderListOrNull,
]),
/* supertype */ unionOfKinds([
ValueKinds.ParserRecovery,
ValueKinds.TypeBuilder,
]),
]));
Object? mixins = pop();
if (mixins is ParserRecovery) {
push(mixins);
} else {
push(_builderFactory.addMixinApplication(
mixins as List<TypeBuilder>, withKeyword.charOffset));
}
assert(checkState(withKeyword, [
/* mixin application */ unionOfKinds([
ValueKinds.ParserRecovery,
ValueKinds.MixinApplicationBuilder,
]),
/* supertype */ unionOfKinds([
ValueKinds.ParserRecovery,
ValueKinds.TypeBuilder,
]),
]));
}
@override
void handleNamedArgument(Token colon) {
debugEvent("handleNamedArgument");
assert(checkState(colon, [
ValueKinds.IdentifierOrParserRecovery,
]));
pop(); // Named argument name.
}
@override
// Coverage-ignore(suite): Not run.
void handleNamedRecordField(Token colon) {
debugEvent("handleNamedRecordField");
assert(checkState(colon, [
ValueKinds.IdentifierOrParserRecovery,
]));
pop(); // Named record field name.
}
@override
void endNamedMixinApplication(Token beginToken, Token classKeyword,
Token equals, Token? implementsKeyword, Token endToken) {
debugEvent("endNamedMixinApplication");
assert(checkState(beginToken, [
if (implementsKeyword != null)
/* interfaces */ unionOfKinds([
ValueKinds.ParserRecovery,
ValueKinds.TypeBuilderListOrNull,
]),
/* mixin application */ unionOfKinds([
ValueKinds.ParserRecovery,
ValueKinds.MixinApplicationBuilder,
]),
/* supertype */ unionOfKinds([
ValueKinds.ParserRecovery,
ValueKinds.TypeBuilder,
]),
/* mixin token */ ValueKinds.TokenOrNull,
/* augment token */ ValueKinds.TokenOrNull,
/* final token */ ValueKinds.TokenOrNull,
/* interface token */ ValueKinds.TokenOrNull,
/* base token */ ValueKinds.TokenOrNull,
/* sealed token */ ValueKinds.TokenOrNull,
/* macro token */ ValueKinds.TokenOrNull,
/* modifiers */ ValueKinds.Integer,
/* type variables */ ValueKinds.NominalVariableListOrNull,
/* name */ ValueKinds.IdentifierOrParserRecovery,
/* metadata */ ValueKinds.MetadataListOrNull,
]));
List<TypeBuilder>? interfaces =
nullIfParserRecovery(popIfNotNull(implementsKeyword))
as List<TypeBuilder>?;
Object? mixinApplication = pop();
Object? supertype = pop();
Token? mixinToken = pop(NullValues.Token) as Token?;
Token? augmentToken = pop(NullValues.Token) as Token?;
Token? finalToken = pop(NullValues.Token) as Token?;
Token? interfaceToken = pop(NullValues.Token) as Token?;
Token? baseToken = pop(NullValues.Token) as Token?;
Token? sealedToken = pop(NullValues.Token) as Token?;
Token? macroToken = pop(NullValues.Token) as Token?;
int modifiers = pop() as int;
List<NominalVariableBuilder>? typeVariables =
pop() as List<NominalVariableBuilder>?;
Object? name = pop();
List<MetadataBuilder>? metadata = pop() as List<MetadataBuilder>?;
checkEmpty(beginToken.charOffset);
if (name is ParserRecovery ||
supertype is ParserRecovery ||
mixinApplication is ParserRecovery) {
_builderFactory.endNamedMixinApplicationForParserRecovery(typeVariables);
} else {
Identifier identifier = name as Identifier;
String classNameForErrors = identifier.name;
MixinApplicationBuilder mixinApplicationBuilder =
mixinApplication as MixinApplicationBuilder;
List<TypeBuilder> mixins = mixinApplicationBuilder.mixins;
if (supertype is TypeBuilder && supertype is! MixinApplicationBuilder) {
if (supertype.nullabilityBuilder.build() == Nullability.nullable) {
_compilationUnit.addProblem(
templateNullableSuperclassError
.withArguments(supertype.fullNameForErrors),
identifier.nameOffset,
classNameForErrors.length,
uri);
}
}
for (TypeBuilder mixin in mixins) {
if (mixin.nullabilityBuilder.build() == Nullability.nullable) {
_compilationUnit.addProblem(
templateNullableMixinError.withArguments(mixin.fullNameForErrors),
identifier.nameOffset,
classNameForErrors.length,
uri);
}
}
if (interfaces != null) {
for (TypeBuilder interface in interfaces) {
if (interface.nullabilityBuilder.build() == Nullability.nullable) {
_compilationUnit.addProblem(
templateNullableInterfaceError
.withArguments(interface.fullNameForErrors),
identifier.nameOffset,
classNameForErrors.length,
uri);
}
}
}
if (sealedToken != null) {
modifiers |= abstractMask;
}
int startCharOffset = beginToken.charOffset;
int charEndOffset = endToken.charOffset;
_builderFactory.addNamedMixinApplication(
metadata,
identifier.name,
typeVariables,
modifiers,
supertype as TypeBuilder?,
mixinApplication,
interfaces,
startCharOffset,
identifier.nameOffset,
charEndOffset,
isMacro: macroToken != null,
isSealed: sealedToken != null,
isBase: baseToken != null,
isInterface: interfaceToken != null,
isFinal: finalToken != null,
isAugmentation: augmentToken != null,
isMixinClass: mixinToken != null);
}
popDeclarationContext(DeclarationContext.NamedMixinApplication);
}
@override
void endTypeArguments(int count, Token beginToken, Token endToken) {
debugEvent("endTypeArguments");
push(const FixedNullableList<TypeBuilder>()
.popNonNullable(stack, count, dummyTypeBuilder) ??
NullValues.TypeArguments);
}
@override
void endArguments(int count, Token beginToken, Token endToken) {
debugEvent("endArguments");
push(beginToken);
}
@override
// Coverage-ignore(suite): Not run.
void handleInvalidTypeArguments(Token token) {
debugEvent("handleInvalidTypeArguments");
pop(NullValues.TypeArguments);
}
@override
void handleScript(Token token) {
debugEvent("handleScript");
_builderFactory.addScriptToken(token.charOffset);
}
@override
// Coverage-ignore(suite): Not run.
void handleNonNullAssertExpression(Token bang) {}
@override
void handleType(Token beginToken, Token? questionMark) {
debugEvent("handleType");
assert(checkState(beginToken, [
/* type arguments = */ ValueKinds.TypeArgumentsOrNull,
/* identifier */ ValueKinds.IdentifierOrParserRecovery,
]));
bool isMarkedAsNullable = questionMark != null;
List<TypeBuilder>? arguments = pop() as List<TypeBuilder>?;
Object name = pop()!;
if (name is ParserRecovery) {
push(name);
} else {
Identifier identifier = name as Identifier;
push(_builderFactory.addNamedType(
identifier.typeName,
isMarkedAsNullable
? const NullabilityBuilder.nullable()
: const NullabilityBuilder.omitted(),
arguments,
identifier.qualifierOffset,
instanceTypeVariableAccess:
declarationContext.instanceTypeVariableAccessState));
}
}
@override
void endTypeList(int count) {
debugEvent("TypeList");
push(const FixedNullableList<TypeBuilder>()
.popNonNullable(stack, count, dummyTypeBuilder) ??
new ParserRecovery(-1));
}
@override
void handleNoArguments(Token token) {
debugEvent("NoArguments");
push(NullValues.Arguments);
}
@override
void handleNoTypeVariables(Token token) {
super.handleNoTypeVariables(token);
inConstructorName = false;
}
@override
void handleNoTypeArguments(Token token) {
debugEvent("NoTypeArguments");
push(NullValues.TypeArguments);
}
@override
void handleNoTypeNameInConstructorReference(Token token) {
debugEvent("NoTypeNameInConstructorReference");
push(NullValues.Identifier);
}
@override
void handleVoidKeyword(Token token) {
debugEvent("VoidKeyword");
push(_builderFactory.addVoidType(token.charOffset));
}
@override
void handleVoidKeywordWithTypeArguments(Token token) {
debugEvent("VoidKeyword");
/*List<TypeBuilder> arguments =*/ pop();
push(_builderFactory.addVoidType(token.charOffset));
}
@override
void beginFormalParameter(Token token, MemberKind kind, Token? requiredToken,
Token? covariantToken, Token? varFinalOrConst) {
_insideOfFormalParameterType = true;
push((covariantToken != null ? covariantMask : 0) |
(requiredToken != null ? requiredMask : 0) |
Modifier.validateVarFinalOrConst(varFinalOrConst?.lexeme));
}
@override
void endFormalParameter(
Token? thisKeyword,
Token? superKeyword,
Token? periodAfterThisOrSuper,
Token nameToken,
Token? initializerStart,
Token? initializerEnd,
FormalParameterKind kind,
MemberKind memberKind) {
debugEvent("endFormalParameter");
assert(checkState(nameToken, [
ValueKinds.IdentifierOrParserRecoveryOrNull,
unionOfKinds([
ValueKinds.TypeBuilderOrNull,
ValueKinds.ParserRecovery,
]),
/* modifiers */ ValueKinds.Integer,
ValueKinds.MetadataListOrNull,
]));
_insideOfFormalParameterType = false;
if (superKeyword != null) {
reportIfNotEnabled(libraryFeatures.superParameters,
superKeyword.charOffset, superKeyword.length);
}
Object? name = pop(NullValues.Identifier);
TypeBuilder? type = nullIfParserRecovery(pop()) as TypeBuilder?;
int modifiers = pop() as int;
List<MetadataBuilder>? metadata = pop() as List<MetadataBuilder>?;
if (name is ParserRecovery) {
push(name);
} else {
Identifier? identifier = name as Identifier?;
push(_builderFactory.addFormalParameter(
metadata,
kind,
modifiers,
type ??
(memberKind.isParameterInferable
? _builderFactory.addInferableType()
: const ImplicitTypeBuilder()),
identifier == null
? FormalParameterBuilder.noNameSentinel
: identifier.name,
thisKeyword != null,
superKeyword != null,
identifier?.nameOffset ?? nameToken.charOffset,
initializerStart,
// Extension type parameters should not have a lowered name for
// wildcard variables.
lowerWildcard:
declarationContext != DeclarationContext.ExtensionType));
}
}
@override
void beginFormalParameterDefaultValueExpression() {
_insideOfFormalParameterType = false;
}
@override
void endFormalParameterDefaultValueExpression() {
debugEvent("endFormalParameterDefaultValueExpression");
// Ignored for now.
}
@override
void handleValuedFormalParameter(
Token equals, Token token, FormalParameterKind kind) {
debugEvent("handleValuedFormalParameter");
// Ignored for now.
}
@override
void handleFormalParameterWithoutValue(Token token) {
debugEvent("handleFormalParameterWithoutValue");
// Ignored for now.
}
@override
void endOptionalFormalParameters(
int count, Token beginToken, Token endToken, MemberKind kind) {
debugEvent("endOptionalFormalParameters");
// When recovering from an empty list of optional arguments, count may be
// 0. It might be simpler if the parser didn't call this method in that
// case, however, then [beginOptionalFormalParameters] wouldn't always be
// matched by this method.
List<FormalParameterBuilder>? parameters =
const FixedNullableList<FormalParameterBuilder>()
.popNonNullable(stack, count, dummyFormalParameterBuilder);
if (parameters == null) {
push(new ParserRecovery(offsetForToken(beginToken)));
} else {
push(parameters);
}
}
@override
void endFormalParameters(
int count, Token beginToken, Token endToken, MemberKind kind) {
debugEvent("FormalParameters");
List<FormalParameterBuilder>? formals;
if (count == 1) {
Object? last = pop();
if (last is List<FormalParameterBuilder>) {
formals = last;
} else if (last is! ParserRecovery) {
assert(last != null);
formals = [last as FormalParameterBuilder];
}
Token? tokenBeforeEnd = endToken.previous;
if (tokenBeforeEnd != null &&
optional(",", tokenBeforeEnd) &&
kind == MemberKind.PrimaryConstructor &&
declarationContext == DeclarationContext.ExtensionType) {
_compilationUnit.addProblem(messageRepresentationFieldTrailingComma,
tokenBeforeEnd.charOffset, 1, uri);
}
} else if (count > 1) {
Object? last = pop();
count--;
if (last is ParserRecovery) {
// Coverage-ignore-block(suite): Not run.
discard(count);
} else if (last is List<FormalParameterBuilder>) {
formals = const FixedNullableList<FormalParameterBuilder>()
.popPaddedNonNullable(
stack, count, last.length, dummyFormalParameterBuilder);
if (formals != null) {
formals.setRange(count, formals.length, last);
}
} else {
formals = const FixedNullableList<FormalParameterBuilder>()
.popPaddedNonNullable(stack, count, 1, dummyFormalParameterBuilder);
if (formals != null) {
formals[count] = last as FormalParameterBuilder;
}
}
}
if (formals != null) {
assert(formals.isNotEmpty);
if (formals.length == 2) {
// The name may be null for generalized function types.
if (formals[0].name != FormalParameterBuilder.noNameSentinel &&
formals[0].name == formals[1].name &&
!formals[0].isWildcard) {
addProblem(
templateDuplicatedParameterName.withArguments(formals[1].name),
formals[1].charOffset,
formals[1].name.length,
context: [
templateDuplicatedParameterNameCause
.withArguments(formals[1].name)
.withLocation(
uri, formals[0].charOffset, formals[0].name.length)
]);
}
} else if (formals.length > 2) {
Map<String, FormalParameterBuilder> seenNames =
<String, FormalParameterBuilder>{};
for (FormalParameterBuilder formal in formals) {
if (formal.isWildcard) {
continue;
}
if (formal.name == FormalParameterBuilder.noNameSentinel) continue;
if (seenNames.containsKey(formal.name)) {
// Coverage-ignore-block(suite): Not run.
addProblem(
templateDuplicatedParameterName.withArguments(formal.name),
formal.charOffset,
formal.name.length,
context: [
templateDuplicatedParameterNameCause
.withArguments(formal.name)
.withLocation(uri, seenNames[formal.name]!.charOffset,
seenNames[formal.name]!.name.length)
]);
} else {
seenNames[formal.name] = formal;
}
}
}
}
if (declarationContext == DeclarationContext.ExtensionType &&
kind == MemberKind.PrimaryConstructor &&
formals == null) {
// In case of primary constructors of extension types, an error is
// reported by the parser if the formals together with the parentheses
// around them are missing. To distinguish that case from the case of the
// formal parameters present, but lacking the representation field, we
// pass the empty list further along instead of `null`.
formals = const [];
} else if ((declarationContext == DeclarationContext.ExtensionType &&
kind == MemberKind.PrimaryConstructor ||
declarationContext ==
DeclarationContext.ExtensionTypeConstructor) &&
formals != null) {
for (FormalParameterBuilder formal in formals) {
if (formal.isSuperInitializingFormal) {
_compilationUnit.addProblem(
messageExtensionTypeConstructorWithSuperFormalParameter,
formal.charOffset,
formal.name.length,
formal.fileUri);
}
}
}
push(beginToken.charOffset);
push(formals ?? NullValues.FormalParameters);
}
@override
void handleNoFormalParameters(Token token, MemberKind kind) {
push(token.charOffset);
super.handleNoFormalParameters(token, kind);
}
@override
void endAssert(Token assertKeyword, Assert kind, Token leftParenthesis,
Token? commaToken, Token endToken) {
debugEvent("Assert");
// Do nothing
}
@override
void beginEnum(Token enumKeyword) {
assert(checkState(enumKeyword, [
ValueKinds.IdentifierOrParserRecovery,
]));
Object? identifier = peek();
String declarationName;
if (identifier is Identifier) {
declarationName = identifier.name;
} else {
declarationName = '#enum';
}
_builderFactory.beginIndexedContainer(declarationName,
isExtensionTypeDeclaration: false);
pushDeclarationContext(DeclarationContext.Enum);
_builderFactory.beginEnumDeclarationHeader(declarationName);
}
@override
void handleEnumElement(Token beginToken, Token? augmentToken) {
debugEvent("handleEnumElement");
assert(checkState(beginToken, [
/* argumentsBeginToken */ ValueKinds.ArgumentsTokenOrNull,
ValueKinds.ConstructorReferenceBuilderOrNull,
ValueKinds.EnumConstantInfoOrParserRecovery,
]));
Token? argumentsBeginToken = pop() as Token?;
ConstructorReferenceBuilder? constructorReferenceBuilder =
pop() as ConstructorReferenceBuilder?;
Object? enumConstantInfo = pop();
if (enumConstantInfo is EnumConstantInfo) {
push(enumConstantInfo
..constructorReferenceBuilder = constructorReferenceBuilder
..argumentsBeginToken = argumentsBeginToken);
} else {
assert(enumConstantInfo is ParserRecovery);
push(NullValues.EnumConstantInfo);
}
}
@override
void handleEnumHeader(
Token? augmentToken, Token enumKeyword, Token leftBrace) {
assert(checkState(enumKeyword, [
/* interfaces */ ValueKinds.TypeBuilderListOrNull,
/* mixins */ unionOfKinds([
ValueKinds.MixinApplicationBuilderOrNull,
ValueKinds.ParserRecovery,
]),
/* type variables */ ValueKinds.NominalVariableListOrNull,
/* name */ ValueKinds.IdentifierOrParserRecovery,
]));
debugEvent("EnumHeader");
// We pop more values than needed to reach typeVariables, offset and name.
List<TypeBuilder>? interfaces =
pop(NullValues.TypeBuilderList) as List<TypeBuilder>?;
Object? mixins = pop(NullValues.MixinApplicationBuilder);
List<NominalVariableBuilder>? typeVariables =
pop() as List<NominalVariableBuilder>?;
Object? identifier = peek();
if (identifier is Identifier) {
_builderFactory.beginEnumDeclaration(
identifier.name, identifier.nameOffset, typeVariables);
} else {
identifier as ParserRecovery;
_builderFactory.beginEnumDeclaration(
"<syntax-error>", identifier.charOffset, typeVariables);
}
_builderFactory.beginEnumBody();
push(typeVariables ?? NullValues.NominalVariables);
push(mixins ?? NullValues.MixinApplicationBuilder);
push(interfaces ?? NullValues.TypeBuilderList);
push(enumKeyword.charOffset); // start char offset.
push(leftBrace.endGroup!.charOffset); // end char offset.
}
@override
void handleEnumElements(Token elementsEndToken, int elementsCount) {
debugEvent("handleEnumElements");
push(elementsCount);
}
@override
void endEnum(Token beginToken, Token enumKeyword, Token leftBrace,
int memberCount, Token endToken) {
assert(checkState(beginToken, [
/* element count */ ValueKinds.Integer,
]));
debugEvent("endEnum");
int elementsCount = pop() as int;
assert(checkState(beginToken, [
/* enum constants */ ...repeatedKind(
ValueKinds.EnumConstantInfoOrNull, elementsCount),
/* endCharOffset */ ValueKinds.Integer,
/* startCharOffset */ ValueKinds.Integer,
/* interfaces */ ValueKinds.TypeBuilderListOrNull,
/* mixins */ unionOfKinds([
ValueKinds.MixinApplicationBuilderOrNull,
ValueKinds.ParserRecovery,
]),
/* type variables */ ValueKinds.NominalVariableListOrNull,
/* name */ ValueKinds.IdentifierOrParserRecovery,
/* metadata */ ValueKinds.MetadataListOrNull,
]));
List<EnumConstantInfo?>? enumConstantInfos =
const FixedNullableList<EnumConstantInfo>().pop(stack, elementsCount);
if (enumConstantInfos != null) {
List<EnumConstantInfo?>? parsedEnumConstantInfos;
for (int index = 0; index < enumConstantInfos.length; index++) {
EnumConstantInfo? info = enumConstantInfos[index];
if (info == null) {
parsedEnumConstantInfos = enumConstantInfos.take(index).toList();
}
// Coverage-ignore(suite): Not run.
else if (parsedEnumConstantInfos != null) {
parsedEnumConstantInfos.add(info);
}
}
if (parsedEnumConstantInfos != null) {
if (parsedEnumConstantInfos.isEmpty) {
enumConstantInfos = null;
} else {
enumConstantInfos = parsedEnumConstantInfos;
}
}
}
int endCharOffset = popCharOffset();
int startCharOffset = popCharOffset();
List<TypeBuilder>? interfaces =
nullIfParserRecovery(pop()) as List<TypeBuilder>?;
MixinApplicationBuilder? mixinBuilder =
nullIfParserRecovery(pop()) as MixinApplicationBuilder?;
List<NominalVariableBuilder>? typeVariables =
pop() as List<NominalVariableBuilder>?;
Object? identifier = pop();
List<MetadataBuilder>? metadata = pop() as List<MetadataBuilder>?;
checkEmpty(startCharOffset);
if (identifier is Identifier) {
if (enumConstantInfos == null) {
if (!leftBrace.isSynthetic) {
// Coverage-ignore-block(suite): Not run.
addProblem(messageEnumDeclarationEmpty, identifier.token.offset,
identifier.token.length);
}
}
if (interfaces != null) {
for (TypeBuilder interface in interfaces) {
if (interface.nullabilityBuilder.build() == Nullability.nullable) {
_compilationUnit.addProblem(
templateNullableInterfaceError
.withArguments(interface.fullNameForErrors),
interface.charOffset ?? startCharOffset,
identifier.name.length,
uri);
}
}
}
_builderFactory.addEnum(
_offsetMap,
metadata,
identifier,
typeVariables,
mixinBuilder,
interfaces,
enumConstantInfos,
startCharOffset,
endCharOffset);
} else {
_builderFactory.endEnumDeclarationForParserRecovery(typeVariables);
}
_builderFactory.endIndexedContainer();
checkEmpty(enumKeyword.charOffset);
popDeclarationContext(DeclarationContext.Enum);
}
@override
void beginTypedef(Token token) {
pushDeclarationContext(DeclarationContext.Typedef);
_builderFactory.beginTypedef();
}
@override
void beginFunctionType(Token beginToken) {
debugEvent("beginFunctionType");
_structuralParameterDepthLevel++;
_builderFactory.beginFunctionType();
}
@override
void beginFunctionTypedFormalParameter(Token token) {
debugEvent("beginFunctionTypedFormalParameter");
_insideOfFormalParameterType = false;
_builderFactory.beginFunctionType();
}
@override
void endRecordType(
Token leftBracket, Token? questionMark, int count, bool hasNamedFields) {
debugEvent("RecordType");
assert(checkState(leftBracket, [
if (hasNamedFields) ValueKinds.RecordTypeFieldBuilderListOrNull,
...repeatedKind(ValueKinds.RecordTypeFieldBuilder,
hasNamedFields ? count - 1 : count),
]));
if (!libraryFeatures.records.isEnabled) {
addProblem(
templateExperimentNotEnabledOffByDefault
.withArguments(ExperimentalFlag.records.name),
leftBracket.offset,
noLength);
}
List<RecordTypeFieldBuilder>? namedFields;
if (hasNamedFields) {
namedFields =
pop(NullValues.RecordTypeFieldList) as List<RecordTypeFieldBuilder>?;
}
List<RecordTypeFieldBuilder>? positionalFields =
const FixedNullableList<RecordTypeFieldBuilder>().popNonNullable(stack,
hasNamedFields ? count - 1 : count, dummyRecordTypeFieldBuilder);
push(new RecordTypeBuilderImpl(
positionalFields,
namedFields,
questionMark != null
? const NullabilityBuilder.nullable()
: const NullabilityBuilder.omitted(),
uri,
leftBracket.charOffset,
));
}
@override
void endRecordTypeEntry() {
debugEvent("endRecordTypeEntry");
assert(checkState(null, [
ValueKinds.IdentifierOrParserRecoveryOrNull,
unionOfKinds([
ValueKinds.TypeBuilder,
ValueKinds.ParserRecovery,
]),
ValueKinds.MetadataListOrNull,
]));
// Offset of name of field (or next token if there's no name).
Object? identifier = pop(NullValues.Identifier);
Object? type = pop();
List<MetadataBuilder>? metadata =
pop(NullValues.Metadata) as List<MetadataBuilder>?;
String? fieldName = identifier is Identifier ? identifier.name : null;
push(new RecordTypeFieldBuilder(
metadata,
type is ParserRecovery
? new InvalidTypeBuilderImpl(uri, type.charOffset)
: type as TypeBuilder,
fieldName,
identifier is Identifier ? identifier.nameOffset : -1,
isWildcard:
libraryFeatures.wildcardVariables.isEnabled && fieldName == '_'));
}
@override
void endRecordTypeNamedFields(int count, Token leftBracket) {
assert(checkState(leftBracket, [
...repeatedKind(ValueKinds.RecordTypeFieldBuilder, count),
]));
List<RecordTypeFieldBuilder>? fields =
const FixedNullableList<RecordTypeFieldBuilder>()
.popNonNullable(stack, count, dummyRecordTypeFieldBuilder);
push(fields ?? NullValues.RecordTypeFieldList);
}
@override
void endFunctionType(Token functionToken, Token? questionMark) {
debugEvent("FunctionType");
_structuralParameterDepthLevel--;
List<FormalParameterBuilder>? formals =
pop() as List<FormalParameterBuilder>?;
pop(); // formals offset
TypeBuilder? returnType = pop() as TypeBuilder?;
List<StructuralVariableBuilder>? typeVariables =
pop() as List<StructuralVariableBuilder>?;
push(_builderFactory.addFunctionType(
returnType ?? const ImplicitTypeBuilder(),
typeVariables,
formals,
questionMark != null
? const NullabilityBuilder.nullable()
: const NullabilityBuilder.omitted(),
uri,
functionToken.charOffset,
hasFunctionFormalParameterSyntax: false));
}
@override
void endFunctionTypedFormalParameter(Token nameToken, Token? question) {
debugEvent("FunctionTypedFormalParameter");
List<FormalParameterBuilder>? formals =
pop() as List<FormalParameterBuilder>?;
int formalsOffset = popCharOffset();
TypeBuilder? returnType = pop() as TypeBuilder?;
List<StructuralVariableBuilder>? typeVariables =
pop() as List<StructuralVariableBuilder>?;
push(_builderFactory.addFunctionType(
returnType ?? const ImplicitTypeBuilder(),
typeVariables,
formals,
question != null
? const NullabilityBuilder.nullable()
: const NullabilityBuilder.omitted(),
uri,
formalsOffset,
hasFunctionFormalParameterSyntax: true));
}
@override
void endTypedef(Token? augmentToken, Token typedefKeyword, Token? equals,
Token endToken) {
debugEvent("endTypedef");
assert(checkState(
typedefKeyword,
equals == null
? [
/* formals */ ValueKinds.FormalListOrNull,
/* formals offset */ ValueKinds.Integer,
/* type variables */ ValueKinds.NominalVariableListOrNull,
/* name */ ValueKinds.IdentifierOrParserRecovery,
/* return type */ ValueKinds.TypeBuilderOrNull,
/* metadata */ ValueKinds.MetadataListOrNull,
]
: [
/* type */ unionOfKinds([
ValueKinds.TypeBuilderOrNull,
ValueKinds.ParserRecovery,
]),
/* type variables */ ValueKinds.NominalVariableListOrNull,
/* name */ ValueKinds.IdentifierOrParserRecovery,
/* metadata */ ValueKinds.MetadataListOrNull,
]));
List<NominalVariableBuilder>? typeVariables;
Object? name;
Identifier identifier;
TypeBuilder aliasedType;
if (equals == null) {
List<FormalParameterBuilder>? formals =
pop(NullValues.FormalParameters) as List<FormalParameterBuilder>?;
pop(); // formals offset
typeVariables =
pop(NullValues.NominalVariables) as List<NominalVariableBuilder>?;
name = pop();
TypeBuilder? returnType = pop(NullValues.TypeBuilder) as TypeBuilder?;
// Create a nested declaration that is ended below by
// `library.addFunctionType`.
if (name is ParserRecovery) {
// Coverage-ignore-block(suite): Not run.
pop(NullValues.Metadata); // Metadata.
_builderFactory.endTypedefForParserRecovery(typeVariables);
popDeclarationContext(DeclarationContext.Typedef);
return;
}
identifier = name as Identifier;
_builderFactory.beginFunctionType();
// TODO(cstefantsova): Make sure that RHS of typedefs can't have '?'.
aliasedType = _builderFactory.addFunctionType(
returnType ?? const ImplicitTypeBuilder(),
null,
formals,
const NullabilityBuilder.omitted(),
uri,
identifier.nameOffset,
hasFunctionFormalParameterSyntax: true);
} else {
Object? type = pop(NullValues.TypeBuilder);
typeVariables =
pop(NullValues.NominalVariables) as List<NominalVariableBuilder>?;
name = pop();
if (name is ParserRecovery) {
// Coverage-ignore-block(suite): Not run.
pop(NullValues.Metadata); // Metadata.
_builderFactory.endTypedefForParserRecovery(typeVariables);
popDeclarationContext(DeclarationContext.Typedef);
return;
}
identifier = name as Identifier;
if (type is FunctionTypeBuilder &&
!libraryFeatures.nonfunctionTypeAliases.isEnabled) {
if (type.nullabilityBuilder.build() == Nullability.nullable) {
addProblem(
messageTypedefNullableType, equals.charOffset, equals.length);
aliasedType = new NamedTypeBuilderImpl.fromTypeDeclarationBuilder(
new InvalidTypeDeclarationBuilder(
identifier.name,
messageTypedefNullableType.withLocation(
uri, equals.charOffset, equals.length)),
const NullabilityBuilder.omitted(),
instanceTypeVariableAccess:
InstanceTypeVariableAccessState.Allowed);
} else {
// TODO(ahe): We need to start a nested declaration when parsing the
// formals and return type so we can correctly bind
// `type.typeVariables`. A typedef can have type variables, and a new
// function type can also have type variables (representing the type
// of a generic function).
aliasedType = type;
}
} else if (libraryFeatures.nonfunctionTypeAliases.isEnabled) {
if (type is TypeBuilder) {
aliasedType = type;
} else {
addProblem(messageTypedefNotType, equals.charOffset, equals.length);
aliasedType = new NamedTypeBuilderImpl.fromTypeDeclarationBuilder(
new InvalidTypeDeclarationBuilder(
"${name}",
messageTypedefNotType.withLocation(
uri, equals.charOffset, equals.length)),
const NullabilityBuilder.omitted(),
instanceTypeVariableAccess:
InstanceTypeVariableAccessState.Allowed);
}
} else {
assert(type is! FunctionTypeBuilder);
// TODO(ahe): Improve this error message.
if (type is TypeBuilder) {
addProblem(
messageTypedefNotFunction, equals.charOffset, equals.length);
aliasedType = new NamedTypeBuilderImpl.fromTypeDeclarationBuilder(
new InvalidTypeDeclarationBuilder(
identifier.name,
messageTypedefNotFunction.withLocation(
uri, equals.charOffset, equals.length)),
const NullabilityBuilder.omitted(),
instanceTypeVariableAccess:
InstanceTypeVariableAccessState.Allowed);
} else {
addProblem(messageTypedefNotType, equals.charOffset, equals.length);
aliasedType = new NamedTypeBuilderImpl.fromTypeDeclarationBuilder(
new InvalidTypeDeclarationBuilder(
identifier.name,
messageTypedefNotType.withLocation(
uri, equals.charOffset, equals.length)),
const NullabilityBuilder.omitted(),
instanceTypeVariableAccess:
InstanceTypeVariableAccessState.Allowed);
}
}
}
List<MetadataBuilder>? metadata =
pop(NullValues.Metadata) as List<MetadataBuilder>?;
checkEmpty(typedefKeyword.charOffset);
_builderFactory.addFunctionTypeAlias(metadata, identifier.name,
typeVariables, aliasedType, identifier.nameOffset);
popDeclarationContext(DeclarationContext.Typedef);
}
@override
void beginFields(
DeclarationKind declarationKind,
Token? abstractToken,
Token? augmentToken,
Token? externalToken,
Token? staticToken,
Token? covariantToken,
Token? lateToken,
Token? varFinalOrConst,
Token lastConsumed) {
DeclarationContext declarationContext;
switch (declarationKind) {
case DeclarationKind.TopLevel:
declarationContext = DeclarationContext.TopLevelField;
break;
case DeclarationKind.Class:
if (staticToken != null) {
declarationContext = DeclarationContext.ClassStaticField;
} else {
declarationContext = DeclarationContext.ClassInstanceField;
}
break;
case DeclarationKind.Mixin:
if (staticToken != null) {
declarationContext = DeclarationContext.MixinStaticField;
} else {
declarationContext = DeclarationContext.MixinInstanceField;
}
break;
case DeclarationKind.Extension:
if (staticToken != null) {
declarationContext = DeclarationContext.ExtensionStaticField;
} else if (externalToken != null) {
declarationContext =
DeclarationContext.ExtensionExternalInstanceField;
} else {
declarationContext = DeclarationContext.ExtensionInstanceField;
}
break;
case DeclarationKind.ExtensionType:
if (staticToken != null) {
declarationContext = DeclarationContext.ExtensionTypeStaticField;
} else {
declarationContext = DeclarationContext.ExtensionTypeInstanceField;
}
break;
case DeclarationKind.Enum:
if (staticToken != null) {
declarationContext = DeclarationContext.EnumStaticMethod;
} else {
declarationContext = DeclarationContext.EnumInstanceMethod;
}
}
pushDeclarationContext(declarationContext);
}
@override
void endTopLevelFields(
Token? augmentToken,
Token? externalToken,
Token? staticToken,
Token? covariantToken,
Token? lateToken,
Token? varFinalOrConst,
int count,
Token beginToken,
Token endToken) {
debugEvent("endTopLevelFields");
assert(checkState(beginToken, [
...repeatedKinds([
/* charEndOffset = */ ValueKinds.Integer,
/* beforeLast = */ ValueKinds.FieldInitializerTokenOrNull,
/* initializerTokenForInference = */ ValueKinds
.FieldInitializerTokenOrNull,
/* name = */ ValueKinds.IdentifierOrParserRecovery,
], count),
/* type = */ unionOfKinds([
ValueKinds.TypeBuilderOrNull,
ValueKinds.ParserRecovery,
]),
/* metadata = */ ValueKinds.MetadataListOrNull,
]));
if (externalToken != null && lateToken != null) {
// Coverage-ignore-block(suite): Not run.
handleRecoverableError(
messageExternalLateField, externalToken, externalToken);
externalToken = null;
}
List<FieldInfo>? fieldInfos = popFieldInfos(count);
TypeBuilder? type = nullIfParserRecovery(pop()) as TypeBuilder?;
int modifiers = (externalToken != null ? externalMask : 0) |
(staticToken != null ? staticMask : 0) |
(covariantToken != null ? covariantMask : 0) |
(lateToken != null ? lateMask : 0) |
Modifier.validateVarFinalOrConst(varFinalOrConst?.lexeme);
List<MetadataBuilder>? metadata = pop() as List<MetadataBuilder>?;
checkEmpty(beginToken.charOffset);
if (fieldInfos != null) {
_builderFactory.addFields(_offsetMap, metadata, modifiers,
/* isTopLevel = */ true, type, fieldInfos);
}
popDeclarationContext();
}
@override
void endClassFields(
Token? abstractToken,
Token? augmentToken,
Token? externalToken,
Token? staticToken,
Token? covariantToken,
Token? lateToken,
Token? varFinalOrConst,
int count,
Token beginToken,
Token endToken) {
assert(checkState(beginToken, [
...repeatedKinds([
/* charEndOffset = */ ValueKinds.Integer,
/* beforeLast = */ ValueKinds.FieldInitializerTokenOrNull,
/* initializerTokenForInference = */ ValueKinds
.FieldInitializerTokenOrNull,
/* name = */ ValueKinds.IdentifierOrParserRecovery,
], count),
/* type = */ ValueKinds.TypeBuilderOrNull,
/* metadata = */ ValueKinds.MetadataListOrNull,
]));
debugEvent("Fields");
if (staticToken != null && abstractToken != null) {
handleRecoverableError(
messageAbstractStaticField, abstractToken, abstractToken);
abstractToken = null;
}
if (abstractToken != null && lateToken != null) {
handleRecoverableError(
messageAbstractLateField, abstractToken, abstractToken);
abstractToken = null;
}
// Coverage-ignore(suite): Not run.
else if (externalToken != null && lateToken != null) {
handleRecoverableError(
messageExternalLateField, externalToken, externalToken);
externalToken = null;
}
List<FieldInfo>? fieldInfos = popFieldInfos(count);
TypeBuilder? type = pop() as TypeBuilder?;
int modifiers = (abstractToken != null ? abstractMask : 0) |
(augmentToken != null ? augmentMask : 0) |
(externalToken != null ? externalMask : 0) |
(staticToken != null ? staticMask : 0) |
(covariantToken != null ? covariantMask : 0) |
(lateToken != null ? lateMask : 0) |
Modifier.validateVarFinalOrConst(varFinalOrConst?.lexeme);
if (staticToken == null && modifiers & constMask != 0) {
// It is a compile-time error if an instance variable is declared to be
// constant.
addProblem(messageConstInstanceField, varFinalOrConst!.charOffset,
varFinalOrConst.length);
modifiers &= ~constMask;
}
List<MetadataBuilder>? metadata = pop() as List<MetadataBuilder>?;
if (fieldInfos != null) {
_builderFactory.addFields(_offsetMap, metadata, modifiers,
/* isTopLevel = */ false, type, fieldInfos);
}
popDeclarationContext();
}
List<FieldInfo>? popFieldInfos(int count) {
assert(checkState(
null,
repeatedKinds([
/* charEndOffset = */ ValueKinds.Integer,
/* beforeLast = */ ValueKinds.FieldInitializerTokenOrNull,
/* initializerTokenForInference = */ ValueKinds
.FieldInitializerTokenOrNull,
/* name = */ ValueKinds.IdentifierOrParserRecovery,
], count)));
if (count == 0) return null;
List<FieldInfo> fieldInfos =
new List<FieldInfo>.filled(count, dummyFieldInfo);
bool isParserRecovery = false;
for (int i = count - 1; i != -1; i--) {
int charEndOffset = popCharOffset();
Token? beforeLast = pop(NullValues.FieldInitializer) as Token?;
Token? initializerTokenForInference =
pop(NullValues.FieldInitializer) as Token?;
Object? name = pop(NullValues.Identifier);
if (name is ParserRecovery) {
isParserRecovery = true;
} else {
fieldInfos[i] = new FieldInfo(name as Identifier,
initializerTokenForInference, beforeLast, charEndOffset);
}
}
return isParserRecovery ? null : fieldInfos;
}
@override
void beginTypeVariable(Token token) {
assert(checkState(token, [
ValueKinds.IdentifierOrParserRecovery,
ValueKinds.MetadataListOrNull,
]));
debugEvent("beginTypeVariable");
Object? name = pop();
List<MetadataBuilder>? metadata = pop() as List<MetadataBuilder>?;
if (name is ParserRecovery) {
push(name);
} else {
Identifier identifier = name as Identifier;
if (inFunctionType) {
push(_builderFactory.addStructuralTypeVariable(
metadata, identifier.name, null, identifier.nameOffset, uri));
} else {
push(_builderFactory.addNominalTypeVariable(
metadata, identifier.name, null, identifier.nameOffset, uri,
kind: declarationContext.typeVariableKind));
}
}
}
@override
void handleTypeVariablesDefined(Token token, int count) {
debugEvent("TypeVariablesDefined");
assert(count > 0);
if (inFunctionType) {
push(const FixedNullableList<StructuralVariableBuilder>()
.popNonNullable(stack, count, dummyStructuralVariableBuilder) ??
NullValues.StructuralVariables);
} else {
push(const FixedNullableList<NominalVariableBuilder>()
.popNonNullable(stack, count, dummyNominalVariableBuilder) ??
NullValues.NominalVariables);
}
}
@override
void endTypeVariable(
Token token, int index, Token? extendsOrSuper, Token? variance) {
debugEvent("endTypeVariable");
TypeBuilder? bound = nullIfParserRecovery(pop()) as TypeBuilder?;
// Peek to leave type parameters on top of stack.
List<TypeVariableBuilder>? typeParameters =
peek() as List<TypeVariableBuilder>?;
if (typeParameters != null) {
typeParameters[index].bound = bound;
if (variance != null) {
if (!libraryFeatures.variance.isEnabled) {
// Coverage-ignore-block(suite): Not run.
reportVarianceModifierNotEnabled(variance);
}
typeParameters[index].variance =
new Variance.fromKeywordString(variance.lexeme);
}
}
}
@override
void endTypeVariables(Token beginToken, Token endToken) {
debugEvent("endTypeVariables");
if (declarationContext == DeclarationContext.Enum) {
reportIfNotEnabled(
libraryFeatures.enhancedEnums, beginToken.charOffset, noLength);
}
if (inConstructorName) {
// Coverage-ignore-block(suite): Not run.
addProblem(messageConstructorWithTypeParameters,
offsetForToken(beginToken), lengthOfSpan(beginToken, endToken));
inConstructorName = false;
}
}
@override
void endPartOf(
Token partKeyword, Token ofKeyword, Token semicolon, bool hasName) {
debugEvent("endPartOf");
assert(checkState(
partKeyword,
hasName
? [
/* library name */ ValueKinds.Identifier,
/* metadata */ ValueKinds.MetadataListOrNull,
]
: [
/* offset */ ValueKinds.Integer,
/* uri string */ ValueKinds.String,
/* metadata */ ValueKinds.MetadataListOrNull,
]));
if (hasName) {
Identifier containingLibrary = pop() as Identifier;
List<MetadataBuilder>? metadata = pop() as List<MetadataBuilder>?;
_builderFactory.addPartOf(
metadata,
flattenName(containingLibrary, containingLibrary.firstOffset, uri),
null,
containingLibrary.firstOffset);
} else {
int charOffset = popCharOffset();
String uriString = pop() as String;
List<MetadataBuilder>? metadata = pop() as List<MetadataBuilder>?;
_builderFactory.addPartOf(metadata, null, uriString, charOffset);
}
}
@override
void endConstructorReference(Token start, Token? periodBeforeName,
Token endToken, ConstructorReferenceContext constructorReferenceContext) {
debugEvent("ConstructorReference");
assert(checkState(start, [
if (periodBeforeName != null) /* suffix */ ValueKinds.Identifier,
ValueKinds.TypeArgumentsOrNull,
/* prefix */ ValueKinds.IdentifierOrParserRecoveryOrNull,
]));
Identifier? suffix = popIfNotNull(periodBeforeName) as Identifier?;
List<TypeBuilder>? typeArguments = pop() as List<TypeBuilder>?;
int charOffset = start.charOffset;
Object? name = pop();
if (name is ParserRecovery) {
push(name);
} else if (name is Identifier) {
push(_builderFactory.addConstructorReference(
name.typeName, typeArguments, suffix?.name, name.qualifierOffset));
} else {
assert(name == null);
// At the moment, the name of the type in a constructor reference can be
// omitted only within an enum element declaration.
if (_builderFactory.currentTypeParameterScopeBuilder.kind ==
TypeParameterScopeKind.enumDeclaration) {
if (libraryFeatures.enhancedEnums.isEnabled) {
int constructorNameOffset = suffix?.nameOffset ?? charOffset;
push(_builderFactory.addConstructorReference(
new SyntheticTypeName(
_builderFactory.currentTypeParameterScopeBuilder.name,
constructorNameOffset),
typeArguments,
suffix?.name,
constructorNameOffset));
} else {
// For entries that consist of their name only, all of the elements
// of the constructor reference should be null.
if (typeArguments != null || suffix != null) {
// Coverage-ignore-block(suite): Not run.
_compilationUnit.reportFeatureNotEnabled(
libraryFeatures.enhancedEnums, uri, charOffset, noLength);
}
push(NullValues.ConstructorReference);
}
} else {
internalProblem(
messageInternalProblemOmittedTypeNameInConstructorReference,
charOffset,
uri);
}
}
}
@override
void beginFactoryMethod(DeclarationKind declarationKind, Token lastConsumed,
Token? externalToken, Token? constToken) {
DeclarationContext declarationContext;
switch (declarationKind) {
case DeclarationKind.TopLevel:
// Coverage-ignore(suite): Not run.
throw new UnsupportedError("Unexpected top level factory method.");
case DeclarationKind.Class:
declarationContext = DeclarationContext.ClassFactory;
break;
case DeclarationKind.Mixin:
declarationContext = DeclarationContext.MixinFactory;
break;
case DeclarationKind.Extension:
declarationContext = DeclarationContext.ExtensionFactory;
break;
case DeclarationKind.ExtensionType:
declarationContext = DeclarationContext.ExtensionTypeFactory;
break;
case DeclarationKind.Enum:
declarationContext = DeclarationContext.EnumFactory;
break;
}
pushDeclarationContext(declarationContext);
inConstructor = true;
_builderFactory.beginFactoryMethod();
push((externalToken != null ? externalMask : 0) |
(constToken != null ? constMask : 0));
}
void _endFactoryMethod(
Token beginToken, Token factoryKeyword, Token endToken) {
assert(checkState(beginToken, [
ValueKinds.MethodBody,
]));
MethodBody kind = pop() as MethodBody;
assert(checkState(beginToken, [
if (kind == MethodBody.RedirectingFactoryBody)
unionOfKinds([
ValueKinds.ConstructorReferenceBuilderOrNull,
ValueKinds.ParserRecovery,
]),
ValueKinds.AsyncMarker,
ValueKinds.FormalListOrNull,
/* formals offset */ ValueKinds.Integer,
ValueKinds.NominalVariableListOrNull,
ValueKinds.IdentifierOrParserRecovery,
/* modifiers */ ValueKinds.Integer,
ValueKinds.MetadataListOrNull,
]));
ConstructorReferenceBuilder? redirectionTarget;
if (kind == MethodBody.RedirectingFactoryBody) {
redirectionTarget =
nullIfParserRecovery(pop()) as ConstructorReferenceBuilder?;
}
AsyncMarker asyncModifier = pop() as AsyncMarker;
List<FormalParameterBuilder>? formals =
pop() as List<FormalParameterBuilder>?;
int formalsOffset = popCharOffset();
pop(); // type variables
Object name = pop()!;
int modifiers = pop() as int;
if (nativeMethodName != null) {
modifiers |= externalMask;
}
List<MetadataBuilder>? metadata = pop() as List<MetadataBuilder>?;
if (name is! Identifier) {
// Coverage-ignore-block(suite): Not run.
assert(name is ParserRecovery,
"Unexpected name $name (${name.runtimeType}).");
_builderFactory.endFactoryMethodForParserRecovery();
} else {
_builderFactory.addFactoryMethod(
_offsetMap,
metadata,
modifiers,
name,
formals,
redirectionTarget,
beginToken.charOffset,
name.qualifierOffset,
formalsOffset,
endToken.charOffset,
nativeMethodName,
asyncModifier,
);
}
nativeMethodName = null;
inConstructor = false;
popDeclarationContext();
}
@override
void endClassFactoryMethod(
Token beginToken, Token factoryKeyword, Token endToken) {
debugEvent("endClassFactoryMethod");
_endFactoryMethod(beginToken, factoryKeyword, endToken);
}
@override
void endMixinFactoryMethod(
Token beginToken, Token factoryKeyword, Token endToken) {
debugEvent("endMixinFactoryMethod");
_endFactoryMethod(beginToken, factoryKeyword, endToken);
}
@override
void endExtensionFactoryMethod(
Token beginToken, Token factoryKeyword, Token endToken) {
debugEvent("endExtensionFactoryMethod");
_endFactoryMethod(beginToken, factoryKeyword, endToken);
}
@override
void endEnumFactoryMethod(
Token beginToken, Token factoryKeyword, Token endToken) {
debugEvent("endEnumFactoryMethod");
reportIfNotEnabled(
libraryFeatures.enhancedEnums, beginToken.charOffset, noLength);
_endFactoryMethod(beginToken, factoryKeyword, endToken);
}
@override
void endEnumMethod(Token? getOrSet, Token beginToken, Token beginParam,
Token? beginInitializers, Token endToken) {
debugEvent("endEnumMethod");
reportIfNotEnabled(
libraryFeatures.enhancedEnums, beginToken.charOffset, noLength);
_endClassMethod(getOrSet, beginToken, beginParam, beginInitializers,
endToken, _MethodKind.enumMethod);
}
@override
void endEnumFields(
Token? abstractToken,
Token? augmentToken,
Token? externalToken,
Token? staticToken,
Token? covariantToken,
Token? lateToken,
Token? varFinalOrConst,
int count,
Token beginToken,
Token endToken) {
reportIfNotEnabled(
libraryFeatures.enhancedEnums, beginToken.charOffset, noLength);
endClassFields(
abstractToken,
augmentToken,
externalToken,
staticToken,
covariantToken,
lateToken,
varFinalOrConst,
count,
beginToken,
endToken);
}
@override
void endEnumConstructor(Token? getOrSet, Token beginToken, Token beginParam,
Token? beginInitializers, Token endToken) {
debugEvent("endEnumConstructor");
reportIfNotEnabled(
libraryFeatures.enhancedEnums, beginToken.charOffset, noLength);
_endClassMethod(getOrSet, beginToken, beginParam, beginInitializers,
endToken, _MethodKind.enumConstructor);
}
@override
void endRedirectingFactoryBody(Token beginToken, Token endToken) {
debugEvent("RedirectingFactoryBody");
push(MethodBody.RedirectingFactoryBody);
}
@override
void handleConstFactory(Token constKeyword) {
debugEvent("ConstFactory");
if (!libraryFeatures.constFunctions.isEnabled) {
// Coverage-ignore-block(suite): Not run.
handleRecoverableError(messageConstFactory, constKeyword, constKeyword);
}
}
@override
void endFieldInitializer(Token assignmentOperator, Token endToken) {
debugEvent("FieldInitializer");
push(assignmentOperator.next);
push(endToken);
// TODO(jensj): Do we actually want the position of the "," or ";" here?
push(endToken.next!.charOffset);
}
@override
void handleNoFieldInitializer(Token token) {
debugEvent("handleNoFieldInitializer");
push(NullValues.FieldInitializer);
push(NullValues.FieldInitializer);
push(token.charOffset);
}
@override
void endInitializers(int count, Token beginToken, Token endToken) {
debugEvent("endInitializers");
// Ignored for now.
}
@override
void handleNoInitializers() {
debugEvent("handleNoInitializers");
// This is a constructor initializer and it's ignored for now.
}
@override
void handleInvalidMember(Token endToken) {
debugEvent("handleInvalidMember");
pop(); // metadata star
}
@override
void endMember() {
debugEvent("endMember");
assert(nativeMethodName == null);
}
@override
void handleClassWithClause(Token withKeyword) {
debugEvent("ClassWithClause");
assert(checkState(withKeyword, [
/* mixins */ unionOfKinds([
ValueKinds.TypeBuilderList,
ValueKinds.ParserRecovery,
]),
/* supertype offset */ ValueKinds.Integer,
/* supertype */ unionOfKinds([
ValueKinds.TypeBuilderOrNull,
ValueKinds.ParserRecovery,
]),
]));
Object? mixins = pop();
int extendsOffset = popCharOffset();
Object? supertype = peek();
push(extendsOffset);
if (supertype is ParserRecovery || mixins is ParserRecovery) {
push(new ParserRecovery(withKeyword.charOffset));
} else {
push(_builderFactory.addMixinApplication(
mixins as List<TypeBuilder>, withKeyword.charOffset));
}
assert(checkState(withKeyword, [
/* mixins */ unionOfKinds([
ValueKinds.MixinApplicationBuilderOrNull,
ValueKinds.ParserRecovery,
]),
/* supertype offset */ ValueKinds.Integer,
/* supertype */ unionOfKinds([
ValueKinds.TypeBuilderOrNull,
ValueKinds.ParserRecovery,
]),
]));
}
@override
void handleClassNoWithClause() {
debugEvent("ClassNoWithClause");
assert(checkState(null, [
/* supertype offset */ ValueKinds.Integer,
/* supertype */ unionOfKinds([
ValueKinds.TypeBuilderOrNull,
ValueKinds.ParserRecovery,
]),
]));
push(NullValues.MixinApplicationBuilder);
assert(checkState(null, [
/* mixins */ ValueKinds.MixinApplicationBuilderOrNull,
/* supertype offset */ ValueKinds.Integer,
/* supertype */ unionOfKinds([
ValueKinds.TypeBuilderOrNull,
ValueKinds.ParserRecovery,
]),
]));
}
@override
void handleEnumWithClause(Token withKeyword) {
debugEvent("EnumWithClause");
assert(checkState(withKeyword, [
/* mixins */ unionOfKinds([
ValueKinds.TypeBuilderListOrNull,
ValueKinds.ParserRecovery,
]),
]));
reportIfNotEnabled(libraryFeatures.enhancedEnums, withKeyword.charOffset,
withKeyword.length);
Object? mixins = pop();
if (mixins is ParserRecovery) {
push(new ParserRecovery(withKeyword.charOffset));
} else {
push(_builderFactory.addMixinApplication(
mixins as List<TypeBuilder>, withKeyword.charOffset));
}
assert(checkState(withKeyword, [
/* mixins */ unionOfKinds([
ValueKinds.MixinApplicationBuilderOrNull,
ValueKinds.ParserRecovery,
]),
]));
}
@override
void handleEnumNoWithClause() {
debugEvent("EnumNoWithClause");
push(NullValues.MixinApplicationBuilder);
}
@override
void handleMixinWithClause(Token withKeyword) {
debugEvent("MixinWithClause");
assert(checkState(withKeyword, [
/* mixins */ unionOfKinds([
ValueKinds.TypeBuilderListOrNull,
ValueKinds.ParserRecovery,
]),
]));
// This is an error case where the parser has already given an error.
// We just discard the data.
pop();
}
@override
void handleClassHeader(Token begin, Token classKeyword, Token? nativeToken) {
debugEvent("ClassHeader");
nativeMethodName = null;
}
@override
void handleMixinHeader(Token mixinKeyword) {
debugEvent("handleMixinHeader");
nativeMethodName = null;
}
@override
void endClassOrMixinOrExtensionBody(
DeclarationKind kind, int memberCount, Token beginToken, Token endToken) {
debugEvent("endClassOrMixinBody");
popDeclarationContext();
}
@override
void handleAsyncModifier(Token? asyncToken, Token? starToken) {
debugEvent("AsyncModifier");
push(asyncMarkerFromTokens(asyncToken, starToken));
}
@override
void addProblem(Message message, int charOffset, int length,
{bool wasHandled = false, List<LocatedMessage>? context}) {
_compilationUnit.addProblem(message, charOffset, length, uri,
wasHandled: wasHandled, context: context);
}
@override
bool isIgnoredError(Code<dynamic> code, Token token) {
return isIgnoredParserError(code, token) ||
super.isIgnoredError(code, token);
}
@override
void debugEvent(String name) {
// printEvent('OutlineBuilder: $name');
}
@override
void handleNewAsIdentifier(Token token) {
reportIfNotEnabled(
libraryFeatures.constructorTearoffs, token.charOffset, token.length);
}
}
/// TODO(johnniwinther): Use [DeclarationContext] instead of [_MethodKind].
enum _MethodKind {
classConstructor,
classMethod,
mixinConstructor,
mixinMethod,
extensionConstructor,
extensionMethod,
extensionTypeConstructor,
extensionTypeMethod,
enumConstructor,
enumMethod,
}
extension on MemberKind {
/// Returns `true` if a parameter occurring in this context can be inferred.
bool get isParameterInferable {
switch (this) {
case MemberKind.Catch:
case MemberKind.FunctionTypeAlias:
case MemberKind.Factory:
case MemberKind.FunctionTypedParameter:
case MemberKind.GeneralizedFunctionType:
case MemberKind.Local:
case MemberKind.StaticMethod:
case MemberKind.TopLevelMethod:
case MemberKind.ExtensionNonStaticMethod:
case MemberKind.ExtensionStaticMethod:
case MemberKind.ExtensionTypeStaticMethod:
case MemberKind.PrimaryConstructor:
return false;
case MemberKind.NonStaticMethod:
case MemberKind.ExtensionTypeNonStaticMethod:
// Coverage-ignore(suite): Not run.
// These can be inferred but cannot hold parameters so the cases are
// dead code:
case MemberKind.NonStaticField:
// Coverage-ignore(suite): Not run.
case MemberKind.StaticField:
// Coverage-ignore(suite): Not run.
case MemberKind.TopLevelField:
return true;
}
}
}