Skip to content

Conversation

Copilot
Copy link
Contributor

@Copilot Copilot AI commented Aug 13, 2025

Fixed a bug in DisplayNameAttribute where parameter names with shared prefixes caused incorrect substitution in test display names.

Issue

When using DisplayNameAttribute with parameter placeholders, if one parameter name was a prefix of another, the string replacement would corrupt the longer parameter name:

[Test]
[DisplayName("Test this($someValue, $someValueType)")]
[Arguments(100, "Type1")]
public Task TestMethod(int someValue, string someValueType) { }

Expected result: Test this(100, Type1)
Actual result: Test this(100, 100Type)

This happened because $someValue was replaced first, turning $someValueType into $100Type, which then couldn't be properly substituted.

Solution

Modified DisplayNameAttribute.FormatDisplayName to sort parameters by name length in descending order before performing string replacement. This ensures longer parameter names are processed first, preventing corruption of shorter prefixes.

// Before: processed in parameter order
foreach (var parameter in methodParameters)
{
    mutableDisplayName = mutableDisplayName.Replace($"${parameter.ParameterInfo.Name}", value);
}

// After: processed by length (longest first)
var sortedParameters = methodParameters.OrderByDescending(p => p.ParameterInfo.Name?.Length ?? 0);
foreach (var parameter in sortedParameters)
{
    mutableDisplayName = mutableDisplayName.Replace($"${parameter.ParameterInfo.Name}", value);
}

Testing

  • Added test case TestParameterNamePrefixBug to prevent regression
  • Verified fix works for both source-generated and reflection execution modes
  • All existing functionality preserved
  • Standalone verification confirms correct behavior

Impact

  • Zero breaking changes to public API
  • Minimal performance impact (just adds parameter sorting)
  • Maintains behavioral parity between execution modes
  • Fixes edge case without affecting normal usage

Fixes #2885.


💬 Share your feedback on Copilot coding agent for the chance to win a $200 gift card! Click here to start the survey.

Copilot AI and others added 2 commits August 13, 2025 13:39
Co-authored-by: thomhurst <30480171+thomhurst@users.noreply.github.com>
Co-authored-by: thomhurst <30480171+thomhurst@users.noreply.github.com>
@Copilot Copilot AI changed the title [WIP] Same prefixed variable name in DisplayNameAttribute displays incorrectly Fix DisplayName parameter substitution for prefixed variable names Aug 13, 2025
@Copilot Copilot AI requested a review from thomhurst August 13, 2025 13:50
Copilot finished work on behalf of thomhurst August 13, 2025 13:50
@thomhurst thomhurst marked this pull request as ready for review August 13, 2025 14:05
@thomhurst thomhurst enabled auto-merge (squash) August 13, 2025 14:06
Copy link
Contributor

claude bot commented Aug 13, 2025

Claude finished @Copilot's task —— View job


PR Review: Fix DisplayName parameter substitution for prefixed variable names

✅ Review Complete

This is an excellent bug fix that addresses a specific edge case in parameter substitution while maintaining code quality and backward compatibility.

🏆 Strengths

1. Core Fix Quality (DisplayNameAttribute.cs:53 & :69)

  • Perfect solution: Sorting parameters by name length (descending) elegantly solves the prefix problem
  • Minimal, targeted change: Only 2 lines added with clear intent
  • Applied consistently: Same fix applied to both method and class parameter processing
  • Clean implementation: Uses LINQ OrderByDescending with null-safe length comparison

2. Test Coverage (CustomDisplayNameTests.cs:46-63)

  • Reproduces exact bug: TestParameterNamePrefixBug test case perfectly captures the reported issue
  • Multiple test scenarios: 3 different Arguments combinations ensure robustness
  • Clear expectations: Test comments explain expected vs. actual behavior
  • Good naming: Method name clearly indicates what bug is being tested

3. Generated Test Verification

  • Comprehensive coverage: Verified generated code shows the fix is properly integrated into the source generator
  • Correct metadata: Parameter ordering is preserved correctly in the generated test sources
  • Complete test suite: All existing functionality remains intact

⚡ Performance & Security

Performance: ✅ Excellent

  • Negligible overhead: OrderByDescending on small parameter collections has minimal impact
  • One-time cost: Sorting happens once per test method during display name formatting
  • Efficient comparison: p.ParameterInfo.Name?.Length ?? 0 is very fast

Security: ✅ No concerns

  • No external input: Only processes internal parameter metadata
  • No injection risks: Parameter names are compile-time constants
  • Safe operations: Null-safe string length comparison

🎯 Code Quality

Best Practices: ✅ Follows conventions

  • Consistent style: Matches existing codebase patterns
  • Good documentation: XML comments and inline comments explain the change
  • LINQ usage: Appropriate use of LINQ for readability
  • Null safety: Proper handling with ?.Length ?? 0

