Skip to content
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

Don't add duplicate suffix in LibraryImport code fix. #85668

Merged
merged 4 commits into from
May 4, 2023
Merged
Show file tree
Hide file tree
Changes from 3 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
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ public sealed class ConvertToLibraryImportFixer : CodeFixProvider
public override FixAllProvider GetFixAllProvider() => CustomFixAllProvider.Instance;

private const string ConvertToLibraryImportKey = "ConvertToLibraryImport,";
private static string AppendSuffix(string entryPoint, char? entryPointSuffix)
=> entryPointSuffix.HasValue && entryPoint.LastOrDefault() == entryPointSuffix.Value
? entryPoint
: entryPoint + entryPointSuffix;
private static string AddSuffixKey(string baseKey, char suffix) => $"{baseKey}{suffix},";
private static string AddUnsafeKey(string baseKey) => baseKey + "AddUnsafe,";
private static string AddMayRequireAdditionalWorkKey(string baseKey) => baseKey + $"{ConvertToLibraryImportAnalyzer.MayRequireAdditionalWork},";
Expand Down Expand Up @@ -563,7 +567,7 @@ private static SyntaxNode GetLibraryImportAttribute(

// Update attribute arguments for LibraryImport
bool hasEntryPointAttributeArgument = false;
List<SyntaxNode> argumentsToAdd= new List<SyntaxNode>();
List<SyntaxNode> argumentsToAdd = new List<SyntaxNode>();
List<SyntaxNode> argumentsToRemove = new List<SyntaxNode>();
foreach (SyntaxNode argument in generator.GetAttributeArguments(libraryImportSyntax))
{
Expand Down Expand Up @@ -647,17 +651,20 @@ private static SyntaxNode GetLibraryImportAttribute(
argumentsToRemove.Add(attrArg);
argumentsToAdd.Add(attrArg.WithExpression(
SyntaxFactory.LiteralExpression(SyntaxKind.StringLiteralExpression,
SyntaxFactory.Literal(entryPoint + entryPointSuffix))));
SyntaxFactory.Literal(AppendSuffix(entryPoint, entryPointSuffix)))));
}
}
else
{
argumentsToRemove.Add(attrArg);
argumentsToAdd.Add(attrArg.WithExpression(
SyntaxFactory.BinaryExpression(SyntaxKind.AddExpression,
attrArg.Expression,
SyntaxFactory.LiteralExpression(SyntaxKind.StringLiteralExpression,
SyntaxFactory.Literal(entryPointSuffix.ToString())))));
if (dllImportData.EntryPointName?.LastOrDefault() != entryPointSuffix.Value)
jtschuster marked this conversation as resolved.
Show resolved Hide resolved
{
argumentsToRemove.Add(attrArg);
argumentsToAdd.Add(attrArg.WithExpression(
SyntaxFactory.BinaryExpression(SyntaxKind.AddExpression,
attrArg.Expression,
SyntaxFactory.LiteralExpression(SyntaxKind.StringLiteralExpression,
SyntaxFactory.Literal(entryPointSuffix.ToString())))));
}
}
}
}
Expand All @@ -671,7 +678,7 @@ private static SyntaxNode GetLibraryImportAttribute(
if (entryPointSuffix.HasValue && !hasEntryPointAttributeArgument)
{
argumentsToAdd.Add(generator.AttributeArgument("EntryPoint",
generator.LiteralExpression(methodName + entryPointSuffix.Value)));
generator.LiteralExpression(AppendSuffix(methodName, entryPointSuffix.Value))));
}

libraryImportSyntax = generator.RemoveNodes(libraryImportSyntax, argumentsToRemove);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -490,6 +490,222 @@ partial class Test
await VerifyCodeFixAsync(source, fixedSourceWithASuffix, $"{ConvertToLibraryImportKey}A,");
}

[InlineData(CharSet.Ansi, 'A')]
[InlineData(CharSet.Unicode, 'W')]
[Theory]
public async Task SuffixPresent_ExactSpelling_False_NoAutoCharSet_Provides_No_Suffix_And_Suffix_Fix(CharSet charSet, char suffix)
{
string source = $$"""
using System.Runtime.InteropServices;
partial class Test
{
[DllImport("DoesNotExist", EntryPoint = "Entry{{suffix}}", ExactSpelling = false, CharSet = CharSet.{{charSet}})]
public static extern void [|Method|]();
}
""";
string fixedSourceNoSuffix = $$"""
using System.Runtime.InteropServices;
partial class Test
{
[LibraryImport("DoesNotExist", EntryPoint = "Entry{{suffix}}")]
public static partial void {|CS8795:Method|}();
}
""";
await VerifyCodeFixAsync(source, fixedSourceNoSuffix, ConvertToLibraryImportKey);
}

[Fact]
public async Task SuffixWPresent_ExactSpelling_False_AutoCharSet_Provides_No_Suffix_And_Both_Suffix_Fixes()
{
string source = """

using System.Runtime.InteropServices;
partial class Test
{
[DllImport("DoesNotExist", EntryPoint = "EntryW", ExactSpelling = false, CharSet = CharSet.Auto)]
public static extern void [|Method|]();
}
""";
string fixedSourceNoSuffix = """

using System.Runtime.InteropServices;
partial class Test
{
[LibraryImport("DoesNotExist", EntryPoint = "EntryW")]
public static partial void {|CS8795:Method|}();
}
""";
await VerifyCodeFixAsync(source, fixedSourceNoSuffix, ConvertToLibraryImportKey);
string fixedSourceWithASuffix = """

using System.Runtime.InteropServices;
partial class Test
{
[LibraryImport("DoesNotExist", EntryPoint = "EntryWA")]
public static partial void {|CS8795:Method|}();
}
""";
await VerifyCodeFixAsync(source, fixedSourceWithASuffix, $"{ConvertToLibraryImportKey}A,");
}

