Skip to content

Commit 368277d

Browse files
munificentCommit Queue
authored andcommitted
[private named parameters] Implement in analyzer
I considered a few different approaches for how to model a formal parameter having a public and private name. Here's a simple example: ```dart class C { int? _f; C({this._f}); } main() { C(f: 1); } ``` Here, it seems like the right approach is to give the formal parameter the public name since that's what you pass for the parameter. Then have resolution understand that the parameter can still map to a private instance variable. But then consider: ```dart class C { int? _f; int? x; C({this._f}) : x = _f; } ``` The formal parameter for _f can also be accessed inside the initializer list and here it must have the private name. So, really, the name of the formal parameter *is* the private name. It's what the user wrote. It's the name that matches the instance field. It's the name that can be used to access the formal parameter in the initializer list. The *only* places the public name come into play are: 1. The name you use to pass an argument to that parameter in a named expression. 2. The generated Dartdoc for that constructor. Given that, I though a simple solution might be to give FormalParameterElement another property for "argument name". In places where we are binding an argument to the parameter, we use that to figure out which parameter is being referred to. Later when I work on Dartdoc support, I'll use that when generating the constructor signature. Everything else just keeps using the name. Thoughts? Change-Id: Id6ccf8d850480f141dc0dc6e26f7b185b60f6c3d Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/459663 Reviewed-by: Konstantin Shcheglov <[email protected]> Reviewed-by: Paul Berry <[email protected]> Reviewed-by: Brian Wilkerson <[email protected]> Commit-Queue: Bob Nystrom <[email protected]> Auto-Submit: Bob Nystrom <[email protected]>
1 parent 3125f46 commit 368277d

File tree

17 files changed

+538
-6
lines changed

17 files changed

+538
-6
lines changed

pkg/analyzer/api.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3642,11 +3642,13 @@ package:analyzer/dart/element/element.dart:
36423642
firstFragment (getter: FieldFormalParameterFragment)
36433643
fragments (getter: List<FieldFormalParameterFragment>)
36443644
isDeclaring (getter: bool, experimental)
3645+
privateName (getter: String?, experimental)
36453646
FieldFormalParameterFragment (class extends Object implements FormalParameterFragment):
36463647
new (constructor: FieldFormalParameterFragment Function())
36473648
element (getter: FieldFormalParameterElement)
36483649
nextFragment (getter: FieldFormalParameterFragment?)
36493650
previousFragment (getter: FieldFormalParameterFragment?)
3651+
privateName (getter: String?, experimental)
36503652
FieldFragment (class extends Object implements PropertyInducingFragment):
36513653
new (constructor: FieldFragment Function())
36523654
element (getter: FieldElement)

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

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1253,6 +1253,24 @@ abstract class FieldFormalParameterElement implements FormalParameterElement {
12531253
/// Whether this is a declaring formal parameter.
12541254
@experimental
12551255
bool get isDeclaring;
1256+
1257+
/// If this field formal parameter is a named parameter with a private name,
1258+
/// the original private name.
1259+
///
1260+
/// In that case, [name] is the corresponding public name for the parameter
1261+
/// and [privateName] is the original declared name. Otherwise (the declared
1262+
/// name wasn't private or was private but has no corresponding public name),
1263+
/// then, [privateName] is `null`.
1264+
///
1265+
/// The private name is used for:
1266+
///
1267+
/// * Accessing the parameter in the initializer list.
1268+
///
1269+
/// * Finding the corresponding instance variable.
1270+
///
1271+
/// * Referring to the parameter in the constructor's doc comment.
1272+
@experimental
1273+
String? get privateName;
12561274
}
12571275

12581276
/// The portion of a [FieldFormalParameterElement] contributed by a single
@@ -1268,6 +1286,13 @@ abstract class FieldFormalParameterFragment implements FormalParameterFragment {
12681286

12691287
@override
12701288
FieldFormalParameterFragment? get previousFragment;
1289+
1290+
/// If this field formal parameter is a named parameter with a private name,
1291+
/// the original private name.
1292+
///
1293+
/// In that case, [name] is the corresponding public name for the parameter.
1294+
@experimental
1295+
String? get privateName;
12711296
}
12721297

12731298
/// The portion of a [FieldElement] contributed by a single declaration.

