Skip to content

Commit f631dc4

Browse files
scheglovCommit Queue
authored andcommitted
Fine. Add ElementImpl.firstFragmentLocation to avoid opaque requirements
Building context messages needs the element’s name location, but calling `firstFragment` records an opaque API-use requirement. This patch adds a specialized accessor that exposes only the needed fields so diagnostics can be produced without introducing spurious dependencies. Changes: - Introduce `ElementImpl.firstFragmentLocation`, returning a lightweight `FirstFragmentLocation` with `libraryFragment`, `name`, and `nameOffset`, without recording an opaque requirement. - Update `base_or_final_type_verifier.dart` to build the context message from `firstFragmentLocation` instead of `firstFragment`. This is intended to preserve diagnostic behavior while avoiding opaque requirement tracking and the follow-on rebuilds it can cause. Found with https://dart-review.googlesource.com/c/sdk/+/446480 Change-Id: I096091cd030824cbd8794f4063b963672056da29 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/446562 Reviewed-by: Paul Berry <[email protected]> Commit-Queue: Konstantin Shcheglov <[email protected]>
1 parent 352addf commit f631dc4

File tree

3 files changed

+118
-7
lines changed

3 files changed

+118
-7
lines changed

pkg/analyzer/lib/src/dart/element/element.dart

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1699,6 +1699,16 @@ abstract class ElementImpl implements Element {
16991699
return buffer.toString();
17001700
}
17011701

1702+
/// The location of [firstFragment], without recording opaque requirement.
1703+
@trackedIncludedInId
1704+
FirstFragmentLocation get firstFragmentLocation {
1705+
return FirstFragmentLocation(
1706+
libraryFragment: _firstFragment.libraryFragment,
1707+
name: _firstFragment.name,
1708+
nameOffset: _firstFragment.nameOffset,
1709+
);
1710+
}
1711+
17021712
@override
17031713
List<Fragment> get fragments {
17041714
return [
@@ -2877,6 +2887,19 @@ class FieldFragmentImpl extends PropertyInducingFragmentImpl
28772887
}
28782888
}
28792889

2890+
/// Location information extracted from [Element.firstFragment].
2891+
class FirstFragmentLocation {
2892+
final LibraryFragmentImpl? libraryFragment;
2893+
final String? name;
2894+
final int? nameOffset;
2895+
2896+
FirstFragmentLocation({
2897+
required this.libraryFragment,
2898+
required this.name,
2899+
required this.nameOffset,
2900+
});
2901+
}
2902+
28802903
class FormalParameterElementImpl extends PromotableElementImpl
28812904
with InternalFormalParameterElement {
28822905
@override

pkg/analyzer/lib/src/error/base_or_final_type_verifier.dart

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -208,10 +208,13 @@ class BaseOrFinalTypeVerifier {
208208
return false;
209209
}
210210

211-
var fragment = baseOrFinalSuperElement.firstFragment;
212-
var fragmentName = fragment.name;
213-
var fragmentNameOffset = fragment.nameOffset;
214-
if (fragmentName == null || fragmentNameOffset == null) {
211+
var superLocation = baseOrFinalSuperElement.firstFragmentLocation;
212+
var superLibraryFragment = superLocation.libraryFragment;
213+
var superName = superLocation.name;
214+
var superNameOffset = superLocation.nameOffset;
215+
if (superLibraryFragment == null ||
216+
superName == null ||
217+
superNameOffset == null) {
215218
return false;
216219
}
217220

@@ -220,13 +223,13 @@ class BaseOrFinalTypeVerifier {
220223
// an induced modifier of the direct super element.
221224
var contextMessages = <DiagnosticMessage>[
222225
DiagnosticMessageImpl(
223-
filePath: fragment.libraryFragment.source.fullName,
224-
length: fragmentName.length,
226+
filePath: superLibraryFragment.source.fullName,
227+
length: superName.length,
225228
message:
226229
"The type '${superElement.displayName}' is a subtype of "
227230
"'${baseOrFinalSuperElement.displayName}', and "
228231
"'${baseOrFinalSuperElement.displayName}' is defined here.",
229-
offset: fragmentNameOffset,
232+
offset: superNameOffset,
230233
url: null,
231234
),
232235
];

pkg/analyzer/test/src/dart/analysis/driver_test.dart

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27019,6 +27019,91 @@ mixin A {
2701927019
);
2702027020
}
2702127021

27022+
test_dependency_notOpaque_baseClassImplementedOutsideOfLibrary() async {
27023+
configuration.withStreamResolvedUnitResults = false;
27024+
await _runChangeScenarioTA(
27025+
initialA: r'''
27026+
base class A {}
27027+
''',
27028+
testCode: r'''
27029+
import 'a.dart';
27030+
base class X implements A {}
27031+
''',
27032+
operation: _FineOperationTestFileGetErrors(),
27033+
expectedInitialEvents: r'''
27034+
[status] working
27035+
[operation] linkLibraryCycle SDK
27036+
[future] getErrors T1
27037+
ErrorsResult #0
27038+
path: /home/test/lib/test.dart
27039+
uri: package:test/test.dart
27040+
flags: isLibrary
27041+
errors
27042+
41 +1 INVALID_USE_OF_TYPE_OUTSIDE_LIBRARY
27043+
[operation] linkLibraryCycle
27044+
package:test/a.dart
27045+
declaredClasses
27046+
A: #M0
27047+
interface: #M1
27048+
requirements
27049+
[operation] linkLibraryCycle
27050+
package:test/test.dart
27051+
declaredClasses
27052+
X: #M2
27053+
interface: #M3
27054+
requirements
27055+
libraries
27056+
package:test/a.dart
27057+
exportedTopLevels
27058+
A: #M0
27059+
interfaces
27060+
A
27061+
interfaceId: #M1
27062+
[operation] analyzeFile
27063+
file: /home/test/lib/test.dart
27064+
library: /home/test/lib/test.dart
27065+
[operation] analyzedLibrary
27066+
file: /home/test/lib/test.dart
27067+
requirements
27068+
libraries
27069+
package:test/a.dart
27070+
exportedTopLevels
27071+
A: #M0
27072+
instances
27073+
A
27074+
[status] idle
27075+
''',
27076+
updatedA: r'''
27077+
base class A {}
27078+
class B {}
27079+
''',
27080+
expectedUpdatedEvents: r'''
27081+
[status] working
27082+
[operation] linkLibraryCycle
27083+
package:test/a.dart
27084+
declaredClasses
27085+
A: #M0
27086+
interface: #M1
27087+
B: #M4
27088+
interface: #M5
27089+
requirements
27090+
[future] getErrors T2
27091+
ErrorsResult #1
27092+
path: /home/test/lib/test.dart
27093+
uri: package:test/test.dart
27094+
flags: isLibrary
27095+
errors
27096+
41 +1 INVALID_USE_OF_TYPE_OUTSIDE_LIBRARY
27097+
[operation] readLibraryCycleBundle
27098+
package:test/test.dart
27099+
[operation] getErrorsFromBytes
27100+
file: /home/test/lib/test.dart
27101+
library: /home/test/lib/test.dart
27102+
[status] idle
27103+
''',
27104+
);
27105+
}
27106+
2702227107
test_dependency_opaqueApiUse_firstFragment() async {
2702327108
_ManualRequirements.install((state) {
2702427109
var A = state.singleUnit.scopeInterfaceElement('A');

0 commit comments

Comments
 (0)