This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
The solution file is SqlServer.Rules.slnx (slnx format — handled by modern dotnet SDK). CI uses .NET 10 SDK; the rules library targets netstandard2.1 + net472, tools/tests target net8.0 and net10.0.
dotnet restore
dotnet build --no-restore --configuration Release
dotnet test --no-build --configuration ReleaseRun a single test project / single test:
dotnet test test/SqlServer.Rules.Test/SqlServer.Rules.Tests.csproj
dotnet test test/SqlServer.Rules.Test/SqlServer.Rules.Tests.csproj --filter "FullyQualifiedName~SRD0039Tests"Run the CLI against samples after a build:
./tools/SqlAnalyzerCli/bin/Release/net10.0/ErikEJ.TSQLAnalyzerCli -i tools/SqlAnalyzerCli/testfiles/simple.sql
./tools/SqlAnalyzerCli/bin/Release/net10.0/ErikEJ.TSQLAnalyzerCli -i tools/SqlAnalyzerCli/testfiles/Chinook.dacpacThe VSIX (tools/SqlAnalyzerVsix) is Windows-only (WPF) and is excluded from the main build (<Build Project="false" /> in the slnx). Build it with MSBuild directly when needed.
sqlprojects/* are also marked non-build in the slnx — they exist as test fixtures (real SQL projects with intentional rule violations) consumed by the test projects via relative file paths.
src/SqlServer.Rules/is packaged asErikEJ.DacFX.SqlServer.Rules— a DacFx code-analysis NuGet that dropsSqlServer.Rules.dll/SqlServer.Rules.NetFx.dllintoanalyzers/dotnet/cs/(thenet472build is renamed to.NetFx.dllin a post-build step, seesrc/SqlServer.Rules/SqlServer.Rules.csproj). Both TFMs ship in one package so the analyzer loads under both legacy SSDT (net472) and modern SDK-style SQL projects.- Every rule inherits from
BaseSqlCodeAnalysisRule(src/SqlServer.Rules/BaseSqlCodeAnalysisRule.cs), which extends DacFx'sSqlCodeAnalysisRule. The base class exposes the sharedProgrammingSchemas/ProgrammingAndViewSchemaselement-type sets, keyword/data-type lists, a shared case-insensitiveComparer, and the heavyGetDataType(...)/GetColumnDataType(...)helpers (withConditionalWeakTablecaches keyed onTSqlObject— don't bypass these caches, column-type resolution is expensive). - Rules are discovered by MEF via
[ExportCodeAnalysisRule]. TheRuleIdis alwaysConstants.RuleNameSpace + "SR{D|N|P}####"(e.g.SqlServer.Rules.SRD0038). The category comes fromConstants.Design/Naming/Performanceinsrc/SqlServer.Rules/Globals/Constants.cs. Rules are organized in folders by category that mirror these constants. - Most rules walk the ScriptDom AST using visitors under
src/SqlServer.Rules/Visitors/. Prefer reusing an existing visitor — there are ~90 of them covering most node types. New visitors derive fromBaseVisitor(or a more specificTSqlConcreteFragmentVisitorsubclass). - XML doc comments on a rule class carry metadata used by the docs generator:
<FriendlyName>,<IsIgnorable>,<ExampleMd>. These get parsed intodocs/{Design,Naming,Performance}/SR*.md.
Two test projects:
test/SqlServer.Rules.Test— unit tests for the rules themselves.- Each rule has a
SR####Tests.csunderDesign/,Naming/, orPerformance/. - Tests inherit from
Helpers/TestModel.cs: add file paths toTestFiles, expected hits toExpectedProblems, thenRunTest(). The helper builds aTSqlModel(SQL 2019 /Sql150), runs the full analysis service, and usesCollectionAssert.AreEquivalentagainst problems whoseRuleIdstarts withSqlServer.Rules.. - Test SQL inputs live under
sqlprojects/TSQLSmellsTest/etc. and are referenced via relative paths like"../../../../../sqlprojects/...". SQL fixture files must be UTF-8 with BOM or DacFx model loading misbehaves. SmokeTests/(TestAw, TestChinook, TestFabric) runs the full ruleset against full sample schemas and asserts the exact problem list — when you add or change a rule, expect these to need updating.
- Each rule has a
test/TSQLAnalyzer.Tests— covers the analyzer library intools/ErikEJ.DacFX.TSQLAnalyzer.
There is an older TestCasesBase.cs / BaselineSetup.cs pattern (GetTestCaseProblems(testCases, ruleId)) used by a handful of tests; new tests should follow the TestModel-based pattern shown in Design/SRD0039Tests.cs.
tools/ErikEJ.DacFX.TSQLAnalyzer— engine that loads a model from.sql/.dacpac/.zip/ live connection, runs DacFx code analysis, applies rule filters (Rules:-SqlServer.Rules.SRD0004syntax matching MSBuild.Sdk.SqlProj), and returnsAnalyzerResult. Used by both the CLI and the VSIX.tools/SqlAnalyzerCli—tsqlanalyze.NET tool (PackageTypeMcpServer). Built on Spectre.Console. Doubles as an MCP server when launched with-mcp(the.mcp/server.jsonis packed into the nupkg).tools/SqlServer.Rules.DocsGenerator— generatesdocs/**/*.mdfrom rule XML doc comments. Do not hand-edit files indocs/— they are regenerated. Includes a hard-codedMicrosoftRulestable that supplements built-in DacFxSR####rules with links to Microsoft Learn.tools/SqlServer.Rules.Generator— console reporter for rule inventory.tools/SqlServer.Rules.Report— serialization helpers for analyzer results.tools/SqlAnalyzerVsix— Visual Studio extension (Windows only).
- Pick the category (Design/Naming/Performance) and the next free
SR{D|N|P}####id. - Add the class in
src/SqlServer.Rules/<Category>/, inheritingBaseSqlCodeAnalysisRule. Use existing files (e.g.Design/AliasTablesRule.cs) as the template — they show theRuleId/RuleDisplayName/Messageconst triple, the[ExportCodeAnalysisRule]attribute, and the<FriendlyName>/<IsIgnorable>XML doc tags the docs generator reads. - Constructor passes the relevant element-type set (typically
ProgrammingAndViewSchemas) to the base. For element rules useRuleScope = SqlRuleScope.Element; for whole-model rules useSqlRuleScope.Model. - Walk the AST with an existing visitor where possible. Return
SqlRuleProbleminstances — the inheritedProblemslist andMessageFormattermay help, but most rules build the list locally. - Add a matching
SR####Tests.csin the parallel folder undertest/SqlServer.Rules.Test/. Author or reuse a SQL fixture undersqlprojects/TSQLSmellsTest/(or another fixture project) and assert the expected(line, column, ruleId)triples. - If the new rule fires on the smoke-test fixtures (AW / Chinook / Fabric), update the
ExpectedProblemslists intest/SqlServer.Rules.Test/SmokeTests/accordingly. - Do not hand-edit
docs/— runningSqlServer.Rules.DocsGeneratorregenerates the markdown.
- The package is signed (
key.snk). Don't addInternalsVisibleTowithout matching the public key. Directory.Build.propsenablesEnableNETAnalyzerswithlatest-all,GenerateDocumentationFile, and includes StyleCop. Suppress with attributes/pragmas inline (existing code uses#pragma warning disable SA####extensively); don't disable analyzers globally..editorconfigat repo root drives formatting — respect it.- Embedded
src/SqlServer.Rules/EditorConfig.Core/is a vendored editorconfig parser used by the CLI's-fformatter (it's not the build's.editorconfig).