Skip to content

Commit c935704

Browse files
committed
Switched row storage from boxed objects to 8KB pages, improving fidelity of SQL Server simulation.
1 parent c62beca commit c935704

79 files changed

Lines changed: 3935 additions & 879 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.editorconfig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,5 @@ dotnet_diagnostic.IDE0022.severity = none # Use block body for method
1616
dotnet_diagnostic.IDE0040.severity = none # Add accessibility modifiers
1717
dotnet_diagnostic.IDE0061.severity = none # Use block body for local function
1818
dotnet_diagnostic.IDE0072.severity = none # Add missing cases
19+
20+
dotnet_diagnostic.MSTEST0049.severity = error # Flow TestContext.CancellationToken to async operations

.github/workflows/dotnetcore.yml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,13 @@ jobs:
1818
dotnet-quality: ga
1919
- name: Restore Dependencies
2020
run: dotnet restore
21+
# `dotnet format` runs the full formatter pipeline (whitespace + style + analyzers)
22+
# which catches a few IDE-prefixed rules, notably IDE0055 (Fix formatting), that
23+
# `dotnet build` skips even with EnforceCodeStyleInBuild=true. This step keeps CI
24+
# parity with what Visual Studio's IDE-side analysis flags.
25+
- name: Format Check
26+
run: dotnet format --verify-no-changes --no-restore
2127
- name: Build
22-
run: dotnet build --configuration ${{ matrix.configuration }} --no-restore
28+
run: dotnet build --configuration ${{ matrix.configuration }} --no-restore -p:EnforceCodeStyleInBuild=false
2329
- name: Test
2430
run: dotnet test --configuration ${{ matrix.configuration }} --no-build --nologo

.gitignore

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,23 @@ obj/
66

