Skip to content

Commit 0bbe7f3

Browse files
Add suppression for obsolete mrw buildable types (microsoft#8258)
This PR adds a generated suppression for obsolete types of ModelReaderWriterBuildable. fixes: microsoft#7989
1 parent 731e520 commit 0bbe7f3

6 files changed

Lines changed: 339 additions & 34 deletions

File tree

packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ModelReaderWriterContextDefinition.cs

Lines changed: 72 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ namespace Microsoft.TypeSpec.Generator.ClientModel.Providers
1616
{
1717
public class ModelReaderWriterContextDefinition : TypeProvider
1818
{
19+
private const string DefaultObsoleteDiagnosticId = "CS0618";
20+
1921
internal static readonly string s_name = $"{RemovePeriods(ScmCodeModelGenerator.Instance.TypeFactory.PrimaryNamespace)}Context";
2022

2123
protected override string BuildName() => s_name;
@@ -39,36 +41,28 @@ protected override IReadOnlyList<MethodBodyStatement> BuildAttributes()
3941
var attributeType = new CSharpType(typeof(ModelReaderWriterBuildableAttribute));
4042
var attributeStatement = new AttributeStatement(attributeType, TypeOf(buildableType.Key));
4143

42-
// If the type is experimental, we add a suppression for it
43-
string justification = $"{buildableType.Key} is experimental and may change in future versions.";
44+
string experimentalTypeJustification = $"{buildableType.Key} is experimental and may change in future versions.";
45+
string obsoleteTypeJustification = $"{buildableType.Key} is obsolete and may be removed in future versions.";
46+
4447
if (buildableType.Value is not null)
4548
{
46-
var experimentalAttribute =
47-
buildableType.Value.CanonicalView.Attributes.FirstOrDefault(a => a.Type.Equals(typeof(ExperimentalAttribute)));
48-
if (experimentalAttribute != null)
49-
{
50-
var key = experimentalAttribute.Arguments[0];
51-
attributes.Add(new SuppressionStatement(attributeStatement, key, justification));
52-
}
53-
else
54-
{
55-
attributes.Add(attributeStatement);
56-
}
49+
// If the type is experimental or obsolete, we add a suppression for it
50+
AddAttributeForType(
51+
attributes,
52+
attributeStatement,
53+
buildableType.Value,
54+
experimentalTypeJustification,
55+
obsoleteTypeJustification);
5756
}
5857
// A dependency model - need to use reflection to get the attribute data
5958
else if (buildableType.Key.IsFrameworkType)
6059
{
61-
var experimentalAttr = buildableType.Key.FrameworkType.GetCustomAttributes(typeof(ExperimentalAttribute), false)
62-
.FirstOrDefault();
63-
if (experimentalAttr != null)
64-
{
65-
var key = experimentalAttr.GetType().GetProperty("DiagnosticId")?.GetValue(experimentalAttr);
66-
attributes.Add(new SuppressionStatement(attributeStatement, Literal(key), justification));
67-
}
68-
else
69-
{
70-
attributes.Add(attributeStatement);
71-
}
60+
AddAttributeForType(
61+
attributes,
62+
attributeStatement,
63+
buildableType.Key.FrameworkType,
64+
experimentalTypeJustification,
65+
obsoleteTypeJustification);
7266
}
7367
}
7468

@@ -175,8 +169,7 @@ private void CollectBuildableTypesFromFrameworkType(
175169
{
176170
var propertyType = property.PropertyType;
177171

178-
// Handle generic types by getting their concrete types if available
179-
if (propertyType.IsGenericTypeDefinition && frameworkType.Arguments.Count > 0)
172+
if (!propertyType.IsVisible || propertyType.IsGenericTypeDefinition && frameworkType.Arguments.Count > 0)
180173
{
181174
continue;
182175
}
@@ -285,6 +278,59 @@ private static bool ImplementsModelReaderWriter(TypeProvider typeProvider)
285278
return false;
286279
}
287280

281+
private static void AddAttributeForType(
282+
List<MethodBodyStatement> attributes,
283+
AttributeStatement attributeStatement,
284+
TypeProvider typeProvider,
285+
string experimentalTypeJustification,
286+
string obsoleteTypeJustification)
287+
{
288+
AttributeStatement? experimentalOrObsoleteAttribute = typeProvider.CanonicalView.Attributes
289+
.FirstOrDefault(a => a.Type.Equals(typeof(ExperimentalAttribute)) || a.Type.Equals(typeof(ObsoleteAttribute)));
290+
291+
if (experimentalOrObsoleteAttribute?.Type.Equals(typeof(ExperimentalAttribute)) == true)
292+
{
293+
attributes.Add(new SuppressionStatement(attributeStatement, experimentalOrObsoleteAttribute.Arguments[0], experimentalTypeJustification));
294+
}
295+
else if (experimentalOrObsoleteAttribute?.Type.Equals(typeof(ObsoleteAttribute)) == true)
296+
{
297+
attributes.Add(new SuppressionStatement(attributeStatement, Literal(DefaultObsoleteDiagnosticId), obsoleteTypeJustification));
298+
}
299+
else
300+
{
301+
attributes.Add(attributeStatement);
302+
}
303+
}
304+
305+
private static void AddAttributeForType(
306+
List<MethodBodyStatement> attributes,
307+
AttributeStatement attributeStatement,
308+
Type frameworkType,
309+
string experimentalTypeJustification,
310+
string obsoleteTypeJustification)
311+
{
312+
var experimentalAttr = frameworkType.GetCustomAttributes(typeof(ExperimentalAttribute), false)
313+
.FirstOrDefault();
314+
if (experimentalAttr != null)
315+
{
316+
var key = experimentalAttr.GetType().GetProperty("DiagnosticId")?.GetValue(experimentalAttr);
317+
attributes.Add(new SuppressionStatement(attributeStatement, Literal(key), experimentalTypeJustification));
318+
return;
319+
}
320+
321+
var obsoleteAttr = frameworkType.GetCustomAttributes(typeof(ObsoleteAttribute), false)
322+
.FirstOrDefault();
323+
if (obsoleteAttr != null)
324+
{
325+
var key = obsoleteAttr.GetType().GetProperty("DiagnosticId")?.GetValue(obsoleteAttr)
326+
?? DefaultObsoleteDiagnosticId;
327+
attributes.Add(new SuppressionStatement(attributeStatement, Literal(key), obsoleteTypeJustification));
328+
return;
329+
}
330+
331+
attributes.Add(attributeStatement);
332+
}
333+
288334
private static bool IsModelReaderWriterInterfaceType(CSharpType type)
289335
{
290336
return type.Name.StartsWith("IPersistableModel") || type.Name.StartsWith("IJsonModel");

0 commit comments

Comments
 (0)