Skip to content

Commit 8a8c1af

Browse files
macsuxclaude
andcommitted
Add C# solution-based parsing and cross-language namespace mappings
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent af6298f commit 8a8c1af

37 files changed

Lines changed: 1700 additions & 1079 deletions

rewrite-csharp/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ tasks.withType<Test> {
8989
dependsOn(csharpBuild)
9090

9191
maxParallelForks = 1
92+
maxHeapSize = "4g"
9293
// Add timeout to identify hanging tests
9394
systemProperty("junit.jupiter.execution.timeout.default", "30s")
9495
// Show test names as they run

rewrite-csharp/csharp/OpenRewrite/CSharp/CSharpParser.cs

Lines changed: 406 additions & 55 deletions
Large diffs are not rendered by default.

rewrite-csharp/csharp/OpenRewrite/CSharp/CSharpPrinter.cs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2311,6 +2311,44 @@ public override J VisitUnary(Unary unary, PrintOutputCapture<P> p)
23112311
return unary;
23122312
}
23132313

2314+
public override J VisitCsUnary(CsUnary csUnary, PrintOutputCapture<P> p)
2315+
{
2316+
BeforeSyntax(csUnary, p);
2317+
2318+
var op = csUnary.Operator.Element;
2319+
bool isPostfix = op == CsUnary.OperatorKind.SuppressNullableWarning;
2320+
2321+
if (!isPostfix)
2322+
{
2323+
p.Append(GetCsUnaryOperatorString(op));
2324+
}
2325+
2326+
Visit(csUnary.Expression, p);
2327+
2328+
if (isPostfix)
2329+
{
2330+
VisitSpace(csUnary.Operator.Before, p);
2331+
p.Append(GetCsUnaryOperatorString(op));
2332+
}
2333+
2334+
AfterSyntax(csUnary, p);
2335+
return csUnary;
2336+
}
2337+
2338+
private static string GetCsUnaryOperatorString(CsUnary.OperatorKind op)
2339+
{
2340+
return op switch
2341+
{
2342+
CsUnary.OperatorKind.SuppressNullableWarning => "!",
2343+
CsUnary.OperatorKind.PointerIndirection => "*",
2344+
CsUnary.OperatorKind.PointerType => "*",
2345+
CsUnary.OperatorKind.AddressOf => "&",
2346+
CsUnary.OperatorKind.Spread => "..",
2347+
CsUnary.OperatorKind.FromEnd => "^",
2348+
_ => throw new InvalidOperationException($"Unknown CsUnary operator: {op}")
2349+
};
2350+
}
2351+
23142352
private static string GetUnaryOperatorString(Unary.OperatorType op)
23152353
{
23162354
return op switch

rewrite-csharp/csharp/OpenRewrite/CSharp/CSharpTypeMapping.cs

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -118,9 +118,20 @@ private JavaType MapNamedType(INamedTypeSymbol symbol)
118118
_typeCache[symbol] = parameterized;
119119

120120
var rawType = MapNamedType(symbol.OriginalDefinition);
121-
var typeArgs = symbol.TypeArguments.Select(MapType).ToList()!;
122-
parameterized.UnsafeSet(rawType as JavaType.FullyQualified, typeArgs!);
123-
return parameterized;
121+
122+
// Guard: if rawType resolved back to the same Parameterized (cache collision
123+
// between symbol and OriginalDefinition) or is not a FullyQualified, fall back
124+
if (ReferenceEquals(rawType, parameterized) || rawType is not JavaType.FullyQualified fq)
125+
{
126+
_typeCache.Remove(symbol);
127+
// Fall through to create as a plain Class below
128+
}
129+
else
130+
{
131+
var typeArgs = symbol.TypeArguments.Select(MapType).ToList()!;
132+
parameterized.UnsafeSet(fq, typeArgs!);
133+
return parameterized;
134+
}
124135
}
125136

126137
// Shell cache pattern: create empty shell, cache it, then populate

rewrite-csharp/csharp/OpenRewrite/CSharp/CSharpVisitor.cs

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,6 @@ public class CSharpVisitor<P> : JavaVisitor<P>
5656
NullSafeExpression nse => VisitNullSafeExpression(nse, p),
5757
// New types
5858
Keyword kw => VisitKeyword(kw, p),
59-
CsArgument csa => VisitCsArgument(csa, p),
6059
NameColon nc => VisitNameColon(nc, p),
6160
AnnotatedStatement ans => VisitAnnotatedStatement(ans, p),
6261
ArrayRankSpecifier ars => VisitArrayRankSpecifier(ars, p),
@@ -602,12 +601,6 @@ public virtual J VisitLineDirective(LineDirective lineDirective, P p)
602601

603602
public virtual J VisitKeyword(Keyword keyword, P p) => keyword;
604603

