Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .fvmrc
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"flutter": "3.35.2",
"flutter": "3.35.6",
"flavors": {}
}
2 changes: 1 addition & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"dart.flutterSdkPath": ".fvm/versions/3.35.2",
"dart.flutterSdkPath": ".fvm/versions/3.35.6",
"dart.sdkPath": ".fvm/flutter_sdk/bin/cache/dart-sdk",
"search.exclude": {
"**/.fvm": true
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Changelog

## Version 0.23.1-dev
- Fix type hierarchy calculations when the type no longer is known by the new public API

## Version 0.23.0
- technical: use package_config to interact with package configs
Expand Down
32 changes: 27 additions & 5 deletions lib/src/diff/package_api_differ.dart
Original file line number Diff line number Diff line change
Expand Up @@ -42,28 +42,33 @@ class PackageApiDiffer {
'Given models have different semantics. Old Package: ${oldApi.semantics}, New Package: ${newApi.semantics}');
}

final mergedTypeHierarchy = _mergeTypeHierarchy(
base: newApi.typeHierarchy,
filler: oldApi.typeHierarchy,
);

try {
final changes = [
..._calculateInterfacesDiff(
oldApi.interfaceDeclarations,
newApi.interfaceDeclarations,
Stack<Declaration>(),
isExperimental: false,
typeHierarchy: newApi.typeHierarchy,
typeHierarchy: mergedTypeHierarchy,
),
..._calculateExecutablesDiff(
oldApi.executableDeclarations,
newApi.executableDeclarations,
Stack<Declaration>(),
isExperimental: false,
typeHierarchy: newApi.typeHierarchy,
typeHierarchy: mergedTypeHierarchy,
),
..._calculateFieldsDiff(
oldApi.fieldDeclarations,
newApi.fieldDeclarations,
Stack<Declaration>(),
isExperimental: false,
typeHierarchy: newApi.typeHierarchy,
typeHierarchy: mergedTypeHierarchy,
),
..._calculateIOSPlatformConstraintsDiff(
oldApi.iosPlatformConstraints,
Expand Down Expand Up @@ -95,6 +100,23 @@ class PackageApiDiffer {
}
}

TypeHierarchy _mergeTypeHierarchy({
required TypeHierarchy base,
required TypeHierarchy filler,
}) {
final merged = base.clone();

// add types that were known in the old hierarchy but are no longer known in the new hierarchy
for (final oldTypeId in filler.registeredTypes) {
if (!merged.containsType(oldTypeId)) {
final baseTypes = filler.baseTypesOf(oldTypeId);
merged.registerType(oldTypeId, baseTypes ?? {});
}
}

return merged;
}

String _interfaceNameWithoutNamespace(String fullName) {
final lastDotIndex = fullName.lastIndexOf('.');
if (lastDotIndex == -1) {
Expand Down Expand Up @@ -1329,7 +1351,7 @@ class PackageApiDiffer {
return result;
}

_compareParameterTypesAndAddChange(
void _compareParameterTypesAndAddChange(
TypeIdentifier oldTypeidentifier,
TypeIdentifier newTypeIdentifier,
Stack<Declaration> context,
Expand Down Expand Up @@ -1360,7 +1382,7 @@ class PackageApiDiffer {
}
}

_comparePropertiesAndAddChange<T>(
void _comparePropertiesAndAddChange<T>(
T oldValue,
T newValue,
Stack<Declaration> context,
Expand Down
51 changes: 51 additions & 0 deletions lib/src/model/type_hierarchy.dart
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,57 @@ class TypeHierarchy {
);
}

/// clones this type hierarchy
TypeHierarchy clone() {
final cloned = TypeHierarchy.empty();
for (final entry in _types.entries) {
cloned._types[entry.key] = {...entry.value};
}
return cloned;
}

/// returns all registered types in this type hierarchy
List<TypeIdentifier> get registeredTypes {
final result = <TypeIdentifier>[];
for (final items in _types.values) {
for (final item in items) {
result.add(item.typeIdentifier);
}
}
return result;
}

/// returns the base types of the given [typeIdentifier]
/// if the base types are not retrievable then [null] is returned
Set<TypeIdentifier>? baseTypesOf(TypeIdentifier typeIdentifier) {
final items = _types[typeIdentifier.packageAndTypeName];
if (items == null || items.isEmpty) {
return null;
}

if (items.length > 1) {
// there is more than one type with the same name in one package => we need to check the full library name
// and remove all occurences that don't match
final matchingItems = items.where((i) =>
i.typeIdentifier.packageRelativeLibraryPath ==
typeIdentifier.packageRelativeLibraryPath);

try {
// finally we try to get that single entry
return matchingItems.single.baseTypeIdentifiers;
} catch (e) {
// and if this fails we treat the base types as not retrievable and return [null]
return null;
}
}
return items.single.baseTypeIdentifiers;
}

/// checks if this type hierarchy contains the given [typeIdentifier]
bool containsType(TypeIdentifier typeIdentifier) {
return _types.containsKey(typeIdentifier.packageAndTypeName);
}

/// checks if [newTypeIdentifier] is a compatible replacement for [oldTypeIdentifier]
bool isCompatibleReplacement({
required TypeIdentifier oldTypeIdentifier,
Expand Down
44 changes: 44 additions & 0 deletions test/integration_tests/diff/native_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import 'package:dart_apitool/api_tool.dart';
import 'package:test/test.dart';

import '../helper/integration_test_helper.dart';

void main() {
final gitUrl = 'https://github.com/dart-lang/native.git';
group('native diff tests', () {
group('widening in extensions', () {
final refParent = '0924cb0e80ed6ac39298363fabe0916808a4a1fe';
final refChild = '29cf243b4b3452354ef905f62874a8c975ef1538';
final parentRetriever = GitPackageApiRetriever(
gitUrl,
refParent,
relativePackagePath: 'pkgs/data_assets',
);
final childRetriever = GitPackageApiRetriever(
gitUrl,
refChild,
relativePackagePath: 'pkgs/data_assets',
);

late PackageApiDiffResult diffResult;

setUpAll(() async {
final oldApi = await parentRetriever.retrieve();
final newApi = await childRetriever.retrieve();
diffResult = PackageApiDiffer(
options: PackageApiDifferOptions(
doCheckSdkVersion: false,
)).diff(
oldApi: oldApi,
newApi: newApi,
);
});

test('should not be breaking', () {
final breakingChanges =
diffResult.apiChanges.where((change) => change.isBreaking).toList();
expect(breakingChanges, []);
});
});
});
}
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,16 @@ class GitPackageApiRetriever {
packagePath = p.join(tempDir.path, relativePackagePath);
}

await DartInteraction.runDartOrFlutterCommand(packagePath,
args: ['pub', 'get']);

final analyzer = PackageApiAnalyzer(
packagePath: packagePath,
doConsiderNonSrcAsEntryPoints: doConsiderNonSrcAsEntryPoints,
);
print('Analyzing $gitUrl $gitRef');
final logSuffix =
(relativePackagePath != null) ? ' at $relativePackagePath' : '';
print('Analyzing $gitUrl $gitRef$logSuffix');
final result = await analyzer.analyze();
await tempDir.delete(recursive: true);
return result;
Expand Down
Loading