pkg/analyzer/lib/src/dart/analysis/driver.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ testFineAfterLibraryAnalyzerHook;
109109
// TODO(scheglov): Clean up the list of implicitly analyzed files.
110110
class AnalysisDriver {
111111
/// The version of data format, should be incremented on every format change.
112-
static const int DATA_VERSION = 584;
112+
static const int DATA_VERSION = 585;
113113

114114
/// The number of exception contexts allowed to write. Once this field is
115115
/// zero, we stop writing any new exception contexts in this process.

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

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ import 'package:analyzer/src/utilities/extensions/collection.dart';
6060
import 'package:analyzer/src/utilities/extensions/element.dart';
6161
import 'package:analyzer/src/utilities/extensions/object.dart';
6262
import 'package:collection/collection.dart';
63+
import 'package:meta/meta.dart';
6364
import 'package:pub_semver/pub_semver.dart';
6465

6566
part 'element.g.dart';
@@ -2856,6 +2857,9 @@ class FieldFormalParameterElementImpl extends FormalParameterElementImpl
28562857
@override
28572858
bool get isDeclaring => _firstFragment.isDeclaring;
28582859

2860+
@override
2861+
String? get privateName => _firstFragment.privateName;
2862+
28592863
@override
28602864
FieldFormalParameterFragmentImpl get _firstFragment =>
28612865
super._firstFragment as FieldFormalParameterFragmentImpl;
@@ -2865,13 +2869,18 @@ class FieldFormalParameterElementImpl extends FormalParameterElementImpl
28652869
class FieldFormalParameterFragmentImpl extends FormalParameterFragmentImpl
28662870
with _FieldFormalParameterFragmentImplMixin
28672871
implements FieldFormalParameterFragment {
2872+
@experimental
2873+
@override
2874+
final String? privateName;
2875+
28682876
/// Initialize a newly created parameter element to have the given [name] and
28692877
/// [nameOffset].
28702878
FieldFormalParameterFragmentImpl({
28712879
super.firstTokenOffset,
28722880
required super.name,
28732881
required super.nameOffset,
28742882
required super.parameterKind,
2883+
required this.privateName,
28752884
});
28762885

28772886
@override
@@ -3110,9 +3119,7 @@ class FormalParameterElementImpl extends PromotableElementImpl
31103119
}
31113120

31123121
@override
3113-
String? get name {
3114-
return _firstFragment.name;
3115-
}
3122+
String? get name => _firstFragment.name;
31163123

31173124
@override
31183125
String get nameShared => _firstFragment.name ?? '';

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -555,6 +555,9 @@ class SubstitutedFieldFormalParameterElementImpl
555555

556556
@override
557557
bool get isDeclaring => baseElement.isDeclaring;
558+
559+
@override
560+
String? get privateName => baseElement.privateName;
558561
}
559562

560563
/// A parameter element defined in a parameterized type where the values of the

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

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,15 @@ class ConstructorInitializerScope extends EnclosedScope {
2323
if (formalParameter.name == '_' && hasWildcardVariables) {
2424
continue;
2525
}
26-
_addGetter(formalParameter);
26+
27+
// If the parameter is a private named parameter, then the formal
28+
// parameter's name is the public name, but in the constructor initializer
29+
// list, it is referred to by its private name.
30+
if (formalParameter case FieldFormalParameterElement(:var privateName?)) {
31+
_getters[privateName] ??= formalParameter;
32+
} else {
33+
_addGetter(formalParameter);
34+
}
2735
}
2836
}
2937
}

pkg/analyzer/lib/src/dart/resolver/resolution_visitor.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -473,6 +473,7 @@ class ResolutionVisitor extends RecursiveAstVisitor<void> {
473473
parameterKind: node.kind,
474474
name: name2,
475475
nameOffset: nameOffset2,
476+
privateName: null,
476477
)..constantInitializer = node.defaultValue;
477478
} else if (node.parameter is SuperFormalParameter) {
478479
// Only for recovery, this should not happen in valid code.
@@ -667,6 +668,7 @@ class ResolutionVisitor extends RecursiveAstVisitor<void> {
667668
name: nameToken.lexeme.nullIfEmpty,
668669
nameOffset: nameToken.offset.nullIfNegative,
669670
parameterKind: node.kind,
671+
privateName: null,
670672
);
671673
_elementHolder.enclose(fragment);
672674
fragment.isConst = node.isConst;

pkg/analyzer/lib/src/generated/error_verifier.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6032,6 +6032,12 @@ class ErrorVerifier extends RecursiveAstVisitor<void>
60326032
return;
60336033
}
60346034

6035+
// Must refer to a field.
6036+
// TODO(rnystrom): Handle primary constructor declaring parameters.
6037+
if (parameter is! FieldFormalParameter) {
6038+
return;
6039+
}
6040+
60356041
if (correspondingPublicName(name.lexeme) == null) {
60366042
diagnosticReporter.atToken(
60376043
name,

pkg/analyzer/lib/src/summary2/bundle_reader.dart

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -743,6 +743,9 @@ class LibraryReader {
743743
});
744744
}
745745

