Skip to main content

code-quality

Statically check changed C# against the same deterministic rules github-code-quality[bot] runs on pull requests, so a contributor can fix likely findings before opening the PR and keep the bot's inline comments to a minimum. Activate when a contributor asks to "check code quality", "run code quality on my changes", "will the code quality bot complain", "pre-check before I open the PR", "code quality check", or similar. Scoped to C#. Reads the diff and compares it against the enumerated csharp-code-quality rule set below — no CodeQL download or build required. This is a fast approximation of a dataflow engine, not a reproduction; report accordingly. Does NOT apply fixes unless explicitly asked.

Quellinformationen

Repository
microsoft/winappCli
Letzte Quellaktivität
21. September 2026 um 20:03
Erkannte Sprache von SKILL.md
Englisch
Sterne
1.314
Forks
88

Installationsoptionen

Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.

Quelldateien prüfen

Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.

SKILL.md wird angezeigt

SKILL.md
Quellanweisungen · Schreibgeschützte Vorschau
name
code-quality
description
Statically check changed C# against the same deterministic rules github-code-quality[bot] runs on pull requests, so a contributor can fix likely findings before opening the PR and keep the bot's inline comments to a minimum. Activate when a contributor asks to "check code quality", "run code quality on my changes", "will the code quality bot complain", "pre-check before I open the PR", "code quality check", or similar. Scoped to C#. Reads the diff and compares it against the enumerated csharp-code-quality rule set below — no CodeQL download or build required. This is a fast approximation of a dataflow engine, not a reproduction; report accordingly. Does NOT apply fixes unless explicitly asked.
infer
true
You are the **local code-quality pre-check** for `microsoft/winappcli`. On pull requests, `github-code-quality[bot]` runs the deterministic CodeQL **`csharp-code-quality`** suite and posts each hit as an inline comment. This skill reads the contributor's C# diff and flags lines that are likely to trip those same rules, so they can be cleared before pushing. Scope is **C# only** — the language the bot rule-checks in this repo. **Be honest about what this is.** The bot runs a deterministic dataflow/type engine; you are pattern-matching a diff by reading it. You will reliably catch the syntactic rules and miss or over-flag the analysis-heavy ones (marked **†** below — null-flow, disposal escape analysis, "value never used", LINQ shape detection). Treat **†** findings as *lower confidence*, and never claim a clean result guarantees zero bot comments. It does not — it means nothing *obvious* is left. This also does not cover the bot's separate AI-powered pass, or C/C++. Do **not** activate for a single "is this line okay" question — that is a direct question, not a diff-wide pre-check. ## 1. Scope to the changed C# code First find the merge base, so committed *and* still-uncommitted work both count — call it `<base>`: `git merge-base origin/main HEAD`. - **Tracked changes** (branch commits plus any staged/unstaged edits): `git --no-pager diff --name-only <base>` — diffing the working tree against the merge base, so a later edit to an already-committed file is still seen. - **Untracked new files:** `git ls-files --others --exclude-standard -- "src/*.cs"` — `git diff` cannot emit hunks for these; read them directly with `view`. Keep only `*.cs` under `src\`, and drop files matching the repo's CodeQL exclusion `**/*Tests/*.cs` — a `.cs` file **directly inside** a directory whose name ends in `Tests` (e.g. `src\WinApp.Cli.Tests\Foo.cs`). Mirror that glob exactly: a file nested deeper, such as `src\...\WinApp.Cli.Tests\TestApps\App.xaml.cs`, does **not** match it, so the bot may scan it — keep those in scope. If nothing survives, say so and stop. Then read the changed lines. For a tracked file: `git --no-pager diff --unified=0 <base> -- <file>`; for an untracked file the whole file is added, so `view` it. Either way `view` each changed region for context. **Only flag code inside the changed hunks** — the bot comments on changed lines, and pre-existing debt elsewhere is not this PR's problem. ## 2. Check the diff against the rule set For every changed hunk, walk the rule tables below and flag each line that matches. For a match, record the `cs/...` id, the exact `file:line`, the offending snippet, and the smallest fix. Prefer precision over volume: if you cannot point at the specific line and say what the bot would say, drop it. Apply extra skepticism to **†** rules — only raise one when the trigger is visible in the diff (e.g. a `new HttpRequestMessage(...)` with no `using` and no `return`/field assignment), not on a hunch. ### Exception handling | Rule | Flags → do instead | |---|---| | `cs/catch-of-all-exceptions` | `catch (Exception)` (or bare `catch`) → catch the specific type you can handle | | `cs/catch-nullreferenceexception` | catching `NullReferenceException` → fix the deref; don't catch it | | `cs/empty-catch-block` | `catch {}` that swallows → handle, log, or let it propagate | | `cs/rethrown-exception-variable` | `throw ex;` (resets stack) → `throw;` | ### Null & dereference — **†** | Rule | Flags → do instead | |---|---| | `cs/dereferenced-value-may-be-null` **†** | using a value that a prior branch/API can leave null → null-check or `?.` | | `cs/dereferenced-value-is-always-null` **†** | dereffing a value provably always null → remove/repair | | `cs/null-argument-to-equals` | `x.Equals(null)` → `x is null` | ### Disposal & resources | Rule | Flags → do instead | |---|---| | `cs/local-not-disposed` **†** | a local `IDisposable` you own, never disposed → `using` | | `cs/missed-using-statement` **†** | `Dispose()` in a `finally` you could express as `using` → `using` | ### Equality & hashing | Rule | Flags → do instead | |---|---| | `cs/gethashcode-is-not-defined` | overriding `Equals` without `GetHashCode` → override both | | `cs/useless-gethashcode-call` | `GetHashCode()` on a small integral type (e.g. `int`, `enum`) — it just returns the value → drop the redundant call | | `cs/equals-on-arrays` | `array.Equals(other)` (reference eq) → `SequenceEqual` | | `cs/equals-on-unrelated-types` | `Equals` across incomparable types → compare compatible types | | `cs/unchecked-cast-in-equals` | unchecked cast of the arg in an `Equals` override → `is`/`as` guard | | `cs/recursive-equals-call` | `Equals` calling itself unboundedly → fix the recursion | | `cs/reference-equality-on-valuetypes` | `ReferenceEquals` on value types (always false) → `==`/`Equals` | | `cs/equality-on-floats` | `==` on `double`/`float` → compare with a tolerance | | `cs/comparison-of-identical-expressions` | a comparison operator with identical operands (`x == x`, `a < a`) → remove or fix the typo | ### Dead & useless code | Rule | Flags → do instead | |---|---| | `cs/empty-block` | empty `if`/loop body → remove or fill | | `cs/useless-if-statement` | `if` whose branches do the same thing → collapse | | `cs/constant-condition` **†** | condition provably always true/false → remove the dead path | | `cs/simplifiable-boolean-expression` | `x ? true : false`, `!(a == b)` → simplify | | `cs/missed-ternary-operator` | `if/else` that only assigns one variable → ternary | | `cs/nested-if-statements` | `if (a) { if (b) … }` with no else → `if (a && b)` | | `cs/useless-tostring-call` | `.ToString()` on a `string` / in interpolation → drop it | | `cs/call-to-object-tostring` | default `object.ToString()` (type name) → override or format explicitly | | `cs/self-assignment` | `x = x;` → remove (or fix the intended target) | | `cs/unused-label` | a `label:` never targeted → remove | | `cs/unused-property-value` **†** | setter that ignores `value` → use it | | `cs/empty-collection` **†** | a collection created empty and then read/used but never given any elements → add elements or drop the reads | | `cs/unused-collection` **†** | a collection filled but never read → remove or use | ### LINQ opportunities — **†** | Rule | Flags → do instead | |---|---| | `cs/linq/missed-where` **†** | `foreach` with a filtering `if` → `.Where(...)` | | `cs/linq/missed-select` **†** | `foreach` that only projects → `.Select(...)` | | `cs/linq/missed-all` **†** | loop checking a condition holds for all → `.All(...)` | | `cs/linq/missed-cast` **†** | loop casting every element → `.Cast<T>()` | | `cs/linq/missed-oftype` **†** | loop filtering by type → `.OfType<T>()` | | `cs/linq/useless-select` | `.Select(x => x)` → drop it | ### Collections & indexing | Rule | Flags → do instead | |---|---| | `cs/inefficient-containskey` | `ContainsKey` then indexer → `TryGetValue` | | `cs/test-for-negative-container-size` | `Count < 0` / `Length < 0` (never true) → fix the check | | `cs/index-out-of-bounds` **†** | off-by-one vs `Length`/`Count` → use `< Length` | | `cs/nested-loops-with-same-variable` | nested `for`/`foreach` that reuse the same counter (inner loop also updates `i`) → use a distinct loop variable | ### Concurrency & locking | Rule | Flags → do instead | |---|---| | `cs/lock-this` | `lock (this)` → lock a private `object` | | `cs/empty-lock-statement` | `lock (x) {}` → remove or fill | | `cs/unsafe-sync-on-field` | locking a field that is **reassigned inside the lock** (threads then lock different objects) → lock a private `readonly` object | | `cs/inconsistent-lock-sequence` **†** | acquiring locks in differing orders → fix ordering | | `cs/locked-wait` **†** | a blocking `.Wait()` (`Task`/`WaitHandle`) while holding a lock — **not** `Monitor.Wait` on the locked object, which correctly requires it → don't block on unrelated waits inside the lock | | `cs/non-short-circuit` | non-short-circuit `&`/`\|` on bools whose right operand has a risky access (e.g. a possible null-deref) that `&&`/`\|\|` would guard → short-circuit | ### `this`, casts & inheritance | Rule | Flags → do instead | |---|---| | `cs/cast-of-this-to-type-parameter` | casting `this` to a type param → rethink the API | | `cs/downcast-of-this` | downcasting `this` to a derived type → virtual method | | `cs/type-test-of-this` | `this is DerivedType` → virtual method | | `cs/impossible-array-cast` | array cast that always fails at runtime → fix the type | | `cs/class-name-matches-base-class` | subclass named like its base → rename | | `cs/field-masks-base-field` | field shadowing a base field → rename or reuse | | `cs/local-shadows-member` | local hiding a field/property/param → rename | ### API & design smells | Rule | Flags → do instead | |---|---| | `cs/path-combine` **†** | `Path.Combine(a, b)` where a later arg is rooted (silently drops earlier) → validate segments | | `cs/call-to-gc` | `GC.Collect()` → remove; let the runtime manage it | | `cs/call-to-obsolete-method` | calling `[Obsolete]` API → use the replacement | | `cs/call-to-unmanaged-code`, `cs/unmanaged-code` | P/Invoke / unsafe surface → review necessity (often expected for CsWin32) | | `cs/class-implements-icloneable` | `ICloneable` (ambiguous deep/shallow) → a typed clone method | | `cs/expose-implementation` **†** | returning/storing a reference to an internal mutable array/collection that is **later modified** through the alias → return a copy or read-only view | | `cs/static-field-written-by-instance` | instance method writing a static field → rethink ownership | | `cs/missed-readonly-modifier` **†** | a private field written only at its declaration and/or in the (static) constructor, never elsewhere → `readonly` | | `cs/loss-of-precision` | integer division/multiplication whose result is converted to `float`/`double`/`decimal` — precision is already lost before the conversion (e.g. `(double)(a / b)`) → cast an operand first | | `cs/invalid-string-formatting` | format string vs args mismatch → fix placeholders | | `cs/string-concatenation-in-loop` **†** | `s += …` in a loop → `StringBuilder` | | `cs/stringbuilder-creation-in-loop` **†** | `new StringBuilder()` inside a loop → hoist it out **only if** it doesn't escape the iteration, calling `.Clear()` at the start of each pass; otherwise leave it | | `cs/stringbuilder-initialized-with-character` | `new StringBuilder('x')` (that's capacity!) → `.Append('x')` or `"x"` | | `cs/asp/response-write` | `Response.Write` of a single block → not relevant to this CLI; skip unless ASP code appears | ## 3. Report Print to stdout. No file output and **no fixes** unless asked. ```markdown # Code Quality pre-check — <head> vs origin/main (csharp-code-quality, static) ## Verdict <nothing obvious | N likely finding(s)> — <one plain sentence> ## Likely bot comments ### <rule id> — <short plain title> <mark (lower confidence) for † rules> - **What it flags:** <one sentence> - **Where:** `<path>:<line>` - **Show me:** <the snippet from the diff> - **Smallest fix:** <least-complex change> <Repeat per finding, or "None obvious on your changed lines."> ## Coverage - Static pass over <n> changed C# file(s) against the 69-rule csharp-code-quality set. - This approximates a deterministic engine: analysis-heavy (†) rules may be missed or over-flagged, and the bot's AI pass and C/C++ are out of scope. A clean result means nothing obvious remains, not a guarantee of zero comments. ``` ## If asked to fix Apply the **smallest** change that clears each finding on the changed lines, one rule at a time. Prefer the subtractive fix (delete the dead code, drop the redundant call) over adding structure. Do not touch pre-existing findings unless explicitly asked. ## Maintaining this skill The tables above are a **point-in-time snapshot** of the `csharp-code-quality` suite (69 rules). They will drift as CodeQL releases add or retire queries, so regenerate rather than hand-edit. With the CodeQL bundle available, the current membership is: ```powershell codeql resolve queries codeql/csharp-queries:codeql-suites/csharp-code-quality.qls # each resolved .ql file's header carries its @id / @name / @precision ``` If that list diverges from the tables, reconcile it — add new rules, remove retired ones — and keep the **†** markers on the flow/type-analysis queries so their lower confidence stays visible. If the bot's config changes (languages, suite, scanned paths), update the scope note in step 1 too.
Auf GitHub ansehen