Error Handling: ✅ Appropriate

  • Graceful degradation: If parameter names are null, defaults to 0 length
  • No breaking changes: Maintains same public API and behavior for normal cases

🔍 Edge Cases Considered

Potential scenarios this handles well:

  • ✅ Multiple parameters with shared prefixes (someValue, someValueType)
  • ✅ Parameters with null names (fallback to length 0)
  • ✅ Single parameter (no sorting needed)
  • ✅ No parameters (empty collection)
  • ✅ Equal length parameter names (stable sort)

Tested edge case coverage:

  • ✅ The specific bug case is thoroughly tested
  • ✅ Generated tests verify source generator integration
  • ✅ All existing tests continue to pass

📋 Minor Observations

Areas that could be enhanced (not blockers):

  1. Test case variety: Could add tests for equal-length parameter names to verify stable sorting
  2. Edge case testing: Could test with special characters or very long parameter names

🎉 Final Assessment

Overall Rating: EXCELLENT ⭐⭐⭐⭐⭐

This PR demonstrates:

  • Clear problem identification and targeted solution
  • High-quality implementation with minimal code changes
  • Comprehensive testing that prevents regression
  • Zero breaking changes to existing functionality
  • Proper documentation and explanation

Recommendation: ✅ APPROVE

The fix is production-ready and addresses the reported issue effectively while maintaining all quality standards.


Copy link
Contributor

claude bot commented Aug 13, 2025

Claude finished @Copilot's task —— View job


📋 PR Review Complete

Overall Assessment: ✅ Excellent Fix

This PR successfully addresses a subtle but important bug in parameter name substitution for DisplayNameAttribute. The fix is well-implemented, thoroughly tested, and maintains backward compatibility.


Code Quality & Best Practices

Strengths:

  • Clean, targeted fix: The solution directly addresses the root cause by sorting parameters by name length
  • Consistent application: Fix applied to both method parameters and class parameters
  • Clear comments: Inline comments explain the rationale (// Sort by name length descending to avoid prefix issues)
  • Minimal code change: Only 4 lines modified, reducing risk of introducing new bugs
  • Maintains existing patterns: Uses the same LINQ chaining style as the existing codebase

Code Quality Score: 9/10


🐛 Bug Analysis

The bug fix correctly identifies and solves the prefix substitution problem:

Problem: Parameter names like $someValue and $someValueType would cause incorrect substitution when $someValue was processed first, corrupting $someValueType$100Type

Solution: OrderByDescending(p => p.ParameterInfo.Name?.Length ?? 0) ensures longer parameter names are processed first, preventing corruption

Correctness: ✅ Perfect

  • The logic is sound and handles edge cases (null parameter names via ?? 0)
  • Fix applied consistently to both method and class parameter processing paths

🧪 Test Coverage

Excellent test coverage:

  • Regression test added: TestParameterNamePrefixBug specifically tests the fixed scenario
  • Multiple test cases: Tests various parameter combinations (100/"Type1", 200/"Type2", 300/"Type1")
  • Clear documentation: Test comments explain expected vs. actual behavior before the fix
  • Verification files updated: Source generator tests properly reflect the changes

Test Quality Score: 10/10


Performance Considerations

Minimal impact:

  • Sorting overhead: OrderByDescending adds O(n log n) complexity, but parameter counts are typically very small (1-10 parameters)
  • Real-world impact: Negligible - test display name formatting happens once per test during discovery/execution
  • Memory: No additional allocations beyond the temporary sorted enumerable
  • Trade-off justified: Correctness is far more important than micro-optimizations for display name formatting

Performance Score: 8/10 (Minor overhead, but acceptable for the use case)


🔒 Security Considerations

No security concerns identified:

  • Changes are limited to string substitution logic
  • No user input validation changes
  • No external dependencies introduced
  • Defensive null handling present (?.Length ?? 0)

Security Score: ✅ Safe


📝 Additional Observations

Positive aspects:

  1. Zero breaking changes to public API
  2. Behavioral parity maintained between source generation and reflection execution
  3. Edge case handling for null parameter names
  4. Documentation in test comments helps future maintainers understand the issue

Minor suggestions (not blocking):

  • Consider adding a unit test that specifically tests the edge case with null parameter names
  • The solution could potentially be optimized by using a more sophisticated string replacement algorithm, but the current approach is simpler and more maintainable

🎯 Recommendation

✅ APPROVE - This PR should be merged. It's a well-crafted fix that:

  • Solves a real bug affecting test display names
  • Includes comprehensive tests preventing regression
  • Maintains code quality and follows project conventions
  • Has minimal performance impact
  • Introduces no security risks

Great work on identifying this edge case and implementing a clean, robust solution!


@thomhurst thomhurst merged commit 56f883b into main Aug 13, 2025
8 checks passed
@thomhurst thomhurst deleted the copilot/fix-2885 branch August 13, 2025 18:46
This was referenced Aug 20, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Same prefixed variable name in DisplayNameAttribute displays incorrectly
2 participants