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

Fix handling of capitalization in class types #22

Merged
merged 5 commits into from
Jan 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ private String suggestNameFromClassType(final ClassType type) throws IOException
final String baseName = name.substring(1, name.length() - 1);
final String simpleName = getSimpleName(baseName);

return Character.toLowerCase(simpleName.charAt(0)) + simpleName.substring(1);
return LvtUtil.parseSimpleTypeName(simpleName);
}

private static final Splitter dollarSplitter = Splitter.on('$');
Expand Down
61 changes: 53 additions & 8 deletions codebook-lvt/src/main/java/io/papermc/codebook/lvt/LvtUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,15 +41,33 @@ public static String capitalize(final String name, final int index) {
return Character.toUpperCase(name.charAt(index)) + name.substring(index + 1);
}

public static @Nullable String decapitalize(final String name, final int index) {
if (!Character.isUpperCase(name.charAt(index))) {
// If the char isn't uppercase, that means it isn't following the typical `lowerCamelCase`
// Java method naming scheme how we expect, so we can't be sure it means what we think it
// means in this instance
return null;
} else {
return Character.toLowerCase(name.charAt(index)) + name.substring(index + 1);
public static String decapitalize(final String name) {
boolean capturingGroup = false;
final StringBuilder result = new StringBuilder();

for (int i = 0; i < name.length(); i++) {
final char character = name.charAt(i);
if (Character.isUpperCase(character)) {
if (capturingGroup) {
if (i < name.length() - 1 && Character.isLowerCase(name.charAt(i + 1))) {
// Next char is lowercase, so this is the start of a new word
result.append(character);
} else {
// Convert the leading capital to lowercase and append to the result
result.append(Character.toLowerCase(character));
}
} else {
// let's start a group, making sure to lowercase if it's the first char of the name
capturingGroup = true;
result.append(i == 0 ? Character.toLowerCase(character) : character);
}
} else {
capturingGroup = false;
result.append(character);
}
}

return result.toString();
}

public static Predicate<String> equalsAny(final String... strings) {
Expand Down Expand Up @@ -108,4 +126,31 @@ public static boolean isStringAllUppercase(final String input) {
public static boolean hasPrefix(final String text, final String prefix) {
return text.length() > prefix.length() && text.startsWith(prefix);
}

public static String parseSimpleTypeName(final String simpleName) {
// Parse all capitalized types into lowercase
// UUID -> uuid
// AABB -> aabb
if (LvtUtil.isStringAllUppercase(simpleName)) {
return simpleName.toLowerCase();
}

// Decapitalize
// HelloWorld -> helloWorld
// abstractUUIDFix -> abstractUuidFix
// myCoolAABBClass -> myCoolAabbClass
return LvtUtil.decapitalize(simpleName);
}

@Nullable
public static String parseSimpleTypeNameFromMethod(final String methodName, int prefix) {
if (!Character.isUpperCase(methodName.charAt(prefix))) {
// If the char isn't uppercase, that means it isn't following the typical `lowerCamelCase`
// Java method naming scheme how we expect, so we can't be sure it means what we think it
// means in this instance
return null;
} else {
return LvtUtil.parseSimpleTypeName(methodName.substring(prefix));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@

package io.papermc.codebook.lvt.suggestion;

import static io.papermc.codebook.lvt.LvtUtil.decapitalize;
import static io.papermc.codebook.lvt.LvtUtil.hasPrefix;
import static io.papermc.codebook.lvt.LvtUtil.parseSimpleTypeNameFromMethod;

import io.papermc.codebook.lvt.suggestion.context.ContainerContext;
import io.papermc.codebook.lvt.suggestion.context.method.MethodCallContext;
Expand Down Expand Up @@ -53,6 +53,6 @@ public class NewPrefixSuggester implements LvtSuggester {
return result;
}

return decapitalize(methodName, 3);
return parseSimpleTypeNameFromMethod(methodName, 3);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@

package io.papermc.codebook.lvt.suggestion;

import static io.papermc.codebook.lvt.LvtUtil.decapitalize;
import static io.papermc.codebook.lvt.LvtUtil.parseSimpleTypeNameFromMethod;
import static io.papermc.codebook.lvt.LvtUtil.tryMatchPrefix;

import io.papermc.codebook.lvt.suggestion.context.ContainerContext;
Expand All @@ -49,6 +49,6 @@ public class SingleVerbSuggester implements LvtSuggester {
return null;
}

return decapitalize(methodName, prefix.length());
return parseSimpleTypeNameFromMethod(methodName, prefix.length());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ freeze,net/minecraft/core/RegistryAccess,()Lnet/minecraft/core/RegistryAccess.Fr
getName,io/paper/Paper,()Ljava/lang/String;,name
getSuperLongDumName,io/paper/Paper,()Ljava/lang/String;,superLongDumName
getOrCreateSomething,io/paper/Paper,()Ljava/lang/String;,something
getUUID,io/paper/Paper,()Ljava/util/UUID;,uuid
# as
asString,io/paper/Paper,()Ljava/lang/String;,string
asLevel,io/paper/paper,()Lnet/minecraft/Level;,level
Expand Down Expand Up @@ -75,3 +76,8 @@ nextIntBetween,net/minecraft/util/RandomSource,(II)J,
nextBoolean,net/minecraft/util/RandomSource,()Z,randomBoolean
nextInt,net/minecraft/util/Mth,(Lnet/minecraft/util/RandomSource;)I,randomInt
nextInt,net/minecraft/util/Mth,(I)I,
# capitalization tests
getDOMSource,io/paper/DOMSource,()Lio/paper/DOMSource;,domSource
getThreadMXBean,java/lang/ManagementFactory,()Ljava/lang/management/ThreadMXBean;,threadMxBean
getSectionYFromSectionIndex,net/minecraft/world/level/chunk/LevelChunkSection,()I,sectionYFromSectionIndex
getLinkFSPath,io/paper/LinkFSPath,()Lio/paper/LinkFSPath;,linkFsPath