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..f53a44b --- /dev/null +++ b/rewrite-csharp/src/main/java/org/openrewrite/csharp/service/CSharpNamingService.java @@ -0,0 +1,58 @@ +/* + * Copyright 2023 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 SNAKE_CASE = Pattern.compile("^[a-zA-Z0-9]+_\\w+$"); + + @Override + public String getMethodName(String oldMethodName) { + 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 (i < nameLength && (!Character.isLetterOrDigit(c) || c > 'z')) { + c = oldMethodName.charAt(i++); + } + if (i < nameLength) { + result.append(Character.toUpperCase(c)); + } + } else { + result.append(c); + } + } + } + } + return result.toString(); + } +} 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..6c389d6 --- /dev/null +++ b/rewrite-csharp/src/main/java/org/openrewrite/csharp/service/package-info.java @@ -0,0 +1,21 @@ +/* + * Copyright 2023 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 f287aef..f093797 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,9 +22,10 @@ import org.openrewrite.*; import org.openrewrite.csharp.CSharpPrinter; import org.openrewrite.csharp.CSharpVisitor; +import org.openrewrite.csharp.service.CSharpNamingService; +import org.openrewrite.internal.NamingService; import org.openrewrite.java.JavaPrinter; import org.openrewrite.java.JavaTypeVisitor; -import org.openrewrite.java.JavaVisitor; import org.openrewrite.java.internal.TypesInUse; import org.openrewrite.java.tree.*; import org.openrewrite.marker.Markers; @@ -74,7 +75,7 @@ final class CompilationUnit implements Cs, JavaSourceFile { @Nullable @NonFinal - transient WeakReference padding; + transient WeakReference padding; @Getter @With @@ -266,8 +267,17 @@ public Padding getPadding() { return p; } + @Override + @Incubating(since = "8.2.0") + public 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 @@ -337,7 +347,9 @@ final class Argument implements Cs, Expression { @With Keyword refKindKeyword; - public J.@Nullable Identifier getNameColumn() { return nameColumn == null ? null : nameColumn.getElement(); } + public J.@Nullable Identifier getNameColumn() { + return nameColumn == null ? null : nameColumn.getElement(); + } public Argument withNameColumn(J.@Nullable Identifier nameColumn) { return getPadding().withNameColumn(JRightPadded.withElement(this.nameColumn, nameColumn)); @@ -1434,7 +1446,7 @@ public

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); @@ -1798,7 +1810,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) { @@ -1890,8 +1902,7 @@ public PropertyDeclaration withInitializer(@Nullable JLeftPadded ini } } - enum KeywordKind - { + enum KeywordKind { Ref, Out, Await, @@ -1903,8 +1914,7 @@ enum KeywordKind @FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) @EqualsAndHashCode(callSuper = false, onlyExplicitlyIncluded = true) @RequiredArgsConstructor - final class Keyword implements Cs - { + final class Keyword implements Cs { @With @Getter @EqualsAndHashCode.Include @@ -1967,7 +1977,7 @@ public CoordinateBuilder.Statement getCoordinates() { @Override public Cs.Lambda withType(@Nullable JavaType type) { - return this.getType() == type ? this : new Cs.Lambda( + return this.getType() == type ? this : new Cs.Lambda( id, prefix, markers, @@ -2313,12 +2323,13 @@ public Cs.TypeParameterConstraintClause withTypeParameterConstraints(@Nullable J } } - interface TypeParameterConstraint extends J {} + interface TypeParameterConstraint extends J { + } /** * Represents a type constraint in a type parameter's constraint clause. * Example: where T : SomeClass - * where T : IInterface + * where T : IInterface */ @FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) @EqualsAndHashCode(callSuper = false, onlyExplicitlyIncluded = true) @@ -2396,9 +2407,8 @@ public TypeConstraint withType(TypeTree type) { /* ------------------ */ - - - interface AllowsConstraint extends J {} + interface AllowsConstraint extends J { + } /** * Represents an `allows` constraint in a where clause. @@ -2523,8 +2533,7 @@ final class ClassOrStructConstraint implements Cs, TypeParameterConstraint { @Getter TypeKind kind; - public enum TypeKind - { + public enum TypeKind { Class, Struct } @@ -2602,7 +2611,7 @@ public

J acceptCSharp(CSharpVisitor

v, P p) { * // use result * } * - * + *

* Example 2: Deconstruction declaration: *

      * (int x, string y) = point;
@@ -2663,6 +2672,7 @@ public CoordinateBuilder.Expression getCoordinates() {
     /**
      * 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
      */
@@ -2672,12 +2682,12 @@ 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
@@ -2716,7 +2726,7 @@ public 

J acceptCSharp(CSharpVisitor

v, P p) { @Override public SingleVariableDesignation withType(@Nullable JavaType type) { - return this.getType() == type ? this : new Cs.SingleVariableDesignation( + return this.getType() == type ? this : new Cs.SingleVariableDesignation( id, prefix, markers, @@ -2733,12 +2743,12 @@ public CoordinateBuilder.Expression getCoordinates() { /** * Represents a parenthesized list of variable declarations used in deconstruction patterns. * Can contain both single variables and nested deconstruction patterns. - * + *

* Example of simple deconstruction: *

      * (int x, string y) = point;
      * 
- * + *

* Example of nested deconstruction: *

      * (int count, (string name, int age)) = GetPersonDetails();
@@ -2880,18 +2890,18 @@ public CoordinateBuilder.Expression getCoordinates() {
     /**
      * Represents a tuple expression in C#.
      * Can be used in tuple construction, deconstruction and tuple literals.
-     *
+     * 

* Examples: * ```csharp * // Tuple construction * var point = (1, 2); - * + *

* // Named tuple elements * var person = (name: "John", age: 25); - * + *

* // Nested tuples * var nested = (1, (2, 3)); - * + *

* // Tuple type with multiple elements * (string name, int age) person = ("John", 25); * ``` @@ -3145,15 +3155,15 @@ public Cs.Unary withOperator(JLeftPadded operator) { /** * Represents a constructor initializer which is a call to another constructor, either in the same class (this) * or in the base class (base). - * + *

* Examples: * ```csharp * 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) { } * } * ``` */