31576

Automatic code simplification via refactoring [closed]

Question:

Is there a tool for automatic java code simplification via refactoring?

There are such tools for Python and C:

<ul><li><a href="https://stackoverflow.com/questions/14517524/automatically-simplifying-refactoring-python-code-e-g-for-loops-list-compre" rel="nofollow">Automatically simplifying/refactoring Python code (e.g. for loops -> list comprehension)?</a></li> <li><a href="https://stackoverflow.com/questions/7259494/is-there-a-tool-to-test-the-conciseness-of-c-program/7259905#7259905" rel="nofollow">Is there a tool to test the conciseness of c program?</a>) </li> </ul>

but I'm not aware of any such program for Java.

There are many cases where a tool could automatically simplify code, like e.g.:

<ul><li>loops: for (String s: a) { b.add(s); }b.addAll(a);</li> <li>if/return: if (x) return true; else return false;return x;</li> <li>ternary operator: if (x) {result = a;} else {result = b;}result = x ? a : b;</li> <li>automatic refactor to diamond operator / exception multi catch / lambdas</li> <li>lots more...</li> </ul>

The advantage of such automatic refactor is removal of lots of boilerplate lines of code, making it more clean and conceise.

Answer1:

Sure. Check out <a href="http://en.wikipedia.org/wiki/Program_transformation" rel="nofollow">Program Transformation Tools (PTS)</a>. Such tools provide a means to define a grammar, use that grammar to parse source text to ASTs, and prettyprint ASTs back to text. More importantly, the same grammar is used to read <em>source-to-source</em> transformation rules, that allow you to express transformations directly (or express compound transformations in terms of sets of rewrites). Such transformations use the expressed patterns to match against the ASTs, and modify the ASTs; these transformations, being structure based, are not confused by layout or whitespace.

As an example, our DMS Software Reengineering Toolkit let you write rules in the form <em>if you see this, replace it by that</em>, taking the general form:

rule rule_name(pattern_variables) : pattern_syntax_category -> replacement_syntax_category = metaquote pattern_text_in_specified_language metaquote => metaquote replacement_text_in_specified_language metaquote if condition_over_bound_pattern_variables;

where

<ul><li><strong>rule</strong> is syntax introducing a rule,</li> <li><em>rule_name</em> gives the rule a name to distinguish it from other rules,</li> <li><em>pattern_variables</em> is a list of pairs <em>n:c</em> of a pattern variable name <em>n</em> and syntax category <em>c</em> which <em>n</em> must satisfy,</li> <li><em>pattern_syntax_category</em> is a syntax category that the <em>pattern_text</em> must satisfy,</li> <li><em>replacement_syntax_category</em> is a syntax category that the <em>replacement_text</em> must satisfy. Usually, and in all examples given here, the same as <em>pattern_syntax_category</em> ; when using rewrite rules to translate between languages, these often differ because the syntax categories in the languages differ.</li> <li><em>metaquote</em> is the " character, which seperates the rule language syntax from that of the pattern or replacement language syntax</li> <li><em>pattern_text_in_specified_language</em> is a well-formed fragment of the source language, containing pattern variables <em>n</em> written as \n; any match of pattern binds the pattern variables to subtrees. If \n occurs twice in pattern, both instances must be identical.</li> <li><em>replacement_text_in_specified_language</em> is a well-formed fragment of the target langauge. A found pattern is replaced by the replacement, with any pattern variables in the replacement substitued by the bound pattern variable value</li> <li><strong>if</strong> is syntax introducing a condition</li> <li><em>condition_over_bound_pattern_variables</em> is a constraint that the pattern variables must satisfy after a pattern match has been found. This is often used to check context conditions that must be satisified.</li> </ul>