[Fact]
public async Task SuffixAPresent_ExactSpelling_False_AutoCharSet_Provides_No_Suffix_And_Both_Suffix_Fixes()
{
string source = """

using System.Runtime.InteropServices;
partial class Test
{
[DllImport("DoesNotExist", EntryPoint = "EntryA", ExactSpelling = false, CharSet = CharSet.Auto)]
public static extern void [|Method|]();
}
""";
string fixedSourceNoSuffix = """

using System.Runtime.InteropServices;
partial class Test
{
[LibraryImport("DoesNotExist", EntryPoint = "EntryA")]
public static partial void {|CS8795:Method|}();
}
""";
await VerifyCodeFixAsync(source, fixedSourceNoSuffix, ConvertToLibraryImportKey);
string fixedSourceWithASuffix = """

using System.Runtime.InteropServices;
partial class Test
{
[LibraryImport("DoesNotExist", EntryPoint = "EntryAW")]
public static partial void {|CS8795:Method|}();
}
""";
await VerifyCodeFixAsync(source, fixedSourceWithASuffix, $"{ConvertToLibraryImportKey}W,");
}

[Fact]
public async Task SuffixPresent_ExactSpelling_False_ImplicitAnsiCharSet_Provides_No_Suffix_And_Suffix_Fix()
{
string source = """

using System.Runtime.InteropServices;
partial class Test
{
[DllImport("DoesNotExist", EntryPoint = "EntryA", ExactSpelling = false)]
public static extern void [|Method|]();
}
""";
string fixedSourceWithNoAdditionalSuffix = """

using System.Runtime.InteropServices;
partial class Test
{
[LibraryImport("DoesNotExist", EntryPoint = "EntryA")]
public static partial void {|CS8795:Method|}();
}
""";
await VerifyCodeFixAsync(source, fixedSourceWithNoAdditionalSuffix, $"{ConvertToLibraryImportKey}A,");
}

[Fact]
public async Task SuffixPresent_ExactSpelling_False_ConstantNonLiteralEntryPoint()
{
string source = """

using System.Runtime.InteropServices;
partial class Test
{
private const string EntryPoint = "EntryA";
[DllImport("DoesNotExist", EntryPoint = EntryPoint, CharSet = CharSet.Ansi, ExactSpelling = false)]
public static extern void [|Method|]();
}
""";
string fixedSourceWithASuffix = """

using System.Runtime.InteropServices;
partial class Test
{
private const string EntryPoint = "EntryA";
[LibraryImport("DoesNotExist", EntryPoint = EntryPoint)]
public static partial void {|CS8795:Method|}();
}
""";
await VerifyCodeFixAsync(source, fixedSourceWithASuffix, ConvertToLibraryImportKey);
}

[Fact]
public async Task SuffixPresent_Implicit_ExactSpelling_False_Offers_Suffix_Fix()
{
string source = """

using System.Runtime.InteropServices;
partial class Test
{
[DllImport("DoesNotExist", CharSet = CharSet.Ansi)]
public static extern void [|MethodA|]();
}
""";
string fixedSourceWithASuffix = """

using System.Runtime.InteropServices;
partial class Test
{
[LibraryImport("DoesNotExist")]
public static partial void {|CS8795:MethodA|}();
}
""";
await VerifyCodeFixAsync(source, fixedSourceWithASuffix, ConvertToLibraryImportKey);
}

[Fact]
public async Task SuffixPresent_ExactSpelling_False_NameOfEntryPoint()
{
string source = """

using System.Runtime.InteropServices;
partial class Test
{
private const string FooA = "BarA";
[DllImport("DoesNotExist", EntryPoint = nameof(FooA), CharSet = CharSet.Ansi, ExactSpelling = false)]
public static extern void [|Method|]();
}
""";
string fixedSourceWithASuffix = """

using System.Runtime.InteropServices;
partial class Test
{
private const string FooA = "BarA";
[LibraryImport("DoesNotExist", EntryPoint = nameof(FooA))]
public static partial void {|CS8795:Method|}();
}
""";
await VerifyCodeFixAsync(source, fixedSourceWithASuffix, ConvertToLibraryImportKey);
}

[Fact]
public async Task SuffixPresent_ExactSpelling_False_ImplicitEntryPointName()
{
string source = """

using System.Runtime.InteropServices;
partial class Test
{
[DllImport("DoesNotExist", CharSet = CharSet.Ansi, ExactSpelling = false)]
public static extern void [|MethodA|]();
}
""";
string fixedSourceWithASuffix = """

using System.Runtime.InteropServices;
partial class Test
{
[LibraryImport("DoesNotExist")]
public static partial void {|CS8795:MethodA|}();
}
""";
await VerifyCodeFixAsync(source, fixedSourceWithASuffix, ConvertToLibraryImportKey);
}

[Fact]
public async Task PreserveSigFalseSignatureModified()
{
Expand Down