605-
public virtual J VisitCsArgument(CsArgument csArgument, P p)
606-
{
607-
Visit(csArgument.Expression, p);
608-
return csArgument;
609-
}
610-
611604
public virtual J VisitNameColon(NameColon nameColon, P p) => nameColon;
612605

613606
public virtual J VisitAnnotatedStatement(AnnotatedStatement annotatedStatement, P p)

rewrite-csharp/csharp/OpenRewrite/CSharp/Cs.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -704,7 +704,7 @@ public sealed class StatementExpression(
704704
Space prefix,
705705
Markers markers,
706706
Statement statement
707-
) : Cs, Expression, IEquatable<StatementExpression>
707+
) : Pattern, IEquatable<StatementExpression>
708708
{
709709
public Guid Id { get; } = id;
710710
public Space Prefix { get; } = prefix;
@@ -2812,21 +2812,21 @@ public sealed class ImplicitElementAccess(
28122812
Guid id,
28132813
Space prefix,
28142814
Markers markers,
2815-
JContainer<CsArgument> argumentList
2815+
JContainer<Expression> argumentList
28162816
) : Cs, Expression, IEquatable<ImplicitElementAccess>
28172817
{
28182818
public Guid Id { get; } = id;
28192819
public Space Prefix { get; } = prefix;
28202820
public Markers Markers { get; } = markers;
2821-
public JContainer<CsArgument> ArgumentList { get; } = argumentList;
2821+
public JContainer<Expression> ArgumentList { get; } = argumentList;
28222822

28232823
public ImplicitElementAccess WithId(Guid id) =>
28242824
id == Id ? this : new(id, Prefix, Markers, ArgumentList);
28252825
public ImplicitElementAccess WithPrefix(Space prefix) =>
28262826
ReferenceEquals(prefix, Prefix) ? this : new(Id, prefix, Markers, ArgumentList);
28272827
public ImplicitElementAccess WithMarkers(Markers markers) =>
28282828
ReferenceEquals(markers, Markers) ? this : new(Id, Prefix, markers, ArgumentList);
2829-
public ImplicitElementAccess WithArgumentList(JContainer<CsArgument> argumentList) =>
2829+
public ImplicitElementAccess WithArgumentList(JContainer<Expression> argumentList) =>
28302830
ReferenceEquals(argumentList, ArgumentList) ? this : new(Id, Prefix, Markers, argumentList);
28312831

28322832
Tree Tree.WithId(Guid id) => WithId(id);

rewrite-csharp/csharp/OpenRewrite/CSharp/Rpc/CSharpReceiver.cs

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,6 @@ public CSharpReceiver()
8989
NullSafeExpression nse => VisitNullSafeExpression(nse, q),
9090
// New types
9191
Keyword kw => VisitKeyword(kw, q),
92-
CsArgument csa => VisitCsArgument(csa, q),
9392
NameColon nc => VisitNameColon(nc, q),
9493
AnnotatedStatement ans => VisitAnnotatedStatement(ans, q),
9594
ArrayRankSpecifier ars => VisitArrayRankSpecifier(ars, q),
@@ -198,7 +197,11 @@ public override J VisitCompilationUnit(CompilationUnit cu, RpcReceiveQueue q)
198197

199198
// Reconstruct members
200199
var allMembers = new List<Statement>();
201-
if (usings != null) allMembers.AddRange(usings.Select(rp => rp.Element));
200+
if (usings != null)
201+
{
202+
foreach (var rp in usings)
203+
allMembers.Add(rp.Element);
204+
}
202205
if (attrLists != null) allMembers.AddRange(attrLists);
203206
if (members != null) allMembers.AddRange(members.Select(rp => rp.Element));
204207

@@ -208,13 +211,14 @@ public override J VisitCompilationUnit(CompilationUnit cu, RpcReceiveQueue q)
208211
// ---- UsingDirective ----
209212
public override J VisitUsingDirective(UsingDirective ud, RpcReceiveQueue q)
210213
{
211-
q.Receive(ud.IsGlobal ? (object?)ud.Global : null);
212-
q.Receive(ud.IsStatic ? (object?)ud.Static : null);
213-
// Unsafe: nagoya doesn't model this
214-
q.Receive<object?>(null);
214+
var global = q.Receive(ud.Global, rp => _delegate.VisitRightPadded(rp, q));
215+
var @static = q.Receive(ud.Static, lp => _delegate.VisitLeftPadded(lp, q));
216+
// Unsafe: nagoya doesn't model this; consume and discard
217+
q.Receive(new JLeftPadded<bool>(Space.Empty, false), lp => _delegate.VisitLeftPadded(lp, q));
215218
var alias = q.Receive(ud.Alias, rp => _delegate.VisitRightPadded(rp!, q));
216219
var namespaceOrType = q.Receive((J)ud.NamespaceOrType, el => (J)VisitNonNull(el, q));
217-
return ud.WithId(PvId).WithPrefix(PvPrefix).WithMarkers(PvMarkers).WithAlias(alias).WithNamespaceOrType((TypeTree)namespaceOrType!);
220+
return ud.WithId(PvId).WithPrefix(PvPrefix).WithMarkers(PvMarkers)
221+
.WithGlobal(global!).WithStatic(@static!).WithAlias(alias).WithNamespaceOrType((TypeTree)namespaceOrType!);
218222
}
219223

220224
// ---- PropertyDeclaration ----
@@ -563,14 +567,6 @@ public override J VisitKeyword(Keyword kw, RpcReceiveQueue q)
563567
return kw.WithId(PvId).WithPrefix(PvPrefix).WithMarkers(PvMarkers).WithKind((KeywordKind)kind!);
564568
}
565569

566-
public override J VisitCsArgument(CsArgument arg, RpcReceiveQueue q)
567-
{
568-
var nameColumn = q.Receive(arg.NameColumn, rp => _delegate.VisitRightPadded(rp!, q));
569-
var refKindKeyword = q.Receive((J?)arg.RefKindKeyword, el => (J)VisitNonNull(el!, q));
570-
var expression = q.Receive((J)arg.Expression, el => (J)VisitNonNull(el, q));
571-
return arg.WithId(PvId).WithPrefix(PvPrefix).WithMarkers(PvMarkers).WithNameColumn(nameColumn).WithRefKindKeyword((Keyword?)refKindKeyword).WithExpression((Expression)expression!);
572-
}
573-
574570
public override J VisitNameColon(NameColon nc, RpcReceiveQueue q)
575571
{
576572
var name = q.Receive(nc.Name, rp => _delegate.VisitRightPadded(rp, q));

rewrite-csharp/csharp/OpenRewrite/CSharp/Rpc/CSharpSender.cs

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,6 @@ public CSharpSender()
9494
NullSafeExpression nse => VisitNullSafeExpression(nse, q),
9595
// New types
9696
Keyword kw => VisitKeyword(kw, q),
97-
CsArgument csa => VisitCsArgument(csa, q),
9897
NameColon nc => VisitNameColon(nc, q),
9998
AnnotatedStatement ans => VisitAnnotatedStatement(ans, q),
10099
ArrayRankSpecifier ars => VisitArrayRankSpecifier(ars, q),
@@ -217,12 +216,10 @@ public override J VisitCompilationUnit(CompilationUnit cu, RpcSendQueue q)
217216
// Nagoya model: Global (RP<bool>), Static (LP<bool>), Alias (RP<Identifier>?), NamespaceOrType
218217
public override J VisitUsingDirective(UsingDirective ud, RpcSendQueue q)
219218
{
220-
// Send null for Global/Static when absent; nagoya's bool representation doesn't
221-
// match Java's Keyword tree, but null/NO_CHANGE is protocol-compatible for absent cases
222-
q.GetAndSend(ud, u => u.IsGlobal ? (object?)u.Global : null);
223-
q.GetAndSend(ud, u => u.IsStatic ? (object?)u.Static : null);
224-
// Unsafe: nagoya doesn't model this
225-
q.GetAndSend(ud, _ => (object?)null);
219+
q.GetAndSend(ud, u => u.Global, rp => VisitRightPadded(rp, q));
220+
q.GetAndSend(ud, u => u.Static, lp => VisitLeftPadded(lp, q));
221+
// Unsafe: nagoya doesn't model this, send a default JLeftPadded<bool>(false)
222+
q.GetAndSend(ud, _ => new JLeftPadded<bool>(Space.Empty, false), lp => VisitLeftPadded(lp, q));
226223
q.GetAndSend(ud, u => u.Alias, rp => VisitRightPadded(rp!, q));
227224
q.GetAndSend(ud, u => (J)u.NamespaceOrType, el => Visit(el, q));
228225
return ud;
@@ -672,14 +669,6 @@ public override J VisitKeyword(Keyword kw, RpcSendQueue q)
672669
return kw;
673670
}
674671

675-
public override J VisitCsArgument(CsArgument arg, RpcSendQueue q)
676-
{
677-
q.GetAndSend(arg, a => a.NameColumn, rp => VisitRightPadded(rp!, q));
678-
q.GetAndSend(arg, a => (J?)a.RefKindKeyword, el => Visit(el!, q));
679-
q.GetAndSend(arg, a => (J)a.Expression, el => Visit(el, q));
680-
return arg;
681-
}
682-
683672
public override J VisitNameColon(NameColon nc, RpcSendQueue q)
684673
{
685674
q.GetAndSend(nc, n => n.Name, rp => VisitRightPadded(rp, q));

0 commit comments

Comments
 (0)