1
1
using Microsoft . CodeAnalysis ;
2
2
using Microsoft . CodeAnalysis . CSharp ;
3
3
using Microsoft . CodeAnalysis . CSharp . Syntax ;
4
+ using System . ComponentModel ;
4
5
using System . Runtime . Serialization ;
5
6
using System . Text ;
6
7
@@ -37,6 +38,7 @@ partial class TypeMeta
37
38
readonly ReferenceSymbols reference ;
38
39
public INamedTypeSymbol Symbol { get ; }
39
40
public GenerateType GenerateType { get ; }
41
+ public SerializeLayout SerializeLayout { get ; }
40
42
/// <summary>MinimallyQualifiedFormat(include generics T>)</summary>
41
43
public string TypeName { get ; }
42
44
public MemberMeta [ ] Members { get ; }
@@ -63,16 +65,24 @@ public TypeMeta(INamedTypeSymbol symbol, ReferenceSymbols reference)
63
65
if ( packableCtorArgs == null )
64
66
{
65
67
this . GenerateType = GenerateType . NoGenerate ;
68
+ this . SerializeLayout = SerializeLayout . Sequential ;
66
69
}
67
70
else if ( packableCtorArgs . Value . Length != 0 )
68
71
{
69
- // TODO: MemoryPackable has two attribtue
70
- // (SerializeLayout serializeLayout)
71
- // (GenerateType generateType = GenerateType.Object, SerializeLayout serializeLayout = SerializeLayout.Sequential)
72
- // so check length first and choose which constructor used.
73
- var ctorValue = packableCtorArgs . Value [ 0 ] ;
74
- var generateType = ctorValue . Value ?? GenerateType . Object ;
75
- this . GenerateType = ( GenerateType ) generateType ;
72
+ // MemoryPackable has two attribtue
73
+ if ( packableCtorArgs . Value . Length == 1 )
74
+ {
75
+ // (SerializeLayout serializeLayout)
76
+ var ctorValue = packableCtorArgs . Value [ 0 ] ;
77
+ this . SerializeLayout = ( SerializeLayout ) ( ctorValue . Value ?? SerializeLayout . Sequential ) ;
78
+ this . GenerateType = GenerateType . Object ;
79
+ }
80
+ else
81
+ {
82
+ // (GenerateType generateType = GenerateType.Object, SerializeLayout serializeLayout = SerializeLayout.Sequential)
83
+ this . GenerateType = ( GenerateType ) ( packableCtorArgs . Value [ 0 ] . Value ?? GenerateType . Object ) ;
84
+ this . SerializeLayout = ( SerializeLayout ) ( packableCtorArgs . Value [ 1 ] . Value ?? SerializeLayout . Sequential ) ;
85
+ }
76
86
}
77
87
78
88
this . TypeName = symbol . ToDisplayString ( SymbolDisplayFormat . MinimallyQualifiedFormat ) ;
@@ -101,8 +111,10 @@ public TypeMeta(INamedTypeSymbol symbol, ReferenceSymbols reference)
101
111
}
102
112
return true ;
103
113
} )
104
- . Select ( x => new MemberMeta ( x , Constructor , reference ) )
114
+ . Select ( ( x , i ) => new MemberMeta ( x , Constructor , reference , i ) )
115
+ . OrderBy ( x => x . Order )
105
116
. ToArray ( ) ;
117
+
106
118
this . IsValueType = symbol . IsValueType ;
107
119
this . IsUnmanagedType = symbol . IsUnmanagedType ;
108
120
this . IsInterfaceOrAbstract = symbol . IsAbstract ;
@@ -112,6 +124,7 @@ public TypeMeta(INamedTypeSymbol symbol, ReferenceSymbols reference)
112
124
this . OnSerialized = CollectMethod ( reference . MemoryPackOnSerializedAttribute , IsValueType ) ;
113
125
this . OnDeserializing = CollectMethod ( reference . MemoryPackOnDeserializingAttribute , IsValueType ) ;
114
126
this . OnDeserialized = CollectMethod ( reference . MemoryPackOnDeserializedAttribute , IsValueType ) ;
127
+
115
128
if ( IsUnion )
116
129
{
117
130
this . UnionTags = symbol . GetAttributes ( )
@@ -271,7 +284,9 @@ public bool Validate(TypeDeclarationSyntax syntax, SourceProductionContext conte
271
284
var allParameterExists = this . Constructor . Parameters . All ( x => nameDict . Contains ( x . Name ) ) ;
272
285
if ( ! allParameterExists )
273
286
{
274
- context . ReportDiagnostic ( Diagnostic . Create ( DiagnosticDescriptors . ConstructorHasNoMatchedParameter , syntax . Identifier . GetLocation ( ) , Symbol . Name ) ) ;
287
+ var location = Constructor . Locations . FirstOrDefault ( ) ?? syntax . Identifier . GetLocation ( ) ;
288
+
289
+ context . ReportDiagnostic ( Diagnostic . Create ( DiagnosticDescriptors . ConstructorHasNoMatchedParameter , location , Symbol . Name ) ) ;
275
290
noError = false ;
276
291
}
277
292
}
@@ -283,12 +298,12 @@ public bool Validate(TypeDeclarationSyntax syntax, SourceProductionContext conte
283
298
{
284
299
// diagnostics location should be method identifier
285
300
// however methodsymbol -> methodsyntax is slightly hard so use type identifier instead.
286
- context . ReportDiagnostic ( Diagnostic . Create ( DiagnosticDescriptors . OnMethodHasParameter , syntax . Identifier . GetLocation ( ) , Symbol . Name , item . Name ) ) ;
301
+ context . ReportDiagnostic ( Diagnostic . Create ( DiagnosticDescriptors . OnMethodHasParameter , item . GetLocation ( syntax ) , Symbol . Name , item . Name ) ) ;
287
302
noError = false ;
288
303
}
289
304
if ( IsUnmanagedType )
290
305
{
291
- context . ReportDiagnostic ( Diagnostic . Create ( DiagnosticDescriptors . OnMethodInUnamannagedType , syntax . Identifier . GetLocation ( ) , Symbol . Name , item . Name ) ) ;
306
+ context . ReportDiagnostic ( Diagnostic . Create ( DiagnosticDescriptors . OnMethodInUnamannagedType , item . GetLocation ( syntax ) , Symbol . Name , item . Name ) ) ;
292
307
noError = false ;
293
308
}
294
309
}
@@ -304,8 +319,10 @@ public bool Validate(TypeDeclarationSyntax syntax, SourceProductionContext conte
304
319
var ignore = item . ContainsAttribute ( reference . MemoryPackIgnoreAttribute ) ;
305
320
if ( include || ignore )
306
321
{
322
+ var location = item . Locations . FirstOrDefault ( ) ?? syntax . Identifier . GetLocation ( ) ;
323
+
307
324
var attr = include ? "MemoryPackInclude" : "MemoryPackIgnore" ;
308
- context . ReportDiagnostic ( Diagnostic . Create ( DiagnosticDescriptors . OverrideMemberCantAddAnnotation , syntax . Identifier . GetLocation ( ) , Symbol . Name , item . Name , attr ) ) ;
325
+ context . ReportDiagnostic ( Diagnostic . Create ( DiagnosticDescriptors . OverrideMemberCantAddAnnotation , location , Symbol . Name , item . Name , attr ) ) ;
309
326
noError = false ;
310
327
}
311
328
}
@@ -322,26 +339,57 @@ public bool Validate(TypeDeclarationSyntax syntax, SourceProductionContext conte
322
339
// exists can't serialize member
323
340
foreach ( var item in Members )
324
341
{
342
+
325
343
if ( item . Kind == MemberKind . NonSerializable )
326
344
{
327
345
if ( item . MemberType . SpecialType is SpecialType . System_Object or SpecialType . System_Array or SpecialType . System_Delegate or SpecialType . System_MulticastDelegate || item . MemberType . TypeKind == TypeKind . Delegate )
328
346
{
329
- context . ReportDiagnostic ( Diagnostic . Create ( DiagnosticDescriptors . MemberCantSerializeType , syntax . Identifier . GetLocation ( ) , Symbol . Name , item . Name , item . MemberType . FullyQualifiedToString ( ) ) ) ;
347
+ context . ReportDiagnostic ( Diagnostic . Create ( DiagnosticDescriptors . MemberCantSerializeType , item . GetLocation ( syntax ) , Symbol . Name , item . Name , item . MemberType . FullyQualifiedToString ( ) ) ) ;
330
348
noError = false ;
331
349
}
332
350
else
333
351
{
334
- context . ReportDiagnostic ( Diagnostic . Create ( DiagnosticDescriptors . MemberIsNotMemoryPackable , syntax . Identifier . GetLocation ( ) , Symbol . Name , item . Name , item . MemberType . FullyQualifiedToString ( ) ) ) ;
352
+ context . ReportDiagnostic ( Diagnostic . Create ( DiagnosticDescriptors . MemberIsNotMemoryPackable , item . GetLocation ( syntax ) , Symbol . Name , item . Name , item . MemberType . FullyQualifiedToString ( ) ) ) ;
335
353
noError = false ;
336
354
}
337
355
}
338
356
else if ( item . Kind == MemberKind . RefLike )
339
357
{
340
- context . ReportDiagnostic ( Diagnostic . Create ( DiagnosticDescriptors . MemberIsRefStruct , syntax . Identifier . GetLocation ( ) , Symbol . Name , item . Name , item . MemberType . FullyQualifiedToString ( ) ) ) ;
358
+ context . ReportDiagnostic ( Diagnostic . Create ( DiagnosticDescriptors . MemberIsRefStruct , item . GetLocation ( syntax ) , Symbol . Name , item . Name , item . MemberType . FullyQualifiedToString ( ) ) ) ;
341
359
noError = false ;
342
360
}
343
361
}
344
362
363
+ // order
364
+ if ( SerializeLayout == SerializeLayout . Explicit )
365
+ {
366
+ // All members must annotate MemoryPackOrder
367
+ foreach ( var item in Members )
368
+ {
369
+ if ( ! item . HasExplicitOrder )
370
+ {
371
+ context . ReportDiagnostic ( Diagnostic . Create ( DiagnosticDescriptors . AllMembersMustAnnotateOrder , item . GetLocation ( syntax ) , Symbol . Name , item . Name ) ) ;
372
+ noError = false ;
373
+ }
374
+ }
375
+
376
+ // Annotated MemoryPackOrder must be continuous number from zero.
377
+ if ( noError )
378
+ {
379
+ var expectedOrder = 0 ;
380
+ foreach ( var item in Members )
381
+ {
382
+ if ( item . Order != expectedOrder )
383
+ {
384
+ context . ReportDiagnostic ( Diagnostic . Create ( DiagnosticDescriptors . AllMembersMustBeContinuousNumber , item . GetLocation ( syntax ) , Symbol . Name , item . Name ) ) ;
385
+ noError = false ;
386
+ break ;
387
+ }
388
+ expectedOrder ++ ;
389
+ }
390
+ }
391
+ }
392
+
345
393
// Union validations
346
394
if ( IsUnion )
347
395
{
@@ -422,12 +470,26 @@ partial class MemberMeta
422
470
public bool IsSettable { get ; }
423
471
public bool IsAssignable { get ; }
424
472
public bool IsConstructorParameter { get ; }
473
+ public int Order { get ; }
474
+ public bool HasExplicitOrder { get ; }
425
475
public MemberKind Kind { get ; }
426
476
427
- public MemberMeta ( ISymbol symbol , IMethodSymbol ? constructor , ReferenceSymbols references )
477
+ public MemberMeta ( ISymbol symbol , IMethodSymbol ? constructor , ReferenceSymbols references , int sequentialOrder )
428
478
{
429
479
this . Symbol = symbol ;
430
480
this . Name = symbol . Name ;
481
+ this . Order = sequentialOrder ;
482
+ var orderAttr = symbol . GetAttribute ( references . MemoryPackOrderAttribute ) ;
483
+ if ( orderAttr != null )
484
+ {
485
+ this . Order = ( int ) ( orderAttr . ConstructorArguments [ 0 ] . Value ?? sequentialOrder ) ;
486
+ this . HasExplicitOrder = true ;
487
+
488
+ }
489
+ else
490
+ {
491
+ this . HasExplicitOrder = false ;
492
+ }
431
493
432
494
if ( constructor != null )
433
495
{
@@ -465,6 +527,12 @@ public MemberMeta(ISymbol symbol, IMethodSymbol? constructor, ReferenceSymbols r
465
527
Kind = ParseMemberKind ( symbol , MemberType , references ) ;
466
528
}
467
529
530
+ public Location GetLocation ( TypeDeclarationSyntax fallback )
531
+ {
532
+ var location = Symbol . Locations . FirstOrDefault ( ) ?? fallback . Identifier . GetLocation ( ) ;
533
+ return location ;
534
+ }
535
+
468
536
static MemberKind ParseMemberKind ( ISymbol ? memberSymbol , ITypeSymbol memberType , ReferenceSymbols references )
469
537
{
470
538
if ( memberType . SpecialType is SpecialType . System_Object or SpecialType . System_Array or SpecialType . System_Delegate or SpecialType . System_MulticastDelegate || memberType . TypeKind == TypeKind . Delegate )
@@ -587,4 +655,10 @@ public MethodMeta(IMethodSymbol symbol, bool isValueType)
587
655
this . IsStatic = symbol . IsStatic ;
588
656
this . IsValueType = isValueType ;
589
657
}
658
+
659
+ public Location GetLocation ( TypeDeclarationSyntax fallback )
660
+ {
661
+ var location = Symbol . Locations . FirstOrDefault ( ) ?? fallback . Identifier . GetLocation ( ) ;
662
+ return location ;
663
+ }
590
664
}
0 commit comments