Skip to content

Commit bf90c93

Browse files
Merge pull request #870 from icsharpcode/vs2019
Vs2019
2 parents 05bea69 + 7321522 commit bf90c93

File tree

89 files changed

+347
-412
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

89 files changed

+347
-412
lines changed

CodeConverter.sln

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,13 @@
11

22
Microsoft Visual Studio Solution File, Format Version 12.00
3-
# Visual Studio Version 16
4-
VisualStudioVersion = 16.0.29721.120
3+
# Visual Studio Version 17
4+
VisualStudioVersion = 17.1.31911.260
55
MinimumVisualStudioVersion = 10.0.40219.1
66
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CodeConverter", "CodeConverter\CodeConverter.csproj", "{7EA075C6-6406-445C-AB77-6C47AFF88D58}"
77
EndProject
88
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tests", "Tests\Tests.csproj", "{21DBA1CE-AF55-4159-B04B-B8C621BE8921}"
99
EndProject
1010
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Vsix", "Vsix\Vsix.csproj", "{99498EF8-C9E0-433B-8D7B-EA8E9E66F0C7}"
11-
ProjectSection(ProjectDependencies) = postProject
12-
{CF18CBCF-67FF-46CA-8D1D-3221B7706D7D} = {CF18CBCF-67FF-46CA-8D1D-3221B7706D7D}
13-
EndProjectSection
1411
EndProject
1512
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{40A4828C-D6D2-43C5-A452-36CB06649680}"
1613
ProjectSection(SolutionItems) = preProject

CodeConverter/CSharp/CommentConvertingVisitorWrapper.cs

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,26 @@
1-
using Microsoft.CodeAnalysis.CSharp;
2-
using Microsoft.CodeAnalysis.Text;
3-
using Microsoft.CodeAnalysis.VisualBasic;
1+
using Microsoft.CodeAnalysis.Text;
42

53
namespace ICSharpCode.CodeConverter.CSharp;
64

