Skip to content

Commit 3301d75

Browse files
committed
VS-73: Display mql for builders variables instances
1 parent 1683e3a commit 3301d75

File tree

12 files changed

+745
-668
lines changed

12 files changed

+745
-668
lines changed

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

Lines changed: 154 additions & 80 deletions
Large diffs are not rendered by default.

tests/MongoDB.Analyzer.Tests.Common.TestCases/Builders/BuildersBasic.cs

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ public void Filters_single_expression_exists()
2828
_ = Builders<User>.Filter.Exists(u => u.Address, false);
2929
}
3030

31-
[BuildersMQL("{ \"Age\" : 1 }", 34, 34)]
32-
[BuildersMQL("{ \"Age\" : -1 }", 35, 35)]
31+
[BuildersMQL("{ \"Age\" : 1 }")]
32+
[BuildersMQL("{ \"Age\" : -1 }")]
3333
public void Sort_single_expression()
3434
{
3535
_ = Builders<User>.Sort.Ascending(u => u.Age);
@@ -269,24 +269,24 @@ public void Referencing_nested_lambda_parameter()
269269
});
270270
}
271271

272-
[BuildersMQL("{ \"Address\" : { \"$exists\" : false } }", 275)]
273-
[BuildersMQL("{ \"Address\" : { \"$exists\" : true } }", 276)]
272+
[BuildersMQL("{ \"Address\" : { \"$exists\" : false } }", 1)]
273+
[BuildersMQL("{ \"Address\" : { \"$exists\" : true } }", 2)]
274274
public void Single_expression_variable_reassignment()
275275
{
276276
var x = Builders<User>.Filter.Exists(u => u.Address, false);
277277
x = Builders<User>.Filter.Exists(u => u.Address, true);
278278
}
279279

280-
[BuildersMQL("{ \"Age\" : 25 }", 291)]
281-
[BuildersMQL("{ \"Age\" : { \"$lt\" : 65 } }", 292)]
282-
[BuildersMQL("{ \"Age\" : { \"$gt\" : 11 } }", 294)]
283-
[BuildersMQL("{ \"Age\" : { \"$lt\" : 25 } }", 295)]
284-
[BuildersMQL("{ \"Age\" : 100 }", 297)]
285-
[BuildersMQL("{ \"Age\" : 11 }", 298)]
286-
[BuildersMQL("{ \"Age\" : 1 }", 300)]
287-
[BuildersMQL("{ \"Age\" : { \"$gt\" : 1 } }", 301)]
288-
[BuildersMQL("{ \"Age\" : 200 }", 303)]
289-
[BuildersMQL("{ \"Age\" : -1 }", 304)]
280+
[BuildersMQL("{ \"Age\" : 25 }", 1)]
281+
[BuildersMQL("{ \"Age\" : { \"$lt\" : 65 } }", 2)]
282+
[BuildersMQL("{ \"Age\" : { \"$gt\" : 11 } }", 4)]
283+
[BuildersMQL("{ \"Age\" : { \"$lt\" : 25 } }", 5)]
284+
[BuildersMQL("{ \"Age\" : 100 }", 7)]
285+
[BuildersMQL("{ \"Age\" : 11 }", 8)]
286+
[BuildersMQL("{ \"Age\" : 1 }", 10)]
287+
[BuildersMQL("{ \"Age\" : { \"$gt\" : 1 } }", 11)]
288+
[BuildersMQL("{ \"Age\" : 200 }", 13)]
289+
[BuildersMQL("{ \"Age\" : -1 }", 14)]
290290
public void Multiple_expression_variables_reassignment()
291291
{
292292
var x = Builders<User>.Filter.Eq(u => u.Age, 25);
@@ -305,12 +305,12 @@ public void Multiple_expression_variables_reassignment()
305305
w = Builders<User>.Sort.Descending(u => u.Age);
306306
}
307307

