Skip to content

Commit 1c274d7

Browse files
authored
Better name generation for resources in ResourceLeakFixer (#355)
Closes #345.
1 parent f016b0a commit 1c274d7

File tree

5 files changed

+66
-41
lines changed

5 files changed

+66
-41
lines changed

core-codemods/src/main/java/io/codemodder/codemods/ResourceLeakFixer.java

Lines changed: 55 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@
66
import com.github.javaparser.ast.body.VariableDeclarator;
77
import com.github.javaparser.ast.expr.*;
88
import com.github.javaparser.ast.stmt.TryStmt;
9+
import com.github.javaparser.ast.type.VarType;
910
import com.github.javaparser.resolution.UnsolvedSymbolException;
11+
import com.github.javaparser.resolution.types.ResolvedType;
1012
import io.codemodder.Either;
1113
import io.codemodder.ast.*;
1214
import java.util.ArrayDeque;
@@ -168,9 +170,29 @@ public static ObjectCreationExpr findRootExpression(final ObjectCreationExpr cre
168170
return current;
169171
}
170172

173+
private static String generateNameWithSuffix(final Expression start) {
174+
var root = rootPrefix;
175+
try {
176+
var typeName = start.calculateResolvedType().describe();
177+
typeName = typeName.substring(typeName.lastIndexOf('.') + 1);
178+
typeName = Character.toLowerCase(typeName.charAt(0)) + typeName.substring(1);
179+
root = typeName;
180+
} catch (RuntimeException e) {
181+
root = rootPrefix;
182+
}
183+
var maybeName = ASTs.findNonCallableSimpleNameSource(start, root);
184+
int count = 0;
185+
String nameWithSuffix = root;
186+
while (maybeName.isPresent()) {
187+
count++;
188+
nameWithSuffix = root + count;
189+
maybeName = ASTs.findNonCallableSimpleNameSource(start, nameWithSuffix);
190+
}
191+
return count == 0 ? root : nameWithSuffix;
192+
}
193+
171194
public static Optional<TryStmt> tryToFix(final ObjectCreationExpr creationExpr) {
172195
final var deque = findInnerExpressions(creationExpr);
173-
int count = 0;
174196
final var maybeLVD =
175197
ASTs.isInitExpr(creationExpr)
176198
.flatMap(LocalVariableDeclaration::fromVariableDeclarator)
@@ -188,26 +210,18 @@ public static Optional<TryStmt> tryToFix(final ObjectCreationExpr creationExpr)
188210
maybeLVD.get().getScope());
189211
var cu = creationExpr.findCompilationUnit().get();
190212
for (var resource : deque) {
191-
var name = count == 0 ? rootPrefix : rootPrefix + count;
192-
// TODO try to resolve type, failing to do that use var declaration?
193-
var type = resource.calculateResolvedType().describe();
194-
resource.replace(new NameExpr(name));
195-
196-
var declaration =
197-
new VariableDeclarator(
198-
StaticJavaParser.parseType(type.substring(type.lastIndexOf('.') + 1)),
199-
name,
200-
resource);
201-
tryStmt.getResources().addFirst(new VariableDeclarationExpr(declaration));
202-
ASTTransforms.addImportIfMissing(cu, type);
203-
count++;
213+
var typeName = calculateResolvedType(resource).map(rt -> rt.describe());
214+
tryStmt
215+
.getResources()
216+
.addFirst(new VariableDeclarationExpr(buildDeclaration(resource, typeName)));
217+
typeName.ifPresent(tn -> ASTTransforms.addImportIfMissing(cu, tn));
204218
}
205219
return Optional.of(tryStmt);
206220
}
207221
return Optional.empty();
208222
}
209223