746+
/// Read the resolution for a formal parameter list fragment for a
747+
/// top-level function, method, constructor, getter, or setter
748+
/// declaration.
746749
void _readFormalParameters2(
747750
LibraryFragmentImpl unitElement,
748751
ResolutionReader reader,
@@ -1051,6 +1054,8 @@ class LibraryReader {
10511054
return _reader.readOptionalObject(() => _readReference());
10521055
}
10531056

1057+
/// Read the formal parameter list for a top-level function, method,
1058+
/// constructor, getter, or setter declaration.
10541059
// TODO(scheglov): Deduplicate parameter reading implementation.
10551060
List<FormalParameterFragmentImpl> _readParameters() {
10561061
return _reader.readTypedList(() {
@@ -1064,10 +1069,12 @@ class LibraryReader {
10641069

10651070
FormalParameterFragmentImpl element;
10661071
if (isInitializingFormal) {
1072+
var privateName = _reader.readOptionalStringReference();
10671073
element = FieldFormalParameterFragmentImpl(
10681074
name: fragmentName,
10691075
nameOffset: null,
10701076
parameterKind: kind,
1077+
privateName: privateName,
10711078
);
10721079
} else if (isSuperFormal) {
10731080
element = SuperFormalParameterFragmentImpl(
@@ -1780,6 +1787,8 @@ class ResolutionReader {
17801787
return type;
17811788
}
17821789

1790+
/// Read the formal parameter list for a function type annotation or type
1791+
/// alias of a function type.
17831792
List<FormalParameterFragmentImpl> _readFormalParameters(
17841793
LibraryFragmentImpl? unitElement,
17851794
) {
@@ -1793,10 +1802,12 @@ class ResolutionReader {
17931802
var name = _readFragmentName();
17941803
FormalParameterFragmentImpl element;
17951804
if (isInitializingFormal) {
1805+
var privateName = _reader.readOptionalStringReference();
17961806
element = FieldFormalParameterFragmentImpl(
17971807
name: name,
17981808
nameOffset: null,
17991809
parameterKind: kind,
1810+
privateName: privateName,
18001811
);
18011812
element.element.type = type;
18021813
} else {

pkg/analyzer/lib/src/summary2/bundle_writer.dart

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -626,13 +626,20 @@ class BundleWriter {
626626
_sink.writeOptionalObject(reference, _writeReference);
627627
}
628628

629+
/// Write a formal parameter fragment in the signature of a top-level
630+
/// function, constructor, method, getter, or setter declaration.
629631
// TODO(scheglov): Deduplicate parameter writing implementation.
630632
void _writeParameterElement(FormalParameterFragmentImpl element) {
631633
_writeFragmentId(element);
632634
_writeFragmentName(element);
633635
_sink.writeBool(element.isInitializingFormal);
634636
_sink.writeBool(element.isSuperFormal);
635637
_sink._writeFormalParameterKind(element);
638+
639+
if (element is FieldFormalParameterFragmentImpl) {
640+
_sink.writeOptionalStringReference(element.privateName);
641+
}
642+
636643
element.writeModifiers(_sink);
637644

638645
_resolutionSink._writeMetadata(element.metadata);
@@ -1019,6 +1026,7 @@ class ResolutionSink extends BinaryWriter {
10191026
writeOptionalStringReference(element.name);
10201027
}
10211028

1029+
/// Write the formal parameter list for a function type alias.
10221030
void _writeFormalParameters(
10231031
List<FormalParameterFragmentImpl> parameters, {
10241032
required bool withAnnotations,
@@ -1030,6 +1038,9 @@ class ResolutionSink extends BinaryWriter {
10301038
_writeTypeParameters(parameter.typeParameters, () {
10311039
writeType(parameter.element.type);
10321040
_writeFragmentName(parameter);
1041+
if (parameter case FieldFormalParameterElementImpl fieldFormal) {
1042+
writeOptionalStringReference(fieldFormal.privateName);
1043+
}
10331044
_writeFormalParameters(
10341045
parameter.formalParameters,
10351046
withAnnotations: withAnnotations,
@@ -1041,6 +1052,7 @@ class ResolutionSink extends BinaryWriter {
10411052
});
10421053
}
10431054

1055+
/// Write the formal parameter list for a function type annotation.
10441056
void _writeFormalParameters2(
10451057
List<InternalFormalParameterElement> parameters, {
10461058
required bool withAnnotations,
@@ -1052,6 +1064,10 @@ class ResolutionSink extends BinaryWriter {
10521064
_writeTypeParameters2(parameter.typeParameters, () {
10531065
writeType(parameter.type);
10541066
_writeElementName(parameter);
1067+
if (parameter.baseElement
1068+
case FieldFormalParameterElementImpl fieldFormal) {
1069+
writeOptionalStringReference(fieldFormal.privateName);
1070+
}
10551071
_writeFormalParameters2(
10561072
parameter.formalParameters.cast(),
10571073
withAnnotations: withAnnotations,

0 commit comments

Comments
 (0)