Skip to content

Commit 0e983cc

Browse files
committed
Resolved merge conflict
2 parents 3338f33 + bd30514 commit 0e983cc

File tree

22 files changed

+714
-67
lines changed

22 files changed

+714
-67
lines changed

.github/workflows/dotnet.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@ jobs:
1414
steps:
1515
- uses: actions/checkout@v3
1616

17+
- name: Setup dotnet
18+
uses: actions/setup-dotnet@v3
19+
with:
20+
dotnet-version: 3.1.x
21+
1722
- name: Setup msbuild
1823
uses: microsoft/[email protected]
1924

src/MongoDB.Analyzer.Helpers/Builders/MqlGenerator.cs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,26 @@
1414

1515
using MongoDB.Driver;
1616
using System.Linq;
17-
using MongoDB.Bson;
17+
using BsonDocumentCustom123 = MongoDB.Bson.BsonDocument;
18+
using BsonValueCustom123 = MongoDB.Bson.BsonValue;
19+
using BsonObjectIdCustom123 = MongoDB.Bson.BsonObjectId;
20+
using BsonTypeCustom123 = MongoDB.Bson.BsonType;
21+
using BsonTimeSpanCustom123 = MongoDB.Bson.Serialization.Options.TimeSpanUnits;
1822

1923
namespace MongoDB.Analyzer.Helpers.Builders
2024
{
2125
public static class MqlGenerator
2226
{
27+
#pragma warning disable CS0169 // The field is never used
28+
#pragma warning disable IDE0051
29+
private static readonly BsonDocumentCustom123 s_dummyRef1;
30+
private static readonly BsonValueCustom123 s_dummyRef2;
31+
private static readonly BsonObjectIdCustom123 s_dummyRef3;
32+
private static readonly BsonTypeCustom123 s_dummyRef4;
33+
private static readonly BsonTimeSpanCustom123 s_dummyRef5;
34+
#pragma warning restore IDE0051 // The field is never used
35+
#pragma warning restore CS0169
36+
2337
private sealed class MqlGeneratorTemplateType
2438
{
2539
public int Field { get; set; }

src/MongoDB.Analyzer.Helpers/Linq/MqlGenerator.cs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,20 @@
1515
using System;
1616
using System.Linq;
1717
using MongoDB.Driver.Linq;
18-
using MongoDB.Bson;
18+
using BsonTypeCustom123 = MongoDB.Bson.BsonType;
19+
using BsonTimeSpanCustom123 = MongoDB.Bson.Serialization.Options.TimeSpanUnits;
1920

2021
namespace MongoDB.Analyzer.Helpers.Linq
2122
{
2223
public static class MqlGenerator
2324
{
25+
#pragma warning disable CS0169 // The field is never used
26+
#pragma warning disable IDE0051
27+
private static readonly BsonTypeCustom123 s_dummyRef1;
28+
private static readonly BsonTimeSpanCustom123 s_dummyRef2;
29+
#pragma warning restore IDE0051 // The field is never used
30+
#pragma warning restore CS0169
31+
2432
private sealed class MqlGeneratorTemplateType
2533
{
2634
public Tuple<int, int> Field { get; set; }

src/MongoDB.Analyzer/Core/Builders/BuildersAnalyzer.cs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,16 +83,16 @@ private static AnalysisStats ReportMqlOrInvalidExpressions(MongoAnalysisContext
8383
}
8484
else if (mqlResult.Exception != null)
8585
{
86-
var isDriverException = mqlResult.Exception.InnerException?.Source?.Contains("MongoDB.Driver") == true;
86+
var isDriverOrBsonException = IsDriverOrBsonException(mqlResult);
8787

88-
if (isDriverException || settings.OutputInternalExceptions)
88+
if (isDriverOrBsonException || settings.OutputInternalExceptions)
8989
{
9090
var diagnosticDescriptor = BuidersDiagnosticsRules.DiagnosticRuleNotSupportedBuilderExpression;
9191
var decoratedMessage = DecorateMessage(mqlResult.Exception.InnerException?.Message ?? "Unsupported builders expression", driverVersion, context.Settings);
9292
semanticContext.ReportDiagnostics(diagnosticDescriptor, decoratedMessage, locations);
9393
}
9494

95-
if (!isDriverException)
95+
if (!isDriverOrBsonException)
9696
{
9797
context.Logger.Log($"Exception while analyzing {analysisContext.Node}: {mqlResult.Exception.InnerException?.Message}");
9898
internalExceptionsCount++;
@@ -107,6 +107,13 @@ private static AnalysisStats ReportMqlOrInvalidExpressions(MongoAnalysisContext
107107
return new AnalysisStats(mqlCount, internalExceptionsCount, driverExceptionsCount, compilationResult.MongoDBDriverVersion.ToString(3), null);
108108
}
109109

110+
private static bool IsDriverOrBsonException(MQLResult mqlResult)
111+
{
112+
var source = mqlResult.Exception.InnerException?.Source;
113+
return source.IsNotEmpty() && (source.Contains("MongoDB.Driver") ||
114+
source.Contains("MongoDB.Bson"));
115+
}
116+
110117
private static string DecorateMessage(string message, string driverVersion, MongoDBAnalyzerSettings settings) =>
111118
settings.OutputDriverVersion ? $"{message}_v{driverVersion}" : message;
112119
}

src/MongoDB.Analyzer/Core/Linq/LinqAnalyzer.cs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -108,16 +108,16 @@ private static AnalysisStats ReportMqlOrInvalidExpressions(MongoAnalysisContext
108108
}
109109
else if (mqlResult.Exception != null)
110110
{
111-
var isDriverException = mqlResult.Exception.InnerException?.Source?.Contains("MongoDB.Driver") == true;
111+
var isDriverOrLinqException = IsDriverOrLinqException(mqlResult);
112112

113-
if (isDriverException || settings.OutputInternalExceptions)
113+
if (isDriverOrLinqException || settings.OutputInternalExceptions)
114114
{
115115
var diagnosticDescriptor = LinqDiagnosticsRules.DiagnosticRuleNotSupportedLinqExpression;
116116
var decoratedMessage = DecorateMessage(mqlResult.Exception.InnerException?.Message ?? "Unsupported LINQ expression", driverVersion, settings);
117117
semanticContext.ReportDiagnostics(diagnosticDescriptor, decoratedMessage, locations);
118118
}
119119

120-
if (!isDriverException)
120+
if (!isDriverOrLinqException)
121121
{
122122
context.Logger.Log($"Exception while analyzing {analysisContext.Node}: {mqlResult.Exception.InnerException?.Message}");
123123
internalExceptionsCount++;
@@ -132,6 +132,13 @@ private static AnalysisStats ReportMqlOrInvalidExpressions(MongoAnalysisContext
132132
return new AnalysisStats(mqlCount, internalExceptionsCount, driverExceptionsCount, compilationResult.MongoDBDriverVersion.ToString(3), null);
133133
}
134134

135+
private static bool IsDriverOrLinqException(MQLResult mqlResult)
136+
{
137+
var source = mqlResult.Exception.InnerException?.Source;
138+
return source.IsNotEmpty() && (source.Contains("MongoDB.Driver") ||
139+
source.Contains("MongoDB.Bson") || source.Contains("System.Linq"));
140+
}
141+
135142
private static string DecorateMessage(string message, string driverVersion, MongoDBAnalyzerSettings settings) =>
136143
settings.OutputDriverVersion ? $"{message}_v{driverVersion}" : message;
137144
}

src/MongoDB.Analyzer/Core/TypesGeneratorHelper.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,12 @@ internal static class TypesGeneratorHelper
2222
.AddUsings(
2323
Using("System"),
2424
Using("MongoDB.Bson"),
25-
Using("MongoDB.Bson.Serialization.Attributes"));
25+
Using("MongoDB.Bson.Serialization.Attributes"),
26+
Using("BsonTimeSpanCustom123", "MongoDB.Bson.Serialization.Options.TimeSpanUnits"),
27+
Using("BsonTypeCustom123", "MongoDB.Bson.BsonType"),
28+
Using("BsonDocumentCustom123", "MongoDB.Bson.BsonDocument"),
29+
Using("BsonValueCustom123", "MongoDB.Bson.BsonValue"),
30+
Using("BsonObjectIdCustom123", "MongoDB.Bson.BsonObjectId"));
2631

2732

2833
private static readonly NamespaceDeclarationSyntax s_namespaceDeclarationSyntaxBuilders = SyntaxFactory.NamespaceDeclaration(SyntaxFactory.ParseName(MqlGeneratorSyntaxElements.Builders.MqlGeneratorNamespace));

src/MongoDB.Analyzer/Core/TypesProcessor.cs

Lines changed: 132 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,15 @@ namespace MongoDB.Analyzer.Core;
1616

1717
internal 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

Comments
 (0)