Skip to content

Commit d3042b6

Browse files
authored
Build getter and setter for safe flattened property (#51714)
* Build getter and setter for safe flattened property * fix generation * minor
1 parent 460b3bb commit d3042b6

File tree

1 file changed

+115
-15
lines changed
  • eng/packages/http-client-csharp-mgmt/generator/Azure.Generator.Management/src/Visitors

1 file changed

+115
-15
lines changed

eng/packages/http-client-csharp-mgmt/generator/Azure.Generator.Management/src/Visitors/SafeFlattenVisitor.cs

Lines changed: 115 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -43,27 +43,19 @@ internal class SafeFlattenVisitor : ScmLibraryVisitor
4343
var singleProperty = propertyTypeProvider.Properties.Single();
4444

4545
// make the current property internal
46-
var internalSingleProperty = type!.Properties.Single(p => p.Type.AreNamesEqual(propertyTypeProvider.Type)); // type equal not working here, so we use AreNamesEqual
47-
internalizedProperties.Add(internalSingleProperty);
46+
var internalProperty = type!.Properties.Single(p => p.Type.AreNamesEqual(propertyTypeProvider.Type)); // type equal not working here, so we use AreNamesEqual
47+
internalizedProperties.Add(internalProperty);
4848

4949
// flatten the single property to public and associate it with the internal property
50-
var flattenPropertyName = $"{internalSingleProperty.Name}{singleProperty.Name}"; // TODO: handle name conflicts
51-
var checkNullExpression = This.Property(internalSingleProperty.Name).Is(Null);
52-
MethodBodyStatement setter = new List<MethodBodyStatement>
53-
{
54-
new IfStatement(checkNullExpression)
55-
{
56-
internalSingleProperty.Assign(New.Instance(propertyTypeProvider.Type!)).Terminate()
57-
},
58-
This.Property(internalSingleProperty.Name).Property(singleProperty.Name).Assign(Value).Terminate()
59-
};
50+
var (isFlattenedPropertyReadOnly, includeGetterNullCheck, includeSetterNullCheck) = GetFlags(property.IsReadOnly, singleProperty, propertyTypeProvider, propertyTypeProvider);
51+
var flattenPropertyName = $"{internalProperty.Name}{singleProperty.Name}"; // TODO: handle name conflicts
6052
var flattenPropertyBody = new MethodPropertyBody(
61-
Return(new TernaryConditionalExpression(checkNullExpression, Default, new MemberExpression(internalSingleProperty, singleProperty.Name))),
62-
singleProperty.Body?.HasSetter == true ? setter : null // only add setter for flattend property if the internal property has a setter
53+
BuildGetter(includeGetterNullCheck, internalProperty, propertyTypeProvider, singleProperty),
54+
isFlattenedPropertyReadOnly ? null : BuildSetter(includeSetterNullCheck, propertyTypeProvider, internalProperty, singleProperty)
6355
);
6456
var flattenedProperty = new PropertyProvider(singleProperty.Description, singleProperty.Modifiers, singleProperty.Type, flattenPropertyName, flattenPropertyBody, type, singleProperty.ExplicitInterface, singleProperty.WireInfo, singleProperty.Attributes);
6557
flattenedProperties.Add(flattenedProperty);
66-
flattenedPropertyMap.Add(internalSingleProperty.Type, flattenedProperty);
58+
flattenedPropertyMap.Add(internalProperty.Type, flattenedProperty);
6759
}
6860
}
6961
}
@@ -75,6 +67,114 @@ internal class SafeFlattenVisitor : ScmLibraryVisitor
7567
return base.PreVisitModel(model, type);
7668
}
7769