210-
/** Tries to fix the leak of {@code expr} and returns its line if it does. */
224+
/** Tries to fix the leak of {@code expr} and returns line if it does. */
211225
public static Optional<TryStmt> tryToFix(final MethodCallExpr mce) {
212226

213227
// Is LocalDeclarationStmt and Never Assigned -> Wrap as a try resource
@@ -228,24 +242,13 @@ public static Optional<TryStmt> tryToFix(final MethodCallExpr mce) {
228242
var tryStmt =
229243
ASTTransforms.wrapIntoResource(
230244
lvd.getStatement(), lvd.getVariableDeclarationExpr(), lvd.getScope());
231-
// TODO check availability here
232-
int count = 0;
233245
var cu = mce.findCompilationUnit().get();
234246
for (var resource : resources) {
235-
var name = count == 0 ? rootPrefix : rootPrefix + count;
236-
// TODO try to resolve type, failing to do that use var declaration?
237-
var type = resource.calculateResolvedType().describe();
238-
239-
resource.replace(new NameExpr(name));
240-
241-
var declaration =
242-
new VariableDeclarator(
243-
StaticJavaParser.parseType(type.substring(type.lastIndexOf('.') + 1)),
244-
name,
245-
resource);
246-
tryStmt.getResources().addFirst(new VariableDeclarationExpr(declaration));
247-
ASTTransforms.addImportIfMissing(cu, type);
248-
count++;
247+
var typeName = calculateResolvedType(resource).map(rt -> rt.describe());
248+
tryStmt
249+
.getResources()
250+
.addFirst(new VariableDeclarationExpr(buildDeclaration(resource, typeName)));
251+
typeName.ifPresent(tn -> ASTTransforms.addImportIfMissing(cu, tn));
249252
}
250253
return Optional.of(tryStmt);
251254
// TODO if vde is multiple declarations, extract the relevant vd and wrap it
@@ -254,6 +257,27 @@ public static Optional<TryStmt> tryToFix(final MethodCallExpr mce) {
254257
return Optional.empty();
255258
}
256259

260+
private static Optional<ResolvedType> calculateResolvedType(final Expression e) {
261+
try {
262+
return Optional.of(e.calculateResolvedType());
263+
} catch (final RuntimeException exception) {
264+
return Optional.empty();
265+
}
266+
}
267+
268+
private static VariableDeclarator buildDeclaration(
269+
final Expression resource, final Optional<String> typeName) {
270+
var name = generateNameWithSuffix(resource);
271+
resource.replace(new NameExpr(name));
272+
return new VariableDeclarator(
273+
typeName.isPresent()
274+
? StaticJavaParser.parseType(
275+
typeName.get().substring(typeName.get().lastIndexOf('.') + 1))
276+
: new VarType(),
277+
name,
278+
resource);
279+
}
280+
257281
private static Deque<Expression> findInnerExpressions(final ObjectCreationExpr creationExpr) {
258282
var deque = new ArrayDeque<Expression>();
259283
var maybeExpr =

core-codemods/src/test/resources/input-resource-leak/Test.java.after

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@ public class Test {
1313
}
1414

1515
public void nestedReaders() throws IOException {
16-
try (FileReader resource1 = new FileReader("~/test.txt");
17-
BufferedReader resource = new BufferedReader(resource1);
18-
BufferedReader br = new BufferedReader(resource)) {
16+
try (FileReader fileReader = new FileReader("~/test.txt");
17+
BufferedReader bufferedReader = new BufferedReader(fileReader);
18+
BufferedReader br = new BufferedReader(bufferedReader)) {
1919
}
2020
}
2121

core-codemods/src/test/resources/output-resource-leak/Test.java.after

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@ public class Test {
1313
}
1414

1515
public void nestedWriters() throws IOException {
16-
try (FileWriter resource1 = new FileWriter("~/test.txt");
17-
BufferedWriter resource = new BufferedWriter(resource1);
18-
BufferedWriter br = new BufferedWriter(resource)) {
16+
try (FileWriter fileWriter = new FileWriter("~/test.txt");
17+
BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);
18+
BufferedWriter br = new BufferedWriter(bufferedWriter)) {
1919
}
2020
}
2121

core-codemods/src/test/resources/resource-leak/Test.java.after

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,10 @@ public class Test {
3232
}
3333

3434
public void nestedReaders() throws IOException {
35-
try (FileReader resource1 = new FileReader("~/test.txt");
36-
BufferedReader resource = new BufferedReader(resource1);
37-
BufferedReader br = new BufferedReader(resource)) {
35+
try (FileReader fileReader = new FileReader("~/test.txt");
36+
BufferedReader bufferedReader1 = new BufferedReader(fileReader);
37+
BufferedReader bufferedReader = new BufferedReader(bufferedReader1);
38+
BufferedReader br = new BufferedReader(bufferedReader)) {
3839
}
3940
}
4041

core-codemods/src/test/resources/resource-leak/Test.java.before

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ public class Test {
2929
}
3030

3131
public void nestedReaders() throws IOException {
32-
BufferedReader br = new BufferedReader(new BufferedReader(new FileReader("~/test.txt")));
32+
BufferedReader br = new BufferedReader(new BufferedReader(new BufferedReader(new FileReader("~/test.txt"))));
3333
}
3434

3535
public void mergeFixes(File f) throws IOException {

0 commit comments

Comments
 (0)