diff --git a/moor_generator/lib/src/analyzer/moor/inline_dart_resolver.dart b/moor_generator/lib/src/analyzer/moor/inline_dart_resolver.dart new file mode 100644 index 00000000..aee7b0a8 --- /dev/null +++ b/moor_generator/lib/src/analyzer/moor/inline_dart_resolver.dart @@ -0,0 +1,45 @@ +import 'package:analyzer/dart/ast/ast.dart'; +import 'package:analyzer/dart/element/type.dart'; +import 'package:moor_generator/src/analyzer/session.dart'; + +/// Resolves the type of Dart expressions given as a string. The +/// [importStatements] are used to discover types. +/// +/// The way this works is that we create a fake file for the analyzer. That file +/// has the following content: +/// ``` +/// import 'package:moor/moor.dart'; // always imported +/// // all import statements +/// +/// var expr = $expression; +/// ``` +/// +/// We can then obtain the type of an expression by reading the inferred type +/// of the top-level `expr` variable in that source. +class InlineDartResolver { + final List importStatements = []; + final MoorTask task; + + InlineDartResolver(this.task); + + Future resolveDartTypeOf(String expression) async { + final template = _createDartTemplate(expression); + final unit = await task.backendTask.parseSource(template); + + final declaration = unit.declarations.single as TopLevelVariableDeclaration; + return declaration.variables.variables.single.initializer.staticType; + } + + String _createDartTemplate(String expression) { + final fakeDart = StringBuffer(); + + fakeDart.write("import 'package:moor/moor.dart';\n"); + for (var import in importStatements) { + fakeDart.write("import '$import';\n"); + } + + fakeDart.write('var expr = $expression;\n'); + + return fakeDart.toString(); + } +} diff --git a/moor_generator/lib/src/analyzer/moor/parser.dart b/moor_generator/lib/src/analyzer/moor/parser.dart index 50d2d8f9..05a7d927 100644 --- a/moor_generator/lib/src/analyzer/moor/parser.dart +++ b/moor_generator/lib/src/analyzer/moor/parser.dart @@ -16,7 +16,10 @@ class MoorParser { final createdReaders = []; for (var parsedStmt in results) { - if (parsedStmt.rootNode is CreateTableStatement) { + if (parsedStmt.rootNode is ImportStatement) { + final importStmt = (parsedStmt.rootNode) as ImportStatement; + task.inlineDartResolver.importStatements.add(importStmt.importedFile); + } else if (parsedStmt.rootNode is CreateTableStatement) { createdReaders.add(CreateTableReader(parsedStmt)); } else { task.reportError(ErrorInMoorFile( diff --git a/moor_generator/lib/src/analyzer/session.dart b/moor_generator/lib/src/analyzer/session.dart index 79d2a42e..c8af9675 100644 --- a/moor_generator/lib/src/analyzer/session.dart +++ b/moor_generator/lib/src/analyzer/session.dart @@ -6,6 +6,7 @@ import 'package:analyzer/dart/element/type.dart'; import 'package:moor/moor.dart' show Table; import 'package:moor_generator/src/analyzer/dart/parser.dart'; import 'package:moor_generator/src/analyzer/errors.dart'; +import 'package:moor_generator/src/analyzer/moor/inline_dart_resolver.dart'; import 'package:moor_generator/src/analyzer/moor/parser.dart'; import 'package:moor_generator/src/analyzer/results.dart'; import 'package:moor_generator/src/analyzer/sql_queries/sql_parser.dart'; @@ -151,9 +152,12 @@ class DartTask extends FileTask { class MoorTask extends FileTask { final String content; final TypeMapper mapper = TypeMapper(); + /* late final */ InlineDartResolver inlineDartResolver; MoorTask(BackendTask task, MoorSession session, this.content) - : super(task, session); + : super(task, session) { + inlineDartResolver = InlineDartResolver(this); + } @override FutureOr compute() { diff --git a/moor_generator/lib/src/backends/backend.dart b/moor_generator/lib/src/backends/backend.dart index 4a5ec059..9b454f2d 100644 --- a/moor_generator/lib/src/backends/backend.dart +++ b/moor_generator/lib/src/backends/backend.dart @@ -1,3 +1,4 @@ +import 'package:analyzer/dart/ast/ast.dart'; import 'package:analyzer/dart/element/element.dart'; import 'package:logging/logging.dart'; import 'package:moor_generator/src/analyzer/session.dart'; @@ -17,5 +18,6 @@ abstract class BackendTask { Logger get log; Future resolveDart(Uri uri); + Future parseSource(String dart); Future readMoor(Uri uri); } diff --git a/moor_generator/lib/src/backends/build/build_backend.dart b/moor_generator/lib/src/backends/build/build_backend.dart index 825e1c3e..8867e961 100644 --- a/moor_generator/lib/src/backends/build/build_backend.dart +++ b/moor_generator/lib/src/backends/build/build_backend.dart @@ -1,3 +1,5 @@ +import 'package:analyzer/analyzer.dart'; +import 'package:analyzer/dart/ast/ast.dart'; import 'package:analyzer/dart/element/element.dart'; import 'package:build/build.dart' hide log; import 'package:build/build.dart' as build show log; @@ -32,6 +34,11 @@ class BuildBackendTask extends BackendTask { return step.resolver.libraryFor(_resolve(uri)); } + @override + Future parseSource(String dart) async { + return null; + } + @override Logger get log => build.log; } diff --git a/moor_generator/test/utils/test_backend.dart b/moor_generator/test/utils/test_backend.dart index 5a6ada24..3669e301 100644 --- a/moor_generator/test/utils/test_backend.dart +++ b/moor_generator/test/utils/test_backend.dart @@ -1,5 +1,6 @@ import 'dart:async'; +import 'package:analyzer/dart/ast/ast.dart'; import 'package:analyzer/dart/element/element.dart'; import 'package:build/build.dart'; import 'package:build_test/build_test.dart'; @@ -60,4 +61,9 @@ class _TestBackendTask extends BackendTask { await backend._ready; return await backend._resolver.libraryFor(AssetId.resolve(path.toString())); } + + @override + Future parseSource(String dart) { + return null; + } }