77
# Code coverage analysis results
88
*.coverage
9+
10+
# Don't want to be prescriptive about the user's development environment.
11+
.devcontainer/
12+
13+
# The simplicity of this project structure enables AI tools to figure it out instantly.
14+
.claude/
15+
CLAUDE.md
16+
.codex/
17+
AGENTS.md
18+
.github/copilot-instructions.md
19+
.gemini/
20+
GEMINI.md
21+
.cursor/
22+
.cursorrules
23+
.aider*
24+
.windsurf/
25+
.windsurfrules
26+
27+
# Suppress temporary files that might otherwise leak into a commit.
28+
tmp/
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
using Microsoft.CodeAnalysis.CSharp.Testing;
2+
using Microsoft.CodeAnalysis.Testing;
3+
4+
namespace SqlServerSimulator.Analyzers;
5+
6+
[TestClass]
7+
public static class AssemblyHooks
8+
{
9+
/// <summary>
10+
/// First-use of <see cref="CSharpAnalyzerTest{TAnalyzer, TVerifier}"/> loads
11+
/// Roslyn assemblies and reference metadata into per-process caches. With
12+
/// method-level parallelism, multiple tests racing through that cold path
13+
/// contend on shared locks (~3x slowdown observed). Running one trivial
14+
/// analysis up front warms the caches so each test only does its unique work.
15+
/// </summary>
16+
[AssemblyInitialize]
17+
public static Task WarmUp(TestContext context) =>
18+
new CSharpAnalyzerTest<WrapperPropertyAnalyzer, DefaultVerifier>
19+
{ TestCode = "internal sealed class C { }" }.RunAsync(context.CancellationToken);
20+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
[assembly: Parallelize(Scope = ExecutionScope.MethodLevel)]
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFramework>net10.0</TargetFramework>
5+
<Nullable>enable</Nullable>
6+
<ImplicitUsings>enable</ImplicitUsings>
7+
<GenerateDocumentationFile>true</GenerateDocumentationFile>
8+
<IsPackable>false</IsPackable>
9+
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
10+
<NoWarn>1591;NU1701</NoWarn>
11+
<RootNamespace>SqlServerSimulator.Analyzers</RootNamespace>
12+
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
13+
</PropertyGroup>
14+
15+
<ItemGroup>
16+
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.3.0" />
17+
<PackageReference Include="MSTest.TestAdapter" Version="4.1.0" />
18+
<PackageReference Include="MSTest.TestFramework" Version="4.1.0" />
19+
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.11.0" />
20+
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="4.11.0" />
21+
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Analyzer.Testing.MSTest" Version="1.1.2" />
22+
</ItemGroup>
23+
24+
<ItemGroup>
25+
<ProjectReference Include="..\SqlServerSimulator.Analyzers\SqlServerSimulator.Analyzers.csproj" />
26+
</ItemGroup>
27+
28+
<ItemGroup>
29+
<None Include="..\.editorconfig" Link=".editorconfig" />
30+
</ItemGroup>
31+
32+
</Project>
Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
using Microsoft.CodeAnalysis.CSharp.Testing;
2+
using Microsoft.CodeAnalysis.Testing;
3+
4+
namespace SqlServerSimulator.Analyzers;
5+
6+
[TestClass]
7+
public sealed class WrapperPropertyAnalyzerTests
8+
{
9+
public TestContext TestContext { get; set; } = null!;
10+
11+
private Task RunAsync(string source) =>
12+
new CSharpAnalyzerTest<WrapperPropertyAnalyzer, DefaultVerifier>
13+
{ TestCode = source }.RunAsync(this.TestContext.CancellationToken);
14+
15+
[TestMethod]
16+
public Task AutoProperty_OnInternalType_Reports() =>
17+
RunAsync("""
18+
internal sealed class C
19+
{
20+
public string {|SSS001:Name|} { get; } = "x";
21+
}
22+
""");
23+
24+
[TestMethod]
25+
public Task AutoProperty_WithSetter_OnInternalType_Reports() =>
26+
RunAsync("""
27+
internal sealed class C
28+
{
29+
public int {|SSS001:Count|} { get; set; }
30+
}
31+
""");
32+
33+
[TestMethod]
34+
public Task AutoProperty_OnPublicType_DoesNotReport() =>
35+
RunAsync("""
36+
public sealed class C
37+
{
38+
public string Name { get; } = "x";
39+
}
40+
""");
41+
42+
[TestMethod]
43+
public Task TrivialWrapper_OnInternalType_Reports() =>
44+
RunAsync("""
45+
using System.Collections.Generic;
46+
internal sealed class C
47+
{
48+
private readonly List<int> items = new();
49+
public IReadOnlyList<int> {|SSS001:Items|} => this.items;
50+
}
51+
""");
52+
53+
[TestMethod]
54+
public Task TrivialWrapper_WithoutThis_OnInternalType_Reports() =>
55+
RunAsync("""
56+
internal sealed class C
57+
{
58+
private readonly int value = 42;
59+
public int {|SSS001:Value|} => value;
60+
}
61+
""");
62+
63+
[TestMethod]
64+
public Task BlockGetter_SingleReturn_OnInternalType_Reports() =>
65+
RunAsync("""
66+
internal sealed class C
67+
{
68+
private readonly int value = 42;
69+
public int {|SSS001:Value|}
70+
{
71+
get { return this.value; }
72+
}
73+
}
74+
""");
75+
76+
[TestMethod]
77+
public Task TrivialWrapper_OnPublicType_DoesNotReport() =>
78+
RunAsync("""
79+
public sealed class C
80+
{
81+
private readonly int value = 42;
82+
public int Value => this.value;
83+
}
84+
""");
85+
86+
[TestMethod]
87+
public Task ComputedProperty_DoesNotReport() =>
88+
RunAsync("""
89+
internal sealed class C
90+
{
91+
private readonly int a = 1, b = 2;
92+
public int Sum => this.a + this.b;
93+
}
94+
""");
95+
96+
[TestMethod]
97+
public Task MethodCall_NotField_DoesNotReport() =>
98+
RunAsync("""
99+
internal sealed class C
100+
{
101+
private readonly int value = 42;
102+
public int Hash => this.value.GetHashCode();
103+
}
104+
""");
105+
106+
[TestMethod]
107+
public Task AbstractProperty_DoesNotReport() =>
108+
RunAsync("""
109+
internal abstract class C
110+
{
111+
public abstract int Value { get; }
112+
}
113+
""");
114+
115+
[TestMethod]
116+
public Task OverrideProperty_DoesNotReport() =>
117+
RunAsync("""
118+
internal abstract class B
119+
{
120+
public abstract string Name { get; }
121+
}
122+
internal sealed class C : B
123+
{
124+
private readonly string name = "x";
125+
public override string Name => this.name;
126+
}
127+
""");
128+
129+
[TestMethod]
130+
public Task StaticProperty_DoesNotReport() =>
131+
RunAsync("""
132+
internal static class C
133+
{
134+
public static int Value { get; } = 42;
135+
}
136+
""");
137+
138+
// A public type nested inside a non-public type is not effectively public.
139+
[TestMethod]
140+
public Task NestedPublicInsideInternal_Reports() =>
141+
RunAsync("""
142+
internal static class Outer
143+
{
144+
public sealed class Inner
145+
{
146+
public int {|SSS001:Value|} { get; } = 1;
147+
}
148+
}
149+
""");
150+
151+
// The wrapped field belongs to a base, not the property's containing type.
152+
[TestMethod]
153+
public Task FieldOfDifferentType_DoesNotReport() =>
154+
RunAsync("""
155+
internal class B
156+
{
157+
protected internal readonly int value = 1;
158+
}
159+
internal sealed class C : B
160+
{
161+
public int Value => this.value;
162+
}
163+
""");
164+
165+
[TestMethod]
166+
public Task ReadonlyStruct_AutoProperty_Reports() =>
167+
RunAsync("""
168+
internal readonly struct S
169+
{
170+
public int {|SSS001:Value|} { get; }
171+
public S(int value) => this.Value = value;
172+
}
173+
""");
174+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFramework>netstandard2.0</TargetFramework>
5+
<Nullable>enable</Nullable>
6+
<LangVersion>latest</LangVersion>
7+
<IsPackable>false</IsPackable>
8+
<IsRoslynComponent>true</IsRoslynComponent>
9+
<EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>
10+
<GenerateDocumentationFile>true</GenerateDocumentationFile>
11+
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
12+
<!-- RS2008 demands AnalyzerReleases.{Shipped,Unshipped}.md files for analyzer NuGet packages. We're an in-repo analyzer, never published; release tracking would be ceremony for nobody. -->
13+
<NoWarn>RS2008</NoWarn>
14+
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
15+
<AnalysisMode>All</AnalysisMode>
16+
</PropertyGroup>
17+
18+
<ItemGroup>
19+
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.11.0" PrivateAssets="all" />
20+
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.11.0" PrivateAssets="all" />
21+
</ItemGroup>
22+
23+
<ItemGroup>
24+
<None Include="..\.editorconfig" Link=".editorconfig" />
25+
</ItemGroup>
26+
27+
</Project>

0 commit comments

Comments
 (0)