308-
[BuildersMQL("{ \"Address\" : \"1\" }", 315)]
309-
[BuildersMQL("{ \"Address\" : \"2\" }", 316)]
310-
[BuildersMQL("{ \"Address\" : \"3\" }", 317)]
311-
[BuildersMQL("{ \"Address\" : \"4\" }", 317)]
312-
[BuildersMQL("{ \"Age\" : { \"$lt\" : 15, \"$gt\" : 65 } }", 319)]
313-
[BuildersMQL("{ \"Age\" : { \"$lt\" : 17, \"$gt\" : 18 } }", 320)]
308+
[BuildersMQL("{ \"Address\" : \"1\" }", 1)]
309+
[BuildersMQL("{ \"Address\" : \"2\" }", 2)]
310+
[BuildersMQL("{ \"Address\" : \"3\" }", 3)]
311+
[BuildersMQL("{ \"Address\" : \"4\" }", 3)]
312+
[BuildersMQL("{ \"Age\" : { \"$lt\" : 15, \"$gt\" : 65 } }", 5)]
313+
[BuildersMQL("{ \"Age\" : { \"$lt\" : 17, \"$gt\" : 18 } }", 6)]
314314
public void Multiple_expression_variables_declaration_and_reassignment()
315315
{
316316
var x = Builders<User>.Filter.Eq(u => u.Address, "1");

tests/MongoDB.Analyzer.Tests.Common.TestCases/Builders/BuildersFluentApi.cs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -267,15 +267,19 @@ public void MongoCollection_various_sources()
267267
.Sort(Builders<User>.Sort.Descending(u => u.Age));
268268
}
269269

270-
[BuildersMQL("{ \"Age\" : { \"$gt\" : 10 } }")]
271-
[BuildersMQL("{ \"Name\" : \"Bob\" }")]
272-
public void Variable_tracking_should_be_ignored()
270+
[BuildersMQL("{ \"Age\" : { \"$gt\" : 10 } }", 1, 2, 5, 7)]
271+
[BuildersMQL("{ \"Name\" : \"Bob\" }", 4, 5, 7)]
272+
[BuildersMQL("{ \"Age\" : { \"$gt\" : 10 }, \"Name\" : \"Bob\" }", 8)]
273+
public void Variable_tracking_should_display_builders_only()
273274
{
274275
var filter1 = Builders<User>.Filter.Gt(u => u.Age, 10);
275276
GetMongoCollection().Find(filter1);
276277

277278
var filter2 = Builders<User>.Filter.Eq(u => u.Name, "Bob");
278279
GetMongoCollection().Find(filter1 | filter2);
280+
281+
var filter3 = filter1 & filter2;
282+
GetMongoCollection().Find(filter3);
279283
}
280284

281285
private FindOptions GetFindOptions() => null;

tests/MongoDB.Analyzer.Tests.Common.TestCases/Builders/BuildersVariables.cs

Lines changed: 461 additions & 474 deletions
Large diffs are not rendered by default.

tests/MongoDB.Analyzer.Tests.Common.TestCases/Linq/LinqBasic.cs

Lines changed: 26 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -258,10 +258,10 @@ public void Referencing_nested_lambda_parameter()
258258
});
259259
}
260260

