Skip to content

Commit

Permalink
Avoid using findLibraryByName
Browse files Browse the repository at this point in the history
  • Loading branch information
simolus3 committed Aug 12, 2023
1 parent 8388579 commit 7f6e22b
Show file tree
Hide file tree
Showing 8 changed files with 125 additions and 37 deletions.
4 changes: 4 additions & 0 deletions drift_dev/lib/src/analysis/backend.dart
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ abstract class DriftBackend {
/// resolved.
Future<Expression> resolveExpression(
Uri context, String dartExpression, Iterable<String> imports);

/// Resolves the Dart element named [reference] in the [imports] of [context].
Future<Element?> resolveTopLevelElement(
Uri context, String reference, Iterable<Uri> imports);
}

/// Thrown when attempting to read a Dart library from a file that's not a
Expand Down
40 changes: 18 additions & 22 deletions drift_dev/lib/src/analysis/preprocess_drift.dart
Original file line number Diff line number Diff line change
Expand Up @@ -81,15 +81,13 @@ class DriftPreprocessor {
.map((token) => token.dartCode)
.toList();

var dartHelperFile = '';
final codeToField = <String, String>{};
final seenFiles = <Uri>{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>{uri};
final queue = [...directImports];

while (queue.isNotEmpty) {
final foundImport = queue.removeLast();

Expand Down Expand Up @@ -120,27 +118,25 @@ class DriftPreprocessor {
}
}
}
}

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.
final importedDartFiles =
seenFiles.where((uri) => url.extension(uri.path) == '.dart');

final dartBuffer = StringBuffer();
for (final import in importedDartFiles) {
final importUri = import.toString();
dartBuffer.writeln('import ${asDartLiteral(importUri)};');
}
// 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.

for (var i = 0; i < dartLexemes.length; i++) {
final name = 'expr_$i';
dartBuffer.writeln('var $name = ${dartLexemes[i]};');
codeToField[dartLexemes[i]] = name;
}
final dartBuffer = StringBuffer();
for (final import in importedDartFiles) {
final importUri = import.toString();
dartBuffer.writeln('import ${asDartLiteral(importUri)};');
}

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 = <String>[];
Expand All @@ -158,6 +154,6 @@ class DriftPreprocessor {
directImports.toList(),
);

return DriftPreprocessor._(result, dartHelperFile);
return DriftPreprocessor._(result, dartBuffer.toString());
}
}
5 changes: 3 additions & 2 deletions drift_dev/lib/src/analysis/resolver/dart/helper.dart
Original file line number Diff line number Diff line change
Expand Up @@ -89,11 +89,12 @@ class KnownDriftTypes {
}

static Future<KnownDriftTypes> 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) {
Expand Down
15 changes: 2 additions & 13 deletions drift_dev/lib/src/analysis/resolver/drift/element_resolver.dart
Original file line number Diff line number Diff line change
Expand Up @@ -67,19 +67,8 @@ abstract class DriftElementResolver<T extends DiscoveredElement>
// 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
Expand Down
34 changes: 34 additions & 0 deletions drift_dev/lib/src/backends/analyzer_context_backend.dart
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,40 @@ class AnalysisContextBackend extends DriftBackend {
}
}

@override
Future<Element?> resolveTopLevelElement(
Uri context, String reference, Iterable<Uri> 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);
Expand Down
25 changes: 25 additions & 0 deletions drift_dev/lib/src/backends/build/backend.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -97,6 +98,30 @@ class DriftBuildBackend extends DriftBackend {
}
return initializer;
}

@override
Future<Element?> resolveTopLevelElement(
Uri context, String reference, Iterable<Uri> 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 {
Expand Down
6 changes: 6 additions & 0 deletions drift_dev/lib/src/services/schema/sqlite_to_drift.dart
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,12 @@ class _SingleFileNoAnalyzerBackend extends DriftBackend {
_noAnalyzer();
}

@override
Future<Element?> resolveTopLevelElement(
Uri context, String reference, Iterable<Uri> imports) {
_noAnalyzer();
}

@override
Uri resolveUri(Uri base, String uriString) {
return uri;
Expand Down
33 changes: 33 additions & 0 deletions drift_dev/test/analysis/test_utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,39 @@ class TestBackend extends DriftBackend {
}
}

@override
Future<Element?> resolveTopLevelElement(
Uri context, String reference, Iterable<Uri> 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<LibraryElement> readDart(Uri uri) async {
await ensureHasDartAnalyzer();
Expand Down

0 comments on commit 7f6e22b

Please sign in to comment.