prepareStaticTypes method
Resolves every in-package .dart file with the real Dart front end so a
subsequent encode sees a type-resolved AST instead of the
syntax-only one parseString produces.
This is what lets DartEncoder dispatch collection methods by RECEIVER
TYPE rather than by method name alone (issue #488): on a resolved unit
expression.staticType is non-null, so Set<String>.add(x) can be told
apart from List<String>.add(x).
Opt-in and fail-soft by design:
- Resolution is asynchronous (the analyzer exposes no synchronous
resolved-unit API) while encode is synchronous, so this is a
separate step callers
awaitbefore encoding rather than a flag. - Every failure mode — no
.dart_tool/package_config.json(the target package was neverpub get-ed), an unreadable file, an analyzer crash — degrades to a warnings entry and an unresolved encode. The tool has always worked on any directory containing apubspec.yamlregardless of dependency-resolution state, and it still does. - Files that fail individually simply stay syntax-only; the rest of the package still benefits.
Cost: the analyzer has a multi-second cold start, so callers that do not need receiver types (Tier A structural studies, plain re-encoding) should keep calling encode directly.
Implementation
Future<void> prepareStaticTypes() async {
_resolvedUnits.clear();
final provider = PhysicalResourceProvider.INSTANCE;
final ctx = provider.pathContext;
final rootPath = ctx.normalize(packageDir.absolute.path);
AnalysisContextCollection collection;
try {
collection = AnalysisContextCollection(
includedPaths: <String>[rootPath],
resourceProvider: provider,
);
} on Object catch (e) {
warnings.add(
'Static type resolution unavailable for "$packageName" '
'($rootPath): $e. Encoding without receiver types.',
);
return;
}
try {
for (final relPath in _fileToModule.keys) {
final filePath = ctx.normalize(
ctx.join(rootPath, ctx.joinAll(relPath.split('/'))),
);
if (!File(filePath).existsSync()) continue;
try {
final session = collection.contextFor(filePath).currentSession;
final result = await session.getResolvedUnit(filePath);
if (result is ResolvedUnitResult) {
_resolvedUnits[relPath] = result.unit;
} else {
warnings.add(
'Could not resolve "$relPath" (${result.runtimeType}); '
'encoding it without receiver types.',
);
}
} on Object catch (e) {
warnings.add(
'Could not resolve "$relPath": $e; '
'encoding it without receiver types.',
);
}
}
} finally {
await collection.dispose();
}
}