Report error when import can't be resolved

This commit is contained in:
Simon Binder 2020-01-06 19:57:44 +01:00
parent e9bd8a43aa
commit debf8b30f4
No known key found for this signature in database
GPG Key ID: 7891917E4147B8C0
6 changed files with 92 additions and 11 deletions

View File

@ -89,14 +89,16 @@ class Task {
continue;
}
final found = session.resolve(file, import.importedFile);
if (!await backend.exists(found.uri)) {
final found = await _resolveOrReportError(file, import.importedFile,
(errorMsg) {
step.reportError(ErrorInMoorFile(
span: import.importString.span,
severity: Severity.error,
message: 'File does not exist: ${import.importedFile}',
message: errorMsg,
));
} else {
});
if (found != null) {
resolvedImports.add(found);
parsed.resolvedImports[import] = found;
}
@ -123,14 +125,14 @@ class Task {
final resolvedForAccessor = <FoundFile>[];
for (final import in accessor.declaredIncludes) {
final found = session.resolve(file, import);
if (!await backend.exists(found.uri)) {
final found = await _resolveOrReportError(file, import, (errorMsg) {
step.reportError(ErrorInDartCode(
affectedElement: accessor.fromClass,
severity: Severity.error,
message: 'Include could not be resolved: $import',
message: errorMsg,
));
} else {
});
if (found != null) {
resolvedImports.add(found);
resolvedForAccessor.add(found);
}
@ -150,6 +152,24 @@ class Task {
return createdStep;
}
Future<FoundFile> _resolveOrReportError(
FoundFile file,
String import,
void Function(String) reporter,
) async {
final found = session.resolve(file, import);
if (found == null) {
reporter('Invalid import: $import');
} else if (!await backend.exists(found.uri)) {
reporter('Imported file does not exist: $import');
} else {
return found;
}
return null;
}
/// Crawls through all (transitive) imports of the provided [roots]. Each
/// [FoundFile] in the iterable provides queries and tables that are available
/// to the entity that imports them.

View File

@ -55,9 +55,13 @@ class MoorSession {
/// Resolves an import directive in the context of the [source] file. This
/// can handle both relative imports and `package:` imports.
///
/// Returns null if the import could not be resolved. Note that it does not
/// return null if the file doesn't exists - that needs to be checked
/// separately.
FoundFile resolve(FoundFile source, String import) {
final resolvedUri = backend.resolve(source.uri, import);
return _uriToFile(resolvedUri);
return resolvedUri == null ? null : _uriToFile(resolvedUri);
}
/// Registers a file by its absolute uri.

View File

@ -9,6 +9,8 @@ import 'package:logging/logging.dart';
abstract class Backend {
/// Resolves an [import] statement from the context of a [base] uri. This
/// should support both relative and `package:` imports.
///
/// Returns null if the url can't be resolved.
Uri resolve(Uri base, String import);
}

View File

@ -12,7 +12,10 @@ class CommonBackend extends Backend {
@override
Uri resolve(Uri base, String import) {
return Uri.parse(driver.absolutePath(Uri.parse(import), base: base));
final absolute = driver.absolutePath(Uri.parse(import), base: base);
if (absolute == null) return null;
return Uri.parse(absolute);
}
}

View File

@ -133,12 +133,13 @@ class MoorDriver implements AnalysisDriverGeneric {
/// Finds the absolute path of a [reference] url, optionally assuming that the
/// [reference] appears in [base]. This supports both "package:"-based uris
/// and relative imports.
/// Returns null if the uri can't be parsed.
String absolutePath(Uri reference, {Uri base}) {
final factory = dartDriver.sourceFactory;
final baseSource = base == null ? null : factory.forUri2(base);
final source = factory.resolveUri(baseSource, reference.toString());
return source.fullName;
return source?.fullName;
}
CommonTask _createTask(Uri uri) {

View File

@ -0,0 +1,51 @@
import 'package:moor_generator/src/analyzer/errors.dart';
import 'package:test/test.dart';
import '../utils.dart';
void main() {
group("reports error when an import can't be found", () {
test('in moor file', () async {
final state = TestState.withContent({
'foo|lib/a.moor': '''
import 'b.moor';
''',
});
final result = await state.analyze('package:foo/a.moor');
expect(
result.errors.errors,
contains(const TypeMatcher<ErrorInMoorFile>().having(
(e) => e.message,
'message',
allOf(contains('b.moor'), contains('file does not exist')),
)),
);
});
test('in a dart file', () async {
final state = TestState.withContent({
'foo|lib/a.dart': '''
import 'package:moor/moor.dart';
@UseMoor(include: {'b.moor'})
class Database {
}
''',
});
final result = await state.analyze('package:foo/a.dart');
expect(
result.errors.errors,
contains(const TypeMatcher<ErrorInDartCode>().having(
(e) => e.message,
'message',
allOf(contains('b.moor'), contains('file does not exist')),
)),
);
});
});
}