70+
private static (bool IsReadOnly, bool? IncludeGetterNullCheck, bool IncludeSetterNullCheck) GetFlags(bool isPropertyReadOnly, PropertyProvider singleProperty, ModelProvider innerModel, ModelProvider propertyModel)
71+
{
72+
var isInnerPropertyReadOnly = !singleProperty.Body.HasSetter;
73+
if (!isPropertyReadOnly && isInnerPropertyReadOnly)
74+
{
75+
if (HasDefaultPublicCtor(innerModel))
76+
{
77+
if (singleProperty.Type.Arguments.Count > 0)
78+
return (true, true, false);
79+
else
80+
return (true, false, false);
81+
}
82+
else
83+
{
84+
return (false, false, false);
85+
}
86+
}
87+
else if (!isPropertyReadOnly && !isInnerPropertyReadOnly)
88+
{
89+
if (HasDefaultPublicCtor(propertyModel))
90+
return (false, false, true);
91+
else
92+
return (false, false, false);
93+
}
94+
95+
return (true, null, false);
96+
}
97+
98+
private static bool HasDefaultPublicCtor(ModelProvider innerModel)
99+
{
100+
foreach (var ctor in innerModel.Constructors)
101+
{
102+
if (ctor.Signature.Modifiers.HasFlag(MethodSignatureModifiers.Public) && !ctor.Signature.Parameters.Any())
103+
return true;
104+
}
105+
106+
return false;
107+
}
108+
109+
private MethodBodyStatement BuildGetter(bool? includeGetterNullCheck, PropertyProvider internalProperty, ModelProvider innerModel, PropertyProvider singleProperty)
110+
{
111+
var checkNullExpression = This.Property(internalProperty.Name).Is(Null);
112+
if (includeGetterNullCheck == true)
113+
{
114+
return new List<MethodBodyStatement> {
115+
new IfStatement(checkNullExpression)
116+
{
117+
internalProperty.Assign(New.Instance(innerModel.Type)).Terminate()
118+
},
119+
Return(new MemberExpression(internalProperty, singleProperty.Name))
120+
};
121+
}
122+
else if (includeGetterNullCheck == false)
123+
{
124+
return Return(new TernaryConditionalExpression(checkNullExpression, Default, new MemberExpression(internalProperty, singleProperty.Name)));
125+
}
126+
else
127+
{
128+
if (innerModel.Type.IsNullable)
129+
{
130+
return Return(new MemberExpression(internalProperty.AsVariableExpression.NullConditional(), singleProperty.Name));
131+
}
132+
return Return(new MemberExpression(internalProperty, singleProperty.Name));
133+
}
134+
}
135+
136+
private MethodBodyStatement BuildSetter(bool includeSetterCheck, ModelProvider innerModel, PropertyProvider internalProperty, PropertyProvider singleProperty)
137+
{
138+
var isOverriddenValueType = innerModel.Type.IsValueType && !innerModel.Type.IsNullable;
139+
var setter = new List<MethodBodyStatement>();
140+
var internalPropertyExpression = This.Property(internalProperty.Name);
141+
if (includeSetterCheck)
142+
{
143+
if (isOverriddenValueType)
144+
{
145+
var ifStatement = new IfStatement(Value.Property(nameof(Nullable<int>.HasValue)))
146+
{
147+
new IfStatement(internalPropertyExpression.Is(Null))
148+
{
149+
internalPropertyExpression.Assign(New.Instance(innerModel.Type!)).Terminate(),
150+
internalPropertyExpression.Property(singleProperty.Name).Assign(Value.Property(nameof(Nullable<int>.Value))).Terminate()
151+
}
152+
};
153+
setter.Add(new IfElseStatement(ifStatement, internalProperty.AsVariableExpression.Assign(Null).Terminate()));
154+
}
155+
else
156+
{
157+
setter.Add(new IfStatement(internalPropertyExpression.Is(Null))
158+
{
159+
internalPropertyExpression.Assign(New.Instance(innerModel.Type!)).Terminate()
160+
});
161+
setter.Add(internalPropertyExpression.Property(singleProperty.Name).Assign(Value).Terminate());
162+
}
163+
}
164+
else
165+
{
166+
if (isOverriddenValueType)
167+
{
168+
setter.Add(internalPropertyExpression.Assign(new TernaryConditionalExpression(Value.Property(nameof(Nullable<int>.HasValue)), new MemberExpression(internalProperty, singleProperty.Name), Default)).Terminate());
169+
}
170+
else
171+
{
172+
setter.Add(internalPropertyExpression.Assign(New.Instance(innerModel.Type, Value)).Terminate());
173+
}
174+
}
175+
return setter;
176+
}
177+
78178
protected override TypeProvider? VisitType(TypeProvider type)
79179
{
80180
if (type is ModelProvider model)

0 commit comments

Comments
 (0)