diff --git a/codebook-lvt/src/main/java/io/papermc/codebook/lvt/LvtTypeSuggester.java b/codebook-lvt/src/main/java/io/papermc/codebook/lvt/LvtTypeSuggester.java index c15c514..e1708c7 100644 --- a/codebook-lvt/src/main/java/io/papermc/codebook/lvt/LvtTypeSuggester.java +++ b/codebook-lvt/src/main/java/io/papermc/codebook/lvt/LvtTypeSuggester.java @@ -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('$'); diff --git a/codebook-lvt/src/main/java/io/papermc/codebook/lvt/LvtUtil.java b/codebook-lvt/src/main/java/io/papermc/codebook/lvt/LvtUtil.java index 2661da1..1fafd14 100644 --- a/codebook-lvt/src/main/java/io/papermc/codebook/lvt/LvtUtil.java +++ b/codebook-lvt/src/main/java/io/papermc/codebook/lvt/LvtUtil.java @@ -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 equalsAny(final String... strings) { @@ -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)); + } + } } diff --git a/codebook-lvt/src/main/java/io/papermc/codebook/lvt/suggestion/NewPrefixSuggester.java b/codebook-lvt/src/main/java/io/papermc/codebook/lvt/suggestion/NewPrefixSuggester.java index 3b9f385..2d5e93f 100644 --- a/codebook-lvt/src/main/java/io/papermc/codebook/lvt/suggestion/NewPrefixSuggester.java +++ b/codebook-lvt/src/main/java/io/papermc/codebook/lvt/suggestion/NewPrefixSuggester.java @@ -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; @@ -53,6 +53,6 @@ public class NewPrefixSuggester implements LvtSuggester { return result; } - return decapitalize(methodName, 3); + return parseSimpleTypeNameFromMethod(methodName, 3); } } diff --git a/codebook-lvt/src/main/java/io/papermc/codebook/lvt/suggestion/SingleVerbSuggester.java b/codebook-lvt/src/main/java/io/papermc/codebook/lvt/suggestion/SingleVerbSuggester.java index 6d77c2d..71315c4 100644 --- a/codebook-lvt/src/main/java/io/papermc/codebook/lvt/suggestion/SingleVerbSuggester.java +++ b/codebook-lvt/src/main/java/io/papermc/codebook/lvt/suggestion/SingleVerbSuggester.java @@ -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; @@ -49,6 +49,6 @@ public class SingleVerbSuggester implements LvtSuggester { return null; } - return decapitalize(methodName, prefix.length()); + return parseSimpleTypeNameFromMethod(methodName, prefix.length()); } } diff --git a/src/test/resources/io/papermc/codebook/lvt/LvtAssignmentSuggesterTest.csv b/src/test/resources/io/papermc/codebook/lvt/LvtAssignmentSuggesterTest.csv index 03676e7..cff7130 100644 --- a/src/test/resources/io/papermc/codebook/lvt/LvtAssignmentSuggesterTest.csv +++ b/src/test/resources/io/papermc/codebook/lvt/LvtAssignmentSuggesterTest.csv @@ -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 @@ -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