CtrlK
BlogDocsLog inGet started
Tessl Logo
SkillPublic

add-lint-rule

Add or change lint rules and static analysis in dd-trace-dotnet. Use when adding a lint rule, Roslyn analyzer, diagnostic, BannedSymbols entry, StyleCop/editorconfig severity, CppCheck suppression, or Clang-Tidy check, or when the user asks how to enforce a coding convention at compile time.

Quality

87%

Does it follow best practices?

Run evals on this skill

Adds up to 20 points to the overall score

View guide
SecuritybySnyk

Passed

No findings from the security scan

SKILL.md
Quality
Evals
Security

Add Lint Rules / Static Analysis

This repo has no dotnet format or clang-format --check CI job. Managed enforcement is compile-time Roslyn (TreatWarningsAsErrors=true). Do not add a new pipeline stage for a C# rule.

Scope: enforcement of rules and scripts applies only to "core" production code for now (Datadog.Trace and other tracer/src libraries; native tracer/loader/profiler product code). Do not apply new analyzers, Banned APIs, CppCheck/Clang-Tidy tightenings, or helper scripts to tests, helpers, samples, or test-applications unless the user explicitly asks to expand scope.

Still add unit tests for the analyzer itself under Datadog.Trace.Tools.Analyzers.Tests — that is testing the rule, not enforcing it on test code.

New rules are introduced as Error. Info diagnostics are legacy: they are IDE-only, they are ignored, and they must not be used for new rules. If the rule is not worth Error, do not add it.

Read reference.md for file layout, ID allocation, and copy-paste templates. Stay in this file until the rule is classified.

1. Classify the rule first

Pick one primary category. Do not mix them in the diagnostic title, category, or PR description.

CategoryWhat it isSeverity (new rules)Typical mechanism
Correctness / safetyWrong code, security, config-key misuse, infinite-loop hazardErrorCustom Roslyn analyzer
Product conventionMust use a helper, logging shape, duck-type null checkErrorAnalyzer or BannedSymbols.txt
StyleNaming, usings, headers, layout, “looks nicer”Error, or do not add. Prefer existing StyleCop / .editorconfigStyleCop, editorconfig, or analyzer
PerformanceProven hot-path winError only if the win is clear. Otherwise do not addAnalyzer or Banned API, with an evidence-backed message

If the same idea is both “style” and “maybe faster”, it is style. Do not rebrand it as performance to justify blocking PRs.

2. Do not over-claim performance

Do not classify a rule as Performance, mention allocations/CPU in the diagnostic message, or sell the PR as a perf win unless at least one of these is true:

  • The replacement mechanistically avoids a known allocation or extra work on a tracer hot path (span create/tag, instrumentation callback, logging, config read). Example already in-tree: Environment.Version allocates a Version on every get; BannedSymbols.txt says so.
  • You have a benchmark or a tight proof (the API’s implementation obviously allocates; the helper is documented as the zero-alloc path).

Not enough:

  • “Sealing types can improve performance” as a reason to add a rule (DDSEAL001 is a legacy Info diagnostic; do not copy it).
  • Micro-optimizations outside bootstrap/hot paths in AGENTS.md.
  • Style preferences (braces, var, usings, is not null) dressed up as perf.
  • “Might help the JIT / inlining / virtual dispatch” without a measured case.

If the case is not strong enough for Error, do not add the rule. Never use a speculative perf claim to justify shipping it.

3. Choose the mechanism

Managed C# (preferred: Roslyn)

Cheapest fit wins:

  1. Ban a specific API → add a line to repo-root BannedSymbols.txt (RS0030 is already error). This file is currently supplied only to Datadog.Trace.csproj; for another project, include it as AdditionalFiles there or choose a custom analyzer. Message must state the replacement and the real reason (correctness, config, or a clear perf win).
  2. Ban a pattern (syntax, types, logging templates, WithKeys arguments) → custom analyzer under tracer/src/Datadog.Trace.Tools.Analyzers/.
  3. Existing StyleCop / IDE diagnostic, new severity → .editorconfig dotnet_diagnostic.<ID>.severity. Do not invent StyleCop IDs.
  4. Do not enable EnableNETAnalyzers / EnforceCodeStyleInBuild globally. Built-in .NET analyzers are off on purpose (shared/CodeAnalysis.props).

