diff --git a/src/MongoDB.Analyzer/AnalyzerReleases.Shipped.md b/src/MongoDB.Analyzer/AnalyzerReleases.Shipped.md index a308e627..6bd8c978 100644 --- a/src/MongoDB.Analyzer/AnalyzerReleases.Shipped.md +++ b/src/MongoDB.Analyzer/AnalyzerReleases.Shipped.md @@ -19,7 +19,7 @@ Rule ID | Category | Severity | Notes MAPoco1001 | MongoDB.Analyzer.Poco | Info | Poco to Json [Documentation](https://www.mongodb.com/docs/mongodb-analyzer/current/rules/#mapoco1001) MAPoco2001 | MongoDB.Analyzer.Poco | Warning | Unsupported POCO [Documentation](https://www.mongodb.com/docs/mongodb-analyzer/current/rules/#mapoco2001) -## Release 1.4.0 +## Release 1.5.0 ### New Rules diff --git a/src/MongoDB.Analyzer/Core/Builders/AnalysisCodeGenerator.cs b/src/MongoDB.Analyzer/Core/Builders/AnalysisCodeGenerator.cs index 73949768..d2e6a066 100644 --- a/src/MongoDB.Analyzer/Core/Builders/AnalysisCodeGenerator.cs +++ b/src/MongoDB.Analyzer/Core/Builders/AnalysisCodeGenerator.cs @@ -20,14 +20,14 @@ namespace MongoDB.Analyzer.Core.Builders; internal static class AnalysisCodeGenerator { - private static readonly BuildersMqlGeneratorTemplateBuilder.SyntaxElements s_mqlGeneratorSyntaxElements; + private static readonly MqlGeneratorTestMethodTemplate s_testMethodTemplate; private static readonly CSharpParseOptions s_parseOptions; private static readonly SyntaxTreesCache s_syntaxTreesCache; static AnalysisCodeGenerator() { var mqlGeneratorSyntaxTree = GetCodeResource(ResourceNames.Builders.MqlGenerator); - s_mqlGeneratorSyntaxElements = BuildersMqlGeneratorTemplateBuilder.CreateSyntaxElements(mqlGeneratorSyntaxTree); + s_testMethodTemplate = BuildersMqlGeneratorTemplateBuilder.CreateTestMethodTemplate(mqlGeneratorSyntaxTree); s_parseOptions = (CSharpParseOptions)mqlGeneratorSyntaxTree.Options; s_syntaxTreesCache = new SyntaxTreesCache(s_parseOptions, ResourceNames.Builders.Renderer); @@ -68,7 +68,7 @@ public static CompilationResult Compile(MongoAnalysisContext context, Expression private static SyntaxTree GenerateMqlGeneratorSyntaxTree(ExpressionsAnalysis builderExpressionAnalysis) { - var testCodeBuilder = new BuildersMqlGeneratorTemplateBuilder(s_mqlGeneratorSyntaxElements); + var testCodeBuilder = new BuildersMqlGeneratorTemplateBuilder(s_testMethodTemplate); var generatedMqlMethodDeclarations = new List(builderExpressionAnalysis.AnalysisNodeContexts.Length); foreach (var builderContext in builderExpressionAnalysis.AnalysisNodeContexts) diff --git a/src/MongoDB.Analyzer/Core/Builders/BuildersMqlGeneratorTemplateBuilder.cs b/src/MongoDB.Analyzer/Core/Builders/BuildersMqlGeneratorTemplateBuilder.cs index de4c63d9..5e797171 100644 --- a/src/MongoDB.Analyzer/Core/Builders/BuildersMqlGeneratorTemplateBuilder.cs +++ b/src/MongoDB.Analyzer/Core/Builders/BuildersMqlGeneratorTemplateBuilder.cs @@ -12,36 +12,27 @@ // See the License for the specific language governing permissions and // limitations under the License. +using MongoDB.Analyzer.Core.Utilities; using static MongoDB.Analyzer.Core.HelperResources.MqlGeneratorSyntaxElements.Builders; namespace MongoDB.Analyzer.Core.Builders; internal sealed class BuildersMqlGeneratorTemplateBuilder { - internal record SyntaxElements( - SyntaxNode Root, - ClassDeclarationSyntax ClassDeclarationSyntax, - MethodDeclarationSyntax TestMethodNode, - SyntaxNode BuilderDefinitionNode, - SyntaxNode CollectionTypeNode) - { - public SyntaxNode[] NodesToReplace { get; } = new[] { BuilderDefinitionNode, CollectionTypeNode }; - } - private ClassDeclarationSyntax _mqlGeneratorDeclarationSyntaxNew; private int _nextTestMethodIndex; - private readonly SyntaxElements _syntaxElements; + private readonly MqlGeneratorTestMethodTemplate _testMethodTemplate; - public BuildersMqlGeneratorTemplateBuilder(SyntaxElements syntaxElements) + public BuildersMqlGeneratorTemplateBuilder(MqlGeneratorTestMethodTemplate testMethodTemplate) { - _syntaxElements = syntaxElements; - _mqlGeneratorDeclarationSyntaxNew = _syntaxElements.ClassDeclarationSyntax; + _testMethodTemplate = testMethodTemplate; + _mqlGeneratorDeclarationSyntaxNew = _testMethodTemplate.ClassDeclarationSyntax; } public void AddMqlGeneratorMethods(MemberDeclarationSyntax[] methodDeclarations) => _mqlGeneratorDeclarationSyntaxNew = _mqlGeneratorDeclarationSyntaxNew.AddMembers(methodDeclarations); - public static SyntaxElements CreateSyntaxElements(SyntaxTree mqlGeneratorSyntaxTree) + public static MqlGeneratorTestMethodTemplate CreateTestMethodTemplate(SyntaxTree mqlGeneratorSyntaxTree) { var root = mqlGeneratorSyntaxTree.GetRoot(); @@ -50,25 +41,25 @@ public static SyntaxElements CreateSyntaxElements(SyntaxTree mqlGeneratorSyntaxT var builderDefinitionNode = mainTestMethodNode.GetSingleIdentifier(FilterName).Parent.Parent; var collectionTypeNode = mainTestMethodNode.GetIdentifiers(MqlGeneratorTemplateType).ElementAt(0); - return new SyntaxElements(root, classDeclarationSyntax, mainTestMethodNode, builderDefinitionNode, collectionTypeNode); + return new MqlGeneratorTestMethodTemplate(root, classDeclarationSyntax, mainTestMethodNode, builderDefinitionNode, collectionTypeNode, AnalysisType.Builders); } public (string newMethodName, MethodDeclarationSyntax newMethodDeclaration) GenerateMqlGeneratorMethod(string typeArgumentName, SyntaxNode buildersExpression) { - var newMethodDeclaration = _syntaxElements.TestMethodNode.ReplaceNodes(_syntaxElements.NodesToReplace, (n, _) => + var newMethodDeclaration = _testMethodTemplate.TestMethodNode.ReplaceNodes(_testMethodTemplate.NodesToReplace, (n, _) => n switch { - _ when n == _syntaxElements.BuilderDefinitionNode => buildersExpression, - _ when n == _syntaxElements.CollectionTypeNode => SyntaxFactory.IdentifierName(typeArgumentName), + _ when n == _testMethodTemplate.ExpressionNode => buildersExpression, + _ when n == _testMethodTemplate.TypeNode => SyntaxFactory.IdentifierName(typeArgumentName), _ => throw new Exception($"Unrecognized node {n}") }); - var newMqlGeneratorMethodName = $"{_syntaxElements.TestMethodNode.Identifier.Value}_{_nextTestMethodIndex++}"; + var newMqlGeneratorMethodName = $"{_testMethodTemplate.TestMethodNode.Identifier.Value}_{_nextTestMethodIndex++}"; newMethodDeclaration = newMethodDeclaration.WithIdentifier(SyntaxFactory.Identifier(newMqlGeneratorMethodName)); return (newMqlGeneratorMethodName, newMethodDeclaration); } public SyntaxTree GenerateSyntaxTree() => - _syntaxElements.Root.ReplaceNode(_syntaxElements.ClassDeclarationSyntax, _mqlGeneratorDeclarationSyntaxNew).SyntaxTree; + _testMethodTemplate.Root.ReplaceNode(_testMethodTemplate.ClassDeclarationSyntax, _mqlGeneratorDeclarationSyntaxNew).SyntaxTree; } diff --git a/src/MongoDB.Analyzer/Core/Linq/AnalysisCodeGenerator.cs b/src/MongoDB.Analyzer/Core/Linq/AnalysisCodeGenerator.cs index d7d6df79..24939f38 100644 --- a/src/MongoDB.Analyzer/Core/Linq/AnalysisCodeGenerator.cs +++ b/src/MongoDB.Analyzer/Core/Linq/AnalysisCodeGenerator.cs @@ -21,13 +21,13 @@ namespace MongoDB.Analyzer.Core.Linq; internal static class AnalysisCodeGenerator { private static readonly SyntaxTreesCache s_syntaxTreesCache; - private static readonly LinqMqlGeneratorTemplateBuilder.SyntaxElements s_mqlGeneratorSyntaxElements; + private static readonly MqlGeneratorTestMethodTemplate s_testMethodTemplate; private static readonly CSharpParseOptions s_parseOptions; static AnalysisCodeGenerator() { var mqlGeneratorSyntaxTree = GetCodeResource(ResourceNames.Linq.MqlGenerator); - s_mqlGeneratorSyntaxElements = LinqMqlGeneratorTemplateBuilder.CreateSyntaxElements(mqlGeneratorSyntaxTree); + s_testMethodTemplate = LinqMqlGeneratorTemplateBuilder.CreateTestMethodTemplate(mqlGeneratorSyntaxTree); s_parseOptions = (CSharpParseOptions)mqlGeneratorSyntaxTree.Options; s_syntaxTreesCache = new SyntaxTreesCache(s_parseOptions, ResourceNames.Linq.QueryableProvider); @@ -72,7 +72,7 @@ public static CompilationResult Compile(MongoAnalysisContext context, Expression private static SyntaxTree GenerateMqlGeneratorSyntaxTree(ExpressionsAnalysis linqExpressionAnalysis) { - var testCodeBuilder = new LinqMqlGeneratorTemplateBuilder(s_mqlGeneratorSyntaxElements); + var testCodeBuilder = new LinqMqlGeneratorTemplateBuilder(s_testMethodTemplate); var generatedMqlMethodDeclarations = new List(linqExpressionAnalysis.AnalysisNodeContexts.Length); foreach (var linqContext in linqExpressionAnalysis.AnalysisNodeContexts) diff --git a/src/MongoDB.Analyzer/Core/Linq/LinqMqlGeneratorTemplateBuilder.cs b/src/MongoDB.Analyzer/Core/Linq/LinqMqlGeneratorTemplateBuilder.cs index 79a9d70b..55160035 100644 --- a/src/MongoDB.Analyzer/Core/Linq/LinqMqlGeneratorTemplateBuilder.cs +++ b/src/MongoDB.Analyzer/Core/Linq/LinqMqlGeneratorTemplateBuilder.cs @@ -12,36 +12,27 @@ // See the License for the specific language governing permissions and // limitations under the License. +using MongoDB.Analyzer.Core.Utilities; using static MongoDB.Analyzer.Core.HelperResources.MqlGeneratorSyntaxElements.Linq; namespace MongoDB.Analyzer.Core.Linq; internal sealed class LinqMqlGeneratorTemplateBuilder { - internal record SyntaxElements( - SyntaxNode Root, - ClassDeclarationSyntax ClassDeclarationSyntax, - MethodDeclarationSyntax TestMethodNode, - SyntaxNode LinqExpressionNode, - SyntaxNode QueryableTypeNode) - { - public SyntaxNode[] NodesToReplace { get; } = new[] { LinqExpressionNode, QueryableTypeNode }; - } - - private readonly SyntaxElements _syntaxElements; + private readonly MqlGeneratorTestMethodTemplate _testMethodTemplate; private ClassDeclarationSyntax _mqlGeneratorDeclarationSyntaxNew; private int _nextTestMethodIndex; - public LinqMqlGeneratorTemplateBuilder(SyntaxElements syntaxElements) + public LinqMqlGeneratorTemplateBuilder(MqlGeneratorTestMethodTemplate testMethodTemplate) { - _syntaxElements = syntaxElements; - _mqlGeneratorDeclarationSyntaxNew = _syntaxElements.ClassDeclarationSyntax; + _testMethodTemplate = testMethodTemplate; + _mqlGeneratorDeclarationSyntaxNew = _testMethodTemplate.ClassDeclarationSyntax; } public void AddMqlGeneratorMethods(MemberDeclarationSyntax[] methodDeclarations) => _mqlGeneratorDeclarationSyntaxNew = _mqlGeneratorDeclarationSyntaxNew.AddMembers(methodDeclarations); - public static SyntaxElements CreateSyntaxElements(SyntaxTree mqlGeneratorSyntaxTree) + public static MqlGeneratorTestMethodTemplate CreateTestMethodTemplate(SyntaxTree mqlGeneratorSyntaxTree) { var root = mqlGeneratorSyntaxTree.GetRoot(); @@ -50,25 +41,25 @@ public static SyntaxElements CreateSyntaxElements(SyntaxTree mqlGeneratorSyntaxT var queryableTypeNode = mainTestMethodNode.GetSingleIdentifier(MqlGeneratorTemplateType); var linqExpressionNode = mainTestMethodNode.GetSingleIdentifier(LinqMethodName).Parent.Parent; - return new SyntaxElements(root, classDeclarationSyntax, mainTestMethodNode, linqExpressionNode, queryableTypeNode); + return new MqlGeneratorTestMethodTemplate(root, classDeclarationSyntax, mainTestMethodNode, linqExpressionNode, queryableTypeNode, AnalysisType.Linq); } public (string newMethodName, MethodDeclarationSyntax newMethodDeclaration) GenerateMqlGeneratorMethod(string collectionTypeName, SyntaxNode linqExpression) { - var newMethodDeclaration = _syntaxElements.TestMethodNode.ReplaceNodes(_syntaxElements.NodesToReplace, (n, _) => + var newMethodDeclaration = _testMethodTemplate.TestMethodNode.ReplaceNodes(_testMethodTemplate.NodesToReplace, (n, _) => n.Kind() switch { - _ when n == _syntaxElements.LinqExpressionNode => linqExpression, - _ when n == _syntaxElements.QueryableTypeNode => SyntaxFactory.IdentifierName(collectionTypeName), + _ when n == _testMethodTemplate.ExpressionNode => linqExpression, + _ when n == _testMethodTemplate.TypeNode => SyntaxFactory.IdentifierName(collectionTypeName), _ => throw new Exception($"Unrecognized node {n}") }); - var newMqlGeneratorMethodName = $"{_syntaxElements.TestMethodNode.Identifier.Value}_{_nextTestMethodIndex++}"; + var newMqlGeneratorMethodName = $"{_testMethodTemplate.TestMethodNode.Identifier.Value}_{_nextTestMethodIndex++}"; newMethodDeclaration = newMethodDeclaration.WithIdentifier(SyntaxFactory.Identifier(newMqlGeneratorMethodName)); return (newMqlGeneratorMethodName, newMethodDeclaration); } public SyntaxTree GenerateSyntaxTree() => - _syntaxElements.Root.ReplaceNode(_syntaxElements.ClassDeclarationSyntax, _mqlGeneratorDeclarationSyntaxNew).SyntaxTree; + _testMethodTemplate.Root.ReplaceNode(_testMethodTemplate.ClassDeclarationSyntax, _mqlGeneratorDeclarationSyntaxNew).SyntaxTree; } diff --git a/src/MongoDB.Analyzer/Core/Poco/AnalysisCodeGenerator.cs b/src/MongoDB.Analyzer/Core/Poco/AnalysisCodeGenerator.cs index 3cabf98e..9c4918db 100644 --- a/src/MongoDB.Analyzer/Core/Poco/AnalysisCodeGenerator.cs +++ b/src/MongoDB.Analyzer/Core/Poco/AnalysisCodeGenerator.cs @@ -19,13 +19,13 @@ namespace MongoDB.Analyzer.Core.Poco; internal static class AnalysisCodeGenerator { - private static readonly PocoJsonGeneratorTemplateBuilder.SyntaxElements s_jsonGeneratorSyntaxElements; + private static readonly MqlGeneratorTestMethodTemplate s_testMethodTemplate; private static readonly ParseOptions s_parseOptions; static AnalysisCodeGenerator() { var jsonGeneratorSyntaxTree = GetCodeResource(ResourceNames.Poco.JsonGenerator); - s_jsonGeneratorSyntaxElements = PocoJsonGeneratorTemplateBuilder.CreateSyntaxElements(jsonGeneratorSyntaxTree); + s_testMethodTemplate = PocoJsonGeneratorTemplateBuilder.CreateTestMethodTemplate(jsonGeneratorSyntaxTree); s_parseOptions = jsonGeneratorSyntaxTree.Options; } @@ -59,7 +59,7 @@ public static CompilationResult Compile(MongoAnalysisContext context, Expression public static SyntaxTree GenerateJsonGeneratorSyntaxTree(ExpressionsAnalysis pocoExpressionAnalysis) { - var testCodeBuilder = new PocoJsonGeneratorTemplateBuilder(s_jsonGeneratorSyntaxElements); + var testCodeBuilder = new PocoJsonGeneratorTemplateBuilder(s_testMethodTemplate); var generatedJsonMethodDeclarations = new List(pocoExpressionAnalysis.AnalysisNodeContexts.Length); foreach (var pocoContext in pocoExpressionAnalysis.AnalysisNodeContexts) diff --git a/src/MongoDB.Analyzer/Core/Poco/PocoJsonGeneratorTemplateBuilder.cs b/src/MongoDB.Analyzer/Core/Poco/PocoJsonGeneratorTemplateBuilder.cs index d8eaae40..81776863 100644 --- a/src/MongoDB.Analyzer/Core/Poco/PocoJsonGeneratorTemplateBuilder.cs +++ b/src/MongoDB.Analyzer/Core/Poco/PocoJsonGeneratorTemplateBuilder.cs @@ -12,35 +12,27 @@ // See the License for the specific language governing permissions and // limitations under the License. +using MongoDB.Analyzer.Core.Utilities; using static MongoDB.Analyzer.Core.HelperResources.JsonSyntaxElements.Poco; namespace MongoDB.Analyzer.Core.Poco; internal sealed class PocoJsonGeneratorTemplateBuilder { - internal record SyntaxElements( - SyntaxNode Root, - ClassDeclarationSyntax ClassDeclarationSyntax, - MethodDeclarationSyntax TestMethodNode, - PredefinedTypeSyntax PredefinedTypeNode) - { - public SyntaxNode[] NodesToReplace { get; } = new[] { PredefinedTypeNode }; - } - - private readonly SyntaxElements _syntaxElements; + private readonly MqlGeneratorTestMethodTemplate _testMethodTemplate; private ClassDeclarationSyntax _jsonGeneratorDeclarationSyntaxNew; private int _nextTestMethodIndex; - public PocoJsonGeneratorTemplateBuilder(SyntaxElements syntaxElements) + public PocoJsonGeneratorTemplateBuilder(MqlGeneratorTestMethodTemplate syntaxElements) { - _syntaxElements = syntaxElements; - _jsonGeneratorDeclarationSyntaxNew = _syntaxElements.ClassDeclarationSyntax; + _testMethodTemplate = syntaxElements; + _jsonGeneratorDeclarationSyntaxNew = _testMethodTemplate.ClassDeclarationSyntax; } public void AddJsonGeneratorMethods(MemberDeclarationSyntax[] methodDeclarations) => _jsonGeneratorDeclarationSyntaxNew = _jsonGeneratorDeclarationSyntaxNew.AddMembers(methodDeclarations); - public static SyntaxElements CreateSyntaxElements(SyntaxTree jsonGeneratorSyntaxTree) + public static MqlGeneratorTestMethodTemplate CreateTestMethodTemplate(SyntaxTree jsonGeneratorSyntaxTree) { var root = jsonGeneratorSyntaxTree.GetRoot(); var classDeclarationSyntax = root.GetSingleClassDeclaration(JsonGenerator); @@ -49,17 +41,17 @@ public static SyntaxElements CreateSyntaxElements(SyntaxTree jsonGeneratorSyntax var localDeclaration = mainTestMethodNode.DescendantNodes().OfType().FirstOrDefault(); var predefinedType = localDeclaration.DescendantNodes().OfType().FirstOrDefault(); - return new(root, classDeclarationSyntax, mainTestMethodNode, predefinedType); + return new(root, classDeclarationSyntax, mainTestMethodNode, null, predefinedType, AnalysisType.Poco); } public (string newMethodName, MethodDeclarationSyntax newMethodDeclaration) GenerateJsonGeneratorMethod(ClassDeclarationSyntax poco) { - var newMethodDeclaration = _syntaxElements.TestMethodNode.ReplaceNode(_syntaxElements.PredefinedTypeNode, SyntaxFactory.IdentifierName(poco.Identifier.ValueText)); - var newJsonGeneratorMethodName = $"{_syntaxElements.TestMethodNode.Identifier.Value}_{_nextTestMethodIndex++}"; + var newMethodDeclaration = _testMethodTemplate.TestMethodNode.ReplaceNode(_testMethodTemplate.TypeNode, SyntaxFactory.IdentifierName(poco.Identifier.ValueText)); + var newJsonGeneratorMethodName = $"{_testMethodTemplate.TestMethodNode.Identifier.Value}_{_nextTestMethodIndex++}"; newMethodDeclaration = newMethodDeclaration.WithIdentifier(SyntaxFactory.Identifier(newJsonGeneratorMethodName)); return (newJsonGeneratorMethodName, newMethodDeclaration); } public SyntaxTree GenerateSyntaxTree() => - _syntaxElements.Root.ReplaceNode(_syntaxElements.ClassDeclarationSyntax, _jsonGeneratorDeclarationSyntaxNew).SyntaxTree; + _testMethodTemplate.Root.ReplaceNode(_testMethodTemplate.ClassDeclarationSyntax, _jsonGeneratorDeclarationSyntaxNew).SyntaxTree; } \ No newline at end of file diff --git a/src/MongoDB.Analyzer/Core/Utilities/MqlGeneratorTestMethodTemplate.cs b/src/MongoDB.Analyzer/Core/Utilities/MqlGeneratorTestMethodTemplate.cs new file mode 100644 index 00000000..8fe7bcd3 --- /dev/null +++ b/src/MongoDB.Analyzer/Core/Utilities/MqlGeneratorTestMethodTemplate.cs @@ -0,0 +1,30 @@ +// Copyright 2021-present MongoDB Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License") +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace MongoDB.Analyzer.Core.Utilities; + +internal sealed record MqlGeneratorTestMethodTemplate( + SyntaxNode Root, + ClassDeclarationSyntax ClassDeclarationSyntax, + MethodDeclarationSyntax TestMethodNode, + SyntaxNode ExpressionNode, + SyntaxNode TypeNode, + AnalysisType AnalysisType) +{ + public SyntaxNode[] NodesToReplace => AnalysisType switch + { + AnalysisType.Poco => new[] { TypeNode }, + _ => new[] { ExpressionNode, TypeNode }, + }; +}