DMS will let you write and apply the following example transformations (including some of OP's examples):

default domain Java~v8; -- specify v8 dialect of Java to manipulate rule reduce_strength_squared(e: term): :product -> product = "\e ^ 2 " ==> "\e * \e " if no_side_effects(e); rule optimize_divide_by_self(e: term): :product -> product = " \e / \e " => " 1 " if is_not_zero(e); rule accumulate_string(n: IDENTIFIER, a: expression, b: left_hand_side) : statement -> statement = "for (String \s: \a) { \b.add(\s); }" => "\b.addAll(\a);"; rule eliminate_useless_if(x: expression, s: statement) : statement -> statement = "if (\x) \s; else \s; " -- generalizes OP's example => "\s;"; rule left_factor_ternary(x: expression; t: left_hand_side; a: expression; b:expression) : statement -> statement = "if (\x) { \t = \a;} else {\t = \b;} " => "\t = \x ? \a : \b "; rule convert_to_diamond( T1: qualified_path, T2: qualified_path, C: qualified_path, i: IDENTIFIER, a: arglist) :statement -> statement = "\T1<\T2> \i = new \C<\T2>(\a);" => "\T1<\T2> \i = new \C<>(\a);" rule merge_multi_catch( b:body, i1: IDENTIFIER, e1: qualified_path, i2: IDENTIFIER, eh: body ) :statement -> statement = "try { \b } catch ( \i1: \e1 ) { \eh } catch ( \i2: \e1 ) { \eh }"; => "try { \b } catch ( \i1, \i2: \e1 ) { \eh }";

More sophisticated transformations are possible, including those that affect parts of the program that are far apart and even across source file boundaries. These usually require some additional metaprogramming (not discussed here) and often some additional checks on the context, e.g., that identifiers are of the right type, etc. [DMS has full symbol tables for Java to support this].

Other PTS can express rules in similar way. Most of them don't provide support for deeper semantic facts such as symbol tables or types, although the claim is that you can program those yourself. Experience shows this is a <em>lot</em> of work, and you really want it to be right. (Who wants their transformation to damage the code because it is operating on bad information?).

Answer2:

I am the author of <a href="http://autorefactor.org" rel="nofollow">AutoRefactor</a>, mentioned by Slanec. All the first refactorings you showed are already implemented, but the following are not yet:

<blockquote> <ul><li>automatic refactor to diamond operator / exception multi catch / lambdas</li> <li>lots more...</li> </ul></blockquote>

See the <a href="https://github.com/JnRouvignac/AutoRefactor/issues" rel="nofollow">open issues</a>, including Java 7 refactorings. For the moment I have only implemented Java 6 compatible refactorings.

Recommend

  • Resteasy (or not Jersey - JAXRS implementation) on WebLogic12c, is possible?
  • Uanble to find dms.jar online to download
  • Simple Injector Prevent Locked Container
  • Mapping BigInteger in YAML file with PlayFramework
  • Customizable Static Java Call-Graph generator?
  • How to convert milliseconds to a date string?
  • XSL to create folders based on attribute
  • Python Pandas Mixed Boolean Yes/True and NaN Columns
  • ADO.NET provider with invariant name 'System.Data.SqlClient;' cannot be found (Entity Fram
  • Append the commit message automatically to the file being committed in Git
  • Conditional serialization with protobuf-net
  • Can I put a + sign in a folder with IIS?
  • disablinging autorecover option for powepoint
  • How does extglob work with shell parameter expansion?
  • How can I stop my python script when another python script is running?
  • Skip Characters in Oracle TO_DATE function
  • how to check the textarea content is blank using javascript?
  • How to initialize context? [closed]
  • Implementation of RTTI using typeid
  • Negating Regex PO BOX
  • Granting permissions to Azure Active Directory Web Application automatically
  • Synchronize windows folders
  • Sensibility of combined Maven/Ant+Ivy build management for dual platform Desktop/Android deployment?
  • In matplotlib, how do you change the fontsize of a single figure?
  • Bootstrap (v3.3.4) glyphicons not displayed in IE when refresh page (F5)
  • How to autopopulate a field in SugarCRM form
  • configure: error: no acceptable C compiler found in $PATH
  • Pycharm: Marking a folder as 'sources root' is not recursive for subfolders
  • DIV instruction jumping to random location?
  • Entity Framework Code First TPC Inheritance Self-Referencing Child Class
  • std::remove_copy_if_ valgrind bytes in block are possibly lost in loss record
  • Eclipse CDT error: Unable to compile
  • OOP Javascript - Is “get property” method necessary?
  • preg_replace Double Spaces to tab (\\t) at the beginning of a line
  • Extracting HTML between tags
  • MongoDB in PHP using aggregate to group by _id is null not working
  • Master page gives error
  • Why HTML5 Canvas with a larger size stretch a drawn line?
  • Redux, normalised entities and lodash merge
  • Unable to use reactive element in my shiny app