Custom analyzers are referenced only from tracer/src/Directory.Build.props as OutputItemType="Analyzer". New [DiagnosticAnalyzer] types are picked up with no CI YAML changes. BannedSymbols.txt is an AdditionalFiles item on Datadog.Trace.csproj (core), not on test projects.

StyleCop and .editorconfig are broader (they include tests). Do not raise a StyleCop/IDE diagnostic severity repo-wide as a way to lint test code, and do not treat that existing breadth as a reason to extend custom rules or scripts beyond core.

Native C/C++ (light)

Do not introduce Roslyn, clang-format CI, or a new analyzer framework.

AreaPrimary toolsWhere they run
Native tracer + native loaderCppCheckAzure static_analysis_checks_tracer
ProfilerClang-Tidy (fails on error:) and CppCheckAzure static_analysis_tests_profiler (only if profiler changed)

Default posture: fix the code or add a narrow suppression. Do not tighten check sets or remove --suppress= flags unless the user asked for a new native rule and existing noise is acceptable.

  • Tracer/loader suppressions are CLI --suppress= lists on the CppCheckNativeSrc / CppCheckNativeLoader Nuke targets.
  • Profiler CppCheck: profiler/cppcheck-suppressions.txt (--inline-suppr is enabled).
  • Profiler Clang-Tidy: base set is profiler/.clang-tidy. CI -checks (ClangTidyChecks in Build.Profiler.Steps.cs) is appended, not a replacement. Do not add style checks by default; a new check is opt-in and fails the profiler analysis stage on error:.
  • .clang-format is local style only; CI does not verify it.

4. Severity (managed)

Introduce every new diagnostic as Error. Set defaultSeverity: DiagnosticSeverity.Error.

  • Error — the only acceptable severity for a new rule. Fails the build and blocks the PR.
  • Warning — not a softer landing. TreatWarningsAsErrors is true, so it already fails the build. Do not use it as the final state.
  • Info — legacy only (DDSEAL001). IDE-only, ignored in CI, and ignored in practice. Do not add new Info rules. Do not “try Info first and bump later.”

If cleanup is large, use stacked PRs to fix hits, then enable the rule as Error. If it is not worth that, do not add it. Match category to §1 (Usage, CodeQuality, Maintainability, Performance only when §2 is satisfied).

5. Implementation workflow (managed)

  1. Classify (§1) and confirm the perf bar (§2).
  2. Grep DiagnosticId under tracer/src/Datadog.Trace.Tools.Analyzers for the next DDxxxx or start DD<AREA>001 for a family (DDLOG, DDDUCK).
  3. Follow reference.md: analyzer, tests, optional code fix.
  4. Clean up all current hits in the same PR (or in stacked PRs before enabling Error), or the tree will not compile. Prefer real fixes over #pragma / GlobalSuppressions.
  5. Tests: Datadog.Trace.Tools.Analyzers.Tests via CSharpAnalyzerVerifier / CSharpCodeFixVerifier.
  6. Compile: CompileManagedSrc or BuildAndRunManagedUnitTests with a filter on the new test class.

Do not add Nuke targets, Azure stages, GitHub workflows, CodeQL config, or static-analysis.datadog.yml entries.

6. PR description

State: category (style / convention / correctness / performance), diagnostic ID, what is forbidden, the replacement, and why. If performance, cite the allocation/hot-path evidence in one sentence. If style, say so and do not claim runtime impact.

Checklist

  • Category is explicit; style is not labeled Performance
  • Perf claims meet §2; otherwise no perf language in the diagnostic
  • Enforcement is "core" production code only; analyzer unit tests still added
  • Managed: Roslyn analyzer or BannedSymbols.txt, not a new CI job
  • Native: CppCheck and/or existing Clang-Tidy surface only
  • Introduced as Error (Info is legacy and will be ignored)
  • Analyzer tests cover a flag case and a no-flag case
  • Existing violations fixed in the same change
  • Generated-code analysis left None; concurrent execution enabled
Repository

DataDog/dd-trace-dotnet

Path

.claude/skills/add-lint-rule/SKILL.md

Last updated
First committed

Is this your skill?

If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.