From 9dae355368eddbb01e37311f3fa6f914d5828ddb Mon Sep 17 00:00:00 2001 From: Emran Bajrami Date: Thu, 24 Sep 2026 12:19:38 +0200 Subject: [PATCH 1/2] Issue #173: Preserve import aliases in generated code --- .github/workflows/check-code-quality.yml | 4 +- widget_driver/example/.gitignore | 2 + .../example/android/app/build.gradle | 8 +- widget_driver/example/android/build.gradle | 13 -- .../gradle/wrapper/gradle-wrapper.properties | 2 +- widget_driver/example/android/settings.gradle | 4 +- .../ios/Flutter/AppFrameworkInfo.plist | 2 +- widget_driver/example/ios/Podfile | 2 +- widget_driver/example/ios/Podfile.lock | 37 ++--- .../ios/Runner.xcodeproj/project.pbxproj | 13 +- .../xcshareddata/xcschemes/Runner.xcscheme | 5 +- .../example/ios/Runner/AppDelegate.swift | 2 +- .../my_first_drivable_widget_driver.g.dart | 2 +- .../coffee_community_page_driver.g.dart | 2 +- .../coffee_detail_page_driver.g.dart | 2 +- .../coffee_library_page_driver.dart | 6 +- .../coffee_library_page_driver.g.dart | 6 +- .../coffee_library/coffee_row.dart | 2 +- .../not_logged_in_page_driver.g.dart | 2 +- .../register_account_page_driver.g.dart | 2 +- ...offee_counter_header_section_driver.g.dart | 2 +- .../coffee_counter_widget_driver.g.dart | 2 +- .../random_coffee_image_widget_driver.g.dart | 2 +- .../widgets/home_page/home_page_driver.g.dart | 2 +- .../log_in_out_button_driver.g.dart | 2 +- .../example/lib/widgets/my_app_driver.g.dart | 2 +- ...playground_test_child_widget_driver.g.dart | 2 +- .../playground_test_widget_driver.g.dart | 2 +- .../Flutter/GeneratedPluginRegistrant.swift | 2 +- widget_driver_generator/CHANGELOG.md | 4 + .../lib/src/models/annotated_element.dart | 4 +- .../lib/src/models/providable_field.dart | 13 +- .../lib/src/utils/element_utils.dart | 41 ++++- .../lib/src/utils/import_prefix_resolver.dart | 118 ++++++++++++++ widget_driver_generator/pubspec.yaml | 4 +- .../utils/import_prefix_resolver_test.dart | 149 ++++++++++++++++++ 36 files changed, 390 insertions(+), 79 deletions(-) create mode 100644 widget_driver_generator/lib/src/utils/import_prefix_resolver.dart create mode 100644 widget_driver_generator/test/utils/import_prefix_resolver_test.dart diff --git a/.github/workflows/check-code-quality.yml b/.github/workflows/check-code-quality.yml index 5809d56..656f063 100644 --- a/.github/workflows/check-code-quality.yml +++ b/.github/workflows/check-code-quality.yml @@ -22,9 +22,9 @@ jobs: uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Prepare flutter - uses: subosito/flutter-action@e938fdf56512cc96ef2f93601a5a40bde3801046 # v2.19.0 + uses: subosito/flutter-action@1a449444c387b1966244ae4d4f8c696479add0b2 # v2.23.0 with: - flutter-version: "3.22.3" + flutter-version: "3.35.6" channel: "stable" - name: Run quality checks if pipeline label was set run: | diff --git a/widget_driver/example/.gitignore b/widget_driver/example/.gitignore index 24476c5..6c31954 100644 --- a/widget_driver/example/.gitignore +++ b/widget_driver/example/.gitignore @@ -5,9 +5,11 @@ *.swp .DS_Store .atom/ +.build/ .buildlog/ .history .svn/ +.swiftpm/ migrate_working_dir/ # IntelliJ related diff --git a/widget_driver/example/android/app/build.gradle b/widget_driver/example/android/app/build.gradle index 8c6155a..259bb2b 100644 --- a/widget_driver/example/android/app/build.gradle +++ b/widget_driver/example/android/app/build.gradle @@ -29,8 +29,12 @@ android { ndkVersion = flutter.ndkVersion compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 + sourceCompatibility JavaVersion.VERSION_11 + targetCompatibility JavaVersion.VERSION_11 + } + + kotlinOptions { + jvmTarget = JavaVersion.VERSION_11.toString() } sourceSets { diff --git a/widget_driver/example/android/build.gradle b/widget_driver/example/android/build.gradle index 3cdaac9..bc157bd 100644 --- a/widget_driver/example/android/build.gradle +++ b/widget_driver/example/android/build.gradle @@ -1,16 +1,3 @@ -buildscript { - ext.kotlin_version = '1.6.10' - repositories { - google() - mavenCentral() - } - - dependencies { - classpath 'com.android.tools.build:gradle:7.1.2' - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - } -} - allprojects { repositories { google() diff --git a/widget_driver/example/android/gradle/wrapper/gradle-wrapper.properties b/widget_driver/example/android/gradle/wrapper/gradle-wrapper.properties index e1ca574..ac3b479 100644 --- a/widget_driver/example/android/gradle/wrapper/gradle-wrapper.properties +++ b/widget_driver/example/android/gradle/wrapper/gradle-wrapper.properties @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.3-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-all.zip diff --git a/widget_driver/example/android/settings.gradle b/widget_driver/example/android/settings.gradle index 536165d..b507b94 100644 --- a/widget_driver/example/android/settings.gradle +++ b/widget_driver/example/android/settings.gradle @@ -18,8 +18,8 @@ pluginManagement { plugins { id "dev.flutter.flutter-plugin-loader" version "1.0.0" - id "com.android.application" version "7.3.0" apply false - id "org.jetbrains.kotlin.android" version "1.7.10" apply false + id "com.android.application" version "8.9.1" apply false + id "org.jetbrains.kotlin.android" version "2.1.0" apply false } include ":app" diff --git a/widget_driver/example/ios/Flutter/AppFrameworkInfo.plist b/widget_driver/example/ios/Flutter/AppFrameworkInfo.plist index 9625e10..1dc6cf7 100644 --- a/widget_driver/example/ios/Flutter/AppFrameworkInfo.plist +++ b/widget_driver/example/ios/Flutter/AppFrameworkInfo.plist @@ -21,6 +21,6 @@ CFBundleVersion 1.0 MinimumOSVersion - 11.0 + 13.0 diff --git a/widget_driver/example/ios/Podfile b/widget_driver/example/ios/Podfile index 5c4ba94..ab9d86b 100644 --- a/widget_driver/example/ios/Podfile +++ b/widget_driver/example/ios/Podfile @@ -1,4 +1,4 @@ -platform :ios, '11.0' +platform :ios, '15.0' # CocoaPods analytics sends network stats synchronously affecting flutter build latency. ENV['COCOAPODS_DISABLE_STATS'] = 'true' diff --git a/widget_driver/example/ios/Podfile.lock b/widget_driver/example/ios/Podfile.lock index 58d6ece..3efb704 100644 --- a/widget_driver/example/ios/Podfile.lock +++ b/widget_driver/example/ios/Podfile.lock @@ -1,37 +1,30 @@ PODS: - Flutter (1.0.0) - - FMDB (2.7.5): - - FMDB/standard (= 2.7.5) - - FMDB/standard (2.7.5) - - path_provider_ios (0.0.1): + - path_provider_foundation (0.0.1): - Flutter - - sqflite (0.0.2): + - FlutterMacOS + - sqflite_darwin (0.0.4): - Flutter - - FMDB (>= 2.7.5) + - FlutterMacOS DEPENDENCIES: - Flutter (from `Flutter`) - - path_provider_ios (from `.symlinks/plugins/path_provider_ios/ios`) - - sqflite (from `.symlinks/plugins/sqflite/ios`) - -SPEC REPOS: - trunk: - - FMDB + - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`) + - sqflite_darwin (from `.symlinks/plugins/sqflite_darwin/darwin`) EXTERNAL SOURCES: Flutter: :path: Flutter - path_provider_ios: - :path: ".symlinks/plugins/path_provider_ios/ios" - sqflite: - :path: ".symlinks/plugins/sqflite/ios" + path_provider_foundation: + :path: ".symlinks/plugins/path_provider_foundation/darwin" + sqflite_darwin: + :path: ".symlinks/plugins/sqflite_darwin/darwin" SPEC CHECKSUMS: - Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854 - FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a - path_provider_ios: 14f3d2fd28c4fdb42f44e0f751d12861c43cee02 - sqflite: 6d358c025f5b867b29ed92fc697fd34924e11904 + Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467 + path_provider_foundation: bb55f6dbba17d0dccd6737fe6f7f34fbd0376880 + sqflite_darwin: 20b2a3a3b70e43edae938624ce550a3cbf66a3d0 -PODFILE CHECKSUM: 985e5b058f26709dc81f9ae74ea2b2775bdbcefe +PODFILE CHECKSUM: cdddfa9a860416e122205d962ea41bf3029a8aaa -COCOAPODS: 1.11.3 +COCOAPODS: 1.16.2 diff --git a/widget_driver/example/ios/Runner.xcodeproj/project.pbxproj b/widget_driver/example/ios/Runner.xcodeproj/project.pbxproj index 4b1a83a..c8f43e1 100644 --- a/widget_driver/example/ios/Runner.xcodeproj/project.pbxproj +++ b/widget_driver/example/ios/Runner.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 51; + objectVersion = 54; objects = { /* Begin PBXBuildFile section */ @@ -155,7 +155,7 @@ 97C146E61CF9000F007C117D /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 1300; + LastUpgradeCheck = 1510; ORGANIZATIONNAME = ""; TargetAttributes = { 97C146ED1CF9000F007C117D = { @@ -199,10 +199,12 @@ /* Begin PBXShellScriptBuildPhase section */ 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); inputPaths = ( + "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", ); name = "Thin Binary"; outputPaths = ( @@ -213,6 +215,7 @@ }; 9740EEB61CF901F6004384FC /* Run Script */ = { isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); @@ -339,7 +342,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; @@ -417,7 +420,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -466,7 +469,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; diff --git a/widget_driver/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/widget_driver/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index c87d15a..9c12df5 100644 --- a/widget_driver/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/widget_driver/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ diff --git a/widget_driver/example/ios/Runner/AppDelegate.swift b/widget_driver/example/ios/Runner/AppDelegate.swift index 70693e4..b636303 100644 --- a/widget_driver/example/ios/Runner/AppDelegate.swift +++ b/widget_driver/example/ios/Runner/AppDelegate.swift @@ -1,7 +1,7 @@ import UIKit import Flutter -@UIApplicationMain +@main @objc class AppDelegate: FlutterAppDelegate { override func application( _ application: UIApplication, diff --git a/widget_driver/example/lib/pub_dev_example_code/my_first_drivable_widget_driver.g.dart b/widget_driver/example/lib/pub_dev_example_code/my_first_drivable_widget_driver.g.dart index b3b2e2a..0a84f4f 100644 --- a/widget_driver/example/lib/pub_dev_example_code/my_first_drivable_widget_driver.g.dart +++ b/widget_driver/example/lib/pub_dev_example_code/my_first_drivable_widget_driver.g.dart @@ -8,7 +8,7 @@ part of 'my_first_drivable_widget_driver.dart'; // coverage:ignore-file -// This file was generated with widget_driver_generator version "1.2.0" +// This file was generated with widget_driver_generator version "1.3.6" class _$TestMyFirstDrivableWidgetDriver extends TestDriver implements MyFirstDrivableWidgetDriver { @override diff --git a/widget_driver/example/lib/widgets/coffee_community/coffee_community_page_driver.g.dart b/widget_driver/example/lib/widgets/coffee_community/coffee_community_page_driver.g.dart index 19fb26d..770cb39 100644 --- a/widget_driver/example/lib/widgets/coffee_community/coffee_community_page_driver.g.dart +++ b/widget_driver/example/lib/widgets/coffee_community/coffee_community_page_driver.g.dart @@ -8,7 +8,7 @@ part of 'coffee_community_page_driver.dart'; // coverage:ignore-file -// This file was generated with widget_driver_generator version "1.2.0" +// This file was generated with widget_driver_generator version "1.3.6" class _$TestCoffeeCommunityPageDriver extends TestDriver implements CoffeeCommunityPageDriver { @override diff --git a/widget_driver/example/lib/widgets/coffee_community/coffee_library/coffee_detail/coffee_detail_page_driver.g.dart b/widget_driver/example/lib/widgets/coffee_community/coffee_library/coffee_detail/coffee_detail_page_driver.g.dart index b1ee309..02c7c20 100644 --- a/widget_driver/example/lib/widgets/coffee_community/coffee_library/coffee_detail/coffee_detail_page_driver.g.dart +++ b/widget_driver/example/lib/widgets/coffee_community/coffee_library/coffee_detail/coffee_detail_page_driver.g.dart @@ -8,7 +8,7 @@ part of 'coffee_detail_page_driver.dart'; // coverage:ignore-file -// This file was generated with widget_driver_generator version "1.2.0" +// This file was generated with widget_driver_generator version "1.3.6" class _$TestCoffeeDetailPageDriver extends TestDriver implements CoffeeDetailPageDriver { @override diff --git a/widget_driver/example/lib/widgets/coffee_community/coffee_library/coffee_library_page_driver.dart b/widget_driver/example/lib/widgets/coffee_community/coffee_library/coffee_library_page_driver.dart index 7c9a4f8..a17475f 100644 --- a/widget_driver/example/lib/widgets/coffee_community/coffee_library/coffee_library_page_driver.dart +++ b/widget_driver/example/lib/widgets/coffee_community/coffee_library/coffee_library_page_driver.dart @@ -1,6 +1,6 @@ import 'dart:async'; -import 'package:example/models/coffee.dart'; +import 'package:example/models/coffee.dart' as c; import 'package:get_it/get_it.dart'; import 'package:widget_driver/widget_driver.dart'; @@ -12,7 +12,7 @@ part 'coffee_library_page_driver.g.dart'; class CoffeeLibraryPageDriver extends WidgetDriver { final CoffeeService _coffeeService; bool _isFetching = false; - List _coffees = []; + List _coffees = []; StreamSubscription? _subscription; CoffeeLibraryPageDriver({ @@ -30,7 +30,7 @@ class CoffeeLibraryPageDriver extends WidgetDriver { int get numberOfCoffees => _coffees.length; - Coffee getCoffeeAtIndex(int index) { + c.Coffee getCoffeeAtIndex(int index) { return _coffees[index]; } diff --git a/widget_driver/example/lib/widgets/coffee_community/coffee_library/coffee_library_page_driver.g.dart b/widget_driver/example/lib/widgets/coffee_community/coffee_library/coffee_library_page_driver.g.dart index 256d089..b2dc5c9 100644 --- a/widget_driver/example/lib/widgets/coffee_community/coffee_library/coffee_library_page_driver.g.dart +++ b/widget_driver/example/lib/widgets/coffee_community/coffee_library/coffee_library_page_driver.g.dart @@ -8,7 +8,7 @@ part of 'coffee_library_page_driver.dart'; // coverage:ignore-file -// This file was generated with widget_driver_generator version "1.2.0" +// This file was generated with widget_driver_generator version "1.3.6" class _$TestCoffeeLibraryPageDriver extends TestDriver implements CoffeeLibraryPageDriver { @override @@ -18,8 +18,8 @@ class _$TestCoffeeLibraryPageDriver extends TestDriver implements CoffeeLibraryP int get numberOfCoffees => 123; @override - Coffee getCoffeeAtIndex(int index) { - return const Coffee( + c.Coffee getCoffeeAtIndex(int index) { + return const c.Coffee( name: 'Coffee', description: 'Some desc', imageUrl: 'http://www.exampleImage.com/image', diff --git a/widget_driver/example/lib/widgets/coffee_community/coffee_library/coffee_row.dart b/widget_driver/example/lib/widgets/coffee_community/coffee_library/coffee_row.dart index f9813ec..f841f62 100644 --- a/widget_driver/example/lib/widgets/coffee_community/coffee_library/coffee_row.dart +++ b/widget_driver/example/lib/widgets/coffee_community/coffee_library/coffee_row.dart @@ -31,7 +31,7 @@ class CoffeeRow extends StatelessWidget { borderRadius: const BorderRadius.all(Radius.circular(8)), boxShadow: [ BoxShadow( - color: Colors.grey.withOpacity(0.5), + color: Colors.grey.withValues(alpha: 0.5), spreadRadius: 1, blurRadius: 1, offset: const Offset(0, 2), // changes position of shadow diff --git a/widget_driver/example/lib/widgets/coffee_community/not_logged_in/not_logged_in_page_driver.g.dart b/widget_driver/example/lib/widgets/coffee_community/not_logged_in/not_logged_in_page_driver.g.dart index 49bdea4..4d50984 100644 --- a/widget_driver/example/lib/widgets/coffee_community/not_logged_in/not_logged_in_page_driver.g.dart +++ b/widget_driver/example/lib/widgets/coffee_community/not_logged_in/not_logged_in_page_driver.g.dart @@ -8,7 +8,7 @@ part of 'not_logged_in_page_driver.dart'; // coverage:ignore-file -// This file was generated with widget_driver_generator version "1.2.0" +// This file was generated with widget_driver_generator version "1.3.6" class _$TestNotLoggedInPageDriver extends TestDriver implements NotLoggedInPageDriver { @override diff --git a/widget_driver/example/lib/widgets/coffee_community/not_logged_in/register_account/register_account_page_driver.g.dart b/widget_driver/example/lib/widgets/coffee_community/not_logged_in/register_account/register_account_page_driver.g.dart index f922977..cfa92da 100644 --- a/widget_driver/example/lib/widgets/coffee_community/not_logged_in/register_account/register_account_page_driver.g.dart +++ b/widget_driver/example/lib/widgets/coffee_community/not_logged_in/register_account/register_account_page_driver.g.dart @@ -8,7 +8,7 @@ part of 'register_account_page_driver.dart'; // coverage:ignore-file -// This file was generated with widget_driver_generator version "1.2.0" +// This file was generated with widget_driver_generator version "1.3.6" class _$TestRegisterAccountPageDriver extends TestDriver implements RegisterAccountPageDriver { @override diff --git a/widget_driver/example/lib/widgets/coffee_consumption/coffee_counter/coffee_counter_header_section_driver.g.dart b/widget_driver/example/lib/widgets/coffee_consumption/coffee_counter/coffee_counter_header_section_driver.g.dart index 59557e0..a6e9c66 100644 --- a/widget_driver/example/lib/widgets/coffee_consumption/coffee_counter/coffee_counter_header_section_driver.g.dart +++ b/widget_driver/example/lib/widgets/coffee_consumption/coffee_counter/coffee_counter_header_section_driver.g.dart @@ -8,7 +8,7 @@ part of 'coffee_counter_header_section_driver.dart'; // coverage:ignore-file -// This file was generated with widget_driver_generator version "1.2.0" +// This file was generated with widget_driver_generator version "1.3.6" class _$TestCoffeeCounterHeaderSectionDriver extends TestDriver implements CoffeeCounterHeaderSectionDriver { @override diff --git a/widget_driver/example/lib/widgets/coffee_consumption/coffee_counter/coffee_counter_widget_driver.g.dart b/widget_driver/example/lib/widgets/coffee_consumption/coffee_counter/coffee_counter_widget_driver.g.dart index 795932f..edd5d92 100644 --- a/widget_driver/example/lib/widgets/coffee_consumption/coffee_counter/coffee_counter_widget_driver.g.dart +++ b/widget_driver/example/lib/widgets/coffee_consumption/coffee_counter/coffee_counter_widget_driver.g.dart @@ -8,7 +8,7 @@ part of 'coffee_counter_widget_driver.dart'; // coverage:ignore-file -// This file was generated with widget_driver_generator version "1.2.0" +// This file was generated with widget_driver_generator version "1.3.6" class _$TestCoffeeCounterWidgetDriver extends TestDriver implements CoffeeCounterWidgetDriver { @override diff --git a/widget_driver/example/lib/widgets/coffee_consumption/random_coffee_image_widget/random_coffee_image_widget_driver.g.dart b/widget_driver/example/lib/widgets/coffee_consumption/random_coffee_image_widget/random_coffee_image_widget_driver.g.dart index 6bf370b..3be0ece 100644 --- a/widget_driver/example/lib/widgets/coffee_consumption/random_coffee_image_widget/random_coffee_image_widget_driver.g.dart +++ b/widget_driver/example/lib/widgets/coffee_consumption/random_coffee_image_widget/random_coffee_image_widget_driver.g.dart @@ -8,7 +8,7 @@ part of 'random_coffee_image_widget_driver.dart'; // coverage:ignore-file -// This file was generated with widget_driver_generator version "1.2.0" +// This file was generated with widget_driver_generator version "1.3.6" class _$TestRandomCoffeeImageWidgetDriver extends TestDriver implements RandomCoffeeImageWidgetDriver { @override diff --git a/widget_driver/example/lib/widgets/home_page/home_page_driver.g.dart b/widget_driver/example/lib/widgets/home_page/home_page_driver.g.dart index 67337ef..ca4262d 100644 --- a/widget_driver/example/lib/widgets/home_page/home_page_driver.g.dart +++ b/widget_driver/example/lib/widgets/home_page/home_page_driver.g.dart @@ -8,7 +8,7 @@ part of 'home_page_driver.dart'; // coverage:ignore-file -// This file was generated with widget_driver_generator version "1.2.0" +// This file was generated with widget_driver_generator version "1.3.6" class _$TestHomePageDriver extends TestDriver implements HomePageDriver { @override diff --git a/widget_driver/example/lib/widgets/home_page/log_in_out_button/log_in_out_button_driver.g.dart b/widget_driver/example/lib/widgets/home_page/log_in_out_button/log_in_out_button_driver.g.dart index eb39cff..d3c3219 100644 --- a/widget_driver/example/lib/widgets/home_page/log_in_out_button/log_in_out_button_driver.g.dart +++ b/widget_driver/example/lib/widgets/home_page/log_in_out_button/log_in_out_button_driver.g.dart @@ -8,7 +8,7 @@ part of 'log_in_out_button_driver.dart'; // coverage:ignore-file -// This file was generated with widget_driver_generator version "1.2.0" +// This file was generated with widget_driver_generator version "1.3.6" class _$TestLogInOutButtonDriver extends TestDriver implements LogInOutButtonDriver { @override diff --git a/widget_driver/example/lib/widgets/my_app_driver.g.dart b/widget_driver/example/lib/widgets/my_app_driver.g.dart index 898d512..7f9e16f 100644 --- a/widget_driver/example/lib/widgets/my_app_driver.g.dart +++ b/widget_driver/example/lib/widgets/my_app_driver.g.dart @@ -8,7 +8,7 @@ part of 'my_app_driver.dart'; // coverage:ignore-file -// This file was generated with widget_driver_generator version "1.2.0" +// This file was generated with widget_driver_generator version "1.3.6" class _$TestMyAppDriver extends TestDriver implements MyAppDriver { @override diff --git a/widget_driver/example/lib/widgets/playground/playground_test_widget/playground_test_child_widget_driver.g.dart b/widget_driver/example/lib/widgets/playground/playground_test_widget/playground_test_child_widget_driver.g.dart index 78ecaff..093a34d 100644 --- a/widget_driver/example/lib/widgets/playground/playground_test_widget/playground_test_child_widget_driver.g.dart +++ b/widget_driver/example/lib/widgets/playground/playground_test_widget/playground_test_child_widget_driver.g.dart @@ -8,7 +8,7 @@ part of 'playground_test_child_widget_driver.dart'; // coverage:ignore-file -// This file was generated with widget_driver_generator version "1.2.0" +// This file was generated with widget_driver_generator version "1.3.6" class _$TestPlaygroundTestChildWidgetDriver extends TestDriver implements PlaygroundTestChildWidgetDriver { @override diff --git a/widget_driver/example/lib/widgets/playground/playground_test_widget/playground_test_widget_driver.g.dart b/widget_driver/example/lib/widgets/playground/playground_test_widget/playground_test_widget_driver.g.dart index 7530321..bfdd60a 100644 --- a/widget_driver/example/lib/widgets/playground/playground_test_widget/playground_test_widget_driver.g.dart +++ b/widget_driver/example/lib/widgets/playground/playground_test_widget/playground_test_widget_driver.g.dart @@ -8,7 +8,7 @@ part of 'playground_test_widget_driver.dart'; // coverage:ignore-file -// This file was generated with widget_driver_generator version "1.2.0" +// This file was generated with widget_driver_generator version "1.3.6" class _$TestPlaygroundTestWidgetDriver extends TestDriver implements PlaygroundTestWidgetDriver { @override diff --git a/widget_driver/example/macos/Flutter/GeneratedPluginRegistrant.swift b/widget_driver/example/macos/Flutter/GeneratedPluginRegistrant.swift index 2bfe7e4..252c004 100644 --- a/widget_driver/example/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/widget_driver/example/macos/Flutter/GeneratedPluginRegistrant.swift @@ -6,7 +6,7 @@ import FlutterMacOS import Foundation import path_provider_foundation -import sqflite +import sqflite_darwin func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) diff --git a/widget_driver_generator/CHANGELOG.md b/widget_driver_generator/CHANGELOG.md index 923a988..ae6e415 100644 --- a/widget_driver_generator/CHANGELOG.md +++ b/widget_driver_generator/CHANGELOG.md @@ -1,5 +1,9 @@ # CHANGELOG +## Unreleased + +- Fixes bug where types imported using an alias (e.g. `import '../constants.dart' as foo;`) were generated without that alias. + ## 1.3.6 - Fixes bug with code generation in child packages using dart 3.6.2 diff --git a/widget_driver_generator/lib/src/models/annotated_element.dart b/widget_driver_generator/lib/src/models/annotated_element.dart index db1f8a9..e05394b 100644 --- a/widget_driver_generator/lib/src/models/annotated_element.dart +++ b/widget_driver_generator/lib/src/models/annotated_element.dart @@ -23,8 +23,10 @@ class AnnotatedElement { ) { final codeDefinition = elementUtils.getCodeDefinitionForElement(element); if (validAnnotationType == null && DefaultReturnValueHelper.hasDefaultValueForType(elementType)) { + final rawReturnValue = DefaultReturnValueHelper.getDefaultValueFor(elementType); + final returnValue = elementUtils.applyImportPrefixes(code: rawReturnValue, type: elementType, element: element); return AnnotatedElement( - returnValue: DefaultReturnValueHelper.getDefaultValueFor(elementType), + returnValue: returnValue, codeDefinition: codeDefinition, ); } else if (validAnnotationType != null) { diff --git a/widget_driver_generator/lib/src/models/providable_field.dart b/widget_driver_generator/lib/src/models/providable_field.dart index c51654a..3482220 100644 --- a/widget_driver_generator/lib/src/models/providable_field.dart +++ b/widget_driver_generator/lib/src/models/providable_field.dart @@ -1,4 +1,5 @@ import 'package:analyzer/dart/element/element.dart'; +import 'package:widget_driver_generator/src/utils/import_prefix_resolver.dart'; import 'package:widget_driver_generator/src/utils/string_extensions.dart'; /// Class representing a field annotated with the `@driverProvidableModel` annotation, to keep track of all the @@ -18,10 +19,18 @@ class ProvidableField { this.defaultValueCode, }); - factory ProvidableField.fromParameterElement(ParameterElement param) { + factory ProvidableField.fromParameterElement( + ParameterElement param, { + ImportPrefixResolver importPrefixResolver = const ImportPrefixResolver(), + }) { + final rawType = param.type.toString().replaceFirst('*', ''); + final library = param.library; + final type = library == null + ? rawType + : importPrefixResolver.applyPrefixes(code: rawType, types: [param.type], library: library); return ProvidableField( name: param.name.removeLeadingUnderscore(), - type: param.type.toString().replaceFirst('*', ''), + type: type, isRequired: param.isRequired, defaultValueCode: param.defaultValueCode, isNamed: param.isNamed, diff --git a/widget_driver_generator/lib/src/utils/element_utils.dart b/widget_driver_generator/lib/src/utils/element_utils.dart index 4dba28d..7fcee2c 100644 --- a/widget_driver_generator/lib/src/utils/element_utils.dart +++ b/widget_driver_generator/lib/src/utils/element_utils.dart @@ -1,12 +1,17 @@ import 'package:analyzer/dart/element/element.dart'; +import 'package:analyzer/dart/element/type.dart'; import 'package:source_gen/source_gen.dart'; import 'package:widget_driver_annotation/widget_driver_annotation.dart'; +import 'import_prefix_resolver.dart'; import 'type_utils.dart'; /// A helper class for getting data out of elements class ElementUtils { - const ElementUtils(); + final ImportPrefixResolver _importPrefixResolver; + + const ElementUtils({ImportPrefixResolver importPrefixResolver = const ImportPrefixResolver()}) + : _importPrefixResolver = importPrefixResolver; /// Checks if the current element has an annotation which is valid. /// If it has a valid annotation, then that annotation type is returned, else it returns null. @@ -38,8 +43,40 @@ class ElementUtils { /// This is defined as the definition for that element. /// For a method you would get back this: /// `void myFunction(int someValue)` + /// + /// If a type used by `element` was imported using an alias (e.g. `import '...' as foo;`), that + /// alias is re-applied to the definition, since the analyzer strips import prefixes on its own. String getCodeDefinitionForElement(Element element) { - return element.toString(); + final codeDefinition = element.toString(); + final library = element.library; + final types = _relevantTypesFor(element); + if (library == null || types.isEmpty) { + return codeDefinition; + } + return _importPrefixResolver.applyPrefixes(code: codeDefinition, types: types, library: library); + } + + List _relevantTypesFor(Element element) { + if (element is FieldElement) { + return [element.type]; + } + if (element is PropertyAccessorElement) { + return [element.returnType, ...element.parameters.map((parameter) => parameter.type)]; + } + if (element is MethodElement) { + return [element.returnType, ...element.parameters.map((parameter) => parameter.type)]; + } + return const []; + } + + /// Re-applies the import alias of `type` (if any) to `code`, e.g. turning a default return value + /// like `Coffee()` into `foo.Coffee()` when `element`'s library imports `Coffee` as `foo`. + String applyImportPrefixes({required String code, required DartType type, required Element element}) { + final library = element.library; + if (library == null) { + return code; + } + return _importPrefixResolver.applyPrefixes(code: code, types: [type], library: library); } /// Gets the return value for the given element. diff --git a/widget_driver_generator/lib/src/utils/import_prefix_resolver.dart b/widget_driver_generator/lib/src/utils/import_prefix_resolver.dart new file mode 100644 index 0000000..16f688f --- /dev/null +++ b/widget_driver_generator/lib/src/utils/import_prefix_resolver.dart @@ -0,0 +1,118 @@ +import 'package:analyzer/dart/element/element.dart'; +import 'package:analyzer/dart/element/type.dart'; + +/// Rewrites generated code so that types keep the import prefix (alias) they were declared with. +/// +/// The analyzer strips import prefixes from `Element.toString()` and `DartType.toString()`, because +/// a prefix is just syntax used by the referencing file and is not part of the type itself. E.g. if a +/// library imports another one with `import '../constants.dart' as foo;` and then declares +/// `foo.SomeClass get someGetter => ...`, the analyzer will report the type as just `SomeClass`. +/// This class re-adds `foo.` in front of `SomeClass`, by looking up the import prefix used for the +/// type's defining library inside the library that declares the inspected element. +class ImportPrefixResolver { + const ImportPrefixResolver(); + + /// Returns [code] with every type in [types] (including their generic type arguments) replaced by + /// its aliased name, if [library] imports that type's defining library with a prefix. + /// Occurrences inside string literals (e.g. `'Coffee'` inside a default value like + /// `Coffee(name: 'Coffee')`) are left untouched. + String applyPrefixes({ + required String code, + required List types, + required LibraryElement library, + }) { + final prefixesByTypeName = _buildPrefixesByTypeName(types, library); + if (prefixesByTypeName.isEmpty) { + return code; + } + return _replaceOutsideStringLiterals(code, prefixesByTypeName); + } + + String _replaceOutsideStringLiterals(String code, Map prefixesByTypeName) { + final result = StringBuffer(); + var codeSegment = StringBuffer(); + var index = 0; + while (index < code.length) { + final delimiterLength = _stringDelimiterLengthAt(code, index); + if (delimiterLength == null) { + codeSegment.writeCharCode(code.codeUnitAt(index)); + index++; + continue; + } + + result.write(_replaceInCode(codeSegment.toString(), prefixesByTypeName)); + codeSegment = StringBuffer(); + + final literalStart = index; + final delimiter = code.substring(index, index + delimiterLength); + index += delimiterLength; + while (index < code.length && !code.startsWith(delimiter, index)) { + // skip escaped characters so an escaped quote doesn't end the literal early. + index += code.codeUnitAt(index) == _backslash ? 2 : 1; + } + final literalEnd = (index + delimiterLength).clamp(0, code.length); + result.write(code.substring(literalStart, literalEnd)); + index = literalEnd; + } + result.write(_replaceInCode(codeSegment.toString(), prefixesByTypeName)); + return result.toString(); + } + + static const _backslash = 0x5C; + + int? _stringDelimiterLengthAt(String code, int index) { + final char = code.substring(index, index + 1); + if (char != "'" && char != '"') { + return null; + } + return code.startsWith(char + char + char, index) ? 3 : 1; + } + + String _replaceInCode(String code, Map prefixesByTypeName) { + var result = code; + for (final entry in prefixesByTypeName.entries) { + // Negative lookbehind avoids re-prefixing names that are already qualified or part of a longer identifier. + final pattern = RegExp('(? _buildPrefixesByTypeName(List types, LibraryElement library) { + final prefixesByTypeName = {}; + for (final type in _flatten(types)) { + final typeElement = type.element; + final typeName = typeElement?.name; + final typeLibrary = typeElement?.library; + if (typeElement == null || typeName == null || typeLibrary == null || typeLibrary == library) { + continue; + } + final prefix = _findImportPrefix(library, typeLibrary); + if (prefix != null) { + prefixesByTypeName[typeName] = '$prefix.$typeName'; + } + } + return prefixesByTypeName; + } + + String? _findImportPrefix(LibraryElement library, LibraryElement typeLibrary) { + for (final import in library.libraryImports) { + final prefix = import.prefix; + if (import.importedLibrary == typeLibrary && prefix != null) { + return prefix.element.name; + } + } + return null; + } + + Iterable _flatten(List types) sync* { + for (final type in types) { + yield type; + if (type is InterfaceType) { + yield* _flatten(type.typeArguments); + } else if (type is FunctionType) { + yield* _flatten([type.returnType, ...type.parameters.map((parameter) => parameter.type)]); + } + } + } +} diff --git a/widget_driver_generator/pubspec.yaml b/widget_driver_generator/pubspec.yaml index 4092362..9e5b0ca 100644 --- a/widget_driver_generator/pubspec.yaml +++ b/widget_driver_generator/pubspec.yaml @@ -1,6 +1,6 @@ name: widget_driver_generator description: This package provides generators for WidgetDriver to automate the creation of your TestDrivers and WidgetDriverProviders -version: 1.3.6 +version: 1.3.7 repository: https://github.com/bmw-tech/widget_driver/tree/master/widget_driver_generator issue_tracker: https://github.com/bmw-tech/widget_driver/issues @@ -15,7 +15,7 @@ environment: dependencies: build: ^2.0.0 source_gen: ^1.0.0 - analyzer: ^5.13.0 + analyzer: '>=5.13.0 <8.0.0' widget_driver_annotation: ^1.0.2 yaml: ^3.1.2 dart_style: ^2.3.2 diff --git a/widget_driver_generator/test/utils/import_prefix_resolver_test.dart b/widget_driver_generator/test/utils/import_prefix_resolver_test.dart new file mode 100644 index 0000000..235a5d6 --- /dev/null +++ b/widget_driver_generator/test/utils/import_prefix_resolver_test.dart @@ -0,0 +1,149 @@ +import 'package:analyzer/dart/element/element.dart'; +import 'package:analyzer/dart/element/type.dart'; +import 'package:mocktail/mocktail.dart'; +import 'package:test/test.dart'; +import 'package:widget_driver_generator/src/utils/import_prefix_resolver.dart'; + +class MockLibraryElement extends Mock implements LibraryElement {} + +class MockLibraryImportElement extends Mock implements LibraryImportElement {} + +class MockImportElementPrefix extends Mock implements ImportElementPrefix {} + +class MockPrefixElement extends Mock implements PrefixElement {} + +class MockElement extends Mock implements Element {} + +class MockDartType extends Mock implements DartType {} + +class MockInterfaceType extends Mock implements InterfaceType {} + +class MockInterfaceElement extends Mock implements InterfaceElement {} + +void main() { + const sut = ImportPrefixResolver(); + + late MockLibraryElement contextLibrary; + late MockLibraryElement typeLibrary; + + setUp(() { + contextLibrary = MockLibraryElement(); + typeLibrary = MockLibraryElement(); + }); + + MockDartType typeNamed(String name, LibraryElement library) { + final element = MockElement(); + when(() => element.name).thenReturn(name); + when(() => element.library).thenReturn(library); + final type = MockDartType(); + when(() => type.element).thenReturn(element); + return type; + } + + MockLibraryImportElement importOf(LibraryElement importedLibrary, {String? prefix}) { + final import = MockLibraryImportElement(); + when(() => import.importedLibrary).thenReturn(importedLibrary); + if (prefix == null) { + when(() => import.prefix).thenReturn(null); + } else { + final prefixElement = MockPrefixElement(); + when(() => prefixElement.name).thenReturn(prefix); + final importPrefix = MockImportElementPrefix(); + when(() => importPrefix.element).thenReturn(prefixElement); + when(() => import.prefix).thenReturn(importPrefix); + } + return import; + } + + group('ImportPrefixResolver:', () { + test('adds the alias in front of a type imported with a prefix', () { + final import = importOf(typeLibrary, prefix: 'foo'); + final type = typeNamed('SomeClass', typeLibrary); + when(() => contextLibrary.libraryImports).thenReturn([import]); + + final result = sut.applyPrefixes( + code: 'SomeClass get someGetter', + types: [type], + library: contextLibrary, + ); + + expect(result, 'foo.SomeClass get someGetter'); + }); + + test('does not change code if the type is declared in the same library', () { + when(() => contextLibrary.libraryImports).thenReturn([]); + final type = typeNamed('SomeClass', contextLibrary); + + final result = sut.applyPrefixes( + code: 'SomeClass get someGetter', + types: [type], + library: contextLibrary, + ); + + expect(result, 'SomeClass get someGetter'); + }); + + test('does not change code if the import has no prefix', () { + final import = importOf(typeLibrary); + final type = typeNamed('SomeClass', typeLibrary); + when(() => contextLibrary.libraryImports).thenReturn([import]); + + final result = sut.applyPrefixes( + code: 'SomeClass get someGetter', + types: [type], + library: contextLibrary, + ); + + expect(result, 'SomeClass get someGetter'); + }); + + test('adds the alias for type arguments of a generic type', () { + final import = importOf(typeLibrary, prefix: 'foo'); + final typeArgument = typeNamed('SomeClass', typeLibrary); + final dartCoreLibrary = MockLibraryElement(); + final listElement = MockInterfaceElement(); + when(() => listElement.name).thenReturn('List'); + when(() => listElement.library).thenReturn(dartCoreLibrary); + final listType = MockInterfaceType(); + when(() => listType.element).thenReturn(listElement); + when(() => listType.typeArguments).thenReturn([typeArgument]); + when(() => contextLibrary.libraryImports).thenReturn([import]); + + final result = sut.applyPrefixes( + code: 'void doSomething(List list)', + types: [listType], + library: contextLibrary, + ); + + expect(result, 'void doSomething(List list)'); + }); + + test('does not re-prefix a name that is already qualified', () { + final import = importOf(typeLibrary, prefix: 'foo'); + final type = typeNamed('SomeClass', typeLibrary); + when(() => contextLibrary.libraryImports).thenReturn([import]); + + final result = sut.applyPrefixes( + code: 'bar.SomeClass get someGetter', + types: [type], + library: contextLibrary, + ); + + expect(result, 'bar.SomeClass get someGetter'); + }); + + test('does not prefix an occurrence of the type name inside a string literal', () { + final import = importOf(typeLibrary, prefix: 'foo'); + final type = typeNamed('SomeClass', typeLibrary); + when(() => contextLibrary.libraryImports).thenReturn([import]); + + final result = sut.applyPrefixes( + code: "const SomeClass(name: 'SomeClass')", + types: [type], + library: contextLibrary, + ); + + expect(result, "const foo.SomeClass(name: 'SomeClass')"); + }); + }); +} From d06f8da090b0f3d08861a6ef740432d500313b13 Mon Sep 17 00:00:00 2001 From: Emran Bajrami Date: Thu, 24 Sep 2026 12:30:59 +0200 Subject: [PATCH 2/2] Update pubspec.yaml --- widget_driver/example/pubspec.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/widget_driver/example/pubspec.yaml b/widget_driver/example/pubspec.yaml index fd4d5fe..8c00183 100644 --- a/widget_driver/example/pubspec.yaml +++ b/widget_driver/example/pubspec.yaml @@ -28,5 +28,11 @@ dev_dependencies: build_runner: widget_driver_generator: ^1.2.0 +# Overrides the published widget_driver_generator with the local package, whose analyzer +# constraint was relaxed to resolve with newer Flutter SDKs (see widget_driver_generator/pubspec.yaml). +dependency_overrides: + widget_driver_generator: + path: ../../widget_driver_generator + flutter: uses-material-design: true