261-
[MQL("aggregate([{ \"$match\" : { \"Name\" : \"Bob\", \"Age\" : { \"$gt\" : 16, \"$lte\" : 21 } } }])", startLine: 266)]
262-
[MQL("aggregate([{ \"$match\" : { \"Name\" : \"John\", \"Age\" : { \"$gt\" : 45, \"$lte\" : 50 } } }])", startLine: 267)]
263-
[MQL("aggregate([{ \"$match\" : { \"Name\" : \"Bob\", \"Age\" : { \"$gt\" : 16, \"$lte\" : 21 } } }])", startLine: 269)]
264-
[MQL("aggregate([{ \"$match\" : { \"Name\" : \"John\", \"Age\" : { \"$gt\" : 45, \"$lte\" : 50 } } }])", startLine: 273)]
261+
[MQL("aggregate([{ \"$match\" : { \"Name\" : \"Bob\", \"Age\" : { \"$gt\" : 16, \"$lte\" : 21 } } }])", 1)]
262+
[MQL("aggregate([{ \"$match\" : { \"Name\" : \"John\", \"Age\" : { \"$gt\" : 45, \"$lte\" : 50 } } }])", 2)]
263+
[MQL("aggregate([{ \"$match\" : { \"Name\" : \"Bob\", \"Age\" : { \"$gt\" : 16, \"$lte\" : 21 } } }])", 4)]
264+
[MQL("aggregate([{ \"$match\" : { \"Name\" : \"John\", \"Age\" : { \"$gt\" : 45, \"$lte\" : 50 } } }])", 8)]
265265
public void Single_expression_variable_reassignment()
266266
{
267267
var x = GetMongoCollection().AsQueryable().Where(u => u.Name == "Bob" && u.Age > 16 && u.Age <= 21);
@@ -276,26 +276,16 @@ public void Single_expression_variable_reassignment()
276276
select user;
277277
}
278278

279-
[MQL("aggregate([{ \"$match\" : { \"Age\" : 45 } }])", startLine: 300)]
280-
[MQL("aggregate([{ \"$match\" : { \"Name\" : \"John\" } }])", startLine: 301)]
281-
[MQL("aggregate([{ \"$match\" : { \"Name\" : \"Bob\", \"Age\" : { \"$gt\" : 16, \"$lte\" : 21 } } }])", startLine: 303)]
282-
[MQL("aggregate([{ \"$match\" : { \"Name\" : \"James\", \"Age\" : { \"$gt\" : 25, \"$lte\" : 99 } } }])", startLine: 304)]
283-
[MQL("aggregate([{ \"$match\" : { \"Name\" : \"Steve\" } }])", startLine: 306)]
284-
[MQL("aggregate([{ \"$match\" : { \"Height\" : 100 } }])", startLine: 307)]
285-
[MQL("aggregate([{ \"$match\" : { \"Age\" : 22 } }])", startLine: 309)]
286-
[MQL("aggregate([{ \"$match\" : { \"LastName\" : \"LastName\" } }])", startLine: 310)]
287-
[MQL("aggregate([{ \"$match\" : { \"Address\" : \"Address\" } }])", startLine: 312)]
288-
[MQL("aggregate([{ \"$match\" : { \"Age\" : { \"$lte\" : 122 } } }])", startLine: 313)]
289-
[MQL("aggregate([{ \"$match\" : { \"Age\" : 45 } }])", startLine: 315)]
290-
[MQL("aggregate([{ \"$match\" : { \"Name\" : \"John\" } }])", startLine: 319)]
291-
[MQL("aggregate([{ \"$match\" : { \"Name\" : \"Bob\", \"Age\" : { \"$gt\" : 16, \"$lte\" : 21 } } }])", startLine: 323)]
292-
[MQL("aggregate([{ \"$match\" : { \"Name\" : \"James\", \"Age\" : { \"$gt\" : 25, \"$lte\" : 99 } } }])", startLine: 327)]
293-
[MQL("aggregate([{ \"$match\" : { \"Name\" : \"Steve\" } }])", startLine: 331)]
294-
[MQL("aggregate([{ \"$match\" : { \"Height\" : 100 } }])", startLine: 335)]
295-
[MQL("aggregate([{ \"$match\" : { \"Age\" : 22 } }])", startLine: 339)]
296-
[MQL("aggregate([{ \"$match\" : { \"LastName\" : \"LastName\" } }])", startLine: 343)]
297-
[MQL("aggregate([{ \"$match\" : { \"Address\" : \"Address\" } }])", startLine: 347)]
298-
[MQL("aggregate([{ \"$match\" : { \"Age\" : { \"$lte\" : 122 } } }])", startLine: 351)]
279+
[MQL("aggregate([{ \"$match\" : { \"Age\" : 45 } }])", 1, 16)]
280+
[MQL("aggregate([{ \"$match\" : { \"Name\" : \"John\" } }])", 2, 20)]
281+
[MQL("aggregate([{ \"$match\" : { \"Name\" : \"Bob\", \"Age\" : { \"$gt\" : 16, \"$lte\" : 21 } } }])", 4, 24)]
282+
[MQL("aggregate([{ \"$match\" : { \"Name\" : \"James\", \"Age\" : { \"$gt\" : 25, \"$lte\" : 99 } } }])", 5, 28)]
283+
[MQL("aggregate([{ \"$match\" : { \"Name\" : \"Steve\" } }])", 7, 32)]
284+
[MQL("aggregate([{ \"$match\" : { \"Height\" : 100 } }])", 8, 36)]
285+
[MQL("aggregate([{ \"$match\" : { \"Age\" : 22 } }])", 10, 40)]
286+
[MQL("aggregate([{ \"$match\" : { \"LastName\" : \"LastName\" } }])", 11, 44)]
287+
[MQL("aggregate([{ \"$match\" : { \"Address\" : \"Address\" } }])", 13, 48)]
288+
[MQL("aggregate([{ \"$match\" : { \"Age\" : { \"$lte\" : 122 } } }])", 14, 52)]
299289
public void Multiple_expression_variables_reassignment()
300290
{
301291
var x = GetMongoCollection().AsQueryable().Where(u => u.Age == 45);
@@ -354,18 +344,18 @@ public void Multiple_expression_variables_reassignment()
354344
select user;
355345
}
356346

