Skip to content

nullsafety #1

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 25 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 8 additions & 6 deletions lib/runtime.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ library runtime;

import 'dart:io';

import 'package:runtime/src/compiler.dart';
import 'src/compiler.dart';
import 'package:runtime/src/mirror_context.dart';

export 'src/analyzer.dart';
Expand All @@ -29,8 +29,8 @@ class RuntimePackageCompiler extends Compiler {
void deflectPackage(Directory destinationDirectory) {
final libraryFile = File.fromUri(
destinationDirectory.uri.resolve("lib/").resolve("runtime.dart"));
libraryFile
.writeAsStringSync("library runtime;\nexport 'src/context.dart';\nexport 'src/exceptions.dart';");
libraryFile.writeAsStringSync(
"library runtime;\nexport 'src/context.dart';\nexport 'src/exceptions.dart';");

final contextFile = File.fromUri(destinationDirectory.uri
.resolve("lib/")
Expand All @@ -41,9 +41,11 @@ class RuntimePackageCompiler extends Compiler {
"import 'package:generated_runtime/generated_runtime.dart' as context;");
contextFile.writeAsStringSync(contextFileContents);

final pubspecFile = File.fromUri(destinationDirectory.uri.resolve("pubspec.yaml"));
final pubspecContents = pubspecFile.readAsStringSync().replaceFirst("\ndependencies:",
"\ndependencies:\n generated_runtime:\n path: ../../generated_runtime/");
final pubspecFile =
File.fromUri(destinationDirectory.uri.resolve("pubspec.yaml"));
final pubspecContents = pubspecFile.readAsStringSync().replaceFirst(
"\ndependencies:",
"\ndependencies:\n generated_runtime:\n path: ../../generated_runtime/");
pubspecFile.writeAsStringSync(pubspecContents);
}
}
76 changes: 48 additions & 28 deletions lib/slow_coerce.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,38 +4,50 @@ const String _listPrefix = "List<";
const String _mapPrefix = "Map<String,";

T cast<T>(dynamic input) {
if (input == null) {
return null;
}

try {
final typeString = T.toString();
var typeString = T.toString();
if (typeString.endsWith('?')) {
if (input == null) {
return null as T;
} else {
typeString = typeString.substring(0, typeString.length - 1);
}
}
if (typeString.startsWith(_listPrefix)) {
if (input is! List) {
throw TypeError();
}

if (typeString == "List<int>") {
if (typeString.startsWith("List<int>")) {
return List<int>.from(input) as T;
} else if (typeString == "List<num>") {
} else if (typeString.startsWith("List<num>")) {
return List<num>.from(input) as T;
} else if (typeString == "List<double>") {
} else if (typeString.startsWith("List<double>")) {
return List<double>.from(input) as T;
} else if (typeString == "List<String>") {
} else if (typeString.startsWith("List<String>")) {
return List<String>.from(input) as T;
} else if (typeString == "List<bool>") {
} else if (typeString.startsWith("List<bool>")) {
return List<bool>.from(input) as T;
} else if (typeString == "List<Map<String, dynamic>>") {
} else if (typeString.startsWith("List<int?>")) {
return List<int?>.from(input) as T;
} else if (typeString.startsWith("List<num?>")) {
return List<num?>.from(input) as T;
} else if (typeString.startsWith("List<double?>")) {
return List<double?>.from(input) as T;
} else if (typeString.startsWith("List<String?>")) {
return List<String?>.from(input) as T;
} else if (typeString.startsWith("List<bool?>")) {
return List<bool?>.from(input) as T;
} else if (typeString.startsWith("List<Map<String, dynamic>>")) {
final objects = <Map<String, dynamic>>[];
(input as List).forEach((o) {
if (o == null) {
objects.add(null);
} else {
if (o is! Map<String, dynamic>) {
throw TypeError();
}
objects.add(o);
}
input.forEach((o) {
objects.add(o);
});
return objects as T;
} else if (typeString.startsWith("List<Map<String, dynamic>?>")) {
final objects = <Map<String, dynamic>?>[];
input.forEach((o) {
objects.add(o);
});
return objects as T;
}
Expand All @@ -45,23 +57,31 @@ T cast<T>(dynamic input) {
}

final inputMap = input as Map<String, dynamic>;
if (typeString == "Map<String, int>") {
if (typeString.startsWith("Map<String, int>")) {
return Map<String, int>.from(inputMap) as T;
} else if (typeString == "Map<String, num>") {
} else if (typeString.startsWith("Map<String, num>")) {
return Map<String, num>.from(inputMap) as T;
} else if (typeString == "Map<String, double>") {
} else if (typeString.startsWith("Map<String, double>")) {
return Map<String, double>.from(inputMap) as T;
} else if (typeString == "Map<String, String>") {
} else if (typeString.startsWith("Map<String, String>")) {
return Map<String, String>.from(inputMap) as T;
} else if (typeString == "Map<String, bool>") {
} else if (typeString.startsWith("Map<String, bool>")) {
return Map<String, bool>.from(inputMap) as T;
} else if (typeString.startsWith("Map<String, int?>")) {
return Map<String, int?>.from(inputMap) as T;
} else if (typeString.startsWith("Map<String, num?>")) {
return Map<String, num?>.from(inputMap) as T;
} else if (typeString.startsWith("Map<String, double?>")) {
return Map<String, double?>.from(inputMap) as T;
} else if (typeString.startsWith("Map<String, String?>")) {
return Map<String, String?>.from(inputMap) as T;
} else if (typeString.startsWith("Map<String, bool?>")) {
return Map<String, bool?>.from(inputMap) as T;
}
}

return input as T;
} on CastError {
throw TypeCoercionException(T, input.runtimeType as Type);
} on TypeError {
throw TypeCoercionException(T, input.runtimeType as Type);
throw TypeCoercionException(T, input.runtimeType);
}
}
16 changes: 8 additions & 8 deletions lib/src/analyzer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,13 @@ class CodeAnalyzer {
return getPath(uri);
}

final Uri uri;
late final Uri uri;

AnalysisContextCollection contexts;
late AnalysisContextCollection contexts;

Map<String, ResolvedUnitResult> _resolvedAsts = {};

Future<ResolvedUnitResult> resolveUnitAt(Uri uri) async {
Future<ResolvedUnitResult?> resolveUnitAt(Uri uri) async {
for (var ctx in contexts.contexts) {
final path = getPath(uri);
if (_resolvedAsts.containsKey(path)) {
Expand All @@ -44,26 +44,26 @@ class CodeAnalyzer {
"${contexts.contexts.map((c) => c.contextRoot.root.toUri()).join(", ")})");
}

ClassDeclaration getClassFromFile(String className, Uri fileUri) {
ClassDeclaration? getClassFromFile(String className, Uri fileUri) {
return _getFileAstRoot(fileUri)
.declarations
.whereType<ClassDeclaration>()
.firstWhere((c) => c.name.name == className, orElse: () => null);
.whereType<ClassDeclaration?>()
.firstWhere((c) => c!.name.name == className, orElse: () => null);
}

List<ClassDeclaration> getSubclassesFromFile(
String superclassName, Uri fileUri) {
return _getFileAstRoot(fileUri)
.declarations
.whereType<ClassDeclaration>()
.where((c) => c.extendsClause.superclass.name.name == superclassName)
.where((c) => c.extendsClause!.superclass.name.name == superclassName)
.toList();
}

CompilationUnit _getFileAstRoot(Uri fileUri) {
final path = getPath(fileUri);
if (_resolvedAsts.containsKey(path)) {
return _resolvedAsts[path].unit;
return _resolvedAsts[path]!.unit!;
}

final unit = contexts.contextFor(path).currentSession.getParsedUnit(path);
Expand Down
23 changes: 13 additions & 10 deletions lib/src/build.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,33 @@ import 'dart:convert';
import 'dart:io';
import 'dart:mirrors';

import 'package:runtime/runtime.dart';
import 'package:runtime/src/build_context.dart';
import 'package:runtime/src/compiler.dart';
import 'package:runtime/src/file_system.dart';
import 'package:runtime/src/generator.dart';

class Build {
Build(this.context);

final BuildContext context;

Map<String, Uri> get packageMap => _packageMap ??= context.resolvedPackages;
Map<String, Uri> _packageMap;
Map<String, Uri>? _packageMap;

Future execute() async {
final compilers = context.context.compilers;

print("Resolving ASTs...");
final astsToResolve = Set.from(compilers.expand((c) => c.getUrisToResolve(context)));
final astsToResolve =
Set.from(compilers.expand((c) => c.getUrisToResolve(context)));
await Future.forEach(astsToResolve, (astUri) async {
await context.analyzer.resolveUnitAt(context.resolveUri(astUri));
await context.analyzer.resolveUnitAt(context.resolveUri(astUri as Uri)!);
});

print("Generating runtime...");

final runtimeGenerator = RuntimeGenerator();
context.context.runtimes.map.forEach((typeName, runtime) {
context.context.runtimes?.map.forEach((typeName, runtime) {
if (runtime is SourceCompiler) {
runtimeGenerator.addRuntime(
name: typeName, source: runtime.compile(context));
Expand All @@ -39,10 +42,10 @@ class Build {
final pubspecMap = {
'name': 'runtime_target',
'version': '1.0.0',
'environment': {'sdk': '>=2.7.0 <3.0.0'},
'environment': {'sdk': '>=2.12.0-0 <3.0.0'},
'dependency_overrides': {}
};
Map overrides = pubspecMap['dependency_overrides'];
Map? overrides = pubspecMap['dependency_overrides'] as Map?;
var sourcePackageIsCompiled = false;

compilers.forEach((compiler) {
Expand All @@ -56,7 +59,7 @@ class Build {
compiler.deflectPackage(Directory.fromUri(targetDirUri));

if (packageInfo.name != nameOfPackageBeingCompiled) {
overrides[packageInfo.name] = {
overrides![packageInfo.name] = {
"path": targetDirUri.toFilePath(windows: Platform.isWindows)
};
} else {
Expand Down Expand Up @@ -158,7 +161,7 @@ class Build {
}

_PackageInfo _getPackageInfoForCompiler(Compiler compiler) {
final compilerUri = reflect(compiler).type.location.sourceUri;
final compilerUri = reflect(compiler).type.location!.sourceUri;
final parser = RegExp("package\:([^\/]+)");
final parsed = parser.firstMatch(compilerUri.toString());
if (parsed == null) {
Expand All @@ -167,7 +170,7 @@ class Build {
}

final packageName = parsed.group(1);
return _getPackageInfoForName(packageName);
return _getPackageInfoForName(packageName!);
}
}

Expand Down
45 changes: 23 additions & 22 deletions lib/src/build_context.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,19 @@ import 'dart:io';
import 'dart:mirrors';

import 'package:analyzer/dart/ast/ast.dart';
import 'package:pubspec_parse/pubspec_parse.dart';
import 'package:pubspec/pubspec.dart';
import 'package:runtime/src/analyzer.dart';
import 'package:runtime/src/context.dart';
import 'package:runtime/src/file_system.dart';
import 'package:runtime/src/mirror_context.dart';
import 'package:yaml/yaml.dart';
import 'package:path/path.dart';

/// Configuration and context values used during [Build.execute].
class BuildContext {
BuildContext(this.rootLibraryFileUri, this.buildDirectoryUri,
this.executableUri, this.source,
{bool forTests})
{bool? forTests})
: this.forTests = forTests ?? false {
analyzer = CodeAnalyzer(sourceApplicationDirectory.uri);
}
Expand All @@ -35,7 +36,7 @@ class BuildContext {
'forTests': forTests
};

CodeAnalyzer analyzer;
late CodeAnalyzer analyzer;

/// A [Uri] to the library file of the application to be compiled.
final Uri rootLibraryFileUri;
Expand All @@ -61,7 +62,7 @@ class BuildContext {
.resolve("main_test.dart")
: buildDirectoryUri.resolve("main.dart");

Pubspec get sourceApplicationPubspec => Pubspec.parse(
PubSpec get sourceApplicationPubspec => PubSpec.fromYamlString(
File.fromUri(sourceApplicationDirectory.uri.resolve("pubspec.yaml"))
.readAsStringSync());

Expand Down Expand Up @@ -117,16 +118,16 @@ class BuildContext {
return file;
}

Uri resolveUri(Uri uri) {
Uri? resolveUri(Uri? uri) {
var outputUri = uri;
if (outputUri?.scheme == "package") {
final segments = outputUri.pathSegments;
outputUri = resolvedPackages[segments.first].resolve("lib/");
final segments = outputUri!.pathSegments;
outputUri = resolvedPackages[segments.first]!.resolve("lib/");
for (var i = 1; i < segments.length; i++) {
if (i < segments.length - 1) {
outputUri = outputUri.resolve("${segments[i]}/");
outputUri = outputUri!.resolve("${segments[i]}/");
} else {
outputUri = outputUri.resolve(segments[i]);
outputUri = outputUri!.resolve(segments[i]);
}
}
} else if (outputUri != null && !outputUri.isAbsolute) {
Expand All @@ -137,7 +138,7 @@ class BuildContext {
}

List<String> getImportDirectives(
{Uri uri, String source, bool alsoImportOriginalFile = false}) {
{Uri? uri, String? source, bool alsoImportOriginalFile = false}) {
if (uri != null && source != null) {
throw ArgumentError(
"either uri or source must be non-null, but not both");
Expand All @@ -154,15 +155,15 @@ class BuildContext {
}

var fileUri = resolveUri(uri);
final text = source ?? File.fromUri(fileUri).readAsStringSync();
final text = source ?? File.fromUri(fileUri!).readAsStringSync();
final importRegex = RegExp("import [\\'\\\"]([^\\'\\\"]*)[\\'\\\"];");

final imports = importRegex.allMatches(text).map((m) {
var importedUri = Uri.parse(m.group(1));
if (importedUri.scheme != "package" && !importedUri.isAbsolute) {
throw ArgumentError(
"Cannot resolve relative URIs in file located at $uri. "
"Replace imported URIs with package or absolute URIs");
var importedUri = Uri.parse(m.group(1)!);

if (!importedUri.isAbsolute) {
final path = fileUri!.resolve(importedUri.path);
return 'import \'file:${absolute(path.path)}\';';
}

return text.substring(m.start, m.end);
Expand All @@ -175,26 +176,26 @@ class BuildContext {
return imports;
}

ClassDeclaration getClassDeclarationFromType(Type type) {
ClassDeclaration? getClassDeclarationFromType(Type type) {
final classMirror = reflectType(type);
return analyzer.getClassFromFile(
MirrorSystem.getName(classMirror.simpleName),
resolveUri(classMirror.location.sourceUri));
resolveUri(classMirror.location!.sourceUri)!);
}

List<Annotation> getAnnotationsFromField(Type _type, String propertyName) {
var type = reflectClass(_type);
var field =
getClassDeclarationFromType(type.reflectedType).getField(propertyName);
getClassDeclarationFromType(type.reflectedType)!.getField(propertyName);
while (field == null) {
type = type.superclass;
type = type.superclass!;
if (type.reflectedType == Object) {
break;
}
field = getClassDeclarationFromType(type.reflectedType)
field = getClassDeclarationFromType(type.reflectedType)!
.getField(propertyName);
}

return (field.parent.parent as FieldDeclaration).metadata.toList();
return (field!.parent!.parent as FieldDeclaration).metadata.toList();
}
}
Loading