From 7f6e22b8921121c9537b51e78ce89340ac48ee52 Mon Sep 17 00:00:00 2001 From: Simon Binder Date: Sat, 12 Aug 2023 23:28:47 +0200 Subject: [PATCH] Avoid using `findLibraryByName` --- drift_dev/lib/src/analysis/backend.dart | 4 ++ .../lib/src/analysis/preprocess_drift.dart | 40 +++++++++---------- .../src/analysis/resolver/dart/helper.dart | 5 ++- .../resolver/drift/element_resolver.dart | 15 +------ .../backends/analyzer_context_backend.dart | 34 ++++++++++++++++ drift_dev/lib/src/backends/build/backend.dart | 25 ++++++++++++ .../src/services/schema/sqlite_to_drift.dart | 6 +++ drift_dev/test/analysis/test_utils.dart | 33 +++++++++++++++ 8 files changed, 125 insertions(+), 37 deletions(-) diff --git a/drift_dev/lib/src/analysis/backend.dart b/drift_dev/lib/src/analysis/backend.dart index 8df3fe70..72c9729c 100644 --- a/drift_dev/lib/src/analysis/backend.dart +++ b/drift_dev/lib/src/analysis/backend.dart @@ -44,6 +44,10 @@ abstract class DriftBackend { /// resolved. Future resolveExpression( Uri context, String dartExpression, Iterable imports); + + /// Resolves the Dart element named [reference] in the [imports] of [context]. + Future resolveTopLevelElement( + Uri context, String reference, Iterable imports); } /// Thrown when attempting to read a Dart library from a file that's not a diff --git a/drift_dev/lib/src/analysis/preprocess_drift.dart b/drift_dev/lib/src/analysis/preprocess_drift.dart index 39823ac1..6733b210 100644 --- a/drift_dev/lib/src/analysis/preprocess_drift.dart +++ b/drift_dev/lib/src/analysis/preprocess_drift.dart @@ -81,15 +81,13 @@ class DriftPreprocessor { .map((token) => token.dartCode) .toList(); - var dartHelperFile = ''; final codeToField = {}; + final seenFiles = {uri}; + final queue = [...directImports]; if (dartLexemes.isNotEmpty) { // Imports in drift files are transitive, so we need to find all // transitive Dart sources to import into the generated helper file. - final seenFiles = {uri}; - final queue = [...directImports]; - while (queue.isNotEmpty) { final foundImport = queue.removeLast(); @@ -120,27 +118,25 @@ class DriftPreprocessor { } } } + } - final importedDartFiles = - seenFiles.where((uri) => url.extension(uri.path) == '.dart'); + final importedDartFiles = + seenFiles.where((uri) => url.extension(uri.path) == '.dart'); - // to analyze the expressions, generate a fake Dart file that declares each - // expression in a `var`, we can then read the static type when resolving - // file later. + // to analyze the expressions, generate a fake Dart file that declares each + // expression in a `var`, we can then read the static type when resolving + // file later. - final dartBuffer = StringBuffer(); - for (final import in importedDartFiles) { - final importUri = import.toString(); - dartBuffer.writeln('import ${asDartLiteral(importUri)};'); - } + final dartBuffer = StringBuffer(); + for (final import in importedDartFiles) { + final importUri = import.toString(); + dartBuffer.writeln('import ${asDartLiteral(importUri)};'); + } - for (var i = 0; i < dartLexemes.length; i++) { - final name = 'expr_$i'; - dartBuffer.writeln('var $name = ${dartLexemes[i]};'); - codeToField[dartLexemes[i]] = name; - } - - dartHelperFile = dartBuffer.toString(); + for (var i = 0; i < dartLexemes.length; i++) { + final name = 'expr_$i'; + dartBuffer.writeln('var $name = ${dartLexemes[i]};'); + codeToField[dartLexemes[i]] = name; } final declaredTablesAndViews = []; @@ -158,6 +154,6 @@ class DriftPreprocessor { directImports.toList(), ); - return DriftPreprocessor._(result, dartHelperFile); + return DriftPreprocessor._(result, dartBuffer.toString()); } } diff --git a/drift_dev/lib/src/analysis/resolver/dart/helper.dart b/drift_dev/lib/src/analysis/resolver/dart/helper.dart index b8f5df60..87259820 100644 --- a/drift_dev/lib/src/analysis/resolver/dart/helper.dart +++ b/drift_dev/lib/src/analysis/resolver/dart/helper.dart @@ -89,11 +89,12 @@ class KnownDriftTypes { } static Future resolve(DriftAnalysisDriver driver) async { - final library = await driver.backend - .readDart(Uri.parse('package:drift/src/drift_dev_helper.dart')); + final library = await driver.backend.readDart(uri); return KnownDriftTypes._fromLibrary(library); } + + static final Uri uri = Uri.parse('package:drift/src/drift_dev_helper.dart'); } Expression? returnExpressionOfMethod(MethodDeclaration method) { diff --git a/drift_dev/lib/src/analysis/resolver/drift/element_resolver.dart b/drift_dev/lib/src/analysis/resolver/drift/element_resolver.dart index 090ced8c..7add9de7 100644 --- a/drift_dev/lib/src/analysis/resolver/drift/element_resolver.dart +++ b/drift_dev/lib/src/analysis/resolver/drift/element_resolver.dart @@ -67,19 +67,8 @@ abstract class DriftElementResolver // are available. .followedBy([AnnotatedDartCode.dartCore]); - for (final import in dartImports) { - LibraryElement library; - try { - library = await resolver.driver.backend.readDart(import); - } on NotALibraryException { - continue; - } - - final foundElement = library.exportNamespace.get(identifier); - if (foundElement != null) return foundElement; - } - - return null; + return await resolver.driver.backend + .resolveTopLevelElement(file.ownUri, identifier, dartImports); } /// Resolves [identifier] to a Dart element declaring a type, or reports an diff --git a/drift_dev/lib/src/backends/analyzer_context_backend.dart b/drift_dev/lib/src/backends/analyzer_context_backend.dart index b5a27e4f..6a5f81cd 100644 --- a/drift_dev/lib/src/backends/analyzer_context_backend.dart +++ b/drift_dev/lib/src/backends/analyzer_context_backend.dart @@ -151,6 +151,40 @@ class AnalysisContextBackend extends DriftBackend { } } + @override + Future resolveTopLevelElement( + Uri context, String reference, Iterable imports) async { + // Create a fake file next to the content + final path = _pathOfUri(context)!; + final pathContext = provider.pathContext; + final pathForTemp = pathContext.join( + pathContext.dirname(path), 'moor_temp_${imports.hashCode}.dart'); + + final content = StringBuffer(); + for (final import in imports) { + content.writeln('import "$import";'); + } + + provider.setOverlay( + pathForTemp, + content: content.toString(), + modificationStamp: DateTime.now().millisecondsSinceEpoch, + ); + + try { + final result = + await this.context.currentSession.getResolvedLibrary(pathForTemp); + + if (result is ResolvedLibraryResult) { + return result.element.scope.lookup(reference).getter; + } + } finally { + provider.removeOverlay(path); + } + + return null; + } + @override Uri resolveUri(Uri base, String uriString) { final resolved = base.resolve(uriString); diff --git a/drift_dev/lib/src/backends/build/backend.dart b/drift_dev/lib/src/backends/build/backend.dart index b723ca58..b72c024e 100644 --- a/drift_dev/lib/src/backends/build/backend.dart +++ b/drift_dev/lib/src/backends/build/backend.dart @@ -11,6 +11,7 @@ import 'package:build/build.dart' as build; import '../../analysis/backend.dart'; import '../../analysis/driver/driver.dart'; import '../../analysis/preprocess_drift.dart'; +import '../../analysis/resolver/dart/helper.dart'; class DriftBuildBackend extends DriftBackend { final BuildStep _buildStep; @@ -97,6 +98,30 @@ class DriftBuildBackend extends DriftBackend { } return initializer; } + + @override + Future resolveTopLevelElement( + Uri context, String reference, Iterable imports) async { + final original = AssetId.resolve(context); + final tempDart = original.changeExtension('.expr.temp.dart'); + + if (await _buildStep.canRead(tempDart)) { + final library = await _buildStep.resolver.libraryFor(tempDart); + + return library.scope.lookup(reference).getter; + } else { + // If there's no temporary file whose imports we can use, then that means + // that there aren't any Dart imports in [context] at all. So we just need + // to look it up in `dart:core`. + // For that, resolve a library we know exists and likely has been resolved + // already. + final libraryWeKnowExists = await _buildStep.resolver + .libraryFor(AssetId.resolve(KnownDriftTypes.uri)); + final dartCore = libraryWeKnowExists.typeProvider.objectElement.library; + + return dartCore.exportNamespace.get(reference); + } + } } class BuildCacheReader implements AnalysisResultCacheReader { diff --git a/drift_dev/lib/src/services/schema/sqlite_to_drift.dart b/drift_dev/lib/src/services/schema/sqlite_to_drift.dart index 13f527d8..753a2e8c 100644 --- a/drift_dev/lib/src/services/schema/sqlite_to_drift.dart +++ b/drift_dev/lib/src/services/schema/sqlite_to_drift.dart @@ -102,6 +102,12 @@ class _SingleFileNoAnalyzerBackend extends DriftBackend { _noAnalyzer(); } + @override + Future resolveTopLevelElement( + Uri context, String reference, Iterable imports) { + _noAnalyzer(); + } + @override Uri resolveUri(Uri base, String uriString) { return uri; diff --git a/drift_dev/test/analysis/test_utils.dart b/drift_dev/test/analysis/test_utils.dart index 180d6b52..79dc1557 100644 --- a/drift_dev/test/analysis/test_utils.dart +++ b/drift_dev/test/analysis/test_utils.dart @@ -184,6 +184,39 @@ class TestBackend extends DriftBackend { } } + @override + Future resolveTopLevelElement( + Uri context, String reference, Iterable imports) async { + final fileContents = StringBuffer(); + for (final import in imports) { + fileContents.writeln("import '$import';"); + } + + final path = '${_pathFor(context)}.imports.dart'; + + await _setupDartAnalyzer(); + + final resourceProvider = _resourceProvider!; + final analysisContext = _dartContext!; + + resourceProvider.setOverlay(path, + content: fileContents.toString(), modificationStamp: 1); + + try { + final result = + await analysisContext.currentSession.getResolvedLibrary(path); + + if (result is ResolvedLibraryResult) { + final lookup = result.element.scope.lookup(reference); + return lookup.getter; + } + } finally { + resourceProvider.removeOverlay(path); + } + + return null; + } + @override Future readDart(Uri uri) async { await ensureHasDartAnalyzer();