blob: d926b6ff733e24cfb93eb01b3736a4dcaa0573db [file] [log] [blame]
// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'dart:io' show File, IOSink;
import 'dart:typed_data' show BytesBuilder, Uint8List;
import 'package:_fe_analyzer_shared/src/parser/formal_parameter_kind.dart';
import 'package:_fe_analyzer_shared/src/scanner/scanner.dart' show Token;
import 'package:_fe_analyzer_shared/src/scanner/token.dart'
show SyntheticToken, TokenType;
import 'package:front_end/src/base/lookup_result.dart';
import 'package:front_end/src/base/scope.dart';
import 'package:kernel/ast.dart';
import 'package:kernel/binary/ast_to_binary.dart';
import 'package:kernel/clone.dart';
import 'package:kernel/text/ast_to_text.dart';
import '../base/combinator.dart';
import '../base/configuration.dart';
import '../base/identifiers.dart';
import '../base/modifiers.dart';
import '../builder/declaration_builders.dart';
import '../builder/fixed_type_builder.dart';
import '../builder/formal_parameter_builder.dart';
import '../builder/library_builder.dart';
import '../builder/metadata_builder.dart';
import '../builder/omitted_type_builder.dart';
import '../builder/record_type_builder.dart';
import '../builder/type_builder.dart';
import '../fragment/fragment.dart';
import '../source/fragment_factory.dart';
import '../source/source_type_parameter_builder.dart';
import 'body_builder.dart';
/// The name for the synthesized field used to store information of
/// unserializable exports in a [Library].
///
/// For instance, if a [Library] tries to export two declarations with the same
/// name, the unserializable exports will map this name to the corresponding
/// error message.
const String unserializableExportName = '_exports#';
/// Sentinel value used in unserializable exports to signal an export of
/// 'dynamic' from 'dart:core'.
const String exportDynamicSentinel = '<dynamic>';
/// Sentinel value used in unserializable exports to signal an export of
/// 'Never' from 'dart:core'.
const String exportNeverSentinel = '<Never>';
// Coverage-ignore(suite): Not run.
void printNodeOn(Node? node, StringSink sink, {NameSystem? syntheticNames}) {
if (node == null) {
sink.write("null");
} else {
syntheticNames ??= new NameSystem();
new Printer(sink, syntheticNames: syntheticNames).writeNode(node);
}
}
// Coverage-ignore(suite): Not run.
void printQualifiedNameOn(Member? member, StringSink sink) {
if (member == null) {
sink.write("null");
} else {
sink.write(member.enclosingLibrary.importUri);
sink.write("::");
Class? cls = member.enclosingClass;
if (cls != null) {
sink.write(cls.name);
sink.write("::");
}
sink.write(member.name.text);
}
}
void bindCoreType(
LibraryBuilder coreLibrary,
NamedTypeBuilder typeBuilder, {
bool isNullClass = false,
}) {
TypeDeclarationBuilder typeDeclarationBuilder =
coreLibrary.lookupRequiredLocalMember(typeBuilder.typeName.name)
as TypeDeclarationBuilder;
typeBuilder.bind(coreLibrary, typeDeclarationBuilder);
if (isNullClass) {
(typeDeclarationBuilder as ClassBuilder).isNullClass = true;
}
}
// Coverage-ignore(suite): Not run.
/// Print the given [component]. Do nothing if it is `null`. If the
/// [libraryFilter] is provided, then only libraries that satisfy it are
/// printed.
void printComponentText(
Component? component, {
bool Function(Library library)? libraryFilter,
bool showOffsets = false,
}) {
if (component == null) return;
StringBuffer sb = new StringBuffer();
Printer printer = new Printer(sb, showOffsets: showOffsets);
printer.writeComponentProblems(component);
for (Library library in component.libraries) {
if (libraryFilter != null && !libraryFilter(library)) continue;
printer.writeLibraryFile(library);
}
printer.writeConstantTable(component);
print(sb);
}
// Coverage-ignore(suite): Not run.
/// Write [component] to file only including libraries that match [filter].
Future<Null> writeComponentToFile(
Component component,
Uri uri, {
bool Function(Library library)? filter,
}) async {
File output = new File.fromUri(uri);
IOSink sink = output.openWrite();
try {
BinaryPrinter printer = new BinaryPrinter(sink, libraryFilter: filter);
printer.writeComponentFile(component);
} finally {
await sink.close();
}
}
// Coverage-ignore(suite): Not run.
/// Serialize the libraries in [component] that match [filter].
Uint8List serializeComponent(
Component component, {
bool Function(Library library)? filter,
bool includeSources = true,
bool includeOffsets = true,
}) {
ByteSink byteSink = new ByteSink();
BinaryPrinter printer = new BinaryPrinter(
byteSink,
libraryFilter: filter,
includeSources: includeSources,
includeOffsets: includeOffsets,
);
printer.writeComponentFile(component);
return byteSink.builder.takeBytes();
}
const String kDebugClassName = "#DebugClass";
// Coverage-ignore(suite): Not run.
class _CollectLibraryDependencies extends RecursiveVisitor {
Set<LibraryDependency> foundLibraryDependencies = {};
@override
void visitLoadLibrary(LoadLibrary node) {
foundLibraryDependencies.add(node.import);
}
@override
void visitCheckLibraryIsLoaded(CheckLibraryIsLoaded node) {
foundLibraryDependencies.add(node.import);
}
}
// Coverage-ignore(suite): Not run.
Component createExpressionEvaluationComponent(Procedure procedure) {
Library realLibrary = procedure.enclosingLibrary;
Uri uri = new Uri(scheme: 'evaluate', path: 'source');
Library fakeLibrary = new Library(uri, fileUri: uri)
..setLanguageVersion(realLibrary.languageVersion);
// Add deferred library dependencies. They are needed for serializing
// references to deferred libraries. We can just claim ownership of the ones
// we find as they were created when doing the expression compilation.
_CollectLibraryDependencies collectLibraryDependencies =
new _CollectLibraryDependencies();
procedure.accept(collectLibraryDependencies);
for (LibraryDependency libraryDependency
in collectLibraryDependencies.foundLibraryDependencies) {
fakeLibrary.addDependency(libraryDependency);
}
TreeNode? realClass = procedure.parent;
if (realClass is Class) {
Class fakeClass = new Class(name: kDebugClassName, fileUri: uri)
..parent = fakeLibrary;
Map<TypeParameter, TypeParameter> typeParams =
<TypeParameter, TypeParameter>{};
Map<TypeParameter, DartType> typeSubstitution = <TypeParameter, DartType>{};
for (TypeParameter typeParam in realClass.typeParameters) {
TypeParameter newNode = new TypeParameter(typeParam.name)
..declaration = fakeClass;
typeParams[typeParam] = newNode;
typeSubstitution[typeParam] = new TypeParameterType(
newNode,
typeParam.computeNullabilityFromBound(),
);
}
CloneVisitorWithMembers cloner = new CloneVisitorWithMembers(
typeSubstitution: typeSubstitution,
typeParams: typeParams,
);
for (TypeParameter typeParam in realClass.typeParameters) {
fakeClass.typeParameters.add(
typeParam.accept<TreeNode>(cloner) as TypeParameter,
);
}
if (realClass.supertype != null) {
// supertype is null for Object.
fakeClass.supertype = new Supertype.byReference(
realClass.supertype!.className,
realClass.supertype!.typeArguments.map(cloner.visitType).toList(),
);
}
// Rebind the type parameters in the procedure.
procedure = cloner.cloneProcedure(procedure, null);
procedure.parent = fakeClass;
fakeClass.procedures.add(procedure);
fakeLibrary.classes.add(fakeClass);
} else {
fakeLibrary.procedures.add(procedure);
procedure.parent = fakeLibrary;
}
// TODO(vegorov) find a way to preserve metadata.
Component component = new Component(libraries: [fakeLibrary]);
component.setMainMethodAndMode(null, false);
return component;
}
// Coverage-ignore(suite): Not run.
List<int> serializeProcedure(Procedure procedure) {
return serializeComponent(createExpressionEvaluationComponent(procedure));
}
/// A [Sink] that directly writes data into a byte builder.
class ByteSink implements Sink<List<int>> {
final BytesBuilder builder = new BytesBuilder();
@override
void add(List<int> data) {
builder.add(data);
}
@override
// Coverage-ignore(suite): Not run.
void close() {}
}
int compareProcedures(Procedure a, Procedure b) {
int i = "${a.fileUri}".compareTo("${b.fileUri}");
if (i != 0) return i;
return a.fileOffset.compareTo(b.fileOffset);
}
List<Combinator>? toCombinators(List<CombinatorBuilder>? combinatorBuilders) {
if (combinatorBuilders == null) {
// Note: it's safe to return null here as Kernel's LibraryDependency will
// convert null to an empty list.
return null;
}
return new List<Combinator>.generate(combinatorBuilders.length, (int i) {
CombinatorBuilder combinator = combinatorBuilders[i];
List<String> nameList = combinator.names.toList();
return combinator.isShow
? new Combinator.show(nameList)
: new Combinator.hide(nameList);
}, growable: true);
}
final Token dummyToken = new SyntheticToken(TokenType.AT, -1);
final Identifier dummyIdentifier = new SimpleIdentifier(dummyToken);
final CombinatorBuilder dummyCombinator = new CombinatorBuilder(
false,
{},
-1,
dummyUri,
);
final MetadataBuilder dummyMetadataBuilder = new MetadataBuilder(
dummyToken,
dummyUri,
);
final TypeBuilder dummyTypeBuilder = new FixedTypeBuilderImpl(
dummyDartType,
dummyUri,
-1,
);
final FormalParameterBuilder dummyFormalParameterBuilder =
new FormalParameterBuilder(
FormalParameterKind.requiredPositional,
Modifiers.empty,
const ImplicitTypeBuilder(),
'',
-1,
fileUri: dummyUri,
hasImmediatelyDeclaredInitializer: false,
);
final FunctionTypeParameterBuilder dummyFunctionTypeParameterBuilder =
new FunctionTypeParameterBuilder(
FormalParameterKind.requiredPositional,
const ImplicitTypeBuilder(),
'',
);
final NominalParameterBuilder dummyNominalVariableBuilder =
new SourceNominalParameterBuilder(
new DirectNominalParameterDeclaration(
name: NominalParameterBuilder.noNameSentinel,
kind: TypeParameterKind.function,
isWildcard: false,
fileOffset: -1,
fileUri: dummyUri,
),
);
final TypeParameterFragment dummyTypeParameterFragment =
new TypeParameterFragment(
metadata: null,
name: '',
nameOffset: -1,
fileUri: dummyUri,
kind: TypeParameterKind.function,
isWildcard: false,
variableName: '',
typeParameterScope: dummyLookupScope,
);
final SourceStructuralParameterBuilder dummyStructuralVariableBuilder =
new SourceStructuralParameterBuilder(
new RegularStructuralParameterDeclaration(
metadata: null,
name: StructuralParameterBuilder.noNameSentinel,
fileOffset: -1,
fileUri: dummyUri,
isWildcard: false,
),
);
final Label dummyLabel = new Label('', -1);
final RecordTypeFieldBuilder dummyRecordTypeFieldBuilder =
new RecordTypeFieldBuilder(null, dummyTypeBuilder, null, -1);
final FieldInfo dummyFieldInfo = new FieldInfo(
dummyIdentifier,
null,
dummyToken,
-1,
);
final Configuration dummyConfiguration = new Configuration(-1, '', '', '');
final LookupScope dummyLookupScope = new _DummyLookupScope();
// Coverage-ignore(suite): Not run.
class _DummyLookupScope implements LookupScope {
@override
void forEachExtension(void Function(ExtensionBuilder p1) f) {}
@override
ScopeKind get kind => ScopeKind.library;
@override
LookupResult? lookup(String name) => null;
}