357-
[MQL("aggregate([{ \"$match\" : { \"Name\" : \"Bob\", \"Age\" : { \"$gt\" : 16, \"$lte\" : 21 } } }])", startLine: 370)]
358-
[MQL("aggregate([{ \"$match\" : { \"Name\" : \"John\", \"Age\" : { \"$gt\" : 22, \"$lte\" : 25 } } }])", startLine: 371)]
359-
[MQL("aggregate([{ \"$match\" : { \"Name\" : \"Steve\", \"Age\" : { \"$gt\" : 27, \"$lte\" : 31 } } }])", startLine: 372)]
360-
[MQL("aggregate([{ \"$match\" : { \"LastName\" : \"LastName\" } }])", startLine: 372)]
361-
[MQL("aggregate([{ \"$match\" : { \"Address\" : \"Address\" } }])", startLine: 374)]
362-
[MQL("aggregate([{ \"$match\" : { \"Height\" : 180 } }])", startLine: 375)]
363-
[MQL("aggregate([{ \"$match\" : { \"Name\" : \"Bob\", \"Age\" : { \"$gt\" : 16, \"$lte\" : 21 } } }])", startLine: 377)]
364-
[MQL("aggregate([{ \"$match\" : { \"Name\" : \"John\", \"Age\" : { \"$gt\" : 22, \"$lte\" : 25 } } }])", startLine: 381)]
365-
[MQL("aggregate([{ \"$match\" : { \"Name\" : \"Steve\", \"Age\" : { \"$gt\" : 27, \"$lte\" : 31 } } }])", startLine: 385)]
366-
[MQL("aggregate([{ \"$match\" : { \"LastName\" : \"LastName\" } }])", startLine: 388)]
367-
[MQL("aggregate([{ \"$match\" : { \"Address\" : \"Address\" } }])", startLine: 392)]
368-
[MQL("aggregate([{ \"$match\" : { \"Height\" : 180 } }])", startLine: 396)]
347+
[MQL("aggregate([{ \"$match\" : { \"Name\" : \"Bob\", \"Age\" : { \"$gt\" : 16, \"$lte\" : 21 } } }])", 1)]
348+
[MQL("aggregate([{ \"$match\" : { \"Name\" : \"John\", \"Age\" : { \"$gt\" : 22, \"$lte\" : 25 } } }])", 2)]
349+
[MQL("aggregate([{ \"$match\" : { \"Name\" : \"Steve\", \"Age\" : { \"$gt\" : 27, \"$lte\" : 31 } } }])", 3)]
350+
[MQL("aggregate([{ \"$match\" : { \"LastName\" : \"LastName\" } }])", 3)]
351+
[MQL("aggregate([{ \"$match\" : { \"Address\" : \"Address\" } }])", 5)]
352+
[MQL("aggregate([{ \"$match\" : { \"Height\" : 180 } }])", 6)]
353+
[MQL("aggregate([{ \"$match\" : { \"Name\" : \"Bob\", \"Age\" : { \"$gt\" : 16, \"$lte\" : 21 } } }])", 8)]
354+
[MQL("aggregate([{ \"$match\" : { \"Name\" : \"John\", \"Age\" : { \"$gt\" : 22, \"$lte\" : 25 } } }])", 12)]
355+
[MQL("aggregate([{ \"$match\" : { \"Name\" : \"Steve\", \"Age\" : { \"$gt\" : 27, \"$lte\" : 31 } } }])", 16)]
356+
[MQL("aggregate([{ \"$match\" : { \"LastName\" : \"LastName\" } }])", 19)]
357+
[MQL("aggregate([{ \"$match\" : { \"Address\" : \"Address\" } }])", 23)]
358+
[MQL("aggregate([{ \"$match\" : { \"Height\" : 180 } }])", 27)]
369359
public void Multiple_expression_variables_declaration_and_reassignment()
370360
{
371361
var x = GetMongoCollection().AsQueryable().Where(u => u.Name == "Bob" && u.Age > 16 && u.Age <= 21);

tests/MongoDB.Analyzer.Tests.Common/DiagnosticTestCaseAttribute.cs

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
// limitations under the License.
1414

1515
using System;
16+
using System.Linq;
1617

1718
namespace MongoDB.Analyzer.Tests.Common
1819
{
@@ -22,7 +23,7 @@ public class DiagnosticRuleTestCaseAttribute : Attribute
2223
public string RuleId { get; }
2324
public string Message { get; }
2425
public string Version { get; }
25-
public Location Location { get; }
26+
public Location[] Locations { get; }
2627
public DriverTargetFramework TargetFramework { get; }
2728
public LinqVersion LinqProvider { get; }
2829

@@ -32,14 +33,14 @@ public DiagnosticRuleTestCaseAttribute(
3233
string version = null,
3334
LinqVersion linqProvider = LinqVersion.V2,
3435
DriverTargetFramework targetFramework = DriverTargetFramework.All,
35-
Location location = null)
36+
Location[] locations = null)
3637
{
3738
RuleId = ruleId;
3839
Message = message;
3940
Version = version;
4041
LinqProvider = linqProvider;
4142
TargetFramework = targetFramework;
42-
Location = location;
43+
Locations = locations ?? new[] { Location.Empty };
4344
}
4445
}
4546

