-
Notifications
You must be signed in to change notification settings - Fork 0
[Analyzer] Support per-diagnostic severity configuration #4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| # EditorConfig for PureSharp Consumer App | ||
| # This file demonstrates Roslyn standard diagnostic severity configuration | ||
|
|
||
| root = true | ||
|
|
||
| [*.cs] | ||
| # Configure PureSharp diagnostic severities using Roslyn standard format: | ||
| # dotnet_diagnostic.<DiagnosticID>.severity = none | silent | suggestion | warning | error | ||
|
|
||
| # Referential Transparency Diagnostics (RT) | ||
| # RT0001: Static mutable field access | ||
| # Change to "none" to suppress, "warning" for warning, "error" for error | ||
| dotnet_diagnostic.RT0001.severity = error | ||
|
|
||
| # RT0002: Non-pure method call | ||
| dotnet_diagnostic.RT0002.severity = error | ||
|
|
||
| # RT0003: I/O operation | ||
| dotnet_diagnostic.RT0003.severity = error | ||
|
Comment on lines
+13
to
+19
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -eu
printf '%s\n' '--- candidate files ---'
git ls-files | grep -E '(^|/)(\.editorconfig|Program\.cs|[^/]+\.csproj|README[^/]*|.*\.yml|.*\.yaml)$' | grep -E 'PureSharp|\.github|README' | head -200
printf '%s\n' '--- ConsumerApp files ---'
find examples/PureSharp.ConsumerApp -maxdepth 3 -type f -print 2>/dev/null | sort
printf '%s\n' '--- editorconfig ---'
cat -n examples/PureSharp.ConsumerApp/.editorconfig
printf '%s\n' '--- source excerpts ---'
find examples/PureSharp.ConsumerApp -type f -name '*.cs' -print -exec sh -c 'echo "--- $1"; cat -n "$1"' sh {} \;
printf '%s\n' '--- project files ---'
find examples/PureSharp.ConsumerApp -type f -name '*.csproj' -print -exec sh -c 'echo "--- $1"; cat -n "$1"' sh {} \;
printf '%s\n' '--- references to ConsumerApp and expected-failure/build behavior ---'
rg -n -i 'ConsumerApp|expected.?failure|PureSharp|RT0001|dotnet build|build contract|should fail' .github examples README.md 2>/dev/null || trueRepository: mao2009/PureSharp Length of output: 8106 🏁 Script executed: #!/bin/bash
set -eu
printf '%s\n' '--- repository project layout ---'
git ls-files src examples | sort | sed -n '1,240p'
printf '%s\n' '--- analyzer declarations and RT0001 implementation ---'
rg -n -C 4 'RT0001|Static mutable|PureMethod|DiagnosticDescriptor|DiagnosticAnalyzer|Analyzer Include|ConsumerApp' src examples README.md
printf '%s\n' '--- core project and solution metadata ---'
find . -maxdepth 3 -type f \( -name '*.sln' -o -name '*.slnx' -o -name 'Directory.*' -o -name '*.props' -o -name '*.targets' \) -print | sort
find src/PureSharp.Core -maxdepth 2 -type f -print -exec sh -c 'case "$1" in *.csproj|*.props|*.targets) echo "--- $1"; cat -n "$1";; esac' sh {} \;
printf '%s\n' '--- workflow and documentation build instructions ---'
cat -n .github/workflows/upload_nuget.yml
sed -n '85,145p' README.mdRepository: mao2009/PureSharp Length of output: 50373 🏁 Script executed: #!/bin/bash
set -eu
printf '%s\n' '--- ReferentialTransparencyAnalyzer.cs ---'
cat -n src/PureSharp.Core/ReferentialTransparencyAnalyzer.cs | sed -n '1,150p'
printf '%s\n' '--- PurityRulesEngine.cs (field rule) ---'
cat -n src/PureSharp.Core/PurityRulesEngine.cs | sed -n '125,155p'
printf '%s\n' '--- PureSharp.Core.csproj ---'
cat -n src/PureSharp.Core/PureSharp.Core.csproj
printf '%s\n' '--- RT0001 tests ---'
rg -n -C 8 'RT0001|StaticMutable|static.*field|globalField' src/PureSharp.Analyzers.Tests/ReferentialTransparencyAnalyzerTests.cs
printf '%s\n' '--- build-related repository metadata ---'
find . -maxdepth 2 -type f \( -name 'global.json' -o -name 'Directory.Build.*' -o -name '*.sln' -o -name '*.slnx' \) -print -exec cat -n {} \;Repository: mao2009/PureSharp Length of output: 14340 🏁 Script executed: #!/bin/bash
set -eu
python3 - <<'PY'
from pathlib import Path
import re
import xml.etree.ElementTree as ET
editor = Path("examples/PureSharp.ConsumerApp/.editorconfig").read_text(encoding="utf-8-sig")
program = Path("examples/PureSharp.ConsumerApp/Program.cs").read_text(encoding="utf-8-sig")
analyzer = Path("src/PureSharp.Core/ReferentialTransparencyAnalyzer.cs").read_text()
rules = Path("src/PureSharp.Core/PurityRulesEngine.cs").read_text()
csproj_path = Path("examples/PureSharp.ConsumerApp/PureSharp.ConsumerApp.csproj")
csproj = csproj_path.read_text(encoding="utf-8-sig")
solution = Path("PureSharp.slnx").read_text()
settings = dict(re.findall(r"^\s*dotnet_diagnostic\.([A-Z0-9]+)\.severity\s*=\s*(\w+)\s*$", editor, re.M))
print("RT0001 severity:", settings.get("RT0001"))
pure_method = bool(re.search(r"\[PureMethod\]\s+public\s+static\s+int\s+AddWithGlobalField", program))
field_decl = re.search(r"private\s+static\s+int\s+_globalCache\s*;", program)
field_refs = re.findall(r"\b_globalCache\b", program)
print("annotated method:", pure_method)
print("mutable static field:", bool(field_decl))
print("field reference count including declaration/comments:", len(field_refs))
print("analyzer registers FieldReference:", "OperationKind.FieldReference" in analyzer)
print("rule rejects non-readonly, non-const static fields:",
"field.IsStatic && !field.IsReadOnly && !field.IsConst" in rules)
root = ET.fromstring(csproj)
analyzer_includes = [
node.attrib.get("Include", "")
for node in root.iter()
if node.tag.rsplit("}", 1)[-1] == "Analyzer"
]
print("analyzer include:", analyzer_includes)
print("analyzer path uses Debug output:", any("bin/Debug/netstandard2.0" in x for x in analyzer_includes))
print("ConsumerApp listed in solution:", "PureSharp.ConsumerApp" in solution)
docs = "\n".join(
p.read_text(errors="ignore")
for p in [Path("README.md"), Path(".github/workflows/upload_nuget.yml")]
if p.exists()
)
print("ConsumerApp build contract documented:", bool(re.search(
r"ConsumerApp|expected.?failure|build.*fail|fail.*build", docs, re.I
)))
PYRepository: mao2009/PureSharp Length of output: 592 🏁 Script executed: #!/bin/bash
set -eu
printf '%s\n' '--- exact documentation matches ---'
rg -n -i -C 2 'ConsumerApp|expected.?failure|build.*fail|fail.*build' README.md .github/workflows/upload_nuget.yml || true
printf '%s\n' '--- all build/failure wording in repository documentation ---'
rg -n -i -C 1 'build|fail|error|example|consumer' README.md README_*.md .github examples 2>/dev/null | head -240Repository: mao2009/PureSharp Length of output: 12500 Define the ConsumerApp build contract.
🤖 Prompt for AI Agents |
||
|
|
||
| # Local Variable Purity Diagnostics (LVP) | ||
| # LVP0001: Reassignment to immutable local variable | ||
| dotnet_diagnostic.LVP0001.severity = error | ||
|
|
||
| # LVP0002: Immutable local variable missing initializer | ||
| dotnet_diagnostic.LVP0002.severity = error | ||
|
|
||
| # LVP0003: Naming suggestion for effectively immutable variables | ||
| dotnet_diagnostic.LVP0003.severity = warning | ||
|
|
||
| # FluentIf Diagnostics (FIF) | ||
| # FIF0001: FluentIf chain not terminated with .Else() | ||
| dotnet_diagnostic.FIF0001.severity = error | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| using PureSharp.Core; | ||
| using System; | ||
|
|
||
| class Program | ||
| { | ||
| private static int _globalCache; | ||
|
|
||
| // Example 1: RT0001 - Static field access | ||
| // This will trigger RT0001 when [PureMethod] is applied | ||
| [PureMethod] | ||
| public static int AddWithGlobalField(int a, int b) | ||
| { | ||
| _globalCache = a + b; // RT0001: Accessing static mutable field | ||
| return _globalCache; | ||
| } | ||
|
|
||
| // Example 2: LVP0001 / LVP0002 - Immutable local variables | ||
| public static void TestImmutableVariables() | ||
| { | ||
| int _result = 10; | ||
| // Uncommenting below would trigger LVP0001 (reassignment to immutable variable) | ||
| // _result = 20; | ||
|
|
||
| // Example of variable that could trigger LVP0003 (naming suggestion) | ||
| // if not reassigned: | ||
| int count = 0; | ||
| } | ||
|
|
||
| // Example 3: FIF0001 - FluentIf termination | ||
| public static void TestFluentIf() | ||
| { | ||
| int status = Fluent.If(true, () => 1) | ||
| .Else(() => 0); | ||
|
|
||
| // Without .Else(), would trigger FIF0001 | ||
| // int incomplete = Fluent.If(true, () => 1); | ||
| } | ||
|
|
||
| static void Main() | ||
| { | ||
| Console.WriteLine("PureSharp Consumer App - Diagnostic Severity Configuration Test"); | ||
| Console.WriteLine("See .editorconfig for severity settings"); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,26 @@ | ||||||||||||||
| <Project Sdk="Microsoft.NET.Sdk"> | ||||||||||||||
|
|
||||||||||||||
| <PropertyGroup> | ||||||||||||||
| <OutputType>Exe</OutputType> | ||||||||||||||
| <TargetFramework>net10.0</TargetFramework> | ||||||||||||||
| <ImplicitUsings>enable</ImplicitUsings> | ||||||||||||||
| <Nullable>enable</Nullable> | ||||||||||||||
| </PropertyGroup> | ||||||||||||||
|
|
||||||||||||||
| <ItemGroup> | ||||||||||||||
| <ProjectReference Include="../../src/PureSharp.Core/PureSharp.Core.csproj" /> | ||||||||||||||
| </ItemGroup> | ||||||||||||||
|
|
||||||||||||||
| <!-- Include Analyzer from ProjectReference --> | ||||||||||||||
| <ItemGroup> | ||||||||||||||
| <CompilerVisibleProperty Include="TargetFramework" /> | ||||||||||||||
| </ItemGroup> | ||||||||||||||
|
|
||||||||||||||
| <!-- Enable Analyzer from local output --> | ||||||||||||||
| <Target Name="AddAnalyzers" AfterTargets="ResolveLockFileReferences"> | ||||||||||||||
| <ItemGroup> | ||||||||||||||
| <Analyzer Include="../../src/PureSharp.Core/bin/Debug/netstandard2.0/PureSharp.Core.dll" Visible="false" /> | ||||||||||||||
|
Comment on lines
+20
to
+22
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win Use the active build configuration for the analyzer path. Line 22 hard-codes Proposed fix- <Analyzer Include="../../src/PureSharp.Core/bin/Debug/netstandard2.0/PureSharp.Core.dll" Visible="false" />
+ <Analyzer Include="../../src/PureSharp.Core/bin/$(Configuration)/netstandard2.0/PureSharp.Core.dll" Visible="false" />📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||
| </ItemGroup> | ||||||||||||||
| </Target> | ||||||||||||||
|
|
||||||||||||||
| </Project> | ||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -197,4 +197,15 @@ public class Printer | |
| " + PureAttributeSource; | ||
| await VerifyCS.VerifyAnalyzerAsync(testCode); | ||
| } | ||
|
|
||
| // ========================================================= | ||
| // 注記: Roslyn 標準 .editorconfig による severity 制御テスト | ||
| // | ||
| // Roslyn標準のDiagnosticOptions機構はAnalyzer側では自動的に機能します。 | ||
| // .editorconfig での severity 設定は、Roslyn が解析時に自動的に適用するため、 | ||
| // Analyzer 実装の側で特別な対応は不要です。 | ||
| // | ||
| // consumer project での実際の .editorconfig 設定を通じた統合テストを推奨します。 | ||
| // (テストプロジェクトのスコープ外で検証) | ||
| // ========================================================= | ||
|
Comment on lines
+200
to
+210
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -e
printf '%s\n' '--- candidate files ---'
git ls-files | rg '(^|/)(ReferentialTransparencyAnalyzerTests\.cs|.*(Integration|EditorConfig|Analyzer).*Tests?\.cs|.*\.editorconfig$|.*\.yml$|.*\.yaml$|.*\.props$|.*\.targets$)$' | head -200
printf '%s\n' '--- test references and severity terms ---'
rg -n -i --glob '!**/bin/**' --glob '!**/obj/**' \
'ReferentialTransparency|DiagnosticSeverity|\.editorconfig|EditorConfig|severity|warning|error|none' . | head -300
printf '%s\n' '--- target test file outline and relevant sections ---'
if [ -f src/PureSharp.Analyzers.Tests/ReferentialTransparencyAnalyzerTests.cs ]; then
wc -l src/PureSharp.Analyzers.Tests/ReferentialTransparencyAnalyzerTests.cs
sed -n '1,280p' src/PureSharp.Analyzers.Tests/ReferentialTransparencyAnalyzerTests.cs
fiRepository: mao2009/PureSharp Length of output: 19643 🏁 Script executed: #!/bin/bash
set -e
printf '%s\n' '--- consumer files ---'
git ls-files examples/PureSharp.ConsumerApp
printf '%s\n' '--- consumer project ---'
for f in $(git ls-files examples/PureSharp.ConsumerApp | rg '\.(csproj|editorconfig|cs)$'); do
echo "--- $f"
wc -l "$f"
cat -n "$f"
done
printf '%s\n' '--- solution/project files ---'
git ls-files | rg '\.(sln|slnx|csproj|props|targets)$' | xargs -r -n1 sh -c 'echo "--- $0"; sed -n "1,220p" "$0"'
printf '%s\n' '--- workflows ---'
for f in $(git ls-files .github/workflows); do
echo "--- $f"
cat -n "$f"
done
printf '%s\n' '--- changed files ---'
git diff --stat
git status --shortRepository: mao2009/PureSharp Length of output: 11381 🏁 Script executed: #!/bin/bash
set -e
python3 - <<'PY'
from pathlib import Path
import re
editorconfig = Path("examples/PureSharp.ConsumerApp/.editorconfig").read_text(encoding="utf-8-sig")
program = Path("examples/PureSharp.ConsumerApp/Program.cs").read_text(encoding="utf-8-sig")
solution = Path("PureSharp.slnx").read_text(encoding="utf-8-sig")
workflow = "\n".join(
p.read_text(encoding="utf-8-sig")
for p in Path(".github/workflows").glob("*")
if p.suffix in {".yml", ".yaml"}
)
settings = dict(re.findall(
r"(?m)^\s*dotnet_diagnostic\.([A-Z]+\d+)\.severity\s*=\s*(\w+)\s*$",
editorconfig,
))
print("configured_severities:", settings)
required_levels = {"error", "warning", "none"}
print("contains_required_levels:", {level: level in settings.values() for level in required_levels})
print("configured_id_count:", len(settings))
print("solution_includes_consumer:", "examples/PureSharp.ConsumerApp" in solution)
print("workflow_mentions_consumer:", "PureSharp.ConsumerApp" in workflow)
active_examples = {}
for diagnostic_id, marker in {
"RT0001": "_globalCache = a + b",
"RT0002": "GetExternalValue()",
"RT0003": "Console.WriteLine",
"LVP0001": "_result = 20",
"LVP0002": "int _result;",
"LVP0003": "int count = 0",
"FIF0001": "Fluent.If(true, () => 1);",
}.items():
active_examples[diagnostic_id] = bool(re.search(
rf"(?m)^(?!\s*//).*{re.escape(marker)}", program
))
print("active_trigger_examples:", active_examples)
print("workflow_build_or_test_commands:",
re.findall(r"(?m)^\s*run:\s*(dotnet (?:build|test)[^\n]*)", workflow))
PYRepository: mao2009/PureSharp Length of output: 785 Add executable The consumer app is not included in 🤖 Prompt for AI Agents |
||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
Repository: mao2009/PureSharp
Length of output: 13453
🏁 Script executed:
Repository: mao2009/PureSharp
Length of output: 18552
🌐 Web query:
Microsoft Roslyn analyzer diagnostics TreatWarningsAsErrors WarningsAsErrors official documentation💡 Result:
To manage how Microsoft Roslyn analyzer diagnostics are treated as errors in a.NET project, you can use several MSBuild properties in your project file (.csproj) or configure individual rule severities via EditorConfig files [1][2][3]. MSBuild Properties The following MSBuild properties control build-time behavior for warnings: 1. TreatWarningsAsErrors: When set to true in a PropertyGroup, all warnings (including compiler warnings and Roslyn analyzer diagnostics) are treated as errors, causing the build to fail [4][5]. true 2. WarningsAsErrors: Allows you to specify a comma-separated list of specific warning IDs (e.g., CA1822) to be treated as errors, even if TreatWarningsAsErrors is not globally enabled [4][6]. CA1822,IDE0001 3. CodeAnalysisTreatWarningsAsErrors: If you have enabled global warning-to-error behavior but want to exempt Roslyn analyzer diagnostics (CAxxxx), you can set this property to false [3][6]. false EditorConfig Configuration For more granular control over specific rules, you can use an.editorconfig file. This is the recommended approach for configuring individual analyzer diagnostic severities [1][7]. By setting the severity to error, the diagnostic will fail the build regardless of global MSBuild warning settings [1][2][8]. dotnet_diagnostic..severity = error Summary of Behavior - Global Settings: Use TreatWarningsAsErrors or WarningsAsErrors in the project file to impact all or specific warnings project-wide [4][6]. - Per-Rule Settings: Use.editorconfig to set individual rule severities to error, warning, suggestion, silent, or none [1][2][8]. - Precedence: When multiple settings conflict, rule-specific severity settings typically take precedence over global MSBuild warning switches [1][8]. If you encounter issues with analyzer warnings being treated as errors, ensure CodeAnalysisTreatWarningsAsErrors is configured as desired [3].
Citations:
🏁 Script executed:
Repository: mao2009/PureSharp
Length of output: 356
🏁 Script executed:
Repository: mao2009/PureSharp
Length of output: 508
🌐 Web query:
site:learn.microsoft.com CodeAnalysisTreatWarningsAsErrors TreatWarningsAsErrors analyzer warnings WarningsAsErrors💡 Result:
In.NET, analyzer warnings and project-level "treat warnings as errors" settings are closely related but managed through distinct mechanisms. 1. TreatWarningsAsErrors The MSBuild property true is a global compiler flag [1]. When enabled, it instructs the compiler to treat all warnings generated by the build as errors, which causes the build to fail [1]. 2. CodeAnalysisTreatWarningsAsErrors If you have enabled globally but want to exclude code analysis (CAxxxx) warnings from causing build failures, you can set false in your project file [2]. This allows code analysis warnings to appear in your build logs without breaking the build [2]. 3. Managing Severity Directly While the properties above control whether warnings halt the build, you can manage the behavior of individual rules or categories of rules more granularly using an EditorConfig or global AnalyzerConfig file [3][4]. By setting a rule's severity to error, you ensure it always causes a build failure, regardless of your global setting [4]: dotnet_diagnostic.<rule_id>.severity = error Precedence and Best Practices: * Compiler Options: Command-line options like -warnaserror always override severity settings specified in EditorConfig or global AnalyzerConfig files [3]. * Modern Approach: Microsoft recommends using EditorConfig files for modern.NET development, as they provide more precise, file-system-aware configuration compared to legacy rule-set files [3][4]. * Avoiding Conflicts: If you are migrating legacy code analysis or experiencing unexpected build errors, explicitly setting false is the standard way to decouple analyzer output from your main compiler warning policy [5][2].
Citations:
Qualify the
warningbuild behavior in both language documents.A
warningnormally does not fail the build, but build settings can treat analyzer warnings as errors.README.md#L145: qualify the English description.README_ja.md#L149: qualify the Japanese description.📍 Affects 2 files
README.md#L144-L145(this comment)README_ja.md#L148-L149🤖 Prompt for AI Agents