Skip to content

Commit 1f4b391

Browse files
Merge pull request #254 from icsharpcode/raise-event
C# -> VB: Improve conversions to RaiseEvent
2 parents 669849e + 5c06d29 commit 1f4b391

7 files changed

Lines changed: 336 additions & 132 deletions

File tree

CHANGELOG.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
# Change Log
22
All notable changes to the code converter will be documented here.
33

4-
# 6.5.0 TBC
4+
# 6.6.0 TBC
5+
6+
### C# -> VB
7+
* Improve event identifier conversion
8+
9+
# 6.5.0 03/03/2019
510
* Avoid fatal error converting a project in a solution containing a website project (#243)
611
* Improve best-effort conversion in the presence of errors
712
* Improved nuget package and web converter's snippet detection

ICSharpCode.CodeConverter/Shared/ProjectConversion.cs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,6 @@ public class ProjectConversion
1919
{
2020
private readonly Compilation _sourceCompilation;
2121
private readonly IEnumerable<SyntaxTree> _syntaxTreesToConvert;
22-
// ReSharper disable once StaticMemberInGenericType - Stateless
23-
private static readonly AdhocWorkspace AdhocWorkspace = new AdhocWorkspace();
2422
private readonly ConcurrentDictionary<string, string> _errors = new ConcurrentDictionary<string, string>();
2523
private readonly Dictionary<string, SyntaxTree> _firstPassResults = new Dictionary<string, SyntaxTree>();
2624
private readonly ILanguageConversion _languageConversion;
@@ -147,12 +145,13 @@ private Dictionary<string, SyntaxNode> Convert()
147145
private Dictionary<string, SyntaxNode> SecondPass()
148146
{
149147
var secondPassByFilePath = new Dictionary<string, SyntaxNode>();
148+
var adhocWorkspace = new AdhocWorkspace();
150149
foreach (var firstPassResult in _firstPassResults) {
151150
var treeFilePath = firstPassResult.Key;
152151
try {
153-
secondPassByFilePath.Add(treeFilePath, SingleSecondPass(firstPassResult));
152+
secondPassByFilePath.Add(treeFilePath, SingleSecondPass(firstPassResult, adhocWorkspace));
154153
} catch (Exception e) {
155-
secondPassByFilePath.Add(treeFilePath, Format(firstPassResult.Value.GetRoot()));
154+
secondPassByFilePath.Add(treeFilePath, Format(firstPassResult.Value.GetRoot(), adhocWorkspace));
156155
_errors.TryAdd(treeFilePath, e.ToString());
157156
}
158157
}
@@ -169,10 +168,10 @@ private void AddProjectWarnings()
169168
}
170169
}
171170

172-
private SyntaxNode SingleSecondPass(KeyValuePair<string, SyntaxTree> cs)
171+
private SyntaxNode SingleSecondPass(KeyValuePair<string, SyntaxTree> cs, AdhocWorkspace workspace)
173172
{
174173
var secondPassNode = _languageConversion.SingleSecondPass(cs);
175-
return Format(secondPassNode);
174+
return Format(secondPassNode, workspace);
176175
}
177176

178177
private void FirstPass()
@@ -237,10 +236,11 @@ private static async Task<SyntaxTree> GetSyntaxTreeWithAnnotatedSelection(Syntax
237236
return root.WithAnnotatedNode(selectedNode, AnnotationConstants.SelectedNodeAnnotationKind);
238237
}
239238

240-
private SyntaxNode Format(SyntaxNode resultNode)
239+
private SyntaxNode Format(SyntaxNode resultNode, Workspace workspace)
241240
{
242241
SyntaxNode selectedNode = _handlePartialConversion ? GetSelectedNode(resultNode) : resultNode;
243-
return Formatter.Format(selectedNode ?? resultNode, AdhocWorkspace);
242+
SyntaxNode nodeToFormat = selectedNode ?? resultNode;
243+
return Formatter.Format(nodeToFormat, workspace);
244244
}
245245

246246
private SyntaxNode GetSelectedNode(SyntaxNode resultNode)

ICSharpCode.CodeConverter/VB/CommonConversions.cs

Lines changed: 41 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
using Microsoft.CodeAnalysis.VisualBasic;
1010
using Microsoft.CodeAnalysis.VisualBasic.Syntax;
1111
using AttributeListSyntax = Microsoft.CodeAnalysis.VisualBasic.Syntax.AttributeListSyntax;
12+
using BinaryExpressionSyntax = Microsoft.CodeAnalysis.CSharp.Syntax.BinaryExpressionSyntax;
1213
using CSharpExtensions = Microsoft.CodeAnalysis.CSharp.CSharpExtensions;
1314
using CSSyntaxKind = Microsoft.CodeAnalysis.CSharp.SyntaxKind;
1415
using ExpressionSyntax = Microsoft.CodeAnalysis.VisualBasic.Syntax.ExpressionSyntax;
@@ -206,7 +207,7 @@ public ExpressionSyntax ReduceArrayUpperBoundExpression(Microsoft.CodeAnalysis.C
206207

207208
public LambdaExpressionSyntax ConvertLambdaExpression(AnonymousFunctionExpressionSyntax node, CSharpSyntaxNode body, IEnumerable<ParameterSyntax> parameters, SyntaxTokenList modifiers)
208209
{
209-
var symbol = ModelExtensions.GetSymbolInfo(_semanticModel, node).Symbol as IMethodSymbol;
210+
var symbol = (IMethodSymbol) ModelExtensions.GetSymbolInfo(_semanticModel, node).Symbol;
210211
var parameterList = SyntaxFactory.ParameterList(SyntaxFactory.SeparatedList(parameters.Select(p => (Microsoft.CodeAnalysis.VisualBasic.Syntax.ParameterSyntax)p.Accept(_nodesVisitor))));
211212
LambdaHeaderSyntax header;
212213
EndBlockStatementSyntax endBlock;
@@ -233,7 +234,8 @@ public LambdaExpressionSyntax ConvertLambdaExpression(AnonymousFunctionExpressio
233234
var vbThrowExpression = (ExpressionSyntax)csThrowExpression.Expression.Accept(_nodesVisitor);
234235
var vbThrowStatement = SyntaxFactory.ThrowStatement(SyntaxFactory.Token(SyntaxKind.ThrowKeyword), vbThrowExpression);
235236

236-
return SyntaxFactory.MultiLineFunctionLambdaExpression(header, SyntaxFactory.SingletonList<StatementSyntax>(vbThrowStatement), endBlock);
237+
return SyntaxFactory.MultiLineFunctionLambdaExpression(header,
238+
SyntaxFactory.SingletonList<StatementSyntax>(vbThrowStatement), endBlock);
237239
} else {
238240
statements = InsertRequiredDeclarations(
239241
SyntaxFactory.SingletonList<StatementSyntax>(
@@ -396,19 +398,25 @@ public VisualBasicSyntaxNode ConvertTopLevelExpression(Microsoft.CodeAnalysis.CS
396398
return topLevelExpression.Accept(_nodesVisitor);
397399
}
398400

399-
private static ModifiedIdentifierSyntax ExtractIdentifier(Microsoft.CodeAnalysis.CSharp.Syntax.VariableDeclaratorSyntax v)
401+
private ModifiedIdentifierSyntax ExtractIdentifier(Microsoft.CodeAnalysis.CSharp.Syntax.VariableDeclaratorSyntax v)
400402
{
401403
return SyntaxFactory.ModifiedIdentifier(ConvertIdentifier(v.Identifier));
402404
}
403405

404-
public static SyntaxToken ConvertIdentifier(SyntaxToken id)
406+
public SyntaxToken ConvertIdentifier(SyntaxToken id)
405407
{
406-
var idText = id.ValueText;
408+
CSharpSyntaxNode parent = (CSharpSyntaxNode) id.Parent;
409+
var idText = IsEventHandlerIdentifier(parent) && !IsEventHandlerAssignLhs(parent) ? id.ValueText + "Event" : id.ValueText;
407410
// Underscore is a special character in VB lexer which continues lines - not sure where to find the whole set of other similar tokens if any
408411
// Rather than a complicated contextual rename, just add an extra dash to all identifiers and hope this method is consistently used
412+
bool keywordRequiresEscaping = KeywordRequiresEscaping(id);
413+
return Identifier(idText, keywordRequiresEscaping);
414+
}
415+
416+
public static SyntaxToken Identifier(string idText, bool keywordRequiresEscaping = false)
417+
{
409418
if (idText.All(c => c == '_')) idText += "_";
410-
411-
return KeywordRequiresEscaping(id) ? SyntaxFactory.Identifier($"[{idText}]") : SyntaxFactory.Identifier(idText);
419+
return keywordRequiresEscaping ? SyntaxFactory.Identifier($"[{idText}]") : SyntaxFactory.Identifier(idText);
412420
}
413421

414422
private static bool KeywordRequiresEscaping(SyntaxToken id)
@@ -530,5 +538,31 @@ private static string UppercaseFirstLetter(string sourceText)
530538
{
531539
return sourceText.Substring(0, 1).ToUpper() + sourceText.Substring(1);
532540
}
541+
542+
public bool IsEventHandlerIdentifier(CSharpSyntaxNode syntax)
543+
{
544+
return GetSymbol(syntax).IsKind(SymbolKind.Event);
545+
}
546+
547+
private static bool IsEventHandlerAssignLhs(CSharpSyntaxNode syntax)
548+
{
549+
var assignmentExpressionSyntax = syntax.GetAncestor<AssignmentExpressionSyntax>();
550+
return assignmentExpressionSyntax != null && assignmentExpressionSyntax.IsKind(CSSyntaxKind.AddAssignmentExpression, CSSyntaxKind.SubtractAssignmentExpression)
551+
&& assignmentExpressionSyntax.Left.DescendantNodes().Contains(syntax);
552+
}
553+
554+
private ISymbol GetSymbol(CSharpSyntaxNode syntax)
555+
{
556+
return syntax.SyntaxTree == _semanticModel.SyntaxTree
557+
? _semanticModel.GetSymbolInfo(syntax).Symbol
558+
: null;
559+
}
560+
561+
private ITypeSymbol GetTypeSymbol(CSharpSyntaxNode syntax)
562+
{
563+
return syntax.SyntaxTree == _semanticModel.SyntaxTree
564+
? _semanticModel.GetTypeInfo(syntax).Type
565+
: null;
566+
}
533567
}
534568
}

0 commit comments

Comments
 (0)