@@ -51,14 +52,25 @@ public NoDiagnosticsAttribute() : base(DiagnosticRulesConstants.NoRule, null) {
5152

5253
public class MQLAttribute : DiagnosticRuleTestCaseAttribute
5354
{
55+
public MQLAttribute(
56+
string message,
57+
params int[] codeLines) :
58+
this(message, null, LinqVersion.V2, DriverTargetFramework.All, codeLines)
59+
{
60+
}
61+
5462
public MQLAttribute(
5563
string message,
5664
string version = null,
5765
LinqVersion linqProvider = LinqVersion.V2,
5866
DriverTargetFramework targetFramework = DriverTargetFramework.All,
59-
int startLine = -1,
60-
int endLine = -1) :
61-
base(DiagnosticRulesConstants.MongoLinq2MQL, message, version, linqProvider, targetFramework)
67+
params int[] codeLines) :
68+
base(DiagnosticRulesConstants.MongoLinq2MQL,
69+
message,
70+
version,
71+
linqProvider,
72+
targetFramework,
73+
codeLines.Any() ? codeLines.Select(l => new Location(l, -1)).ToArray() : null)
6274
{
6375
}
6476
}
@@ -107,8 +119,10 @@ public NotSupportedLinq2Attribute(
107119

108120
public sealed class BuildersMQLAttribute : DiagnosticRuleTestCaseAttribute
109121
{
110-
public BuildersMQLAttribute(string message, int startLine = -1, int endLine = -1) :
111-
base(DiagnosticRulesConstants.Builders2MQL, message, location: new Location(startLine, endLine))
122+
public BuildersMQLAttribute(string message, params int[] codeLines) :
123+
base(DiagnosticRulesConstants.Builders2MQL,
124+
message,
125+
locations: codeLines.Any() ? codeLines.Select(l => new Location(l, -1)).ToArray() : null)
112126
{
113127
}
114128
}

tests/MongoDB.Analyzer.Tests.Common/Location.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ namespace MongoDB.Analyzer.Tests.Common
1919
[Serializable]
2020
public sealed class Location
2121
{
22+
public static Location Empty { get; } = new Location(-1, -1);
23+
2224
public int StartLine { get; }
2325
public int EndLine { get; }
2426

@@ -27,5 +29,7 @@ public Location(int startLine, int endLine)
2729
StartLine = startLine;
2830
EndLine = endLine;
2931
}
32+
33+
public override string ToString() => $"{StartLine}:{EndLine}";
3034
}
3135
}

