Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adjust MethodNameCasing to work with C# #397

Merged
merged 9 commits into from
Dec 4, 2024
49 changes: 6 additions & 43 deletions src/main/java/org/openrewrite/staticanalysis/MethodNameCasing.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,12 @@
import lombok.Value;
import org.jspecify.annotations.Nullable;
import org.openrewrite.*;
import org.openrewrite.internal.NameCaseConvention;
import org.openrewrite.internal.NamingService;
import org.openrewrite.internal.StringUtils;
import org.openrewrite.java.ChangeMethodName;
import org.openrewrite.java.JavaIsoVisitor;
import org.openrewrite.java.MethodMatcher;
import org.openrewrite.java.VariableNameUtils;
import org.openrewrite.java.marker.JavaSourceSet;
import org.openrewrite.java.tree.J;
import org.openrewrite.java.tree.JavaSourceFile;
import org.openrewrite.java.tree.JavaType;
Expand All @@ -40,8 +39,6 @@
public class MethodNameCasing extends ScanningRecipe<List<MethodNameCasing.MethodNameChange>> {

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+$");

@Option(displayName = "Apply recipe to test source set",
description = "Changes only apply to main by default. `includeTestSources` will apply the recipe to `test` source files.",
required = false)
Expand All @@ -62,8 +59,8 @@ public String getDisplayName() {
@Override
public String getDescription() {
return "Fixes method names that do not follow standard naming conventions. " +
"For example, `String getFoo_bar()` would be adjusted to `String getFooBar()` " +
"and `int DoSomething()` would be adjusted to `int doSomething()`.";
"For example, `String getFoo_bar()` would be adjusted to `String getFooBar()` " +
"and `int DoSomething()` would be adjusted to `int doSomething()`.";
}

@Override
Expand All @@ -85,17 +82,11 @@ public List<MethodNameChange> getInitialValue(ExecutionContext ctx) {
public TreeVisitor<?, ExecutionContext> getScanner(List<MethodNameChange> changes) {
return new JavaIsoVisitor<ExecutionContext>() {
UUID scope;

@Override
public J preVisit(J tree, ExecutionContext ctx) {
if (tree instanceof JavaSourceFile) {
scope = tree.getId();
JavaSourceFile cu = (JavaSourceFile) tree;
Optional<JavaSourceSet> sourceSet = cu.getMarkers().findFirst(JavaSourceSet.class);
if (!sourceSet.isPresent()) {
stopAfterPreVisit();
} else if (!Boolean.TRUE.equals(includeTestSources) && !"main".equals(sourceSet.get().getName())) {
stopAfterPreVisit();
}
}
return super.preVisit(tree, ctx);
}
Expand All @@ -113,37 +104,9 @@ public J.MethodDeclaration visitMethodDeclaration(J.MethodDeclaration method, Ex
!method.isConstructor() &&
!simpleName.startsWith("_") &&
!STANDARD_METHOD_NAME.matcher(simpleName).matches()) {
Laurens-W marked this conversation as resolved.
Show resolved Hide resolved
StringBuilder standardized = new StringBuilder();
String normalized = VariableNameUtils.normalizeName(simpleName);

if (SNAKE_CASE.matcher(normalized).matches()) {
standardized.append(NameCaseConvention.format(NameCaseConvention.LOWER_CAMEL, normalized));
} else {
int nameLength = normalized.length();
for (int i = 0; i < nameLength; i++) {
char c = normalized.charAt(i);

if (i == 0) {
// the java specification requires identifiers to start with [a-zA-Z$_]
if (c != '$' && c != '_') {
standardized.append(Character.toLowerCase(c));
}
} else {
if (!Character.isLetterOrDigit(c)) {
while (i < nameLength && (!Character.isLetterOrDigit(c) || c > 'z')) {
c = normalized.charAt(i++);
}
if (i < nameLength) {
standardized.append(Character.toUpperCase(c));
}
} else {
standardized.append(c);
}
}
}
}

String toName = standardized.toString();
NamingService service = getCursor().firstEnclosing(SourceFile.class).service(NamingService.class);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The JavaVisitor in fact has a service() method which is much easier to use. We might want to pull that up to TreeVisitor at some point.

We might also have to cache the services a bit more as "breadcrumbs" along the cursor path, so that the service lookups don't get too expensive for deeply nested elements. But that is also something for another day.

String toName = service.getMethodName(normalized);
Laurens-W marked this conversation as resolved.
Show resolved Hide resolved
if (!StringUtils.isBlank(toName) && !StringUtils.isNumeric(toName) &&
!methodExists(method.getMethodType(), toName)) {
changes.add(new MethodNameChange(
Expand Down
Loading