@@ -16,6 +16,15 @@ namespace MongoDB.Analyzer.Core;
1616
1717internal sealed class TypesProcessor
1818{
19+ private static readonly Dictionary < string , string > s_knownBsonTypes = new ( )
20+ {
21+ { "MongoDB.Bson.BsonDocument" , "BsonDocumentCustom123" } ,
22+ { "MongoDB.Bson.BsonValue" , "BsonValueCustom123" } ,
23+ { "MongoDB.Bson.BsonObjectId" , "BsonObjectIdCustom123" } ,
24+ { "MongoDB.Bson.BsonType" , "BsonTypeCustom123" } ,
25+ { "MongoDB.Bson.Serialization.Options.TimeSpanUnits" , "BsonTimeSpanCustom123" }
26+ } ;
27+
1928 private readonly Dictionary < string , ( string NewName , MemberDeclarationSyntax NewDeclaration ) > _processedTypes ;
2029
2130 private int _nextTypeId = 0 ;
@@ -27,57 +36,59 @@ public TypesProcessor()
2736 _processedTypes = new Dictionary < string , ( string , MemberDeclarationSyntax ) > ( ) ;
2837 }
2938
30- public string GetTypeSymbolToGeneratedTypeMapping ( ITypeSymbol typeSymbol )
39+ public string GetTypeSymbolToGeneratedTypeMapping ( ITypeSymbol typeSymbol ) => GetGeneratedTypeMapping ( typeSymbol ) . RemappedName ;
40+
41+ public string ProcessTypeSymbol ( ITypeSymbol typeSymbol )
3142 {
32- if ( typeSymbol == null )
43+ var ( remappedName , fullTypeName ) = GetGeneratedTypeMapping ( typeSymbol ) ;
44+ if ( fullTypeName == null )
3345 {
3446 return null ;
3547 }
3648
37- var fullTypeName = GetFullName ( typeSymbol ) ;
38- if ( typeSymbol . IsSupportedBsonType ( ) )
49+ if ( remappedName != null )
3950 {
40- return typeSymbol . Name ;
51+ return remappedName ;
4152 }
4253
43- if ( _processedTypes . TryGetValue ( fullTypeName , out var result ) )
44- {
45- return result . NewName ;
46- }
54+ remappedName = GetNewNameForSymbol ( typeSymbol ) ;
55+ _processedTypes [ fullTypeName ] = ( remappedName , null ) ; // Cache the name, for self referencing types
4756
48- return null ;
57+ var rewrittenDeclarationSyntax = GetSyntaxNodeFromSymbol ( typeSymbol , remappedName ) ;
58+
59+ var typeCode = rewrittenDeclarationSyntax . ToFullString ( ) ;
60+ var newTypeDeclaration = SyntaxFactory . ParseMemberDeclaration ( typeCode ) ;
61+
62+ remappedName = rewrittenDeclarationSyntax . Identifier . Text ;
63+ _processedTypes [ fullTypeName ] = ( remappedName , newTypeDeclaration ) ;
64+
65+ return remappedName ;
4966 }
5067
51- public string ProcessTypeSymbol ( ITypeSymbol typeSymbol )
68+ private ( string RemappedName , string FullTypeName ) GetGeneratedTypeMapping ( ITypeSymbol typeSymbol )
5269 {
5370 if ( typeSymbol == null )
5471 {
55- return null ;
72+ return default ;
5673 }
5774
5875 var fullTypeName = GetFullName ( typeSymbol ) ;
59- if ( typeSymbol . IsSupportedBsonType ( ) )
76+ if ( s_knownBsonTypes . TryGetValue ( fullTypeName , out var knowTypeName ) )
6077 {
61- return typeSymbol . Name ;
78+ return ( knowTypeName , fullTypeName ) ;
6279 }
6380
64- if ( _processedTypes . TryGetValue ( fullTypeName , out var pair ) )
81+ if ( _processedTypes . TryGetValue ( fullTypeName , out var result ) )
6582 {
66- return pair . NewName ;
83+ return ( result . NewName , fullTypeName ) ;
6784 }
6885
69- var newTypeName = GetNewNameForSymbol ( typeSymbol ) ;
70- _processedTypes [ fullTypeName ] = ( newTypeName , null ) ; // Cache the name, for self referencing types
71-
72- var rewrittenDeclarationSyntax = GetSyntaxNodeFromSymbol ( typeSymbol , newTypeName ) ;
73-
74- var typeCode = rewrittenDeclarationSyntax . ToFullString ( ) ;
75- var newTypeDeclaration = SyntaxFactory . ParseMemberDeclaration ( typeCode ) ;
76-
77- newTypeName = rewrittenDeclarationSyntax . Identifier . Text ;
78- _processedTypes [ fullTypeName ] = ( newTypeName , newTypeDeclaration ) ;
86+ if ( typeSymbol . IsSupportedSystemType ( ) )
87+ {
88+ return ( fullTypeName , fullTypeName ) ;
89+ }
7990
80- return newTypeName ;
91+ return ( null , fullTypeName ) ;
8192 }
8293
8394 private BaseTypeDeclarationSyntax GetSyntaxNodeFromSymbol ( ITypeSymbol typeSymbol , string newTypeName )
@@ -129,6 +140,12 @@ private TypeDeclarationSyntax GetSyntaxForClassOrStruct(ITypeSymbol typeSymbol,
129140 typeDeclaration = typeDeclaration . WithBaseList ( GetBaseListSyntax ( baseTypeNameGenerated ) ) ;
130141 }
131142
143+ var bsonAttributeList = GenerateBsonAttributeList ( typeSymbol ) ;
144+ if ( bsonAttributeList != null && bsonAttributeList . Attributes . AnySafe ( ) )
145+ {
146+ typeDeclaration = typeDeclaration . AddAttributeLists ( bsonAttributeList ) ;
147+ }
148+
132149 return typeDeclaration ;
133150 }
134151
@@ -189,6 +206,12 @@ private void GenerateProperties(ITypeSymbol typeSymbol, List<MemberDeclarationSy
189206 propertyDeclaration = propertyDeclaration . AddAccessorListAccessors ( SyntaxFactory . AccessorDeclaration ( SyntaxKind . SetAccessorDeclaration ) . WithSemicolonToken ( SyntaxFactory . Token ( SyntaxKind . SemicolonToken ) ) ) ;
190207 }
191208
209+ var bsonAttributeList = GenerateBsonAttributeList ( propertySymbol ) ;
210+ if ( bsonAttributeList != null && bsonAttributeList . Attributes . AnySafe ( ) )
211+ {
212+ propertyDeclaration = propertyDeclaration . AddAttributeLists ( bsonAttributeList ) ;
213+ }
214+
192215 members . Add ( propertyDeclaration ) ;
193216 }
194217 }
@@ -209,8 +232,13 @@ private void GenerateFields(ITypeSymbol typeSymbol, List<MemberDeclarationSyntax
209232
210233 var variableDeclaration = SyntaxFactory . VariableDeclaration ( typeSyntax , SyntaxFactory . SingletonSeparatedList ( SyntaxFactory . VariableDeclarator ( fieldSymbol . Name ) ) ) ;
211234
235+ var bsonAttributeList = GenerateBsonAttributeList ( fieldSymbol ) ;
236+ var attributeLists = bsonAttributeList != null && bsonAttributeList . Attributes . AnySafe ( ) ?
237+ SyntaxFactory . List < AttributeListSyntax > ( SyntaxFactory . SingletonSeparatedList < AttributeListSyntax > ( bsonAttributeList ) ) :
238+ SyntaxFactory . List < AttributeListSyntax > ( ) ;
239+
212240 var fieldDeclaration = SyntaxFactory . FieldDeclaration (
213- attributeLists : SyntaxFactory . List < AttributeListSyntax > ( ) ,
241+ attributeLists : attributeLists ,
214242 modifiers : SyntaxFactory . TokenList ( SyntaxFactory . Token ( SyntaxKind . PublicKeyword ) ) ,
215243 declaration : variableDeclaration ) ;
216244
@@ -246,19 +274,16 @@ private TypeSyntax CreateTypeSyntaxForSymbol(ITypeSymbol typeSymbol)
246274 SyntaxFactory . TypeArgumentList ( SyntaxFactory . SeparatedList ( new [ ] { underlyingTypeSyntax } ) ) ) ;
247275
248276 result = SyntaxFactory . QualifiedName (
249- SyntaxFactory . QualifiedName (
250277 SyntaxFactory . QualifiedName (
251- SyntaxFactory . IdentifierName ( "System" ) ,
252- SyntaxFactory . IdentifierName ( "Collections" ) ) ,
253- SyntaxFactory . IdentifierName ( "Generic" ) ) ,
254- listSyntax ) ;
278+ SyntaxFactory . QualifiedName (
279+ SyntaxFactory . IdentifierName ( "System" ) ,
280+ SyntaxFactory . IdentifierName ( "Collections" ) ) ,
281+ SyntaxFactory . IdentifierName ( "Generic" ) ) ,
282+ listSyntax ) ;
255283 }
256284 else
257285 {
258- var typeName = typeSymbol . SpecialType == SpecialType . None ?
259- ProcessTypeSymbol ( typeSymbol ) : typeSymbol . Name ;
260-
261- result = SyntaxFactory . ParseTypeName ( typeName ) ;
286+ result = SyntaxFactory . ParseTypeName ( ProcessTypeSymbol ( typeSymbol ) ) ;
262287 }
263288
264289 return result ;
@@ -275,4 +300,74 @@ TypeKind.Enum or
275300
276301 private string GetFullName ( ITypeSymbol typeSymbol ) =>
277302 typeSymbol . ToDisplayString ( ) ;
303+
304+ private AttributeListSyntax GenerateBsonAttributeList ( ISymbol symbol )
305+ {
306+ var bsonAttributes = symbol . GetAttributes ( ) . Where ( attribute => attribute . AttributeClass . IsSupportedBsonAttribute ( ) ) ;
307+ if ( bsonAttributes . EmptyOrNull ( ) )
308+ {
309+ return null ;
310+ }
311+
312+ var generatedBsonAttributes = new List < AttributeSyntax > ( ) ;
313+ foreach ( var bsonAttribute in bsonAttributes )
314+ {
315+ var bsonAttributeArgumentList = new List < AttributeArgumentSyntax > ( ) ;
316+
317+ bsonAttributeArgumentList . AddRange ( bsonAttribute . ConstructorArguments
318+ . Select ( bsonAttributeArgument => GenerateBsonAttributeArgument ( bsonAttributeArgument , false , null ) ) ) ;
319+
320+ bsonAttributeArgumentList . AddRange ( bsonAttribute . NamedArguments
321+ . Select ( bsonAttributeArgument => GenerateBsonAttributeArgument ( bsonAttributeArgument . Value , true , bsonAttributeArgument . Key ) ) ) ;
322+
323+ var bsonAttributeSyntaxNode = SyntaxFactoryUtilities . GetAttribute ( bsonAttribute . AttributeClass . Name , bsonAttributeArgumentList ) ;
324+ generatedBsonAttributes . Add ( bsonAttributeSyntaxNode ) ;
325+ }
326+
327+ var bsonAttributeList = SyntaxFactory . AttributeList ( SyntaxFactory . SeparatedList < AttributeSyntax > ( generatedBsonAttributes ) ) ;
328+ return bsonAttributeList ;
329+ }
330+
331+ private AttributeArgumentSyntax GenerateBsonAttributeArgument ( TypedConstant argumentValue , bool isNamed , string argumentKey )
332+ {
333+ var expressionSyntax = GenerateExpressionFromBsonAttributeArgumentInfo ( argumentValue ) ;
334+ var attributeArgument = isNamed ? SyntaxFactory . AttributeArgument ( SyntaxFactory . NameEquals ( SyntaxFactory . IdentifierName ( argumentKey ) ) , null , expressionSyntax ) :
335+ SyntaxFactory . AttributeArgument ( expressionSyntax ) ;
336+
337+ return attributeArgument ;
338+ }
339+
340+ private ExpressionSyntax GenerateExpressionFromBsonAttributeArgumentInfo ( TypedConstant attributeArgumentInfo ) =>
341+ attributeArgumentInfo . Kind switch
342+ {
343+ TypedConstantKind . Enum => HandleEnumInBsonAttributeArgument ( attributeArgumentInfo . Value , attributeArgumentInfo . Type ) ,
344+ TypedConstantKind . Primitive => HandlePrimitiveInBsonAttributeArgument ( attributeArgumentInfo . Value ) ,
345+ TypedConstantKind . Array => HandleArrayInBsonAttributeArgument ( attributeArgumentInfo . Values , attributeArgumentInfo . Type as IArrayTypeSymbol ) ,
346+ TypedConstantKind . Type => HandleTypeInBsonAttributeArgument ( attributeArgumentInfo . Value ) ,
347+ _ => null
348+ } ;
349+
350+ private ExpressionSyntax HandleEnumInBsonAttributeArgument ( object value , ITypeSymbol typeSymbol ) =>
351+ SyntaxFactoryUtilities . GetCastConstantExpression ( ProcessTypeSymbol ( typeSymbol ) , value ) ;
352+
353+ private LiteralExpressionSyntax HandlePrimitiveInBsonAttributeArgument ( object value ) =>
354+ SyntaxFactoryUtilities . GetConstantExpression ( value ) ;
355+
356+ private ExpressionSyntax HandleArrayInBsonAttributeArgument ( ImmutableArray < TypedConstant > argumentValues , IArrayTypeSymbol arrayTypeSymbol )
357+ {
358+ var ranksList = SyntaxFactory . SeparatedList (
359+ Enumerable . Range ( 0 , arrayTypeSymbol . Rank )
360+ . Select ( _ => ( ExpressionSyntax ) SyntaxFactory . OmittedArraySizeExpression ( ) ) ) ;
361+
362+ var arrayRankSpecifiers = SyntaxFactory . List ( new [ ] { SyntaxFactory . ArrayRankSpecifier ( ranksList ) } ) ;
363+ var arrayElementTypeName = ProcessTypeSymbol ( arrayTypeSymbol . ElementType ) ;
364+
365+ var arrayTypeSyntax = SyntaxFactory . ArrayType ( SyntaxFactory . ParseTypeName ( arrayElementTypeName ) , arrayRankSpecifiers ) ;
366+ var expressionList = argumentValues . Select ( argumentValue => GenerateExpressionFromBsonAttributeArgumentInfo ( argumentValue ) ) . ToArray ( ) ;
367+
368+ return SyntaxFactoryUtilities . GetArrayCreationExpression ( arrayTypeSyntax , expressionList ) ;
369+ }
370+
371+ private ExpressionSyntax HandleTypeInBsonAttributeArgument ( object argumentValue ) =>
372+ SyntaxFactory . TypeOfExpression ( SyntaxFactory . ParseTypeName ( ProcessTypeSymbol ( argumentValue as INamedTypeSymbol ) ) ) ;
278373}
0 commit comments