Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions .github/workflows/nightly-fix-finder.lock.yml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 10 additions & 3 deletions .github/workflows/nightly-fix-finder.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ on:
- "03-region-directives"
- "04-missing-xml-docs"
- "05-general-mistakes"
- "06-unused-using-directives"
- "07-asynctask-log-property"
- "06-completely-dead-code"
- "07-stale-xamarin-references"
- "08-string-literal-error-messages"
required: false
type: choice
Expand Down Expand Up @@ -63,6 +63,7 @@ safe-outputs:
- src/**
- tests/**
- Documentation/**
- README.md
auto-close-issue: false
draft: false
fallback-as-issue: false
Expand Down Expand Up @@ -205,14 +206,20 @@ Before changing files, score the proposed fix on a 0–30 scale across three dim

**Threshold: ≥ 22 / 30 to implement.** Additionally, **safety must be ≥ 6** — any fix scoring lower on safety must be declined regardless of total. The SkiaSharp project that pioneered this rubric confirmed it correctly stops risky behavior-change fixes that otherwise look attractive.

For `08-string-literal-error-messages`, a change that only moves an existing
diagnostic into the English resource system, preserving its meaning, arguments,
severity, and control flow, scores at least 8 for safety and 8 for scope. Treat
the required resource, checked-in resource accessor, source call site, and XA
message documentation as one cohesive fix.

If the proposal scores below either bar, call `noop` with a message that includes the score breakdown and why you declined. Do not modify files.

## Phase 4: Implement and Validate

Implement the fix yourself:

1. Make the smallest complete change that resolves the verified problem.
2. Follow all repository instructions and existing style. Never modify generated files, non-English localization files, or unrelated code.
2. Follow all repository instructions and existing style. Never modify generated files, non-English localization files, or unrelated code. The only generated-file exception is a checked-in `Resources.Designer.cs` accessor required by `08-string-literal-error-messages`; change only the accessor for the new English resource.
3. Add or update a focused test when behavior changes or a regression test is practical.
4. Bootstrap the repository toolchain with `./build.sh Prepare` before validation. This installs the repository-pinned .NET 11 SDK under the active `bin/{Debug|Release}/dotnet` configuration and prepares generated build prerequisites. Then run the smallest targeted build or test command through `./dotnet-local.sh`; never use the runner's system `dotnet` or lower `DotNetTargetFrameworkVersion` to work around missing tooling. A PR requires successful validation; if the fix cannot be validated in this environment, revert only your own changes and call `noop`.
5. Review `git diff` for accidental or unrelated edits.
Expand Down
86 changes: 86 additions & 0 deletions .github/workflows/nightly-fix-finder/06-completely-dead-code.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
#!/usr/bin/env bash
# Category: Completely Dead Code

cat << 'GUIDANCE'
## Category: Completely Dead Code

### What to look for
Code under `src/` that can be proven to have no callers and no execution path:
- Private members or nested types whose identifier has no references
- Branches that are unconditionally unreachable
- Disabled `#if false` blocks with no documented reason to retain them

The proof must account for every target framework and build configuration in
the owning project. "Probably unused" is not sufficient.

### How to fix
Delete the smallest complete dead member or block, then remove imports or helper
code that became unused as a direct result. Add or update a focused test only
when removal changes a code path that can be exercised.

Before deleting a private member, search the full repository for its identifier
and inspect attributes, interfaces, partial declarations, build targets, and
generated-code inputs that could reference it indirectly.

### What NOT to flag
- Public, protected, or internal API
- JNI callbacks, `[Register]` members, Java peer members, or native entry points
- MSBuild task types or properties, serialization members, reflection targets,
dependency-injection entry points, or members referenced by name
- Platform-, runtime-, ABI-, or TFM-specific code that is live in another build
- Compatibility code retained for older Android or .NET versions
- Generated files, submodules under `external/`, or test code
- Code that is merely redundant, inefficient, or currently untested
GUIDANCE

echo ""
echo "## Scan Data"
echo "### Explicitly unreachable or disabled constructs"
OBVIOUS=$(grep -rnP '^\s*(#if\s+false\b|if\s*\(\s*false\s*\)|while\s*\(\s*false\s*\))' \
--include='*.cs' \
--exclude-dir=obj --exclude-dir=bin \
--exclude-dir=Tests --exclude-dir=Test --exclude-dir=tests \
--exclude='*.generated.cs' --exclude='*.Designer.cs' --exclude='*.g.cs' \
src/ 2>/dev/null \
| shuf -n 20)
if [ -n "$OBVIOUS" ]; then
echo "$OBVIOUS"
else
echo "None found"
fi

echo ""
echo "### Private declarations whose identifier appears only once in repository C# source"
SINGLETON_TOKENS=$(mktemp)
PRIVATE_DECLARATIONS=$(mktemp)
trap 'rm -f "$SINGLETON_TOKENS" "$PRIVATE_DECLARATIONS"' EXIT

grep -rhoP '\b[A-Za-z_][A-Za-z0-9_]*\b' \
--include='*.cs' \
--exclude-dir=obj --exclude-dir=bin \
src/ 2>/dev/null \
| sort | uniq -c \
| awk '$1 == 1 { print $2 }' > "$SINGLETON_TOKENS"

grep -rnPo '^\s*private\s+(?:(?:static|readonly|const|async|unsafe|partial|volatile|new|sealed)\s+)*(?:[A-Za-z_][A-Za-z0-9_.<>,?\[\]]*\s+)+\K[A-Za-z_][A-Za-z0-9_]*(?=\s*(?:\(|\{|=>|=|;))' \
--include='*.cs' \
--exclude-dir=obj --exclude-dir=bin \
--exclude-dir=Tests --exclude-dir=Test --exclude-dir=tests \
--exclude='*.generated.cs' --exclude='*.Designer.cs' --exclude='*.g.cs' \
src/ 2>/dev/null > "$PRIVATE_DECLARATIONS"

CANDIDATES=$(awk -F: '
NR == FNR {
singleton [$1] = 1
next
}
length ($NF) >= 4 && singleton [$NF] {
print
}
' "$SINGLETON_TOKENS" "$PRIVATE_DECLARATIONS" | shuf -n 20)

if [ -n "$CANDIDATES" ]; then
echo "$CANDIDATES"
else
echo "None found"
fi

This file was deleted.

Loading