diff --git a/rewrite-csharp/src/main/java/org/openrewrite/csharp/service/CSharpNamingService.java b/rewrite-csharp/src/main/java/org/openrewrite/csharp/service/CSharpNamingService.java new file mode 100644 index 0000000..0686d5f --- /dev/null +++ b/rewrite-csharp/src/main/java/org/openrewrite/csharp/service/CSharpNamingService.java @@ -0,0 +1,66 @@ +/* + * Copyright 2024 the original author or authors. + *
+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *
+ * https://www.apache.org/licenses/LICENSE-2.0 + *
+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.csharp.service; + +import org.openrewrite.internal.NameCaseConvention; +import org.openrewrite.internal.NamingService; + +import java.util.regex.Pattern; + +public class CSharpNamingService implements NamingService { + + private static final Pattern STANDARD_METHOD_NAME = Pattern.compile("^[A-Z][a-zA-Z0-9]*$"); + private static final Pattern SNAKE_CASE = Pattern.compile("^[a-zA-Z0-9]+_\\w+$"); + + @Override + public String standardizeMethodName(String oldMethodName) { + if (!STANDARD_METHOD_NAME.matcher(oldMethodName).matches()) { + StringBuilder result = new StringBuilder(); + if (SNAKE_CASE.matcher(oldMethodName).matches()) { + result.append(NameCaseConvention.format(NameCaseConvention.UPPER_CAMEL, oldMethodName)); + } else { + int nameLength = oldMethodName.length(); + for (int i = 0; i < nameLength; i++) { + char c = oldMethodName.charAt(i); + if (i == 0) { + // the java specification requires identifiers to start with [a-zA-Z$_] + if (c != '$' && c != '_') { + result.append(Character.toUpperCase(c)); + } + } else { + if (!Character.isLetterOrDigit(c)) { + while ((!Character.isLetterOrDigit(c) || c > 'z')) { + i++; + if (i < nameLength) { + c = oldMethodName.charAt(i); + } else { + break; + } + } + if (i < nameLength) { + result.append(Character.toUpperCase(c)); + } + } else { + result.append(c); + } + } + } + } + return result.toString(); + } + return oldMethodName; + } +} diff --git a/rewrite-csharp/src/main/java/org/openrewrite/csharp/service/package-info.java b/rewrite-csharp/src/main/java/org/openrewrite/csharp/service/package-info.java new file mode 100644 index 0000000..310d549 --- /dev/null +++ b/rewrite-csharp/src/main/java/org/openrewrite/csharp/service/package-info.java @@ -0,0 +1,21 @@ +/* + * Copyright 2024 the original author or authors. + *
+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *
+ * https://www.apache.org/licenses/LICENSE-2.0 + *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+@NullMarked
+@NonNullFields
+package org.openrewrite.csharp.service;
+
+import org.jspecify.annotations.NullMarked;
+import org.openrewrite.internal.lang.NonNullFields;
diff --git a/rewrite-csharp/src/main/java/org/openrewrite/csharp/tree/Cs.java b/rewrite-csharp/src/main/java/org/openrewrite/csharp/tree/Cs.java
index 712ba51..d3496f0 100644
--- a/rewrite-csharp/src/main/java/org/openrewrite/csharp/tree/Cs.java
+++ b/rewrite-csharp/src/main/java/org/openrewrite/csharp/tree/Cs.java
@@ -22,7 +22,9 @@
import org.openrewrite.*;
import org.openrewrite.csharp.CSharpPrinter;
import org.openrewrite.csharp.CSharpVisitor;
+import org.openrewrite.csharp.service.CSharpNamingService;
import org.openrewrite.internal.ListUtils;
+import org.openrewrite.internal.NamingService;
import org.openrewrite.java.JavaPrinter;
import org.openrewrite.java.JavaTypeVisitor;
import org.openrewrite.java.internal.TypesInUse;
@@ -72,7 +74,7 @@ final class CompilationUnit implements Cs, JavaSourceFile {
@Nullable
@NonFinal
- transient WeakReference J acceptCSharp(CSharpVisitor v, P p) {
return v.visitInterpolation(this, p);
}
- public Padding getPadding() {
+ public Padding getPadding() {
Padding p;
if (this.padding == null) {
p = new Padding(this);
@@ -1966,7 +1979,7 @@ public PropertyDeclaration withType(@Nullable JavaType type) {
}
public @Nullable NameTree getInterfaceSpecifier() {
- return interfaceSpecifier!= null ? interfaceSpecifier.getElement() : null;
+ return interfaceSpecifier != null ? interfaceSpecifier.getElement() : null;
}
public PropertyDeclaration withInterfaceSpecifier(@Nullable NameTree interfaceSpecifier) {
@@ -2058,14 +2071,11 @@ public PropertyDeclaration withInitializer(@Nullable JLeftPadded J acceptCSharp(CSharpVisitor v, P p) {
* // use result
* }
*
- *
* Example 2: Deconstruction declaration:
* J acceptCSharp(CSharpVisitor v, P p) {
@Override
public SingleVariableDesignation withType(@Nullable JavaType type) {
- return this.getType() == type ? this : new SingleVariableDesignation(
+ return this.getType() == type ? this : new SingleVariableDesignation(
id,
prefix,
markers,
@@ -2924,12 +2930,10 @@ public CoordinateBuilder.Expression getCoordinates() {
/**
* Represents a parenthesized list of variable declarations used in deconstruction patterns.
- *
* Example of simple deconstruction:
*
@@ -5274,8 +5279,6 @@ public CoordinateBuilder.Expression getCoordinates() {
}
-
-
/**
* Represents a property pattern clause in C# pattern matching, which matches against object properties.
*
@@ -5863,8 +5866,7 @@ public SwitchSection withStatements(List J acceptCSharp(CSharpVisitor v, P p) {
return v.visitFixedStatement(this, p);
@@ -6385,7 +6385,6 @@ public CoordinateBuilder.Statement getCoordinates() {
}
}
-
/**
* Represents a C# checked statement which enforces overflow checking for arithmetic operations
* and conversions. Operations within a checked block will throw OverflowException if arithmetic
diff --git a/rewrite-csharp/src/test/java/org/openrewrite/csharp/service/CSharpNamingServiceTest.java b/rewrite-csharp/src/test/java/org/openrewrite/csharp/service/CSharpNamingServiceTest.java
new file mode 100644
index 0000000..78e8b8f
--- /dev/null
+++ b/rewrite-csharp/src/test/java/org/openrewrite/csharp/service/CSharpNamingServiceTest.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2024 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.openrewrite.csharp.service;
+
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.CsvSource;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+class CSharpNamingServiceTest {
+
+ @ParameterizedTest
+ @CsvSource(textBlock = """
+ foo_bar,FooBar
+ foo$bar,FooBar
+ foo_bar$,FooBar
+ foo$bar$,FooBar
+ """)
+ void changeMethodName(String before, String after) {
+ String actual = new CSharpNamingService().standardizeMethodName(before);
+ assertThat(actual).isEqualTo(after);
+ }
+
+}
T service(Class service) {
+ if (NamingService.class.getName().equals(service.getName())) {
+ return (T) new CSharpNamingService();
+ }
+ return JavaSourceFile.super.service(service);
+ }
+
@RequiredArgsConstructor
- public static class Padding implements JavaSourceFile.Padding {
+ public static class Padding implements JavaSourceFile.Padding {
private final Cs.CompilationUnit t;
@Override
@@ -505,7 +516,9 @@ final class Argument implements Cs, Expression {
@With
Keyword refKindKeyword;
- public @Nullable Identifier getNameColumn() { return nameColumn == null ? null : nameColumn.getElement(); }
+ public @Nullable Identifier getNameColumn() {
+ return nameColumn == null ? null : nameColumn.getElement();
+ }
public Argument withNameColumn(@Nullable Identifier nameColumn) {
return getPadding().withNameColumn(JRightPadded.withElement(this.nameColumn, nameColumn));
@@ -1602,7 +1615,7 @@ public
* int (x, y) = point;
@@ -2852,9 +2858,11 @@ public CoordinateBuilder.Expression getCoordinates() {
}
//region VariableDesignation
+
/**
* Interface for variable designators in declaration expressions.
* This can be either a single variable name or a parenthesized list of designators for deconstruction.
+ *
* @see SingleVariableDesignation
* @see ParenthesizedVariableDesignation
*/
@@ -2864,12 +2872,10 @@ interface VariableDesignation extends Expression, Cs {
/**
* Represents a single variable declaration within a declaration expression.
* Used both for simple out variable declarations and as elements within deconstruction declarations.
- *
* Example in out variable:
*
* int.TryParse(s, out int x) // 'int x' is the SingleVariable
*
- *
* Example in deconstruction:
*
* (int x, string y) = point; // both 'int x' and 'string y' are SingleVariables
@@ -2908,7 +2914,7 @@ public
* int (x, y) = point;
*
- *
* Example of nested deconstruction:
*
* (int count, var (string name, int age)) = GetPersonDetails();
@@ -3413,15 +3417,13 @@ public Cs.Unary withOperator(JLeftPadded
+ *
* class Person {
- * // Constructor with 'this' initializer
- * public Person(string name) : this(name, 0) { }
- *
- * // Constructor with 'base' initializer
- * public Person(string name, int age) : base(name) { }
+ * // Constructor with 'this' initializer
+ * public Person(string name) : this(name, 0) { }
+ * // Constructor with 'base' initializer
+ * public Person(string name, int age) : base(name) { }
* }
*
*/
@@ -3701,6 +3703,7 @@ public CoordinateBuilder.Statement getCoordinates() {
}
}
+
/**
* Represents an initializer expression that consists of a list of expressions, typically used in array
* or collection initialization contexts. The expressions are contained within delimiters like curly braces.
@@ -4157,6 +4160,7 @@ public IsPattern withPattern(JLeftPadded