tests/MongoDB.Analyzer.Tests/Infrastructure/CodeBasedTestCasesSourceAttribute.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,11 @@ private DiagnosticTestCase[] CreateTestCases(MemberInfo memberInfo)
6565
from attribute in testCasesAttributes
6666
where EnvironmentUtilities.IsDriverTargetFrameworkSupported((Core.DriverTargetFramework)(int)attribute.TargetFramework)
6767
from version in DriverVersionHelper.FilterVersionForRange(attribute.Version)
68-
group new DiagnosticRule(attribute.RuleId, $"{attribute.Message}_v{version.ToString("V", new VersionFormatter())}", attribute.Location)
68+
from location in attribute.Locations
69+
orderby
70+
location.StartLine >= 0 ? location.StartLine : 0,
71+
location.StartLine >= 0 ? attribute.Message : null
72+
group new DiagnosticRule(attribute.RuleId, $"{attribute.Message}_v{version.ToString("V", new VersionFormatter())}", location)
6973
by new { version, attribute.LinqProvider } into g
7074
select new DiagnosticTestCase(fileName, memberInfo.Name, g.Key.version.ToString(), g.Key.LinqProvider, g.ToArray());
7175

tests/MongoDB.Analyzer.Tests/Infrastructure/DiagnosticTestCaseResult.cs

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,34 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15+
using System.Linq;
16+
using System.Text;
1517
using Microsoft.CodeAnalysis;
1618

1719
namespace MongoDB.Analyzer.Tests.Infrastructure;
1820

1921
public record DiagnosticTestCaseResult(
2022
string Name,
21-
Diagnostic[] Diagnostics);
23+
int TestCaseMethodStartLine,
24+
Diagnostic[] Diagnostics)
25+
{
26+
public override string ToString()
27+
{
28+
var sb = new StringBuilder();
29+
sb.AppendLine($"Name: {Name}");
30+
sb.AppendLine($"Offset: {TestCaseMethodStartLine}");
31+
32+
foreach (var group in Diagnostics.GroupBy(d => d.GetMessage()))
33+
{
34+
sb.Append("\"");
35+
sb.Append(group.Key);
36+
sb.Append("\",");
37+
sb.Append(string.Join(",", group.Select(d => d.Location.GetLineSpan().StartLinePosition.Line - TestCaseMethodStartLine)));
38+
sb.Append(" a: ");
39+
sb.Append(string.Join(",", group.Select(d => d.Location.GetLineSpan().StartLinePosition.Line)));
40+
sb.AppendLine();
41+
}
42+
43+
return sb.ToString();
44+
}
45+
}

tests/MongoDB.Analyzer.Tests/Infrastructure/DiagnosticsComparer.cs

Lines changed: 0 additions & 35 deletions
This file was deleted.

0 commit comments

Comments
 (0)