75
[System.Diagnostics.DebuggerStepThrough]
86
internal class CommentConvertingVisitorWrapper
97
{
10-
private readonly VBasic.VisualBasicSyntaxVisitor<Task<CS.CSharpSyntaxNode>> _wrappedVisitor;
8+
private readonly VBasic.VisualBasicSyntaxVisitor<Task<CSharpSyntaxNode>> _wrappedVisitor;
119
private readonly SyntaxTree _syntaxTree;
1210
private static readonly CSSyntax.LiteralExpressionSyntax _dummyLiteral = ValidSyntaxFactory.DefaultExpression;
1311
private static readonly CSSyntax.StatementSyntax _dummyStatement = CS.SyntaxFactory.EmptyStatement();
1412
private static readonly CSSyntax.CompilationUnitSyntax _dummyCompilationUnit = CS.SyntaxFactory.CompilationUnit();
1513

16-
public CommentConvertingVisitorWrapper(VisualBasicSyntaxVisitor<Task<CSharpSyntaxNode>> wrappedVisitor, SyntaxTree syntaxTree)
14+
public CommentConvertingVisitorWrapper(VBasic.VisualBasicSyntaxVisitor<Task<CSharpSyntaxNode>> wrappedVisitor, SyntaxTree syntaxTree)
1715
{
1816
_wrappedVisitor = wrappedVisitor;
1917
_syntaxTree = syntaxTree;
2018
}
2119

22-
public async Task<T> AcceptAsync<T>(VisualBasicSyntaxNode vbNode, SourceTriviaMapKind sourceTriviaMap) where T : CS.CSharpSyntaxNode =>
20+
public async Task<T> AcceptAsync<T>(VisualBasicSyntaxNode vbNode, SourceTriviaMapKind sourceTriviaMap) where T : CSharpSyntaxNode =>
2321
await ConvertHandledAsync<T>(vbNode, sourceTriviaMap);
2422

25-
public async Task<SeparatedSyntaxList<TOut>> AcceptAsync<TIn, TOut>(SeparatedSyntaxList<TIn> vbNodes, SourceTriviaMapKind sourceTriviaMap) where TIn : VBasic.VisualBasicSyntaxNode where TOut : CS.CSharpSyntaxNode
23+
public async Task<SeparatedSyntaxList<TOut>> AcceptAsync<TIn, TOut>(SeparatedSyntaxList<TIn> vbNodes, SourceTriviaMapKind sourceTriviaMap) where TIn : VisualBasicSyntaxNode where TOut : CSharpSyntaxNode
2624
{
2725
var convertedNodes = await vbNodes.SelectAsync(n => ConvertHandledAsync<TOut>(n, sourceTriviaMap));
2826
var convertedSeparators = vbNodes.GetSeparators().Select(s =>
@@ -33,7 +31,7 @@ public async Task<SeparatedSyntaxList<TOut>> AcceptAsync<TIn, TOut>(SeparatedSyn
3331
return CS.SyntaxFactory.SeparatedList(convertedNodes, convertedSeparators);
3432
}
3533

36-
private async Task<T> ConvertHandledAsync<T>(VisualBasicSyntaxNode vbNode, SourceTriviaMapKind sourceTriviaMap) where T : CS.CSharpSyntaxNode
34+
private async Task<T> ConvertHandledAsync<T>(VisualBasicSyntaxNode vbNode, SourceTriviaMapKind sourceTriviaMap) where T : CSharpSyntaxNode
3735
{
3836
try {
3937
var converted = (T)await _wrappedVisitor.Visit(vbNode);
@@ -56,7 +54,7 @@ private async Task<T> ConvertHandledAsync<T>(VisualBasicSyntaxNode vbNode, Sourc
5654
/// <remarks>
5755
/// If lots of special cases, move to wrapping the wrappedVisitor in another visitor, but I'd rather use a simple switch here initially.
5856
/// </remarks>
59-
private static T WithSourceMapping<T>(SyntaxNode vbNode, T converted) where T : CS.CSharpSyntaxNode
57+
private static T WithSourceMapping<T>(SyntaxNode vbNode, T converted) where T : CSharpSyntaxNode
6058
{
6159
converted = vbNode.CopyAnnotationsTo(converted);
6260
switch (vbNode) {

CodeConverter/CSharp/CommonConversions.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ public CommonConversions(Document document, SemanticModel semanticModel,
7575
foreach (var name in declarator.Names) {
7676

7777
var declaredSymbol = SemanticModel.GetDeclaredSymbol(name);
78-
if (symbolsToSkip?.Contains(declaredSymbol) == true) continue;
78+
if (symbolsToSkip?.Contains(declaredSymbol, SymbolEqualityComparer.IncludeNullability) == true) continue;
7979
var declaredSymbolType = declaredSymbol.GetSymbolType();
8080
var equalsValueClauseSyntax = await ConvertEqualsValueClauseSyntaxAsync(declarator, name, vbInitValue, declaredSymbolType, declaredSymbol, initializerOrMethodDecl);
8181
var v = SyntaxFactory.VariableDeclarator(ConvertIdentifier(name.Identifier), null, equalsValueClauseSyntax);
@@ -107,7 +107,7 @@ public bool ShouldPreferExplicitType(VBSyntax.ExpressionSyntax exp,
107107
exp = op.Syntax as VBSyntax.ExpressionSyntax;
108108
var vbInitConstantValue = SemanticModel.GetConstantValue(exp);
109109
isNothingLiteral = vbInitConstantValue.HasValue && vbInitConstantValue.Value == null || exp is VBSyntax.LiteralExpressionSyntax les && les.IsKind(SyntaxKind.NothingLiteralExpression);
110-
bool shouldPreferExplicitType = expConvertedType != null && (expConvertedType.HasCsKeyword() || !expConvertedType.Equals(op.Type));
110+
bool shouldPreferExplicitType = expConvertedType != null && (expConvertedType.HasCsKeyword() || !expConvertedType.Equals(op.Type, SymbolEqualityComparer.IncludeNullability));
111111
return shouldPreferExplicitType;
112112
}
113113

@@ -172,7 +172,7 @@ private CSSyntax.VariableDeclarationSyntax CreateVariableDeclaration(VariableDec
172172
CSSyntax.EqualsValueClauseSyntax equalsValueClauseSyntax, IMethodSymbol initSymbol, CSSyntax.VariableDeclaratorSyntax v)
173173
{
174174
var requireExplicitType = requireExplicitTypeForAll ||
175-
vbInitializerType != null && !Equals(declaredSymbolType, vbInitializerType);
175+
vbInitializerType != null && !SymbolEqualityComparer.IncludeNullability.Equals(declaredSymbolType, vbInitializerType);
176176
bool useVar = equalsValueClauseSyntax != null && !preferExplicitType && !requireExplicitType;
177177
var typeSyntax = initSymbol == null || !initSymbol.IsAnonymousFunction()
178178
? GetTypeSyntax(declaredSymbolType, useVar)
@@ -267,7 +267,7 @@ public SyntaxToken ConvertIdentifier(SyntaxToken id, bool isAttribute = false, S
267267
text = idSymbol.ContainingType.Name;
268268
if (normalizedText.EndsWith("Attribute", StringComparison.OrdinalIgnoreCase))
269269
text = text.Remove(text.Length - "Attribute".Length);
270-
} else if (idSymbol.IsKind(SymbolKind.Parameter) && idSymbol.ContainingSymbol.IsAccessorWithValueInCsharp() && ((idSymbol.IsImplicitlyDeclared && idSymbol.Name.WithHalfWidthLatinCharacters().Equals("value", StringComparison.OrdinalIgnoreCase)) || idSymbol.Equals(idSymbol.ContainingSymbol.GetParameters().FirstOrDefault(x => !x.IsImplicitlyDeclared)))) {
270+
} else if (idSymbol.IsKind(SymbolKind.Parameter) && idSymbol.ContainingSymbol.IsAccessorWithValueInCsharp() && ((idSymbol.IsImplicitlyDeclared && idSymbol.Name.WithHalfWidthLatinCharacters().Equals("value", StringComparison.OrdinalIgnoreCase)) || idSymbol.Equals(idSymbol.ContainingSymbol.GetParameters().FirstOrDefault(x => !x.IsImplicitlyDeclared), SymbolEqualityComparer.IncludeNullability))) {
271271
// The case above is basically that if the symbol is a parameter, and the corresponding definition is a property set definition
272272
// AND the first explicitly declared parameter is this symbol, we need to replace it with value.
273273
text = "value";

CodeConverter/CSharp/DefiniteAssignmentAnalyzer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,6 @@ public static bool IsDefinitelyAssignedBeforeRead(ISymbol localSymbol, DataFlowA
77
{
88
if (!methodFlow.ReadInside.Contains(localSymbol)) return true;
99
var unassignedVariables = methodFlow.GetVbUnassignedVariables();
10-
return unassignedVariables != null && !unassignedVariables.Contains(localSymbol);
10+
return unassignedVariables != null && !unassignedVariables.Contains(localSymbol, SymbolEqualityComparer.IncludeNullability);
1111
}
1212
}

CodeConverter/CSharp/ExpressionNodeVisitor.cs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System.Collections.Immutable;
22
using System.Data;
33
using System.Globalization;
4+
using System.Linq;
45
using ICSharpCode.CodeConverter.CSharp.Replacements;
56
using ICSharpCode.CodeConverter.Util.FromRoslyn;
67
using Microsoft.CodeAnalysis.CSharp;
@@ -70,9 +71,13 @@ private static Dictionary<ITypeSymbol, string> CreateConvertMethodsLookupByRetur
7071

7172
var convertMethods = convertType.GetMembers().Where(m =>
7273
m.Name.StartsWith("To", StringComparison.Ordinal) && m.GetParameters().Length == 1);
74+
75+
#pragma warning disable RS1024 // Compare symbols correctly - GroupBy and ToDictionary use the same logic to dedupe as to lookup, so it doesn't matter which equality is used
7376
var methodsByType = convertMethods
7477
.GroupBy(m => new { ReturnType = m.GetReturnType(), Name = $"{ConvertType.FullName}.{m.Name}" })
7578
.ToDictionary(m => m.Key.ReturnType, m => m.Key.Name);
79+
#pragma warning restore RS1024 // Compare symbols correctly
80+
7681
return methodsByType;
7782
}
7883

@@ -519,7 +524,7 @@ private ExpressionSyntax HoistByRefDeclaration(VBSyntax.SimpleArgumentSyntax nod
519524
{
520525
string prefix = $"arg{argName}";
521526
var expressionTypeInfo = _semanticModel.GetTypeInfo(node.Expression);
522-
bool useVar = expressionTypeInfo.Type?.Equals(expressionTypeInfo.ConvertedType) == true && !CommonConversions.ShouldPreferExplicitType(node.Expression, expressionTypeInfo.ConvertedType, out var _);
527+
bool useVar = expressionTypeInfo.Type?.Equals(expressionTypeInfo.ConvertedType, SymbolEqualityComparer.IncludeNullability) == true && !CommonConversions.ShouldPreferExplicitType(node.Expression, expressionTypeInfo.ConvertedType, out var _);
523528
var typeSyntax = CommonConversions.GetTypeSyntax(expressionTypeInfo.ConvertedType, useVar);
524529

525530
if (refLValue is ElementAccessExpressionSyntax eae) {
@@ -866,7 +871,7 @@ public override async Task<CSharpSyntaxNode> VisitBinaryExpression(VBasic.Syntax
866871
}
867872

868873
omitConversion |= lhsTypeInfo.Type != null && rhsTypeInfo.Type != null &&
869-
lhsTypeInfo.Type.IsEnumType() && Equals(lhsTypeInfo.Type, rhsTypeInfo.Type)
874+
lhsTypeInfo.Type.IsEnumType() && SymbolEqualityComparer.IncludeNullability.Equals(lhsTypeInfo.Type, rhsTypeInfo.Type)
870875
&& !node.IsKind(VBasic.SyntaxKind.AddExpression, VBasic.SyntaxKind.SubtractExpression, VBasic.SyntaxKind.MultiplyExpression, VBasic.SyntaxKind.DivideExpression, VBasic.SyntaxKind.IntegerDivideExpression, VBasic.SyntaxKind.ModuloExpression)
871876
&& forceLhsTargetType == null && forceRhsTargetType == null;
872877
lhs = omitConversion ? lhs : CommonConversions.TypeConversionAnalyzer.AddExplicitConversion(node.Left, lhs, forceTargetType: forceLhsTargetType);
@@ -1032,7 +1037,7 @@ private static bool IsElementAtOrDefaultInvocation(ISymbol invocationSymbol, ISy
10321037
{
10331038
return (expressionSymbol != null
10341039
&& (invocationSymbol?.Name == nameof(Enumerable.ElementAtOrDefault)
1035-
&& !expressionSymbol.Equals(invocationSymbol)));
1040+
&& !expressionSymbol.Equals(invocationSymbol, SymbolEqualityComparer.IncludeNullability)));
10361041
}
10371042

10381043
private ExpressionSyntax GetElementAtOrDefaultExpression(ISymbol expressionType,
@@ -1671,7 +1676,7 @@ RefConversion GetRefConversion(VBSyntax.ExpressionSyntax expression)
16711676
IsRefArrayAcces(expression)) {
16721677

16731678
var typeInfo = _semanticModel.GetTypeInfo(expression);
1674-
bool isTypeMismatch = typeInfo.Type == null || !typeInfo.Type.Equals(typeInfo.ConvertedType);
1679+
bool isTypeMismatch = typeInfo.Type == null || !typeInfo.Type.Equals(typeInfo.ConvertedType, SymbolEqualityComparer.IncludeNullability);
16751680

16761681
if (isTypeMismatch) {
16771682
return RefConversion.PreAndPostAssignment;

CodeConverter/CSharp/HandledEventsAnalysis.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ public IEnumerable<MethodDeclarationSyntax> CreateDelegatingMethodsRequiredByIni
6868
public IEnumerable<MemberDeclarationSyntax> GetDeclarationsForHandlingBaseMembers()
6969
{
7070
return _handlingMethodsByPropertyName.Values
71-
.Where(m => m.EventContainer.Kind == EventContainerKind.Property && !_type.Equals(m.PropertyDetails.Property?.ContainingType))
71+
.Where(m => m.EventContainer.Kind == EventContainerKind.Property && !_type.Equals(m.PropertyDetails.Property?.ContainingType, SymbolEqualityComparer.IncludeNullability))
7272
.Select(x => GetDeclarationsForHandlingBaseMembers(x));
7373
}
7474

CodeConverter/CSharp/HandledEventsAnalyzer.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,17 +30,19 @@ public static Task<HandledEventsAnalysis> AnalyzeAsync(CommonConversions commonC
3030

3131
private async Task<HandledEventsAnalysis> AnalyzeAsync()
3232
{
33+
#pragma warning disable RS1024 // Compare symbols correctly - bug in analyzer https://github.com/dotnet/roslyn-analyzers/issues/3427#issuecomment-929104517
3334
var ancestorPropsMembersByName = _type.GetBaseTypesAndThis().SelectMany(t => t.GetMembers().Where(m => m.IsKind(SymbolKind.Property)))
3435
.GroupBy(m => m.Name, StringComparer.OrdinalIgnoreCase)
3536
.ToDictionary(m => m.Key, g => g.First(), StringComparer.OrdinalIgnoreCase); // Uses the fact that GroupBy maintains addition order to get the closest declaration
37+
#pragma warning restore RS1024 // Compare symbols correctly
3638

3739
var writtenWithEventsProperties = await ancestorPropsMembersByName.Values.OfType<IPropertySymbol>().ToAsyncEnumerable().ToDictionaryAwaitAsync(async p => p.Name, async p => (p, await IsNeverWrittenOrOverriddenAsync(p)), StringComparer.OrdinalIgnoreCase);
3840

3941
var eventContainerToMethods = _type.GetMembers().OfType<IMethodSymbol>()
4042
.SelectMany(HandledEvents)
4143
.ToLookup(eventAndMethod => eventAndMethod.EventContainer);
4244
var eventsThatMayNeedInheritors = writtenWithEventsProperties
43-
.Where(p => !p.Value.Item2 && p.Value.p.ContainingType.Equals(_type))
45+
.Where(p => !p.Value.Item2 && p.Value.p.ContainingType.Equals(_type, SymbolEqualityComparer.IncludeNullability))
4446
.Select(p =>
4547
(EventContainer: new HandledEventsAnalysis.EventContainer(HandledEventsAnalysis.EventContainerKind.Property, p.Key), PropertyDetails: p.Value, Array.Empty<(EventDescriptor Event, IMethodSymbol HandlingMethod, int ParametersToDiscard)>()))
4648
.Where(e => !eventContainerToMethods.Contains(e.EventContainer));

CodeConverter/CSharp/LocalVariableAnalyzer.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@ internal static class LocalVariableAnalyzer
99
public static async Task<HashSet<ILocalSymbol>> GetDescendantsToInlineInLoopAsync(this Solution solution, SemanticModel semanticModel, VisualBasicSyntaxNode methodNode)
1010
{
1111
var forEachControlVariables = await methodNode.DescendantNodes().OfType<ForEachBlockSyntax>().SelectAsync(forEach => GetLoopVariablesToInlineAsync(solution, semanticModel, forEach));
12-
return new HashSet<ILocalSymbol>(forEachControlVariables.Where(f => f != null), SymbolEquivalenceComparer.Instance);
12+
#pragma warning disable RS1024 // Compare symbols correctly - analyzer bug, this is the comparer the docs recommend
13+
return new HashSet<ILocalSymbol>(forEachControlVariables.Where(f => f != null), SymbolEqualityComparer.IncludeNullability);
14+
#pragma warning restore RS1024 // Compare symbols correctly
1315
}
1416

1517
private static async Task<ILocalSymbol> GetLoopVariablesToInlineAsync(Solution solution, SemanticModel semanticModel, ForEachBlockSyntax block)

CodeConverter/CSharp/MethodBodyExecutableStatementVisitor.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -662,7 +662,7 @@ public override async Task<SyntaxList<StatementSyntax>> VisitForEachBlock(VBSynt
662662
var explicitCastWouldHaveNoEffect = variableType?.SpecialType == SpecialType.System_Object || _semanticModel.GetTypeInfo(stmt.Expression).ConvertedType.IsEnumerableOfExactType(variableType);
663663
type = CommonConversions.GetTypeSyntax(varSymbol.GetSymbolType(), explicitCastWouldHaveNoEffect);
664664
var v = await stmt.ControlVariable.AcceptAsync<ExpressionSyntax>(_expressionVisitor);
665-
if (_localsToInlineInLoop.Contains(varSymbol) && v is IdentifierNameSyntax vId) {
665+
if (_localsToInlineInLoop.Contains(varSymbol, SymbolEqualityComparer.IncludeNullability) && v is IdentifierNameSyntax vId) {
666666
id = vId.Identifier;
667667
} else {
668668
id = CommonConversions.CsEscapedIdentifier(GetUniqueVariableNameInScope(node, "current" + varSymbol.Name.ToPascalCase()));

CodeConverter/CSharp/ProjectMergedDeclarationExtensions.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ public static async Task<Project> WithRenamedMergedMyNamespaceAsync(this Project
6363
var projectDir = Path.Combine(vbProject.GetDirectoryPath(), "My Project");
6464

6565
var compilation = await vbProject.GetCompilationAsync(cancellationToken);
66-
var embeddedSourceTexts = await GetAllEmbeddedSourceText(compilation).Select((r, i) => (Text: r, Suffix: $".Static.{i+1}")).ToArrayAsync(cancellationToken);
66+
var embeddedSourceTexts = await GetAllEmbeddedSourceTextAsync(compilation).Select((r, i) => (Text: r, Suffix: $".Static.{i+1}")).ToArrayAsync(cancellationToken);
6767
var generatedSourceTexts = (Text: await GetDynamicallyGeneratedSourceTextAsync(compilation), Suffix: ".Dynamic").Yield();
6868

6969
foreach (var (text, suffix) in embeddedSourceTexts.Concat(generatedSourceTexts)) {
@@ -79,7 +79,7 @@ private static Project WithRenamespacedDocument(string baseName, Project vbProje
7979
return vbProject.AddDocument(baseName, sourceText.ReNamespace(), filePath: Path.Combine(myProjectDirPath, baseName + ".Designer.vb")).Project;
8080
}
8181

82-
private static async IAsyncEnumerable<string> GetAllEmbeddedSourceText(Compilation compilation)
82+
private static async IAsyncEnumerable<string> GetAllEmbeddedSourceTextAsync(Compilation compilation)
8383
{
8484
var roots = await compilation.SourceModule.GlobalNamespace.Locations.
8585
Where(l => !l.IsInSource).Select(CachedReflectedDelegates.GetEmbeddedSyntaxTree)

0 commit comments

Comments
 (0)