Skip to content

Commit

Permalink
MA0151 handles backslashs in expressions
Browse files Browse the repository at this point in the history
  • Loading branch information
meziantou committed Oct 30, 2024
1 parent 7c884cf commit 32732ae
Show file tree
Hide file tree
Showing 2 changed files with 122 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ namespace Meziantou.Analyzer.Rules;
[DiagnosticAnalyzer(LanguageNames.CSharp)]
public sealed class DebuggerDisplayAttributeShouldContainValidExpressionsAnalyzer : DiagnosticAnalyzer
{
private static readonly char[] MemberSeparators = [',', '(', '.', '['];
private static readonly char[] MemberSeparators = [',', '(', '.', '[', ' '];

private static readonly DiagnosticDescriptor Rule = new(
RuleIdentifiers.DebuggerDisplayAttributeShouldContainValidExpressions,
Expand Down Expand Up @@ -80,36 +80,60 @@ static bool MemberExists(INamedTypeSymbol? symbol, string name)
{
List<string>? result = null;

static int IndexOf(ReadOnlySpan<char> value, char c)
{
var skipped = 0;
while (!value.IsEmpty)
{
var index = value.IndexOfAny(c, '\\');
if (index < 0)
return -1;

if (value[index] == c)
return index + skipped;

if (index + 1 < value.Length)
{
skipped += index + 2;
value = value[(index + 2)..];
}
else
{
return -1;
}
}

return -1;
}

while (!value.IsEmpty)
{
var startIndex = value.IndexOf('{');
var startIndex = IndexOf(value, '{');
if (startIndex < 0)
break;

value = value[(startIndex + 1)..];
var endIndex = value.IndexOf('}');
var endIndex = IndexOf(value, '}');
if (endIndex < 0)
break;

var member = value[..endIndex];


static string GetMemberName(ReadOnlySpan<char> member)
{
var index = member.IndexOfAny(MemberSeparators);
if (index < 0)
return member.ToString();

return member[..index].ToString();
}

result ??= [];
result.Add(GetMemberName(member));

value = value[(endIndex + 1)..];
}

return result;

static string GetMemberName(ReadOnlySpan<char> member)
{
var index = member.IndexOfAny(MemberSeparators);
if (index < 0)
return member.ToString();

return member[..index].ToString();
}
}

static void ValidateValue(SymbolAnalysisContext context, INamedTypeSymbol symbol, AttributeData attribute, string value)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -206,4 +206,88 @@ await CreateProjectBuilder()
.WithSourceCode(SourceCode)
.ValidateAsync();
}

[Fact]
public async Task SkipEscapedBraces1()
{
const string SourceCode = """
using System.Diagnostics;
[DebuggerDisplay(@"Person \{ Name = {Name} \}")]
public record Person(string Name);
""";
await CreateProjectBuilder()
.WithSourceCode(SourceCode)
.ValidateAsync();
}

[Fact]
public async Task SkipEscapedBraces2()
{
const string SourceCode = """
using System.Diagnostics;
[[|DebuggerDisplay(@"Person \\{NameInvalid}")|]]
public record Person(string Name);
""";
await CreateProjectBuilder()
.WithSourceCode(SourceCode)
.ValidateAsync();
}

[Fact]
public async Task SkipEscapedBraces3()
{
const string SourceCode = """
using System.Diagnostics;
[DebuggerDisplay(@"Person \\\{NameInvalid}")]
public record Person(string Name);
""";
await CreateProjectBuilder()
.WithSourceCode(SourceCode)
.ValidateAsync();
}

[Fact]
public async Task EscapeSingleChar()
{
const string SourceCode = """
using System.Diagnostics;
[DebuggerDisplay(@"\")]
public record Person(int Value);
""";
await CreateProjectBuilder()
.WithSourceCode(SourceCode)
.ValidateAsync();
}

[Fact]
public async Task Escape_IncompleteExpression()
{
const string SourceCode = """
using System.Diagnostics;
[DebuggerDisplay(@"{\")]
public record Person(int Value);
""";
await CreateProjectBuilder()
.WithSourceCode(SourceCode)
.ValidateAsync();
}

[Fact]
public async Task ExpressionLessThan()
{
const string SourceCode = """
using System.Diagnostics;
[DebuggerDisplay(@"{Value < 10}")]
public record Person(int Value);
""";
await CreateProjectBuilder()
.WithSourceCode(SourceCode)
.ValidateAsync();
}
}

0 comments on commit 32732ae

Please sign in to comment.