Skip to content

Commit

Permalink
Fix CA2101 triggering when BestFitMapping=false
Browse files Browse the repository at this point in the history
The documentation for CA2101 indicates that the problem is not the use
of single-byte character marshalling, but that when doing so .NET will
by default try and substite characters that cannot be directly
marshalled.

Unfortunately, when a developer actually tries to use
BestFitMapping=false, such as when using ANSI-only APIs (which are
particularly common on non-Windows operating systems), CA2101 triggers
anyway and the developer has no choice but to suppress the Diagnostic or
disable the rule, adding noise to their code and reducing trust in the
analyzer.

CA2101 appears to work correctly in
Microsoft.CodeAnalysis.FxCopAnalyzers and in NetAnalyzers through
version 5.0.3. BestFitMapping=false only got disabled in version 6.0.0,
apparently due to a small mistake when refactoring to take the new
InvariantGlobalization setting into account.

This commit adds tests for BestFitMapping (which for some reason was
completely untested previously) and fixes the refactoring error.
  • Loading branch information
yaakov-h committed Sep 30, 2022
1 parent 06a9733 commit 049eddb
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ public void AnalyzeSymbol(SymbolAnalysisContext context)
}

// CA2101 - Specify marshalling for PInvoke string arguments
if (dllImportData.BestFitMapping != false ||
if (dllImportData.BestFitMapping != false &&
context.Options.GetMSBuildPropertyValue(MSBuildPropertyOptionNames.InvariantGlobalization, context.Compilation) is not "true")
{
bool appliedCA2101ToMethod = false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -640,6 +640,43 @@ End Class
BasicResult2101(22, 30));
}

[Fact]
public async Task CA2101WithoutBestFitMappingCSharpTestAsync()
{
await VerifyCS.VerifyAnalyzerAsync(@"
using System.Runtime.InteropServices;
using System.Text;
class C
{
[DllImport(""user32.dll"", BestFitMapping = false)]
private static extern void Method1(string s);
[DllImport(""user32.dll"", CharSet = CharSet.Ansi, BestFitMapping = false)]
private static extern void Method2(string s);
[DllImport(""user32.dll"", BestFitMapping = false)]
private static extern void Method3(StringBuilder s);
[DllImport(""user32.dll"", CharSet = CharSet.Ansi, BestFitMapping = false)]
private static extern void Method4(StringBuilder s);
[DllImport(""user32.dll"", BestFitMapping = false)]
private static extern string Method5();
[DllImport(""user32.dll"", BestFitMapping = false)]
private static extern StringBuilder Method6();
[DllImport(""user32.dll"", CharSet = CharSet.Ansi, BestFitMapping = false)]
private static extern string Method7();
[DllImport(""user32.dll"", CharSet = CharSet.Ansi, BestFitMapping = false)]
private static extern StringBuilder Method8();
}
");
}

#endregion
}
}

0 comments on commit 049eddb

Please sign in to comment.