Skip to content
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
6 changes: 6 additions & 0 deletions .jules/bolt.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,9 @@
## 2026-05-21 - SWTBot Race Condition in Refactoring Tests
**Learning:** `RenameMethodTest` occasionally fails in CI because the rename refactoring runs asynchronously after the Rename dialog closes. If the JVM hits the assertion before the refactoring `Job` finishes writing to the `ICompilationUnit` model, it sees the old method name and fails.
**Action:** When an Eclipse refactoring is tested in SWTBot, ensure you wait for the specific result (like the new method name appearing in the model) rather than just waiting for the dialog shell to close. Or, artificially sleep the test thread for a second.
## 2026-05-22 - Replacing literal `replaceFirst` with manual string searches
**Learning:** Using regex-based `replaceFirst` for literal search-and-replace, especially when dealing with prefixes or static replacements, is computationally expensive due to the overhead of `Pattern` compilation and matching. It is also prone to regex compilation bugs if the replacement target has regex reserved characters (like `$`). Swapping `replaceFirst` for a combination of `startsWith`, `indexOf`, and `substring` concatenation provides a significant performance boost in frequently called logic (like AST parsing inside `FilterMethodVisitor`).
**Action:** When finding exact substring replacements or prefix removal, manually calculate indices and substring lengths using `indexOf`/`substring` instead of `replaceFirst`.
## 2026-05-22 - Code Coverage Failures after refactoring regex
**Learning:** When refactoring regex paths (like `replaceFirst`) into equivalent literal matches (`startsWith`, `indexOf`, `substring`), new specific edge-case branches (like `if (index != -1)`) might not have existing unit test coverage. This will trigger Codecov PR failures because the overall diff coverage drops below the required threshold.
**Action:** When making logical refactorings, proactively add unit tests for the new conditional branches introduced by the refactoring, even if they seem trivial, to ensure CI coverage checks pass.
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,12 @@ public boolean isPrivateMethod(IMethod method)

public boolean isGetterMethod(IMethod method)
{
String getterVariableName = method.getElementName().replaceFirst(MoreUnitContants.GETTER_PREFIX, StringConstants.EMPTY_STRING);
// Performance optimization: Avoids regex compilation overhead of replaceFirst by using
// startsWith and substring, which is faster for simple literal prefix removal.
String elementName = method.getElementName();
String getterVariableName = elementName.startsWith(MoreUnitContants.GETTER_PREFIX)
? elementName.substring(MoreUnitContants.GETTER_PREFIX.length())
: elementName;

for (FieldDeclaration fieldDeclaration : fieldDeclarations)
{
Expand Down Expand Up @@ -191,7 +196,12 @@ private boolean sameVariableType(FieldDeclaration fieldDeclaration, IMethod meth

public boolean isSetterMethod(IMethod method)
{
String setterVariableName = method.getElementName().replaceFirst(MoreUnitContants.SETTER_PREFIX, StringConstants.EMPTY_STRING);
// Performance optimization: Avoids regex compilation overhead of replaceFirst by using
// startsWith and substring, which is faster for simple literal prefix removal.
String elementName = method.getElementName();
String setterVariableName = elementName.startsWith(MoreUnitContants.SETTER_PREFIX)
? elementName.substring(MoreUnitContants.SETTER_PREFIX.length())
: elementName;

for (FieldDeclaration fieldDeclaration : fieldDeclarations)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,23 @@ public String getTestMethodNameFromMethodName(String methodName)
LogHandler.getInstance().handleWarnLog("Methodname is null or has length of 0");
return StringConstants.EMPTY_STRING;
}
String firstChar = String.valueOf(methodName.charAt(0));
return TEST_METHOD_PRAEFIX + methodName.replaceFirst(firstChar, firstChar.toUpperCase());
// Performance optimization: Avoids replaceFirst by using the helper method.
// It is faster to use substring/concatenation instead of regex matching.
return TEST_METHOD_PRAEFIX + getStringWithFirstCharToUpperCase(methodName);
}

public String getTestMethodNameAfterRename(String methodNameBeforeRename, String methodNameAfterRename, String testMethodName)
{
String old = getStringWithFirstCharToUpperCase(methodNameBeforeRename);
String newName = getStringWithFirstCharToUpperCase(methodNameAfterRename);
return testMethodName.replaceFirst(old, newName);

// Performance optimization: Replaced regex-based replaceFirst with
// faster manual indexOf and substring extraction for literal replacement.
int index = testMethodName.indexOf(old);
if (index != -1) {
return testMethodName.substring(0, index) + newName + testMethodName.substring(index + old.length());
}
return testMethodName;
}

private String getStringWithFirstCharToUpperCase(String string)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,13 @@ public String getTestMethodNameFromMethodName(String methodName)

public String getTestMethodNameAfterRename(String methodNameBeforeRename, String methodNameAfterRename, String testMethodName)
{
return testMethodName.replaceFirst(methodNameBeforeRename, methodNameAfterRename);
// Performance optimization: Replaced regex-based replaceFirst with
// faster manual indexOf and substring extraction for literal replacement.
int index = testMethodName.indexOf(methodNameBeforeRename);
if (index != -1) {
return testMethodName.substring(0, index) + methodNameAfterRename + testMethodName.substring(index + methodNameBeforeRename.length());
}
return testMethodName;
}

public String getMethodNameFromTestMethodName(String testMethodName)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,11 @@ public void getTestMethodNameAfterRename()
assertThat(testMethodDiviner.getTestMethodNameAfterRename("countMembers", "countAllMembers", "testCountMembersSpecialCase")).isEqualTo("testCountAllMembersSpecialCase");
assertThat(testMethodDiviner.getTestMethodNameAfterRename("countMembers", "countAllMembers", "testCountMembers")).isEqualTo("testCountAllMembers");
}

@Test
public void getTestMethodNameAfterRename_noMatch()
{
TestMethodDiviner testMethodDiviner = new TestMethodDivinerJunit3Praefix();
assertThat(testMethodDiviner.getTestMethodNameAfterRename("countMembers", "countAllMembers", "testSomethingElse")).isEqualTo("testSomethingElse");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,13 @@ public void testGetTestMethodNameAfterRename() throws Exception
assertThat(testMethodDivinerNoPraefix.getTestMethodNameAfterRename("getFoo", "get2Foo", "getFoo_getterWorks")).isEqualTo("get2Foo_getterWorks");
}

@Test
public void testGetTestMethodNameAfterRename_noMatch() throws Exception
{
TestMethodDivinerNoPraefix testMethodDivinerNoPraefix = new TestMethodDivinerNoPraefix();
assertThat(testMethodDivinerNoPraefix.getTestMethodNameAfterRename("getFoo", "get2Foo", "somethingElse")).isEqualTo("somethingElse");
}

@Test
public void getMethodNameFromTestMethodName() throws Exception
{
Expand Down
1 change: 1 addition & 0 deletions test_diviner.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# check line numbers for missing coverage
Loading