From 8a702445dedcfe06fed7d19126f0433f79412bd4 Mon Sep 17 00:00:00 2001 From: BorisDog Date: Wed, 15 Feb 2023 12:14:02 -0800 Subject: [PATCH] VS-88: Set DefaultLinqVersion to V3 in 2.19 and higher. --- samples/BasicSample/Linq3Sample.cs | 8 ++- samples/BasicSample/mongodb.analyzer.json | 3 +- .../Core/Linq/AnalysisCodeGenerator.cs | 4 +- .../Core/Linq/LinqAnalysisConstants.cs | 3 +- .../Core/Settings/MongoDBAnalyzerSettings.cs | 2 +- .../Telemetry/ITelemetryServiceExtensions.cs | 2 +- .../Linq/LinqDefaultVersionInference.cs | 61 +++++++++++++++++++ .../DiagnosticTestCaseAttribute.cs | 6 +- .../DriverVersions.cs | 3 + .../LinqVersion.cs | 3 +- .../CodeBasedTestCasesSourceAttribute.cs | 3 +- .../Infrastructure/DiagnosticsAnalyzer.cs | 3 +- .../MongoDB.Analyzer.Tests/Linq/Linq3Tests.cs | 4 ++ 13 files changed, 93 insertions(+), 12 deletions(-) create mode 100644 tests/MongoDB.Analyzer.Tests.Common.TestCases/Linq/LinqDefaultVersionInference.cs diff --git a/samples/BasicSample/Linq3Sample.cs b/samples/BasicSample/Linq3Sample.cs index 24c8d845..147d53ec 100644 --- a/samples/BasicSample/Linq3Sample.cs +++ b/samples/BasicSample/Linq3Sample.cs @@ -25,10 +25,14 @@ public void NotSupportedInLinq2Expressions() var db = mongoClient.GetDatabase("testdb"); var moviesCollection = db.GetCollection("movies").AsQueryable(); - // Trim() supported in LINQ3 but not in LINQ2 (analyzer provides warning and LINQ3 mql) + // Trim() supported in LINQ3 but not in LINQ2. + // In 2.18 and lower drivers, analyzer provides a warning and LINQ3 mql. + // In 2.19 and higher drivers,LINQ3 MQL is provided without warning. _ = moviesCollection.Where(m => m.Title.Trim() == "Avatar"); - // Substring() supported in LINQ3 but not in LINQ2 (analyzer provides warning and LINQ3 mql) + // Substring() supported in LINQ3 but not in LINQ2. + // In 2.18 and lower drivers, analyzer provides a warning and LINQ3 mql. + // In 2.19 and higher drivers,LINQ3 MQL is provided without warning. _ = moviesCollection.Where(m => m.Producer.Substring(0, 6) == "Steven"); } } diff --git a/samples/BasicSample/mongodb.analyzer.json b/samples/BasicSample/mongodb.analyzer.json index 73a786ba..73f30e89 100644 --- a/samples/BasicSample/mongodb.analyzer.json +++ b/samples/BasicSample/mongodb.analyzer.json @@ -1,6 +1,7 @@ { // Default LINQ provider, for drivers supporting LINQ3 (2.14 and higher) - "DefaultLinqVersion": "V2", + // Default value is V2 in [2.14, 2.18] versions and V3 in [2.19, ) versions + // "DefaultLinqVersion": "V2", // Enables builders variables tracking and composition, enabled by default "EnableVariableTracking": true, diff --git a/src/MongoDB.Analyzer/Core/Linq/AnalysisCodeGenerator.cs b/src/MongoDB.Analyzer/Core/Linq/AnalysisCodeGenerator.cs index 9a294586..105dc73f 100644 --- a/src/MongoDB.Analyzer/Core/Linq/AnalysisCodeGenerator.cs +++ b/src/MongoDB.Analyzer/Core/Linq/AnalysisCodeGenerator.cs @@ -48,7 +48,9 @@ public static CompilationResult Compile(MongoAnalyzerContext context, Expression } var isLinq3 = referencesContainer.Version >= LinqAnalysisConstants.MinLinq3Version; + var isLinq3Default = referencesContainer.Version >= LinqAnalysisConstants.DefaultLinq3Version; var linqProviderSyntaxTree = isLinq3 ? s_linqProviderV3SyntaxTree : s_linqProviderV2SyntaxTree; + var defaultLinqVersion = context.Settings.DefaultLinqVersion ?? (isLinq3Default ? LinqVersion.V3 : LinqVersion.V2); var typesSyntaxTree = TypesGeneratorHelper.GenerateTypesSyntaxTree(AnalysisType.Linq, linqExpressionAnalysis.TypesDeclarations, s_parseOptions); var mqlGeneratorSyntaxTree = GenerateMqlGeneratorSyntaxTree(linqExpressionAnalysis, isLinq3); @@ -80,7 +82,7 @@ public static CompilationResult Compile(MongoAnalyzerContext context, Expression var mqlGeneratorType = DynamicTypeProvider.GetType(referencesContainer, memoryStream, MqlGeneratorFullName); linqTestCodeExecutor = mqlGeneratorType != null ? - new LinqMqlGeneratorExecutor(mqlGeneratorType, isLinq3 ? LinqVersion.V3 : LinqVersion.V2, context.Settings.DefaultLinqVersion) : null; + new LinqMqlGeneratorExecutor(mqlGeneratorType, isLinq3 ? LinqVersion.V3 : LinqVersion.V2, defaultLinqVersion) : null; } else { diff --git a/src/MongoDB.Analyzer/Core/Linq/LinqAnalysisConstants.cs b/src/MongoDB.Analyzer/Core/Linq/LinqAnalysisConstants.cs index 25531687..1dfeff59 100644 --- a/src/MongoDB.Analyzer/Core/Linq/LinqAnalysisConstants.cs +++ b/src/MongoDB.Analyzer/Core/Linq/LinqAnalysisConstants.cs @@ -17,8 +17,9 @@ namespace MongoDB.Analyzer.Core.Linq; internal static class LinqAnalysisConstants { public const string AnalysisAssemblyName = "DynamicProxyGenAssembly2"; - public const string GeneratedTypeName = "GenType"; + + public static readonly Version DefaultLinq3Version = Version.Parse("2.19"); public static readonly Version MinLinq3Version = Version.Parse("2.14"); } diff --git a/src/MongoDB.Analyzer/Core/Settings/MongoDBAnalyzerSettings.cs b/src/MongoDB.Analyzer/Core/Settings/MongoDBAnalyzerSettings.cs index 5de18c3c..2adb681b 100644 --- a/src/MongoDB.Analyzer/Core/Settings/MongoDBAnalyzerSettings.cs +++ b/src/MongoDB.Analyzer/Core/Settings/MongoDBAnalyzerSettings.cs @@ -31,7 +31,7 @@ internal record MongoDBAnalyzerSettings( [DefaultValue(false)] bool OutputInternalLogsToFile = false, [DefaultValue(null)] string LogFileName = null, [DefaultValue(true)] bool SendTelemetry = true, - [DefaultValue(LinqVersion.V2)] LinqVersion DefaultLinqVersion = LinqVersion.V2, + [DefaultValue(null)] LinqVersion? DefaultLinqVersion = null, [DefaultValue(true)] bool EnableVariableTracking = true) { } diff --git a/src/MongoDB.Analyzer/Core/Telemetry/ITelemetryServiceExtensions.cs b/src/MongoDB.Analyzer/Core/Telemetry/ITelemetryServiceExtensions.cs index a347b25a..ff52d7b9 100644 --- a/src/MongoDB.Analyzer/Core/Telemetry/ITelemetryServiceExtensions.cs +++ b/src/MongoDB.Analyzer/Core/Telemetry/ITelemetryServiceExtensions.cs @@ -44,7 +44,7 @@ public static void AnalysisStarted( ("output_platform", (csharpOptions?.Platform)?.ToString() ?? "Unknown"), ("lang_version", (csharpCompilation?.LanguageVersion)?.ToString() ?? "Unknown"), ("syntax_tree_length", semanticModelAnalysisContext.SemanticModel.SyntaxTree.Length), - ("linq_version", settings.DefaultLinqVersion.ToString()), + ("linq_version", settings.DefaultLinqVersion?.ToString()), ("logs_enabled", settings.OutputInternalLogsToFile), ("analyzer_version", s_version) }; diff --git a/tests/MongoDB.Analyzer.Tests.Common.TestCases/Linq/LinqDefaultVersionInference.cs b/tests/MongoDB.Analyzer.Tests.Common.TestCases/Linq/LinqDefaultVersionInference.cs new file mode 100644 index 00000000..966f08a0 --- /dev/null +++ b/tests/MongoDB.Analyzer.Tests.Common.TestCases/Linq/LinqDefaultVersionInference.cs @@ -0,0 +1,61 @@ +// 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. + +using System.Linq; +using MongoDB.Driver.Linq; + +namespace MongoDB.Analyzer.Tests.Common.TestCases.Linq +{ + public sealed class LinqDefaultVersionInference : TestCasesBase + { + // DriverVersion = (,2.14.0-beta1] + // DefaultLinqProvider = V2 + [InvalidLinq("{document}{Name}.Trim() is not supported.", DriverVersions.Linq2AndLower, LinqVersion.V2)] + // DefaultLinqProvider = V3 + [InvalidLinq("{document}{Name}.Trim() is not supported.", DriverVersions.Linq2AndLower, LinqVersion.V3)] + // DefaultLinqProvider = Undefined + [InvalidLinq("{document}{Name}.Trim() is not supported.", DriverVersions.Linq2AndLower, LinqVersion.Undefined)] + public void Expression_should_not_be_supported_in_LINQ2_only() + { + _ = GetMongoQueryable() + .Where(u => u.Name.Trim() == "123"); + } + + // DriverVersion = [2.14.0-beta1, 2.19.0) + // DefaultLinqProvider = V2 + [NotSupportedLinq2("Supported in LINQ3 only: db.coll.Aggregate([{ \"$match\" : { \"Name\" : /^\\s*(?!\\s)123(? u.Name.Trim() == "123"); + } + + // DriverVersion = [2.19.0,) + // DefaultLinqProvider = V2 + [NotSupportedLinq2("Supported in LINQ3 only: db.coll.Aggregate([{ \"$match\" : { \"Name\" : /^\\s*(?!\\s)123(? u.Name.Trim() == "123"); + } + } +} diff --git a/tests/MongoDB.Analyzer.Tests.Common/DiagnosticTestCaseAttribute.cs b/tests/MongoDB.Analyzer.Tests.Common/DiagnosticTestCaseAttribute.cs index 1c1a4757..4ed80e1f 100644 --- a/tests/MongoDB.Analyzer.Tests.Common/DiagnosticTestCaseAttribute.cs +++ b/tests/MongoDB.Analyzer.Tests.Common/DiagnosticTestCaseAttribute.cs @@ -111,8 +111,10 @@ public sealed class NotSupportedLinq2Attribute : DiagnosticRuleTestCaseAttribute { public NotSupportedLinq2Attribute( string message, - DriverTargetFramework targetFramework = DriverTargetFramework.All) : - base(DiagnosticRulesConstants.NotSupportedLinq2Expression, message, DriverVersions.Linq3AndHigher, LinqVersion.V2, targetFramework) + DriverTargetFramework targetFramework = DriverTargetFramework.All, + string version = DriverVersions.Linq3AndHigher, + LinqVersion linqVersion = LinqVersion.V2) : + base(DiagnosticRulesConstants.NotSupportedLinq2Expression, message, version, linqVersion, targetFramework) { } } diff --git a/tests/MongoDB.Analyzer.Tests.Common/DriverVersions.cs b/tests/MongoDB.Analyzer.Tests.Common/DriverVersions.cs index 45f9f2b2..bfd53074 100644 --- a/tests/MongoDB.Analyzer.Tests.Common/DriverVersions.cs +++ b/tests/MongoDB.Analyzer.Tests.Common/DriverVersions.cs @@ -18,6 +18,9 @@ public static class DriverVersions { public const string Linq3AndHigher = "[2.14.0-beta1,)"; public const string Linq2AndLower = "(,2.14.0-beta1)"; + public const string Linq3NonDefault = "[2.14.0-beta1, 2.19.0)"; + public const string Linq3DefaultAndHigher = V2_19_AndHigher; + public const string Linq2DefaultAndLower = V2_18_AndLower; public const string V2_18_AndLower = "(, 2.19.0)"; public const string V2_19_AndHigher = "[2.19.0,)"; } diff --git a/tests/MongoDB.Analyzer.Tests.Common/LinqVersion.cs b/tests/MongoDB.Analyzer.Tests.Common/LinqVersion.cs index 6b991e50..a4189b55 100644 --- a/tests/MongoDB.Analyzer.Tests.Common/LinqVersion.cs +++ b/tests/MongoDB.Analyzer.Tests.Common/LinqVersion.cs @@ -17,6 +17,7 @@ namespace MongoDB.Analyzer.Tests.Common public enum LinqVersion { V2, - V3 + V3, + Undefined } } diff --git a/tests/MongoDB.Analyzer.Tests/Infrastructure/CodeBasedTestCasesSourceAttribute.cs b/tests/MongoDB.Analyzer.Tests/Infrastructure/CodeBasedTestCasesSourceAttribute.cs index c1b168d1..52aac6e3 100644 --- a/tests/MongoDB.Analyzer.Tests/Infrastructure/CodeBasedTestCasesSourceAttribute.cs +++ b/tests/MongoDB.Analyzer.Tests/Infrastructure/CodeBasedTestCasesSourceAttribute.cs @@ -49,8 +49,9 @@ public IEnumerable GetData(MethodInfo methodInfo) public string GetDisplayName(MethodInfo methodInfo, object[] data) { var testCase = (DiagnosticTestCase)data[0]; + var linqVersion = testCase.LinqVersion == Common.LinqVersion.V3 ? "V3" : testCase.LinqVersion == Common.LinqVersion.Undefined ? "U" : ""; - return $"v{testCase.Version}_{(testCase.LinqVersion == Common.LinqVersion.V3 ? "V3" : "")}_{testCase.MethodName}"; + return $"v{testCase.Version}_{linqVersion}_{testCase.MethodName}"; } private DiagnosticTestCase[] CreateTestCases(MemberInfo memberInfo) diff --git a/tests/MongoDB.Analyzer.Tests/Infrastructure/DiagnosticsAnalyzer.cs b/tests/MongoDB.Analyzer.Tests/Infrastructure/DiagnosticsAnalyzer.cs index d1fd89c4..6261b6b0 100644 --- a/tests/MongoDB.Analyzer.Tests/Infrastructure/DiagnosticsAnalyzer.cs +++ b/tests/MongoDB.Analyzer.Tests/Infrastructure/DiagnosticsAnalyzer.cs @@ -58,10 +58,11 @@ public static async Task> Analyze( compilationOptions); var mongodbAnalyzer = new MongoDBDiagnosticAnalyzer(); + var linqDefaultVersion = linqVersion == Common.LinqVersion.Undefined ? null : (LinqVersion?)linqVersion; var settings = new MongoDBAnalyzerSettings( OutputDriverVersion: true, - DefaultLinqVersion: (LinqVersion)linqVersion, + DefaultLinqVersion: linqDefaultVersion, SendTelemetry: false); var analyzerOptions = new AnalyzerOptions(ImmutableArray.Create(new AdditionalTextAnalyzerSettings(settings))); diff --git a/tests/MongoDB.Analyzer.Tests/Linq/Linq3Tests.cs b/tests/MongoDB.Analyzer.Tests/Linq/Linq3Tests.cs index c62bc69a..8a6b12f8 100644 --- a/tests/MongoDB.Analyzer.Tests/Linq/Linq3Tests.cs +++ b/tests/MongoDB.Analyzer.Tests/Linq/Linq3Tests.cs @@ -22,6 +22,10 @@ namespace MongoDB.Analyzer.Tests.Linq; [TestClass] public sealed class Linq3Tests : DiagnosticsTestCasesRunner { + [DataTestMethod] + [CodeBasedTestCasesSource(typeof(LinqDefaultVersionInference))] + public Task LinqDefaultVersionInference(DiagnosticTestCase testCase) => VerifyTestCase(testCase); + [DataTestMethod] [CodeBasedTestCasesSource(typeof(NotSupportedLinq2))] public Task NotSupportedLinq2(DiagnosticTestCase testCase) => VerifyTestCase(testCase);