feat: implement separate diagnostics for variables named '_' and unnecessary typed discards
This PR addresses feedback from #888 by implementing separate diagnostic IDs and improving the analyzer's precision for different scenarios involving underscores and discards.
Changes Made
Separate Diagnostic IDs
- PH2147: "Avoid variables named ''" - flags variables explicitly named "" that can be confused with discards
-
PH2152: "Avoid unnecessary typed discard" - flags typed discards like
out string _whenout _would suffice
Enhanced Overload Resolution Detection
Implemented simplified but effective overload detection that accurately determines when typed discards are necessary:
// This will be flagged - typed discard unnecessary
GetValue(out string _); // Should use: out _
// This will NOT be flagged - typed discard necessary for overload resolution
Parse("123", out int _); // Disambiguates from Parse(string, out string)
Parse("test", out string _); // Disambiguates from Parse(string, out int)
Named Arguments Support
Added proper handling for named arguments in overload resolution:
// Both positional and named arguments work correctly
GetValue(value: out string _); // Flagged as unnecessary
Parse(input: "123", result: out int _); // Not flagged if needed for overload resolution
Documentation and Performance Improvements
- Split documentation: Created separate documentation files for PH2147 and PH2152
- Performance optimization: Moved SemanticModel access lower in method for better performance
- Simplified LINQ: Removed unnecessary operations as suggested in code review
- Fixed diagnostic ID conflict: Resolved PH2153 mapping conflict between analyzers
Code Quality Improvements
- Resolved duplicate code detection issues (PH2071) in test methods
- Uses
DiagnosticAnalyzerBasefor proper dual diagnostic support - Maintains all original functionality for variables named "_"
- Improved test coverage with all 15 tests passing
Impact
- More precise diagnostics: Separate IDs allow different handling of variable naming vs discard usage
- Better overload detection: Uses semantic analysis to detect when typed discards are truly necessary
- Named argument support: Handles modern C# syntax correctly
- Cleaner code: Follows analyzer best practices and formatting standards
- Better performance: Optimized semantic model usage
This maintains the original intent of promoting anonymous discards (out _) while ensuring typed discards are only flagged when truly unnecessary for overload resolution.
💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.