Skip to content

Commit

Permalink
Add CSharp implementation of proposed NamingService (#25)
Browse files Browse the repository at this point in the history
* Add CSharp implementation that is also returned when a NamingService is requested from a Cs.CompilationUnit

* Apply regex to check if name isn't pascal case already

* FMT

* FMT pt2

* Add test and improvement that was also made to JavaNamingService

* Touching up
  • Loading branch information
Laurens-W authored Dec 4, 2024
1 parent 98ab2cc commit e5e4bd7
Show file tree
Hide file tree
Showing 4 changed files with 163 additions and 40 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* Copyright 2024 the original author or authors.
* <p>
* 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
* <p>
* https://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* Copyright 2024 the original author or authors.
* <p>
* 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
* <p>
* https://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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;
79 changes: 39 additions & 40 deletions rewrite-csharp/src/main/java/org/openrewrite/csharp/tree/Cs.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -72,7 +74,7 @@ final class CompilationUnit implements Cs, JavaSourceFile {

@Nullable
@NonFinal
transient WeakReference<Padding> padding;
transient WeakReference<Padding> padding;

@Getter
@With
Expand Down Expand Up @@ -264,8 +266,17 @@ public Padding getPadding() {
return p;
}

@Override
@Incubating(since = "8.2.0")
public <S, T extends S> T service(Class<S> 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
Expand Down Expand Up @@ -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));
Expand Down Expand Up @@ -1602,7 +1615,7 @@ public <P> J acceptCSharp(CSharpVisitor<P> v, P p) {
return v.visitInterpolation(this, p);
}

public Padding getPadding() {
public Padding getPadding() {
Padding p;
if (this.padding == null) {
p = new Padding(this);
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -2058,14 +2071,11 @@ public PropertyDeclaration withInitializer(@Nullable JLeftPadded<Expression> ini
}
}



@Getter
@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
Expand All @@ -2088,8 +2098,7 @@ final class Keyword implements Cs
return v.visitKeyword(this, p);
}

public enum KeywordKind
{
public enum KeywordKind {
Ref,
Out,
Await,
Expand Down Expand Up @@ -2145,7 +2154,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,
Expand Down Expand Up @@ -2491,12 +2500,13 @@ public TypeParameterConstraintClause withTypeParameterConstraints(@Nullable JCon
}
}

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)
Expand Down Expand Up @@ -2573,10 +2583,8 @@ public TypeConstraint withType(TypeTree type) {

/* ------------------ */




interface AllowsConstraint extends J {}
interface AllowsConstraint extends J {
}

/**
* Represents an `allows` constraint in a where clause.
Expand Down Expand Up @@ -2701,8 +2709,7 @@ final class ClassOrStructConstraint implements Cs, TypeParameterConstraint {
@Getter
TypeKind kind;

public enum TypeKind
{
public enum TypeKind {
Class,
Struct
}
Expand Down Expand Up @@ -2788,7 +2795,6 @@ public <P> J acceptCSharp(CSharpVisitor<P> v, P p) {
* // use result
* }
* </pre>
*
* Example 2: Deconstruction declaration:
* <pre>
* int (x, y) = point;
Expand Down Expand Up @@ -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
*/
Expand All @@ -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:
* <pre>
* int.TryParse(s, out int x) // 'int x' is the SingleVariable
* </pre>
*
* Example in deconstruction:
* <pre>
* (int x, string y) = point; // both 'int x' and 'string y' are SingleVariables
Expand Down Expand Up @@ -2908,7 +2914,7 @@ public <P> J acceptCSharp(CSharpVisitor<P> 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,
Expand All @@ -2924,12 +2930,10 @@ public CoordinateBuilder.Expression getCoordinates() {

/**
* Represents a parenthesized list of variable declarations used in deconstruction patterns.
*
* Example of simple deconstruction:
* <pre>
* int (x, y) = point;
* </pre>
*
* Example of nested deconstruction:
* <pre>
* (int count, var (string name, int age)) = GetPersonDetails();
Expand Down Expand Up @@ -3413,15 +3417,13 @@ public Cs.Unary withOperator(JLeftPadded<Type> 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:
* <pre>
* <pre>
* 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) { }
* }
* </pre>
*/
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -4157,6 +4160,7 @@ public IsPattern withPattern(JLeftPadded<Pattern> pattern) {
}

//region Patterns

/**
* Base interface for all C# pattern types that can appear on the right-hand side of an 'is' expression.
* This includes type patterns, constant patterns, declaration patterns, property patterns, etc.
Expand Down Expand Up @@ -4709,6 +4713,7 @@ public ListPattern withPatterns(JContainer<Pattern> patterns) {

}
}

/**
* Represents a C# parenthesized pattern expression that groups a nested pattern.
* <p>
Expand Down Expand Up @@ -5274,8 +5279,6 @@ public CoordinateBuilder.Expression getCoordinates() {

}



/**
* Represents a property pattern clause in C# pattern matching, which matches against object properties.
* <p>
Expand Down Expand Up @@ -5863,8 +5866,7 @@ public SwitchSection withStatements(List<JRightPadded<Statement>> statements) {
}
}

public interface SwitchLabel extends Expression
{
public interface SwitchLabel extends Expression {

}

Expand Down Expand Up @@ -6371,8 +6373,6 @@ final class FixedStatement implements Cs, Statement {
@Getter
J.Block block;



@Override
public <P> J acceptCSharp(CSharpVisitor<P> v, P p) {
return v.visitFixedStatement(this, p);
Expand All @@ -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
Expand Down
Loading

0 comments on commit e5e4bd7

Please sign in to comment.