jnrouvignac / autorefactor Goto Github PK
View Code? Open in Web Editor NEWEclipse plugin to automatically refactor Java code bases
License: Other
Eclipse plugin to automatically refactor Java code bases
License: Other
As a user, I want to choose which refactorings to apply automatically.
Some of it could be automatically configured based on the Java > Code Style > Cleanup and/or Java > Code Style > Formatting.
A selected section of text,
AutoRefactor is launched,
It should only apply refactorings in the selected section of text.
Do it from Workspace > Preferences, then Java > ???, like the Code Cleanups actions.
Also allow people to select by group/capabilities:
Here are the replacements to do for Vector:
Vector()
=> ArrayList()
Vector(Collection c)
=> ArrayList(Collection c)
Vector(int initialCapacity)
=> ArrayList(int initialCapacity)
Vector(int initialCapacity, int capacityIncrement)
=> ArrayList(int initialCapacity)
Vector.addElement()
=> List.add()
Vector.capacity()
=> ?Vector.elementAt()
=> List.get()
Vector.elements()
=> List.iterator()
- somewhat equivalentVector.firstElement()
=> List.get(0)
-- Hmmm is it equivalent? Need to use if statement to ensure size?Vector.indexOf(Object, int)
=> ?Vector.lastElement()
=> List.get(Vector.size())
-- Hmmm is it equivalent? Need to use if statement to ensure size?Vector.lastIndexOf(Object, int)
=> ?Vector.copyInto()
=> List.toArray()
Vector.insertElementAt()
=> List.add()
Vector.removeAllElements()
=> List.removeAll()
Vector.removeElement()
=> List.remove()
Vector.removeElementAt()
=> List.remove()
Vector.setElementAt()
=> List.set()
Vector.setSize()
=> while (col.size() < X) { col.add(null)
;Vector.trimToSize()
=> ArrayList.trimToSize()
And for Hashtable:
Hashtable.elements()
=> Hashtable.entrySet().iterator()
- somewhatHashtable.keys()
=> Hashtable.keySet().iterator()
- somewhatHashtable.rehash()
=> ?Issue #14 should cover this one.
assertTrue(a.equals(b));
assertTrue(i == 0);
assertTrue(obj != null);
assertTrue(obj1 == obj2);
// etc.
into
assertEquals(a, b);
assertEquals(i, 0);
assertNotNull(obj);
assertSame(obj1, obj2);
// etc.
Do this for:
org.junit.Assert
junit.framework.Assert
org.testng.Assert
Let the exception put the current test method in error.
@Test
public testMethod() {
try {
// ...
} catch (Exception e) {
fail("Unexpected Exception");
}
}
Becomes:
@Test
public testMethod() throws Exception {
// ...
}
import org.testng.annotations.Test;
@Test(expectedExceptions = ArithmeticException.class)
import org.junit.Test;
@Test(expected = ArithmeticException.class)
JUnit's and TestNG's Assert classes assume a very specific order for expected vs. actual value (Note: JUnit and TestNG use reversed order, but this is of no particular matter for the rest of this discussion).
If the developer does not respect this order, then a test failure will provide the wrong error message. The following assert with JUnit:
assertEquals(i, 6598);
Would output the following failure message::
junit.framework.AssertionFailedError: expected:<2883> but was:<6598>
Where logically, the message should have been:
junit.framework.AssertionFailedError: expected:<6598> but was:<2883>
This refactoring would consist in properly ordering the expected and actual values (with respect to the underlying framework), where constants are passed in the concrete parameters of the assert*() methods.
For implementation, here is the expected vs. actual order for each framework:
Code to refactor:
public <A, B> Map<A,B> getBla(A a, B b)
{
if (a == null) {
return Collections.<A,B>emptyMap();
}
return Collections.<A,B>singletonMap(val, val);
}
Refactored code:
public <A, B> Map<A,B> getBla(A a, B b)
{
if (a == null) {
return Collections.emptyMap();
}
return Collections.singletonMap(val, val);
}
Code to refactor:
import java.util.ArrayList;
import java.util.List;
// ...
java.util.List l = new java.util.ArrayList();
Refactor to:
import java.util.ArrayList;
import java.util.List;
// ...
List l = new ArrayList();
Define which refactoring can be transformed and also what they can be transformed into. Then create one issue for each pair of (refactoring, one transformation)
A Type / Method / Field declaration,
modifiers are badly ordered (according to?),
automatically reorder them
An invoked method that supports varargs
The code is like one of these:
f(0, null);
f(0, new Object[] { 1, 2, 3 });
Refactor to:
f(0);
f(0, 1, 2, 3);
The EclEmma logo and icons look cool to me. I wonder if something in the same vein could be done for AutoRefactor?
As a developer I start writing a string concatenation until I figure out I need to convert it to StringBuilder appends.
String s = "foo" + "bar" + "baz";
triggering the "convert to StringBuilder appends" quick fix
Code is rewritten to:
String s = new StringBuilder("foo").append("bar").apend("baz").toString;
Because Exception is a super type of IOException and NullPointerException.
This code:
if (b) {
return someMethod();
} else {
return false;
}
Can be rewritten to:
return b && someMethod();
This code:
if (b) {
return someMethod();
} else {
return true;
}
Can be rewritten to:
return !b || someMethod();
Improve performance for large code bases by changing how the refactorings are executed.
Instead of making each refactoring go visit the entire AST for a Java file, register each refactoring.
Only one visitor will visit the entire AST and will delegate each ASTNode to the refactorings one by one. When one refactoring decides to change the AST, other refactoring will be skipped (and subtree will not be visited) and will the visitor will move to the next sibling.
#See http://www.techempower.com/blog/2013/03/26/everything-about-java-8/ :
@FunctionalInterface
with lambdas, - automatically convert code to do it
@FunctionalInterface
to single method interfacesCollection.removeIf()
is O(n) for ArrayList
rather than O(n2)Collections.sort(list, comparator)
=> List.sort(Comparator)
Map.computeIfAbsent()
to simplify MultiMap
usagejava.util.function
- can anything be done automatically here?java.util.stream
- can anything be done automatically here?java.time
- can anything be done automatically here?
java.util.Optional
- can anything be done automatically here?Comparator
(ex: comparingInt()
), Objects::nonNull()
, etc.java.lang
, java.util
, and elsewhere - can anything be done automatically here?Also see https://blog.jetbrains.com/upsource/2016/08/03/what-to-look-for-in-java-8-code/
Replace
if (i == 10) {
break;
// continue;
// return;
} else {
i++;
}
with
if (i == 10) {
break;
// continue;
// return;
}
i++;
Replace
if (i == 10) {
i++;
} else {
break;
// continue;
// return;
}
with
if (!(i == 10)) { // may revert condition
break;
// continue;
// return;
}
i++;
This will certainly require building a Control Flow Graph to do some variable analysis. It would be nice to build the CFG without looking at the IBinding's to avoid the need to dump then reload the whole tree each time a change is made.
A user has one file (or a group of file) to refactor,
the user hit Shift+Alt+Y to apply automatic refactorings
Actual: User might have to hit again Shift+Alt+Y several times to ensure all the possible automatic refactorings have been applied
Expected: All the possible refactorings should have been applied to the file (or the group of files), even the refactorings that are enabled by other automatic refactorings
Being able to use a CFG allow to build new or safer refactorings.
It analyses better how and where variables are used, allowing to make more informed decisions. Moreover other analysis can be built on top of it.
See:
for (String s : strings) {
...; /// no branches
break;
}
This code is encountered
Rewrite it to:
if (!strings.isEmpty()) {
String s = strings.iterator().next();
...; /// no branches
break;
}
Code to refactor:
if (b) {
} else {
if (c) {
}
}
Refactored code:
if (b) {
} else if (c) {
}
Automatically correct spelling mistakes using the installed Eclipse dictionary (including user dictionary).
When there is only one correction suggestion, then it is safe to assume it can be replaced.
Problem comes when some words are used across the whole codebase, but it is not in the dictionary or the user dictionary. Can we somehow offer a first pass that finds all badly written words and offer to add them to the dictionary in batch, based on number of occurrences.
This can be done for:
Replace
String s = "";
for (Var v...) {
s += v.some + v.thing;
return s;
with
StringBuilder s = new StringBuilder();
for (Var v...) {
s.append(v.some).append(v.thing);
return s.toString();
Replace
String s = "init";
for (Var v...) {
s = s + v.some + v.thing;
return s;
with
StringBuilder s = new StringBuilder("init");
for (Var v...) {
s.append(v.some).append(v.thing);
return s.toString();
Also replace new StringBuffer("")
with new StringBuffer()
. Ditto for StringBuilder
Code to refactor:
if (b) {
} else if (!b) {
}
Refactored code:
if (b) {
} else {
}
Code to refactor:
if (b) {
} else if (!b && c) {
}
Refactored code:
if (b) {
} else if (c) {
}
Code to refactor:
if (b || (!b && c)) {
}
Refactored code:
if (b || c) {
}
Code to refactor:
boolean bool = b || (!b && c);
Refactored code:
boolean bool = b || c;
When methods are short, it is very beneficial to turn single exit point style into return statement. Here is a reference:
http://www.leepoint.net/JavaBasics/methods/method-commentary/methcom-30-multiple-return.html
Refactor this code:
public static double max(double a, double b) {
double result; // Stores the maximum value until the return.
if (a > b) {
result = a;
} else {
result = b;
}
return result;
}
To this:
public static double max(double a, double b) {
if (a > b) {
return a;
} else {
return b;
}
}
and then to this:
public static double max(double a, double b) {
if (a > b) {
return a;
}
return b; // Only executed if comparison was false.
}
public void f() throws IOException, NullPointerException, Exception {
...
}
triggering automatic refactoring
Code is rewritten to:
public void f() throws Exception {
...
}
Because Exception is a super type of IOException and NullPointerException.
Add StringUtilsRefactoring, CollectionUtilsRefactoring, etc.
Reference:
public class WithInnerClass {
private class InnerClass {
int i;
}
public void m() {
InnerClass ic = new InnerClass();
ic.i = 0;
}
}
calling autorefactor...
Rewrite code to:
public class WithInnerClass {
private static class InnerClass {
int i;
}
public void m() {
InnerClass ic = new InnerClass();
ic.i = 0;
}
}
The plugin outputs code that does not compile.
Input:
if (b) {
int i = 1;
i++;
} else {
int i = 42;
i++;
}
Incorrect output:
if (b) {
int i = 1;
} else {
int i = 42;
}
i++;
Fixing this bug depends on issue #32.
A method's last parameter is an array:
void f(int, Object[]);
Convert the last parameter to use varargs
void f(int, Object...);
Provide an entry in menu Window > Preferences, then Java > Code Style > AutoRefactor where user can select/deselect the refactorings.
Convert from:
public void compare(int i, int j) {
Integer ii = new Integer(i);
Integer jj = Integer.valueOf(j);
return ii.compareTo(jj);
}
to:
public void compare(int i, int j) {
Integer ii = i;
Integer jj = j;
return ii.compareTo(jj);
}
and then (raise another bug for this one):
public void compare(int i, int j) {
Integer ii = i;
return ii.compareTo(j);
}
The same applies to all primitives and their wrappers.
A method named M with a javadoc in an interface or class named A
And a method named MM overriding M with the same javadoc, in a sub-interface/class of A named B
User triggers auto refactor on B
The javadoc for MM is transformed to a javadoc with
/** {@inheritDoc} */
If possible, improve or build on the JDT extract method.
It would be nice to provide Extract method refactoring across:
Probably too hard to do, would be to move statements together, but this might require deep inter procedural analysis. Maybe simple arithmetics or boolean expressions that all live in the current method body can be moved like this.
Also, if we hit specific thresholds: If more than X (10? 20? 30?) consecutive lines of code are only here to output one variable: then we suggest to extract a method.
See info about Eclipse's JDT Extract Method here:
For development, see:
Example tests with in and out folders:
Code to be refactored with embedded comments
Automatic refactoring is performed
Actual: Comments are removed
Expected: Comments should be kept the same.
Using the File Search for refactoring suffer from the limits of regular expressions It would be nice to have a Java AST Search that ignores whitespace, expressions, or group of statements.
For this we need to define a DSL to express expression types, or statements we want to ignore, etc.
Here are a few examples of possible syntax:
if (EXPR<boolean>) { STMT+ }
any boolean expression in the if condition will match, and one or more statements in the body of the loop will match.if (EXPR) { STMT+ }
same, but no type specified for the expression (even though nothing else than boolean can exist here).if (IDENT != null) { try { IDENT.close(); } catch (TYPE IDENT) { STMT* } }
this must reuse be the same identifier, how to convey it? The type of the identifier must be java.io.Closeable. How to convey it?if (IDENT1 != null) { try { IDENT1.close(); } catch (TYPE IDENT2) { STMT* } }
if (EXPR1<java.io.Closeable> != null) { try { EXPR1.close(); } catch (TYPE IDENT) { STMT* } }
to convey it?Difficulties:
See:
New refactorings could be implemented using the JavaScript engine embedded in the JREs since Java 1.6.
Linked to Issue #23.
This could also include converting from Apache Commons to Guava.
See https://code.google.com/p/guava-libraries/wiki/ApacheCommonCollectionsEquivalents
When "the natural ordering for a class is consistent with equals" as defined in java.lang.Comparable, then we can replace such code:
boolean b1 = obj1.compareTo(obj2) == 0;
boolean b2 = obj1.compareTo(obj2) != 0;
with:
boolean b1 = obj1.equals(obj2);
boolean b2 = !obj1.equals(obj2);
Such natural ordering is valid with all the java primitive wrappers, java.lang.String, java.math.BigInteger, java.util.Date, etc. (Test all the classes listed in java.lang.Comparable's javadoc).
A java file opened in a Java Editor
user automatically applies refactorings
and some refactorings modify the java file
Actual: the editor view jumps to the start of the file
Expected: the editor sticks to the relative place it is in the file
This applies to empty line and block comments, empty javadocs.
It should also apply to TODO comments automatically generated by Eclipse.
Convert line and block comments to javadocs if they are situated before a field, method, constructor or type declaration.
Code would need to ensure the comment ends with a period, that all parameters, return and throw are covered, and that it respects the configured style (line length, indentation).
Select a project/package.
Apply automatic refactoring (Right-click > Refactoring or Shift+Alt+Y).
Actual: only opened java files are automatically refactored, yet not saved to disk.
Expected: all java files are automatically refactored and saved to disk.
Replace use of concrete classes with use of interfaces if only the interface methods are called on the variable (when the variable is local to a method).
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.