├── .gitignore ├── .travis.yml ├── README.asciidoc ├── pom.xml └── src ├── main ├── java │ └── org │ │ └── walkmod │ │ └── refactor │ │ ├── config │ │ ├── ConstantTransformationDictionary.java │ │ ├── ConstantTransformationRule.java │ │ ├── MethodHeaderDeclaration.java │ │ ├── MethodHeaderDeclarationDictionary.java │ │ ├── MethodRefactoringRule.java │ │ ├── RefactorConfigurationController.java │ │ ├── RefactoringRulesDictionary.java │ │ └── RefactoringUtils.java │ │ ├── exceptions │ │ ├── InvalidRefactoringRuleException.java │ │ └── InvalidTypeException.java │ │ └── visitors │ │ ├── ASTTypeNameResolver.java │ │ ├── ClassOrInterfaceRefactor.java │ │ ├── ExpressionRefactor.java │ │ └── MethodRefactor.java ├── license-header.txt └── resources │ └── META-INF │ └── walkmod │ └── walkmod-refactor-plugin.xml └── test ├── java └── org │ └── walkmod │ └── refactor │ └── visitors │ ├── ClassOrInterfaceRefactorTest.java │ └── MethodRefactorTest.java └── resources ├── refactoring-class-config.json ├── refactoring-constants-to-enum.json └── refactoring-methods-config.json /.gitignore: -------------------------------------------------------------------------------- 1 | /.settings/ 2 | /src/test/resources/tmp/ 3 | /target/ 4 | *.classpath 5 | *.project 6 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | jdk: openjdk6 -------------------------------------------------------------------------------- /README.asciidoc: -------------------------------------------------------------------------------- 1 | walkmod-refactor-plugin 2 | ======================= 3 | Raquel Pau 4 | 5 | image:https://travis-ci.org/walkmod/walkmod-refactor-plugin.svg?branch=master["Build Status", link="https://travis-ci.org/walkmod/walkmod-refactor-plugin"] 6 | 7 | This is a http://www.walkmod.com[walkmod] plugin to support refactoring rules (mainly for migrations) in Java source files. 8 | 9 | This plugin is specially useful when you need to upgrade a project dependency (java library), and in the new version, you have found that some methods have changed their names, arguments..; others become deprecated and some classes have been renamed, too. 10 | In this situation, you can spend a lot of time changing those parts of code that stop to compile or update automatically your code with this walkmod plugin :). 11 | 12 | This walkmod plugins reads all your code expressions and rewrite them according the new API of the updraded library. These code expressions are 13 | rewriten according a set of refactoring rules. 14 | 15 | 16 | == Refactoring rules 17 | 18 | This plugin supports two types of refactoring rules: **class refactoring rules** to rewrite those references of classes whose name has changed; and 19 | **method refactoring rules** to rewrite those method calls that have a different name or arguments. 20 | 21 | === Class refactoring rules 22 | 23 | Class refactoring rules are renaming rules for Java classes. To specify class refactoring rules, you need to create a json file, with a simple 24 | json object, whose field names are the old names of Java classes, and their values the new class names. 25 | 26 | For example, imagine you are using a Java library (Maven dependency), which contains a class called `foo.Bar` and you need to upgrade 27 | this library to the newest version, where the class `foo.Bar` has been renamed to `foo.BarDAO`. You need to specify this rule as follows: 28 | ```json 29 | { 30 | "foo.Bar": "foo.BarDAO" 31 | } 32 | ``` 33 | === Method refactoring rules 34 | 35 | Method refactoring rules support three scenarios: 36 | 37 | 1. **Method Renaming**: For those methods that have changed their name. Example: `foo.Bar:execute() => foo.Bar:run()` 38 | 2. **Argument Rules**: For those methods that have changed their arguments (type, order o quantity). For this type of rules, you need to specify 39 | the whole class name and an alias for each argument (e.g `foo.Bar:open(java.io.File file)`). Then, you could use the alias in expressions if 40 | you can derive the new argument type of these methods (e.g `foo.Bar:open(file.getPath())`). The character separator between arguments is the `;`. 41 | 3. **Result Rules**: for those methods that have changed their result type. There is a keyword called `result` to specify how the new 42 | method call must be transformed into a new expression to ensure the code follows the same workflow. For example: `foo.Resource:isOpen() => foo.Resource:isClosed():!result` 43 | 44 | To specify method refactoring rules, you need to create a json file with a simple json oblect, with key-value pairs consisting of 45 | the original method declaration and the new one, as follows: 46 | 47 | ```json 48 | { 49 | "foo.Bar:execute()" : "foo.Bar:run()", 50 | "foo.Bar:open(java.io.File file)" : "foo.Bar:open(file.getPath())", 51 | "foo.Bar:open(java.io.File file; java.lang.Boolean append)" : "foo.Bar:open(file.getPath(); append)", 52 | "foo.Resource:isOpen()" : "foo.Resource:isClosed():!result" 53 | } 54 | ``` 55 | 56 | === Example 57 | 58 | According the previous configurations, if we have the following Java code: 59 | 60 | ```java 61 | public void hello(File file){ 62 | Bar bar = new Bar(); 63 | bar.open(file); 64 | Resource res = bar.getResource(); 65 | if(res.isOpen()){ 66 | ... 67 | } 68 | ... 69 | } 70 | ``` 71 | 72 | It is rewriten to this one: 73 | 74 | ```java 75 | public void hello(File file){ 76 | BarDAO bar = new BarDAO(); 77 | bar.open(file.getPath()); 78 | Resource res = bar.getResource(); 79 | if(!res.isClosed()){ 80 | ... 81 | } 82 | ... 83 | } 84 | ``` 85 | 86 | == Usage 87 | We recommend to use the last version of walkmod because it becomes easier to configure. 88 | 89 | === Walkmod >= 2.2.0 90 | 91 | If your project is build with maven or gradle, you simply need to execute: 92 | 93 | ---- 94 | walkmod add -DrefactoringConfigFile="src/main/walkmod/refactor/refactoring-methods.json" refactor:methods 95 | ---- 96 | 97 | To refactor methods. 98 | 99 | If you need to refactor java classes: 100 | ---- 101 | walkmod add -DrefactoringConfigFile="src/main/walkmod/refactor/refactoring-methods.json" refactor:classes 102 | ---- 103 | 104 | === Previous versions 105 | 1. Add your project build tool (maven or gradle) ad a configuration provider into the `walkmod.xml. 106 | 107 | 2. Add the transformations `org.walkmod:walkmod-refactor-plugin:methods` and `org.walkmod:walkmod-refactor-plugin:classes` into your `walkmod.xml` and 108 | set your refactoring configurations. 109 | 110 | ```XML 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | src/main/walkmod/refactor/refactoring-methods.json 119 | 120 | 121 | src/main/walkmod/refactor/refactoring-classes.json 122 | 123 | 124 | 125 | ``` 126 | 127 | If you decide to store the refactor configurations in the same place than the example, you can avoid define these params. 128 | 129 | 5. Type and execute `walkmod apply` in your shell from your project directory. 130 | 131 | 6. Now, you can upgrade you maven dependency and check if the project compiles :) 132 | 133 | 134 | == Contributing 135 | 136 | If you want to hack on this, fork it, improve it and send me a pull request. 137 | 138 | To get started using it, just clone it and call `mvn install`. 139 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | org.walkmod 5 | walkmod-refactor-plugin 6 | 2.3.3 7 | https://github.com/rpau/walkmod-refactor-plugin 8 | walkmod-refactor-plugin 9 | 10 | 11 | GNU General Public License (GPL v.3) 12 | http://www.gnu.org/licenses/gpl.txt 13 | 14 | 15 | 16 | UTF-8 17 | UTF-8 18 | UTF-8 19 | 20 | 21 | 22 | 23 | org.apache.maven.plugins 24 | maven-compiler-plugin 25 | 2.3.2 26 | 27 | 1.6 28 | 1.6 29 | 30 | 31 | 32 | org.apache.maven.plugins 33 | maven-javadoc-plugin 34 | 35 | 36 | attach-javadocs 37 | 38 | jar 39 | 40 | 41 | 42 | 43 | 44 | org.apache.maven.plugins 45 | maven-source-plugin 46 | 47 | 48 | attach-sources 49 | 50 | jar 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | org.walkmod 60 | javalang-compiler 61 | [2.0, 3.0) 62 | 63 | 64 | junit 65 | junit 66 | 4.12 67 | test 68 | 69 | 70 | org.walkmod 71 | walkmod-core 72 | [2.0.0, 3.0.0) 73 | 74 | 75 | 76 | 77 | default-tools.jar 78 | 79 | 80 | java.vendor 81 | Sun Microsystems Inc. 82 | 83 | 84 | 85 | 86 | com.sun 87 | tools 88 | 1.4.2 89 | system 90 | ${java.home}/../lib/tools.jar 91 | 92 | 93 | 94 | 95 | 96 | https://github.com/rpau/walkmod-refactor-plugin.git 97 | https://github.com/rpau/walkmod-refactor-plugin.git 98 | 99 | 100 | 101 | rpau 102 | rpau 103 | raquelpau@gmail.com 104 | 105 | 106 | acoroleu 107 | acoroleu 108 | acoroleu@gmail.com 109 | 110 | 111 | Visitors for refactoring (migration) purposes (i.e upgrade a third-party API). 112 | -------------------------------------------------------------------------------- /src/main/java/org/walkmod/refactor/config/ConstantTransformationDictionary.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2013 Raquel Pau and Albert Coroleu. 3 | 4 | Walkmod is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Lesser General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | Walkmod is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Lesser General Public License for more details. 13 | 14 | You should have received a copy of the GNU Lesser General Public License 15 | along with Walkmod. If not, see .*/ 16 | package org.walkmod.refactor.config; 17 | 18 | import java.util.Collection; 19 | import java.util.LinkedList; 20 | import java.util.Map; 21 | import java.util.Map.Entry; 22 | 23 | import org.walkmod.javalang.ast.expr.Expression; 24 | 25 | 26 | 27 | public class ConstantTransformationDictionary { 28 | 29 | private Collection constantTransformations = new LinkedList(); 30 | 31 | public Expression get(String originalValue, String targetType){ 32 | for(ConstantTransformationRule transformation : constantTransformations){ 33 | if(transformation.match(originalValue, targetType)){ 34 | return transformation.getTargetASTExpr(); 35 | } 36 | } 37 | return null; 38 | } 39 | 40 | public Collection get(String originalValue){ 41 | Collection result = new LinkedList(); 42 | for(ConstantTransformationRule transformation : constantTransformations){ 43 | if(transformation.matchOriginalValue(originalValue)){ 44 | result.add(transformation.getTargetASTExpr()); 45 | } 46 | } 47 | return result; 48 | } 49 | 50 | public void addAll(Map transformations) { 51 | for(Entry entry : transformations.entrySet()){ 52 | ConstantTransformationRule rule = new ConstantTransformationRule(); 53 | rule.setSourceConstantExpr(entry.getKey()); 54 | rule.setTargetConstantExpr(entry.getValue()); 55 | constantTransformations.add(rule); 56 | } 57 | } 58 | 59 | public boolean hasEnumTransformation(String originalValue){ 60 | 61 | for(ConstantTransformationRule transformation : constantTransformations){ 62 | if(transformation.matchOriginalValue(originalValue)){ 63 | return transformation.isEnum(); 64 | } 65 | } 66 | return false; 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/org/walkmod/refactor/config/ConstantTransformationRule.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2013 Raquel Pau and Albert Coroleu. 3 | 4 | Walkmod is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Lesser General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | Walkmod is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Lesser General Public License for more details. 13 | 14 | You should have received a copy of the GNU Lesser General Public License 15 | along with Walkmod. If not, see .*/ 16 | package org.walkmod.refactor.config; 17 | 18 | import org.walkmod.exceptions.WalkModException; 19 | import org.walkmod.javalang.ASTManager; 20 | import org.walkmod.javalang.ParseException; 21 | import org.walkmod.javalang.ast.expr.Expression; 22 | import org.walkmod.javalang.ast.expr.FieldAccessExpr; 23 | import org.walkmod.javalang.ast.expr.NameExpr; 24 | 25 | public class ConstantTransformationRule { 26 | 27 | private String sourceConstantExpr; 28 | 29 | private String targetConstantExpr; 30 | 31 | private boolean isEnum = false; 32 | 33 | public String getSourceConstantExpr() { 34 | return sourceConstantExpr; 35 | } 36 | 37 | public void setSourceConstantExpr(String sourceConstantExpr) { 38 | this.sourceConstantExpr = sourceConstantExpr; 39 | } 40 | 41 | public String getTargetConstantExpr() { 42 | return targetConstantExpr; 43 | } 44 | 45 | public Expression getTargetASTExpr() { 46 | try { 47 | return (Expression) ASTManager.parse(Expression.class, 48 | targetConstantExpr); 49 | 50 | } catch (ParseException e) { 51 | throw new WalkModException(e); 52 | } 53 | } 54 | 55 | public void setTargetConstantExpr(String targetConstantExpr) { 56 | try { 57 | if (targetConstantExpr.contains("enum ")) { 58 | isEnum = true; 59 | targetConstantExpr = targetConstantExpr.replace("enum ", ""); 60 | } 61 | Expression targetASTExpr = (Expression) ASTManager.parse( 62 | Expression.class, targetConstantExpr); 63 | if (!(targetASTExpr instanceof FieldAccessExpr) 64 | && !(targetASTExpr instanceof NameExpr)) { 65 | 66 | throw new WalkModException( 67 | "The target rule expression is invalid " 68 | + targetConstantExpr); 69 | } 70 | this.targetConstantExpr = targetConstantExpr; 71 | } catch (ParseException e) { 72 | 73 | throw new WalkModException(e); 74 | } 75 | } 76 | 77 | public boolean matchOriginalValue(String originalValue) { 78 | return sourceConstantExpr.equals(originalValue); 79 | } 80 | 81 | public boolean match(String originalValue, String targetType) { 82 | 83 | int index = targetConstantExpr.lastIndexOf("."); 84 | String aux = targetConstantExpr; 85 | if (index != -1) { 86 | aux = aux.substring(0, index); 87 | } 88 | return originalValue.equals(sourceConstantExpr) 89 | && targetType.equals(aux); 90 | } 91 | 92 | public boolean isEnum() { 93 | return isEnum; 94 | } 95 | 96 | } 97 | -------------------------------------------------------------------------------- /src/main/java/org/walkmod/refactor/config/MethodHeaderDeclaration.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2013 Raquel Pau and Albert Coroleu. 3 | 4 | Walkmod is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Lesser General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | Walkmod is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Lesser General Public License for more details. 13 | 14 | You should have received a copy of the GNU Lesser General Public License 15 | along with Walkmod. If not, see .*/ 16 | package org.walkmod.refactor.config; 17 | 18 | import java.util.LinkedList; 19 | import java.util.List; 20 | 21 | import org.walkmod.javalang.ast.body.Parameter; 22 | import org.walkmod.javalang.ast.type.ClassOrInterfaceType; 23 | import org.walkmod.javalang.ast.type.Type; 24 | import org.walkmod.javalang.compiler.symbols.SymbolType; 25 | import org.walkmod.refactor.visitors.ASTTypeNameResolver; 26 | 27 | 28 | public class MethodHeaderDeclaration { 29 | 30 | private String scope; 31 | 32 | private String name; 33 | 34 | private List args = new LinkedList(); 35 | 36 | private List exceptions; 37 | 38 | private Type result; 39 | 40 | private int modifiers; 41 | 42 | 43 | public String getScope() { 44 | return scope; 45 | } 46 | 47 | public void setScope(String scope) { 48 | this.scope = scope; 49 | } 50 | 51 | public String getName() { 52 | return name; 53 | } 54 | 55 | public void setName(String name) { 56 | this.name = name; 57 | } 58 | 59 | public List getArgs() { 60 | return args; 61 | } 62 | 63 | public void setArgs(List args) { 64 | if (args != null) { 65 | this.args = args; 66 | } 67 | } 68 | 69 | public SymbolType[] getArgTypeClasses() throws ClassNotFoundException { 70 | SymbolType[] res = new SymbolType[this.args.size()]; 71 | int i = 0; 72 | for (Parameter type : getArgs()) { 73 | Type t = type.getType(); 74 | res[i] = ASTTypeNameResolver.getInstance().valueOf(t); 75 | i++; 76 | } 77 | return res; 78 | } 79 | 80 | public List getExceptions() { 81 | return exceptions; 82 | } 83 | 84 | public void setExceptions(List exceptions) { 85 | this.exceptions = exceptions; 86 | } 87 | 88 | public Type getResult() { 89 | return result; 90 | } 91 | 92 | public void setResult(Type result) { 93 | this.result = result; 94 | } 95 | 96 | public int getModifiers() { 97 | return modifiers; 98 | } 99 | 100 | public void setModifiers(int modifiers) { 101 | this.modifiers = modifiers; 102 | } 103 | 104 | } 105 | -------------------------------------------------------------------------------- /src/main/java/org/walkmod/refactor/config/MethodHeaderDeclarationDictionary.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2013 Raquel Pau and Albert Coroleu. 3 | 4 | Walkmod is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Lesser General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | Walkmod is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Lesser General Public License for more details. 13 | 14 | You should have received a copy of the GNU Lesser General Public License 15 | along with Walkmod. If not, see .*/ 16 | package org.walkmod.refactor.config; 17 | 18 | import java.util.Arrays; 19 | import java.util.Collection; 20 | import java.util.Collections; 21 | import java.util.HashMap; 22 | import java.util.Iterator; 23 | import java.util.LinkedList; 24 | import java.util.List; 25 | import java.util.Map; 26 | 27 | import org.walkmod.javalang.ASTManager; 28 | import org.walkmod.javalang.ParseException; 29 | import org.walkmod.javalang.ast.body.MethodDeclaration; 30 | import org.walkmod.javalang.ast.body.Parameter; 31 | import org.walkmod.javalang.compiler.symbols.ASTSymbolTypeResolver; 32 | 33 | public class MethodHeaderDeclarationDictionary implements 34 | Collection { 35 | 36 | private Collection methods = new LinkedList(); 37 | 38 | private Map> dictionary = new HashMap>(); 39 | 40 | private ClassLoader classLoader; 41 | 42 | public MethodHeaderDeclarationDictionary(){ 43 | 44 | } 45 | 46 | public void setClassLoader(ClassLoader classLoader){ 47 | this.classLoader = classLoader; 48 | } 49 | 50 | public MethodHeaderDeclarationDictionary(ClassLoader classLoader){ 51 | this.classLoader = classLoader; 52 | } 53 | 54 | public MethodHeaderDeclaration parse(String methodHeaderDeclaration) 55 | throws ParseException { 56 | 57 | if (methodHeaderDeclaration != null 58 | && !methodHeaderDeclaration.trim().equals("")) { 59 | 60 | int indexMethod = methodHeaderDeclaration.indexOf("#"); 61 | 62 | if (indexMethod != -1) { 63 | indexMethod++; 64 | } else { 65 | throw new ParseException("Error Any scope has been defined in " 66 | + methodHeaderDeclaration); 67 | 68 | } 69 | String scope = methodHeaderDeclaration 70 | .substring(0, indexMethod - 1); 71 | 72 | String method = methodHeaderDeclaration.substring(indexMethod) 73 | + ";"; 74 | 75 | MethodDeclaration md = (MethodDeclaration) ASTManager.parse( 76 | MethodDeclaration.class, method); 77 | 78 | MethodHeaderDeclaration mhd = new MethodHeaderDeclaration(); 79 | 80 | mhd.setName(md.getName()); 81 | mhd.setModifiers(md.getModifiers()); 82 | mhd.setScope(scope); 83 | mhd.setArgs(md.getParameters()); 84 | mhd.setExceptions(md.getThrows()); 85 | mhd.setResult(md.getType()); 86 | return mhd; 87 | 88 | } 89 | return null; 90 | } 91 | 92 | public boolean add(String methodDeclaration) throws ParseException { 93 | 94 | MethodHeaderDeclaration md = parse(methodDeclaration); 95 | 96 | String method = md.getName(); 97 | String scope = md.getScope(); 98 | String key = method; 99 | if (scope != null && !"".equals(scope.trim())) { 100 | key = scope + "#" + key; 101 | } 102 | Collection value = dictionary.get(key); 103 | if (value == null) { 104 | value = new LinkedList(); 105 | } 106 | value.add(md); 107 | dictionary.remove(key); 108 | dictionary.put(key, value); 109 | return methods.add(md); 110 | 111 | } 112 | 113 | public Collection get(String scope) { 114 | 115 | Collection result = new LinkedList(); 116 | 117 | for (MethodHeaderDeclaration mhd : methods) { 118 | 119 | if (mhd.getScope().equals(scope)) { 120 | result.add(mhd); 121 | } 122 | } 123 | 124 | return result; 125 | } 126 | 127 | public Collection getAllMethods(String scope) { 128 | Collection result = new LinkedList(); 129 | Class c = null; 130 | 131 | try { 132 | c = Class.forName(scope, false, classLoader); 133 | 134 | } catch (ClassNotFoundException e) { 135 | 136 | return result; 137 | } 138 | 139 | for (MethodHeaderDeclaration mhd : methods) { 140 | 141 | try { 142 | 143 | if ( Class.forName(mhd.getScope(), false, classLoader).isAssignableFrom(c)) { 144 | result.add(mhd); 145 | } 146 | } catch (ClassNotFoundException e) { 147 | // Do nothing. Analyze the next item. 148 | } 149 | 150 | } 151 | return result; 152 | } 153 | 154 | public MethodHeaderDeclaration get(String scope, String method, 155 | String[] args) { 156 | if (args == null) { 157 | List emptyList = Collections.emptyList(); 158 | return get(scope, method, emptyList); 159 | } 160 | return get(scope, method, Arrays.asList(args)); 161 | 162 | } 163 | 164 | public MethodHeaderDeclaration get(String scope, String method, 165 | List args) { 166 | String key = method; 167 | if (scope != null && !"".equals(scope.trim())) { 168 | key = scope + "#" + key; 169 | } 170 | 171 | Collection value = dictionary.get(key); 172 | if (value == null) { 173 | return null; 174 | } else if (value.size() == 1) { 175 | return value.iterator().next(); 176 | } else { 177 | 178 | for (MethodHeaderDeclaration md : value) { 179 | List margs = md.getArgs(); 180 | Iterator it = args.iterator(); 181 | Iterator it2 = margs.iterator(); 182 | boolean equals = true; 183 | // la comparacion se hace por igualdad porque este diccionario 184 | // se usa en target donde no tengo el classpath 185 | while (it.hasNext() && it2.hasNext() && equals) { 186 | 187 | Parameter tp = it2.next(); 188 | 189 | equals = it.next().equals(ASTSymbolTypeResolver.getInstance().valueOf(tp.getType())); 190 | } 191 | if (equals) { 192 | return md; 193 | } 194 | } 195 | return null; 196 | } 197 | } 198 | 199 | public boolean contains(String scope, String method, List args) { 200 | return get(scope, method, args) != null; 201 | } 202 | 203 | public boolean contains(String scope, String method, String[] args) { 204 | return get(scope, method, args) != null; 205 | } 206 | 207 | @Override 208 | public int size() { 209 | return methods.size(); 210 | } 211 | 212 | @Override 213 | public boolean isEmpty() { 214 | return methods.isEmpty(); 215 | } 216 | 217 | @Override 218 | public boolean contains(Object o) { 219 | return methods.contains(o); 220 | } 221 | 222 | @Override 223 | public Iterator iterator() { 224 | return methods.iterator(); 225 | } 226 | 227 | @Override 228 | public Object[] toArray() { 229 | return methods.toArray(); 230 | } 231 | 232 | @Override 233 | public T[] toArray(T[] a) { 234 | return methods.toArray(a); 235 | } 236 | 237 | @Override 238 | public boolean add(MethodHeaderDeclaration e) { 239 | return methods.add(e); 240 | } 241 | 242 | @Override 243 | public boolean remove(Object o) { 244 | return methods.remove(o); 245 | } 246 | 247 | @Override 248 | public boolean containsAll(Collection c) { 249 | return methods.containsAll(c); 250 | } 251 | 252 | @Override 253 | public boolean addAll(Collection c) { 254 | 255 | return methods.addAll(c); 256 | } 257 | 258 | @Override 259 | public boolean removeAll(Collection c) { 260 | return methods.removeAll(c); 261 | } 262 | 263 | @Override 264 | public boolean retainAll(Collection c) { 265 | return methods.retainAll(c); 266 | } 267 | 268 | @Override 269 | public void clear() { 270 | methods.clear(); 271 | } 272 | 273 | 274 | } 275 | -------------------------------------------------------------------------------- /src/main/java/org/walkmod/refactor/config/MethodRefactoringRule.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2013 Raquel Pau and Albert Coroleu. 3 | 4 | Walkmod is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Lesser General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | Walkmod is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Lesser General Public License for more details. 13 | 14 | You should have received a copy of the GNU Lesser General Public License 15 | along with Walkmod. If not, see .*/ 16 | 17 | package org.walkmod.refactor.config; 18 | 19 | import java.util.LinkedList; 20 | import java.util.List; 21 | 22 | import org.walkmod.javalang.ASTManager; 23 | import org.walkmod.javalang.ParseException; 24 | import org.walkmod.javalang.ast.body.Parameter; 25 | import org.walkmod.javalang.ast.expr.Expression; 26 | import org.walkmod.javalang.ast.type.ClassOrInterfaceType; 27 | import org.walkmod.javalang.ast.type.ReferenceType; 28 | import org.walkmod.javalang.ast.type.VoidType; 29 | import org.walkmod.javalang.compiler.symbols.SymbolType; 30 | import org.walkmod.refactor.visitors.ASTTypeNameResolver; 31 | 32 | public class MethodRefactoringRule { 33 | 34 | private MethodHeaderDeclaration sourceMethod; 35 | 36 | private MethodHeaderDeclaration targetMethod; 37 | 38 | private List variables = new LinkedList(); 39 | 40 | private List expressions = new LinkedList(); 41 | 42 | private Boolean isConstant = true; 43 | 44 | private String resultExpression; 45 | 46 | private String resultVariable = "result"; 47 | 48 | private String implicitVaribale = "this"; 49 | 50 | private String implicitExpression; 51 | 52 | 53 | public MethodRefactoringRule(ClassLoader classLoader) { 54 | sourceMethod = new MethodHeaderDeclaration(); 55 | targetMethod = new MethodHeaderDeclaration(); 56 | } 57 | 58 | public String getScope() { 59 | return targetMethod.getScope(); 60 | } 61 | 62 | public void setScope(String scope) { 63 | this.targetMethod.setScope(scope); 64 | } 65 | 66 | /** 67 | * Ha de crear una instancia nueva de expresion por cada string que describe 68 | * la expr 69 | * 70 | * @return 71 | * @throws ParseException 72 | */ 73 | public List getExpressionTreeArgs() throws ParseException { 74 | List res = new LinkedList(); 75 | for (String expression : expressions) { 76 | res.add((Expression) ASTManager.parse(Expression.class, expression)); 77 | } 78 | return res; 79 | } 80 | 81 | public Expression getResultTreeExpression() throws ParseException { 82 | return (Expression) ASTManager.parse(Expression.class, resultExpression); 83 | } 84 | 85 | public Expression getImplicitTreeExpression() throws ParseException { 86 | return (Expression) ASTManager.parse(Expression.class, implicitExpression); 87 | } 88 | 89 | public void setResultExpression(String resultExpression) { 90 | if ("void".equals(resultExpression)) { 91 | targetMethod.setResult(new VoidType()); 92 | } 93 | else if(resultExpression != null && resultExpression.startsWith("void")){ 94 | this.resultExpression = resultExpression.substring("void".length()); 95 | targetMethod.setResult(new VoidType()); 96 | } 97 | else { 98 | this.resultExpression = resultExpression; 99 | } 100 | } 101 | 102 | public boolean isVoidResult() { 103 | return targetMethod.getResult() != null 104 | && targetMethod.getResult().toString().equals("void"); 105 | } 106 | 107 | public String getResultVariable() { 108 | return resultVariable; 109 | } 110 | 111 | public void setResultVariable(String resultVariable) { 112 | this.resultVariable = resultVariable; 113 | } 114 | 115 | public void setExpressions(List expressions) { 116 | this.expressions = expressions; 117 | } 118 | 119 | public Boolean getIsConstant() { 120 | return isConstant; 121 | } 122 | 123 | public void setIsConstant(Boolean isConstant) { 124 | this.isConstant = isConstant; 125 | } 126 | 127 | public String getMethodName() { 128 | return targetMethod.getName(); 129 | } 130 | 131 | public void setMethodName(String methodName) { 132 | this.targetMethod.setName(methodName); 133 | } 134 | 135 | public List getVariables() { 136 | return variables; 137 | } 138 | 139 | public void setVariables(List variables) { 140 | this.variables = variables; 141 | } 142 | 143 | public boolean hasResultExpression() { 144 | return resultExpression != null; 145 | } 146 | 147 | public boolean hasImplicitExpression() { 148 | return implicitExpression != null; 149 | } 150 | 151 | public SymbolType[] getArgTypes() { 152 | List params = sourceMethod.getArgs(); 153 | SymbolType[] result = new SymbolType[params.size()]; 154 | int i = 0; 155 | for (Parameter tp : params) { 156 | result[i]= ASTTypeNameResolver.getInstance().valueOf(tp.getType()); 157 | i++; 158 | } 159 | return result; 160 | } 161 | 162 | public void setArgTypes(List argTypes) { 163 | List result = new LinkedList(); 164 | for (String arg : argTypes) { 165 | Parameter tp = new Parameter(); 166 | ReferenceType rt = new ReferenceType(); 167 | ClassOrInterfaceType cit = new ClassOrInterfaceType(arg); 168 | rt.setType(cit); 169 | tp.setType(rt); 170 | result.add(tp); 171 | } 172 | this.sourceMethod.setArgs(result); 173 | } 174 | 175 | public String getSourceScope() { 176 | return sourceMethod.getScope(); 177 | } 178 | 179 | public void setSourceScope(String sourceScope) { 180 | this.sourceMethod.setScope(sourceScope); 181 | } 182 | 183 | public String getSourceMethodName() { 184 | return sourceMethod.getName(); 185 | } 186 | 187 | public void setSourceMethodName(String sourceMethodName) { 188 | this.sourceMethod.setName(sourceMethodName); 189 | } 190 | 191 | public SymbolType[] getArgTypeClasses() throws ClassNotFoundException { 192 | return sourceMethod.getArgTypeClasses(); 193 | } 194 | 195 | 196 | 197 | public String getImplicitVaribale() { 198 | return implicitVaribale; 199 | } 200 | 201 | public void setImplicitVaribale(String implicitVaribale) { 202 | this.implicitVaribale = implicitVaribale; 203 | } 204 | 205 | public String getImplicitExpression() { 206 | return implicitExpression; 207 | } 208 | 209 | public void setImplicitExpression(String implicitExpression) { 210 | this.implicitExpression = implicitExpression; 211 | } 212 | 213 | 214 | } 215 | -------------------------------------------------------------------------------- /src/main/java/org/walkmod/refactor/config/RefactorConfigurationController.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2013 Raquel Pau and Albert Coroleu. 3 | 4 | Walkmod is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Lesser General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | Walkmod is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Lesser General Public License for more details. 13 | 14 | You should have received a copy of the GNU Lesser General Public License 15 | along with Walkmod. If not, see .*/ 16 | package org.walkmod.refactor.config; 17 | 18 | import java.lang.reflect.Method; 19 | import java.util.Collection; 20 | import java.util.HashMap; 21 | import java.util.Iterator; 22 | import java.util.LinkedList; 23 | import java.util.List; 24 | import java.util.Map; 25 | 26 | import org.walkmod.conf.entities.ChainConfig; 27 | import org.walkmod.conf.entities.Configuration; 28 | import org.walkmod.conf.entities.TransformationConfig; 29 | import org.walkmod.conf.entities.WalkerConfig; 30 | import org.walkmod.conf.entities.impl.ChainConfigImpl; 31 | import org.walkmod.conf.entities.impl.TransformationConfigImpl; 32 | import org.walkmod.conf.entities.impl.WalkerConfigImpl; 33 | import org.walkmod.javalang.visitors.VoidVisitor; 34 | import org.walkmod.refactor.visitors.MethodRefactor; 35 | import org.walkmod.walkers.VisitorContext; 36 | 37 | public class RefactorConfigurationController { 38 | 39 | private ChainConfigImpl createChainConfig(Configuration conf, String chainName, ChainConfig currentCC, 40 | Map refactoringRules, Map> refactoringVisitors) { 41 | Collection chains = conf.getChainConfigs(); 42 | ChainConfigImpl cc = new ChainConfigImpl(); 43 | cc.setName(chainName); 44 | cc.setReaderConfig(currentCC.getReaderConfig()); 45 | WalkerConfig wc = new WalkerConfigImpl(); 46 | WalkerConfig currentWC = currentCC.getWalkerConfig(); 47 | wc.setParserConfig(currentWC.getParserConfig()); 48 | wc.setType(currentWC.getType()); 49 | wc.setRootNamespace(currentWC.getRootNamespace()); 50 | List transformations = new LinkedList(); 51 | TransformationConfig tc = new TransformationConfigImpl(); 52 | tc.setType(MethodRefactor.class.getName()); 53 | 54 | Map parameters = new HashMap(); 55 | 56 | parameters.put("refactoringRules", refactoringRules); 57 | parameters.put("refactoringVisitors", refactoringVisitors); 58 | tc.setParameters(parameters); 59 | transformations.add(tc); 60 | wc.setTransformations(transformations); 61 | cc.setWalkerConfig(wc); 62 | cc.setWriterConfig(currentCC.getWriterConfig()); 63 | LinkedList newChains = new LinkedList(chains); 64 | newChains.add(cc); 65 | conf.setChainConfigs(newChains); 66 | 67 | return cc; 68 | } 69 | 70 | private ChainConfig findChainConfig(String chainName, VisitorContext ctx) { 71 | Configuration conf = ctx.getArchitectureConfig().getConfiguration(); 72 | Collection chains = conf.getChainConfigs(); 73 | 74 | Iterator it = chains.iterator(); 75 | ChainConfig cc = null; 76 | while (it.hasNext() && cc == null) { 77 | ChainConfig next = it.next(); 78 | String name = next.getName(); 79 | if (chainName.equals(name)) { 80 | cc = next; 81 | } 82 | } 83 | return cc; 84 | } 85 | 86 | private TransformationConfig findTransformationConfig(ChainConfig cc) { 87 | List transformations = cc.getWalkerConfig().getTransformations(); 88 | Iterator itTransf = transformations.iterator(); 89 | TransformationConfig tc = null; 90 | 91 | while (itTransf.hasNext() && tc == null) { 92 | TransformationConfig next = itTransf.next(); 93 | if (MethodRefactor.class.getName().equals(next.getType())) { 94 | tc = next; 95 | } 96 | } 97 | return tc; 98 | } 99 | 100 | public Map getMethodRefactorRules(VisitorContext ctx) { 101 | ChainConfig currentCC = ctx.getArchitectureConfig(); 102 | Map refactoringRules = new HashMap(); 103 | if (currentCC.getName() == null) { 104 | currentCC.setName("default"); 105 | } 106 | String chainName = currentCC.getName() + "_refactor_gen"; 107 | Configuration conf = ctx.getArchitectureConfig().getConfiguration(); 108 | 109 | ChainConfig cc = findChainConfig(chainName, ctx); 110 | 111 | if (cc == null) { 112 | cc = createChainConfig(conf, chainName, currentCC, refactoringRules, new HashMap>()); 113 | 114 | } else { 115 | 116 | TransformationConfig tc = findTransformationConfig(cc); 117 | 118 | if (tc != null) { 119 | Map parameters = tc.getParameters(); 120 | refactoringRules = (Map) parameters.get("refactoringRules"); 121 | } else { 122 | List transformations = cc.getWalkerConfig().getTransformations(); 123 | tc = new TransformationConfigImpl(); 124 | tc.setType(MethodRefactor.class.getName()); 125 | Map parameters = new HashMap(); 126 | 127 | parameters.put("refactoringRules", refactoringRules); 128 | tc.setParameters(parameters); 129 | transformations.add(tc); 130 | } 131 | 132 | } 133 | return refactoringRules; 134 | } 135 | 136 | public Map> getRefactoringVisitors(VisitorContext ctx) { 137 | ChainConfig currentCC = ctx.getArchitectureConfig(); 138 | Map> refactoringVisitors = new HashMap>(); 139 | if (currentCC.getName() == null) { 140 | currentCC.setName("default"); 141 | } 142 | String chainName = currentCC.getName() + "_refactor_gen"; 143 | Configuration conf = ctx.getArchitectureConfig().getConfiguration(); 144 | 145 | ChainConfig cc = findChainConfig(chainName, ctx); 146 | 147 | if (cc == null) { 148 | cc = createChainConfig(conf, chainName, currentCC, new HashMap(), refactoringVisitors); 149 | 150 | } else { 151 | 152 | TransformationConfig tc = findTransformationConfig(cc); 153 | 154 | if (tc != null) { 155 | Map parameters = tc.getParameters(); 156 | refactoringVisitors = (Map>) parameters.get("refactoringVisitors"); 157 | } else { 158 | List transformations = cc.getWalkerConfig().getTransformations(); 159 | tc = new TransformationConfigImpl(); 160 | tc.setType(MethodRefactor.class.getName()); 161 | Map parameters = new HashMap(); 162 | 163 | parameters.put("refactoringVisitors", refactoringVisitors); 164 | tc.setParameters(parameters); 165 | transformations.add(tc); 166 | } 167 | 168 | } 169 | return refactoringVisitors; 170 | } 171 | } 172 | -------------------------------------------------------------------------------- /src/main/java/org/walkmod/refactor/config/RefactoringRulesDictionary.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2013 Raquel Pau and Albert Coroleu. 3 | 4 | Walkmod is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Lesser General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | Walkmod is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Lesser General Public License for more details. 13 | 14 | You should have received a copy of the GNU Lesser General Public License 15 | along with Walkmod. If not, see .*/ 16 | package org.walkmod.refactor.config; 17 | 18 | import java.util.Arrays; 19 | import java.util.Collection; 20 | import java.util.Iterator; 21 | import java.util.LinkedList; 22 | import java.util.List; 23 | import java.util.Map; 24 | import java.util.Map.Entry; 25 | 26 | import org.apache.log4j.Logger; 27 | import org.walkmod.javalang.compiler.symbols.SymbolType; 28 | import org.walkmod.refactor.exceptions.InvalidRefactoringRuleException; 29 | 30 | 31 | public class RefactoringRulesDictionary { 32 | 33 | private Collection refactoringRules; 34 | 35 | 36 | 37 | private static Logger log = Logger.getLogger(RefactoringRulesDictionary.class); 38 | 39 | private ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); 40 | 41 | public RefactoringRulesDictionary(ClassLoader classLoader) { 42 | refactoringRules = new LinkedList(); 43 | this.classLoader = classLoader; 44 | } 45 | 46 | public MethodRefactoringRule getRefactoringRule(SymbolType scopeType, 47 | String method, SymbolType[] args) throws ClassNotFoundException { 48 | 49 | if (scopeType == null) { 50 | throw new IllegalArgumentException("scopeType is null"); 51 | } 52 | if (method == null) { 53 | throw new IllegalArgumentException("method is null"); 54 | } 55 | 56 | Iterator it = refactoringRules.iterator(); 57 | 58 | while (it.hasNext()) { 59 | 60 | MethodRefactoringRule current = it.next(); 61 | SymbolType st = new SymbolType(current.getSourceScope()); 62 | 63 | if (st.isCompatible(scopeType)) { 64 | 65 | if (current.getSourceMethodName().equals(method)) { 66 | 67 | SymbolType[] argTypes = current.getArgTypes(); 68 | 69 | boolean compatible = args.length == argTypes.length; 70 | 71 | int i = 0; 72 | while(compatible && i < args.length){ 73 | compatible = args[i].isCompatible(argTypes[i]); 74 | i++; 75 | } 76 | 77 | if (compatible) { 78 | 79 | return current; 80 | } 81 | } 82 | 83 | } 84 | } 85 | return null; 86 | } 87 | 88 | public void putRules(Map refactoringRules) 89 | throws InvalidRefactoringRuleException { 90 | 91 | String key, value; 92 | MethodRefactoringRule rule; 93 | 94 | int ruleNumber = 0; 95 | for (Entry entry : refactoringRules.entrySet()) { 96 | 97 | log.info(ruleNumber+": for "+entry.getKey()); 98 | ruleNumber++; 99 | key = entry.getKey(); 100 | value = entry.getValue(); 101 | 102 | rule = new MethodRefactoringRule(classLoader); 103 | 104 | // source scope 105 | int parentScopeIndex = key.indexOf(':'); 106 | if (parentScopeIndex == -1) { 107 | throw new InvalidRefactoringRuleException( 108 | "Invalid rule format. " 109 | + "The scope cannot be parsed for the rule:<" 110 | + key + " => " + value 111 | + ">. Please verify the documentation"); 112 | } 113 | String scope = key.substring(0, parentScopeIndex); 114 | 115 | rule.setSourceScope(scope); 116 | 117 | int scopeIndex = value.indexOf(':'); 118 | if (scopeIndex == -1) { 119 | throw new InvalidRefactoringRuleException( 120 | "Invalid rule format. " 121 | + "The scope cannot be parsed for the rule:<" 122 | + key + " => " + value 123 | + ">. Please verify the documentation"); 124 | } 125 | scope = value.substring(0, scopeIndex); 126 | rule.setScope(scope); 127 | 128 | // scope 129 | int implicitIndex = scope.indexOf('['); 130 | if (implicitIndex != -1) { 131 | 132 | String implicitExpression = scope.substring(implicitIndex + 1, 133 | scope.indexOf(']')); 134 | 135 | rule.setImplicitExpression(implicitExpression); 136 | scope = value.substring(0, implicitIndex); 137 | rule.setScope(scope); 138 | } 139 | 140 | int methodIndex = key.indexOf('(', parentScopeIndex); 141 | if (methodIndex == -1) { 142 | 143 | throw new InvalidRefactoringRuleException( 144 | "Invalid rule format. " 145 | + "The method cannot be parsed for the rule: <" 146 | + key + " => " + value 147 | + ">. Please verify the documentation"); 148 | } 149 | String method = key.substring(parentScopeIndex + 1, methodIndex); 150 | rule.setSourceMethodName(method); 151 | 152 | // method 153 | int parentIndex = value.indexOf('(', scopeIndex); 154 | if (parentIndex == -1) { 155 | 156 | throw new InvalidRefactoringRuleException( 157 | "Invalid rule format. " 158 | + "The method cannot be parsed for the rule: <" 159 | + key + " => " + value 160 | + ">. Please verify the documentation"); 161 | } 162 | method = value.substring(scopeIndex + 1, parentIndex); 163 | rule.setMethodName(method); 164 | 165 | // result 166 | int resultIndex = value.indexOf(':', parentIndex); 167 | if (resultIndex > parentIndex) { 168 | String resultExpr = value.substring(resultIndex + 1); 169 | rule.setResultExpression(resultExpr); 170 | } else { 171 | resultIndex = value.length(); 172 | } 173 | 174 | // param expressions 175 | String args = value.substring(parentIndex + 1, resultIndex - 1); 176 | if (args.trim().length() > 0) { 177 | String[] expressions = args.split(";"); 178 | rule.setExpressions(Arrays.asList(expressions)); 179 | } 180 | 181 | scopeIndex = key.indexOf(':'); 182 | 183 | if (scopeIndex == -1) { 184 | throw new InvalidRefactoringRuleException( 185 | "Invalid rule format. " 186 | + "The scope cannot be parsed for the rule:<" 187 | + key + " => " + value 188 | + ">. Please verify the documentation"); 189 | } 190 | 191 | // variables 192 | int startIndex = key.indexOf('(', scopeIndex); 193 | 194 | if (startIndex == -1) { 195 | throw new InvalidRefactoringRuleException( 196 | "Invalid rule format. " 197 | + "The args cannot be parsed for the rule:<" 198 | + key + " => " + value 199 | + ">. Please verify the documentation"); 200 | } 201 | 202 | String argExpressions = key.substring(startIndex + 1, 203 | key.length() - 1); 204 | if (!argExpressions.isEmpty()) { 205 | String[] argExpr = argExpressions.split(";"); 206 | String[] variables = new String[argExpr.length]; 207 | List argTypes = new LinkedList(); 208 | for (int i = 0; i < variables.length; i++) { 209 | int varIndex = argExpr[i].lastIndexOf(" "); 210 | if (varIndex == -1) { 211 | throw new InvalidRefactoringRuleException( 212 | "Invalid rule format. " 213 | + "The variables cannot be parsed for the rule:<" 214 | + key + " => " + value 215 | + ">. Please verify the documentation"); 216 | } 217 | String type = argExpr[i].substring(0, varIndex).trim(); 218 | argTypes.add(type); 219 | variables[i] = argExpr[i].substring(varIndex + 1).trim(); 220 | } 221 | rule.setArgTypes(argTypes); 222 | rule.setVariables(Arrays.asList(variables)); 223 | } 224 | 225 | this.refactoringRules.add(rule); 226 | } 227 | } 228 | } 229 | -------------------------------------------------------------------------------- /src/main/java/org/walkmod/refactor/config/RefactoringUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2013 Raquel Pau and Albert Coroleu. 3 | 4 | Walkmod is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Lesser General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | Walkmod is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Lesser General Public License for more details. 13 | 14 | You should have received a copy of the GNU Lesser General Public License 15 | along with Walkmod. If not, see .*/ 16 | package org.walkmod.refactor.config; 17 | 18 | import java.lang.reflect.Method; 19 | import java.util.Iterator; 20 | import java.util.LinkedList; 21 | import java.util.List; 22 | 23 | import org.walkmod.javalang.ast.MethodSymbolData; 24 | import org.walkmod.javalang.ast.SymbolData; 25 | import org.walkmod.javalang.ast.body.MethodDeclaration; 26 | import org.walkmod.javalang.ast.body.Parameter; 27 | import org.walkmod.javalang.compiler.reflection.MethodInspector; 28 | 29 | public class RefactoringUtils { 30 | 31 | /** 32 | * Evaluates if the method declaration overrides a more generic definition. 33 | * @param md The method declaration to analyze. 34 | * @return is the method declaration overrides a more generic definition. 35 | */ 36 | public static boolean overrides(MethodDeclaration md) { 37 | MethodSymbolData msd = md.getSymbolData(); 38 | 39 | if (msd != null) { 40 | Method method = msd.getMethod(); 41 | Class declaringClass = method.getDeclaringClass(); 42 | Class parentClass = declaringClass.getSuperclass(); 43 | 44 | if (parentClass != null) { 45 | 46 | // it should be initialized after resolving the method 47 | 48 | List params = md.getParameters(); 49 | SymbolData[] args = null; 50 | if (params != null) { 51 | args = new SymbolData[params.size()]; 52 | int i = 0; 53 | for (Parameter param : params) { 54 | args[i] = param.getType().getSymbolData(); 55 | i++; 56 | } 57 | } else { 58 | args = new SymbolData[0]; 59 | } 60 | 61 | List> scopesToCheck = new LinkedList>(); 62 | scopesToCheck.add(parentClass); 63 | Class[] interfaces = declaringClass.getInterfaces(); 64 | for (int i = 0; i < interfaces.length; i++) { 65 | scopesToCheck.add(interfaces[i]); 66 | } 67 | Iterator> it = scopesToCheck.iterator(); 68 | boolean found = false; 69 | while (it.hasNext() && !found) { 70 | found = (MethodInspector.findMethod(it.next(), args, md.getName()) != null); 71 | } 72 | return found; 73 | } 74 | return false; 75 | } else { 76 | throw new UnsupportedOperationException("This operation cannot be used with a method without symbol data"); 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/main/java/org/walkmod/refactor/exceptions/InvalidRefactoringRuleException.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2013 Raquel Pau and Albert Coroleu. 3 | 4 | Walkmod is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Lesser General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | Walkmod is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Lesser General Public License for more details. 13 | 14 | You should have received a copy of the GNU Lesser General Public License 15 | along with Walkmod. If not, see .*/ 16 | package org.walkmod.refactor.exceptions; 17 | 18 | import org.walkmod.exceptions.WalkModException; 19 | 20 | public class InvalidRefactoringRuleException extends WalkModException { 21 | 22 | /** 23 | * serialVersionUID 24 | */ 25 | private static final long serialVersionUID = 9001388591915734947L; 26 | 27 | public InvalidRefactoringRuleException() { 28 | super(); 29 | } 30 | 31 | public InvalidRefactoringRuleException(String msg, Throwable cause) { 32 | super(msg, cause); 33 | } 34 | 35 | public InvalidRefactoringRuleException(String msg) { 36 | super(msg); 37 | } 38 | 39 | public InvalidRefactoringRuleException(Throwable cause) { 40 | super(cause); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/org/walkmod/refactor/exceptions/InvalidTypeException.java: -------------------------------------------------------------------------------- 1 | package org.walkmod.refactor.exceptions; 2 | 3 | import java.lang.reflect.Type; 4 | 5 | public class InvalidTypeException extends Exception { 6 | 7 | public InvalidTypeException(Type t) { 8 | super("Invalid Type " + t); 9 | } 10 | 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/org/walkmod/refactor/visitors/ASTTypeNameResolver.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2015 Raquel Pau and Albert Coroleu. 3 | 4 | Walkmod is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Lesser General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | Walkmod is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Lesser General Public License for more details. 13 | 14 | You should have received a copy of the GNU Lesser General Public License 15 | along with Walkmod. If not, see .*/ 16 | package org.walkmod.refactor.visitors; 17 | 18 | import java.util.Iterator; 19 | import java.util.LinkedList; 20 | import java.util.List; 21 | 22 | import org.walkmod.javalang.ast.Node; 23 | import org.walkmod.javalang.ast.TypeParameter; 24 | import org.walkmod.javalang.ast.expr.ObjectCreationExpr; 25 | import org.walkmod.javalang.ast.type.ClassOrInterfaceType; 26 | import org.walkmod.javalang.ast.type.PrimitiveType; 27 | import org.walkmod.javalang.ast.type.PrimitiveType.Primitive; 28 | import org.walkmod.javalang.ast.type.ReferenceType; 29 | import org.walkmod.javalang.ast.type.Type; 30 | import org.walkmod.javalang.ast.type.VoidType; 31 | import org.walkmod.javalang.ast.type.WildcardType; 32 | import org.walkmod.javalang.compiler.symbols.SymbolType; 33 | import org.walkmod.javalang.compiler.symbols.SymbolTypeResolver; 34 | import org.walkmod.javalang.compiler.types.TypesLoaderVisitor; 35 | import org.walkmod.javalang.visitors.GenericVisitorAdapter; 36 | 37 | public class ASTTypeNameResolver extends 38 | GenericVisitorAdapter> implements 39 | SymbolTypeResolver { 40 | 41 | private static ASTTypeNameResolver instance = null; 42 | 43 | 44 | private ASTTypeNameResolver() { 45 | 46 | } 47 | 48 | public static ASTTypeNameResolver getInstance() { 49 | if (instance == null) { 50 | instance = new ASTTypeNameResolver(); 51 | } 52 | return instance; 53 | } 54 | 55 | @Override 56 | public SymbolType visit(PrimitiveType n, List arg) { 57 | SymbolType result = new SymbolType(); 58 | Primitive pt = n.getType(); 59 | if (pt.equals(Primitive.Boolean)) { 60 | result.setName(boolean.class.getName()); 61 | 62 | } else if (pt.equals(Primitive.Char)) { 63 | result.setName(char.class.getName()); 64 | } else if (pt.equals(Primitive.Double)) { 65 | result.setName(double.class.getName()); 66 | } else if (pt.equals(Primitive.Float)) { 67 | result.setName(float.class.getName()); 68 | } else if (pt.equals(Primitive.Int)) { 69 | result.setName(int.class.getName()); 70 | } else if (pt.equals(Primitive.Long)) { 71 | result.setName(long.class.getName()); 72 | } else if (pt.equals(Primitive.Short)) { 73 | result.setName(short.class.getName()); 74 | } else if (pt.equals(Primitive.Byte)) { 75 | result.setName(byte.class.getName()); 76 | } 77 | return result; 78 | } 79 | 80 | @Override 81 | public SymbolType visit(ClassOrInterfaceType type, List arg) { 82 | SymbolType result = null; 83 | 84 | String name = type.getName(); 85 | ClassOrInterfaceType scope = type.getScope(); 86 | Node parent = type.getParentNode(); 87 | boolean isObjectCreationCtxt = (parent != null && parent instanceof ObjectCreationExpr); 88 | 89 | if (scope == null) { 90 | 91 | if (arg != null) { 92 | Iterator it = arg.iterator(); 93 | while (it.hasNext() && result == null) { 94 | TypeParameter next = it.next(); 95 | if (next.getName().equals(name)) { 96 | List bounds = next.getTypeBound(); 97 | if (bounds == null || bounds.isEmpty()) { 98 | result = new SymbolType(Object.class); 99 | } else { 100 | List params = new LinkedList(); 101 | for (ClassOrInterfaceType bound : bounds) { 102 | params.add(bound.accept(this, arg)); 103 | } 104 | result = new SymbolType(params); 105 | } 106 | } 107 | } 108 | } 109 | if (result == null) { 110 | 111 | result = new SymbolType(name); 112 | 113 | } 114 | 115 | } else { 116 | // it is a fully qualified name or a inner class (>1 hop) 117 | 118 | String scopeName = ""; 119 | String parentName = ""; 120 | 121 | ClassOrInterfaceType ctxt = type; 122 | while (ctxt.getScope() != null) { 123 | ctxt = (ClassOrInterfaceType) ctxt.getScope(); 124 | if (ctxt.getSymbolData() != null) { 125 | scopeName = ctxt.getName() + "$" + scopeName; 126 | } else { 127 | scopeName = ctxt.getName() + "." + scopeName; 128 | } 129 | } 130 | scopeName = parentName + scopeName; 131 | 132 | String innerClassName = name; 133 | if (scopeName.length() > 1) { 134 | innerClassName = scopeName.substring(0, scopeName.length() - 1) 135 | + "$" + name; 136 | } 137 | String fullName = scopeName + name; 138 | 139 | result = new SymbolType(); 140 | try { 141 | TypesLoaderVisitor.getClassLoader().loadClass(fullName); 142 | result.setName(fullName); 143 | } catch (ClassNotFoundException e) { 144 | 145 | result.setName(innerClassName); 146 | } 147 | 148 | } 149 | 150 | if (type.getTypeArgs() != null) { 151 | if (result == null) { 152 | result = new SymbolType(); 153 | } 154 | List typeArgs = new LinkedList(); 155 | 156 | for (Type typeArg : type.getTypeArgs()) { 157 | SymbolType aux = valueOf(typeArg); 158 | if (aux == null) { 159 | aux = new SymbolType(Object.class); 160 | } 161 | typeArgs.add(aux); 162 | } 163 | if (!typeArgs.isEmpty()) { 164 | result.setParameterizedTypes(typeArgs); 165 | } 166 | } 167 | 168 | return result; 169 | } 170 | 171 | @Override 172 | public SymbolType visit(VoidType n, List arg) { 173 | return new SymbolType(Void.class.getName()); 174 | } 175 | 176 | @Override 177 | public SymbolType visit(WildcardType n, List arg) { 178 | SymbolType result = null; 179 | if (n.toString().equals("?")) { 180 | result = new SymbolType("java.lang.Object"); 181 | } else { 182 | List upperBounds = null; 183 | List lowerBounds = null; 184 | ReferenceType extendsRef = n.getExtends(); 185 | ReferenceType superRef = n.getSuper(); 186 | if (extendsRef != null) { 187 | 188 | SymbolType aux = extendsRef.accept(this, arg); 189 | if (aux != null) { 190 | upperBounds = new LinkedList(); 191 | upperBounds.add(aux); 192 | } 193 | 194 | } else { 195 | 196 | SymbolType aux = superRef.accept(this, arg); 197 | if (aux != null) { 198 | lowerBounds = new LinkedList(); 199 | lowerBounds.add(aux); 200 | } 201 | } 202 | if (upperBounds != null || lowerBounds != null) { 203 | result = new SymbolType(upperBounds, lowerBounds); 204 | } 205 | 206 | } 207 | return result; 208 | } 209 | 210 | public SymbolType visit(ReferenceType n, List arg) { 211 | Type containerType = n.getType(); 212 | SymbolType result = null; 213 | if (containerType instanceof PrimitiveType) { 214 | result = new SymbolType(containerType.accept(this, arg).getName()); 215 | 216 | } else if (containerType instanceof ClassOrInterfaceType) { 217 | 218 | result = containerType.accept(this, arg); 219 | 220 | } 221 | if (result != null) { 222 | result.setArrayCount(n.getArrayCount()); 223 | } 224 | return result; 225 | } 226 | 227 | @Override 228 | public SymbolType valueOf(Type parserType) { 229 | return valueOf(parserType, (List) null); 230 | } 231 | 232 | public SymbolType valueOf(Type parserType, List tps) { 233 | return parserType.accept(this, tps); 234 | } 235 | 236 | @Override 237 | public SymbolType[] valueOf(List nodes) { 238 | if (nodes == null) { 239 | return new SymbolType[0]; 240 | } 241 | SymbolType[] result = new SymbolType[nodes.size()]; 242 | int i = 0; 243 | for (Type node : nodes) { 244 | result[i] = valueOf(node); 245 | i++; 246 | } 247 | return result; 248 | } 249 | 250 | } 251 | -------------------------------------------------------------------------------- /src/main/java/org/walkmod/refactor/visitors/ClassOrInterfaceRefactor.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2013 Raquel Pau and Albert Coroleu. 3 | 4 | Walkmod is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Lesser General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | Walkmod is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Lesser General Public License for more details. 13 | 14 | You should have received a copy of the GNU Lesser General Public License 15 | along with Walkmod. If not, see .*/ 16 | package org.walkmod.refactor.visitors; 17 | 18 | import java.io.File; 19 | import java.util.HashMap; 20 | import java.util.Iterator; 21 | import java.util.LinkedList; 22 | import java.util.List; 23 | import java.util.Map; 24 | import java.util.Scanner; 25 | import java.util.Set; 26 | 27 | import org.apache.commons.logging.Log; 28 | import org.apache.commons.logging.LogFactory; 29 | import org.walkmod.exceptions.WalkModException; 30 | import org.walkmod.javalang.ASTManager; 31 | import org.walkmod.javalang.ParseException; 32 | import org.walkmod.javalang.ast.CompilationUnit; 33 | import org.walkmod.javalang.ast.ImportDeclaration; 34 | import org.walkmod.javalang.ast.PackageDeclaration; 35 | import org.walkmod.javalang.ast.body.TypeDeclaration; 36 | import org.walkmod.javalang.ast.expr.NameExpr; 37 | import org.walkmod.javalang.ast.type.ClassOrInterfaceType; 38 | import org.walkmod.javalang.visitors.VoidVisitorAdapter; 39 | import org.walkmod.walkers.VisitorContext; 40 | 41 | import com.alibaba.fastjson.JSON; 42 | import com.alibaba.fastjson.JSONObject; 43 | 44 | public class ClassOrInterfaceRefactor extends 45 | VoidVisitorAdapter { 46 | 47 | private Map refactoringRules; 48 | 49 | private Map aliasOldNamesMap; 50 | 51 | private Map aliasNewNamesMap; 52 | 53 | private List imports = new LinkedList(); 54 | 55 | private CompilationUnit cu; 56 | 57 | private static final Log LOG = LogFactory 58 | .getLog(ClassOrInterfaceRefactor.class); 59 | 60 | @Override 61 | public void visit(ClassOrInterfaceType n, VisitorContext arg) { 62 | 63 | String name = n.toString(); 64 | 65 | ClassOrInterfaceType aux = null; 66 | 67 | String simpleName = name; 68 | 69 | if (aliasOldNamesMap.containsKey(simpleName)) { 70 | name = aliasOldNamesMap.get(simpleName); 71 | } 72 | 73 | // n has a complete class name 74 | if (refactoringRules.containsKey(name)) { 75 | 76 | String newFullName = refactoringRules.get(name); 77 | String simplifiedName = aliasNewNamesMap.get(newFullName); 78 | if(simplifiedName != null){ 79 | newFullName = simplifiedName; 80 | } 81 | try { 82 | aux = (ClassOrInterfaceType) ASTManager.parse( 83 | ClassOrInterfaceType.class, newFullName); 84 | 85 | } catch (ParseException e) { 86 | throw new WalkModException(e); 87 | } 88 | 89 | n.setName(aux.getName()); 90 | n.setScope(aux.getScope()); 91 | n.setTypeArgs(aux.getTypeArgs()); 92 | 93 | } 94 | 95 | } 96 | 97 | @Override 98 | public void visit(ImportDeclaration n, VisitorContext arg) { 99 | imports.add(n); 100 | try { 101 | String selectedType = n.getName().toString(); 102 | 103 | if (!n.isAsterisk()) { 104 | int index = selectedType.lastIndexOf("."); 105 | String value = refactoringRules.get(selectedType); 106 | if (value != null) { 107 | 108 | if (!n.isStatic()) { 109 | if (index != -1) { 110 | String simpleName = selectedType 111 | .substring(index + 1); 112 | aliasOldNamesMap.put(simpleName, selectedType); 113 | index = value.lastIndexOf("."); 114 | String aliasNewName = null; 115 | if(index != -1){ 116 | aliasNewName = value.substring(index+1); 117 | } 118 | else{ 119 | aliasNewName = value; 120 | } 121 | aliasNewNamesMap.put(value, aliasNewName); 122 | } 123 | } 124 | LOG.debug("Replacing the imports. Import: " + n.getName()); 125 | 126 | NameExpr newName = (NameExpr) ASTManager.parse( 127 | NameExpr.class, 128 | refactoringRules.get(n.getName().toString())); 129 | n.setName(newName); 130 | 131 | } 132 | } else { 133 | Set oldClassNames = refactoringRules.keySet(); 134 | for (String oldClassName : oldClassNames) { 135 | if (oldClassName.startsWith(selectedType)) { 136 | 137 | int index = oldClassName.indexOf("."); 138 | if (!n.isStatic()) { 139 | if (index != -1) { 140 | String simpleName = oldClassName 141 | .substring(index + 1); 142 | aliasOldNamesMap.put(simpleName, selectedType); 143 | 144 | String value = refactoringRules.get(oldClassName); 145 | index = value.lastIndexOf("."); 146 | String aliasNewName = null; 147 | if(index != -1){ 148 | aliasNewName = value.substring(index+1); 149 | } 150 | else{ 151 | aliasNewName = value; 152 | } 153 | aliasNewNamesMap.put(value, aliasNewName); 154 | } 155 | ImportDeclaration id = new ImportDeclaration((NameExpr) 156 | ASTManager.parse(NameExpr.class, 157 | selectedType, true), 158 | n.isAsterisk(), n.isStatic()); 159 | imports.add(id); 160 | } 161 | } 162 | } 163 | 164 | } 165 | } catch (Exception e) { 166 | throw new WalkModException(e); 167 | } 168 | } 169 | 170 | public void visit(TypeDeclaration n, VisitorContext arg) { 171 | n.accept(this, arg); 172 | } 173 | 174 | public void visit(PackageDeclaration pd, VisitorContext arg) { 175 | String name = pd.getName().toString(); 176 | Set keys = refactoringRules.keySet(); 177 | 178 | for (String key : keys) { 179 | if (key.startsWith(name)) { 180 | int index = key.indexOf("."); 181 | if (index != -1) { 182 | String alias = key.substring(index + 1); 183 | aliasOldNamesMap.put(alias, key); 184 | String value = refactoringRules.get(key); 185 | index = value.lastIndexOf("."); 186 | String aliasNewName = null; 187 | if(index != -1){ 188 | aliasNewName = value.substring(index+1); 189 | } 190 | else{ 191 | aliasNewName = value; 192 | } 193 | aliasNewNamesMap.put(value, aliasNewName); 194 | } 195 | } 196 | } 197 | } 198 | 199 | @Override 200 | public void visit(CompilationUnit n, VisitorContext arg) { 201 | if (refactoringRules != null && !refactoringRules.isEmpty()) { 202 | this.cu = n; 203 | aliasOldNamesMap = new HashMap(); 204 | aliasNewNamesMap = new HashMap(); 205 | 206 | imports = new LinkedList(); 207 | if (n.getPackage() != null) { 208 | n.getPackage().accept(this, arg); 209 | } 210 | if (n.getImports() != null) { 211 | // visiting the complete names 212 | for (ImportDeclaration i : n.getImports()) { 213 | if (!i.isAsterisk()) { 214 | i.accept(this, arg); 215 | } 216 | } 217 | // visiting package imports 218 | for (ImportDeclaration i : n.getImports()) { 219 | if (i.isAsterisk()) { 220 | i.accept(this, arg); 221 | } 222 | } 223 | 224 | } 225 | if (n.getTypes() != null) { 226 | for (TypeDeclaration typeDeclaration : n.getTypes()) { 227 | typeDeclaration.accept(this, arg); 228 | } 229 | } 230 | cu.setImports(imports); 231 | } 232 | } 233 | 234 | public void setRefactoringConfigFile(String refactoringConfigFile) 235 | throws Exception { 236 | File file = new File(refactoringConfigFile); 237 | if (!file.exists()) { 238 | file = new File("src/main/walkmod/refactor/refactoring-classes.json"); 239 | } 240 | if (file.exists()) { 241 | 242 | if (file.canRead()) { 243 | 244 | String text = new Scanner(file).useDelimiter("\\A").next(); 245 | 246 | JSONObject o = JSON.parseObject(text); 247 | 248 | Map aux = new HashMap(); 249 | 250 | Set> entries = o.entrySet(); 251 | 252 | Iterator> it = entries.iterator(); 253 | 254 | while (it.hasNext()) { 255 | Map.Entry entry = it.next(); 256 | aux.put(entry.getKey(), entry.getValue().toString()); 257 | it.remove(); 258 | } 259 | setRefactoringRules(aux); 260 | } else { 261 | LOG.error("The constants config file [" 262 | + refactoringConfigFile + "] cannot be read"); 263 | } 264 | } else { 265 | LOG.error("The constants config file [" + refactoringConfigFile 266 | + "] does not exist"); 267 | } 268 | } 269 | 270 | public void setRefactoringRules(Map refactoringRules) { 271 | this.refactoringRules = refactoringRules; 272 | } 273 | 274 | } 275 | -------------------------------------------------------------------------------- /src/main/java/org/walkmod/refactor/visitors/ExpressionRefactor.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2013 Raquel Pau and Albert Coroleu. 3 | 4 | Walkmod is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Lesser General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | Walkmod is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Lesser General Public License for more details. 13 | 14 | You should have received a copy of the GNU Lesser General Public License 15 | along with Walkmod. If not, see .*/ 16 | package org.walkmod.refactor.visitors; 17 | 18 | import java.util.HashMap; 19 | import java.util.HashSet; 20 | import java.util.LinkedList; 21 | import java.util.List; 22 | import java.util.Map; 23 | import java.util.Set; 24 | 25 | import org.apache.log4j.Logger; 26 | import org.walkmod.javalang.ASTManager; 27 | import org.walkmod.javalang.ParseException; 28 | import org.walkmod.javalang.ast.SymbolData; 29 | import org.walkmod.javalang.ast.body.BodyDeclaration; 30 | import org.walkmod.javalang.ast.expr.CastExpr; 31 | import org.walkmod.javalang.ast.expr.Expression; 32 | import org.walkmod.javalang.ast.expr.FieldAccessExpr; 33 | import org.walkmod.javalang.ast.expr.MethodCallExpr; 34 | import org.walkmod.javalang.ast.expr.NameExpr; 35 | import org.walkmod.javalang.ast.expr.ObjectCreationExpr; 36 | import org.walkmod.javalang.ast.expr.UnaryExpr; 37 | import org.walkmod.javalang.ast.type.Type; 38 | import org.walkmod.javalang.compiler.types.Types; 39 | import org.walkmod.javalang.visitors.VoidVisitorAdapter; 40 | import org.walkmod.walkers.VisitorContext; 41 | 42 | /** 43 | * Changes an AST expression applying a variable substitution. 44 | * 45 | * @author rpau 46 | * 47 | */ 48 | public class ExpressionRefactor extends VoidVisitorAdapter { 49 | 50 | private Map variables; 51 | 52 | private Map variableTypes; 53 | 54 | private Set refactoredVariables = new HashSet(); 55 | 56 | 57 | 58 | private static Logger log = Logger.getLogger(ExpressionRefactor.class); 59 | 60 | public Set getRefactoredVariables() { 61 | return refactoredVariables; 62 | } 63 | 64 | public ExpressionRefactor(){ 65 | this(new HashMap()); 66 | } 67 | 68 | public ExpressionRefactor(Map variable) { 69 | this.variables = variable; 70 | } 71 | 72 | public Map getVariable() { 73 | return variables; 74 | } 75 | 76 | public void setVariable(Map variable) { 77 | this.variables = variable; 78 | refactoredVariables.clear(); 79 | } 80 | 81 | @Override 82 | public void visit(NameExpr n, VisitorContext arg) { 83 | if (variables.containsKey(n.getName())) { 84 | n.setData(variables.get(n.getName())); 85 | refactoredVariables.add(n.getName()); 86 | } 87 | } 88 | 89 | @Override 90 | public void visit(UnaryExpr n, VisitorContext arg) { 91 | if (n.getExpr() instanceof NameExpr) { 92 | 93 | NameExpr ne = ((NameExpr) n.getExpr()); 94 | 95 | if (variables.containsKey(ne.getName())) { 96 | n.setExpr(variables.get(ne.getName())); 97 | refactoredVariables.add(ne.getName()); 98 | } 99 | 100 | } else { 101 | n.getExpr().accept(this, arg); 102 | } 103 | } 104 | 105 | public void visit(CastExpr n, VisitorContext arg) { 106 | if (n.getExpr() instanceof NameExpr) { 107 | 108 | NameExpr ne = ((NameExpr) n.getExpr()); 109 | 110 | if (variables.containsKey(ne.getName())) { 111 | 112 | Expression updatedExpr = variables.get(ne.getName()); 113 | refactoredVariables.add(ne.getName()); 114 | 115 | Class classExpr = variableTypes.get(ne.getName()).getClazz(); 116 | 117 | Class castClass = n.getType().getSymbolData().getClazz(); 118 | 119 | if ( Types.isCompatible(classExpr, castClass)) { 120 | 121 | n.setData(updatedExpr); 122 | } else { 123 | 124 | if (castClass.isPrimitive() && !classExpr.isPrimitive() 125 | && Types.getWrapperClasses().containsKey(classExpr)) { 126 | 127 | updatedExpr = getPrimitiveMethodCallExpr(classExpr, 128 | updatedExpr); 129 | 130 | } 131 | 132 | n.setExpr(updatedExpr); 133 | } 134 | 135 | } 136 | } else { 137 | n.getExpr().accept(this, arg); 138 | } 139 | 140 | } 141 | 142 | private MethodCallExpr getPrimitiveMethodCallExpr(Class clazz, 143 | Expression scope) { 144 | Map wrapperClasses = Types.getWrapperClasses(); 145 | if (wrapperClasses.containsKey(clazz.getName())) { 146 | String basicType = wrapperClasses.get(clazz.getName()); 147 | String methodCallExpr = scope.toString() + "." + basicType 148 | + "Value()"; 149 | 150 | try { 151 | return (MethodCallExpr) ASTManager.parse(MethodCallExpr.class, 152 | methodCallExpr); 153 | 154 | } catch (ParseException e) { 155 | throw new RuntimeException(e.getCause()); 156 | } 157 | 158 | } 159 | throw new RuntimeException("The clazz " + clazz.getName() 160 | + " is not a basic type"); 161 | } 162 | 163 | @Override 164 | public void visit(MethodCallExpr n, VisitorContext arg) { 165 | if (n.getScope() != null) { 166 | 167 | if (n.getScope() instanceof NameExpr) { 168 | 169 | NameExpr ne = ((NameExpr) n.getScope()); 170 | 171 | if (variables.containsKey(ne.getName())) { 172 | n.setScope(variables.get(ne.getName())); 173 | refactoredVariables.add(ne.getName()); 174 | } 175 | } else { 176 | n.getScope().accept(this, arg); 177 | } 178 | } 179 | 180 | if (n.getTypeArgs() != null) { 181 | for (Type t : n.getTypeArgs()) { 182 | t.accept(this, arg); 183 | } 184 | } 185 | if (n.getArgs() != null) { 186 | List newExpr = new LinkedList(); 187 | for (Expression e : n.getArgs()) { 188 | e.accept(this, arg); 189 | if (e.getData() != null) { 190 | newExpr.add((Expression) e.getData()); 191 | } else { 192 | newExpr.add(e); 193 | } 194 | n.setArgs(newExpr); 195 | 196 | } 197 | } 198 | } 199 | 200 | @Override 201 | public void visit(FieldAccessExpr n, VisitorContext arg) { 202 | 203 | if (n.getScope() != null) { 204 | 205 | if (n.getScope() instanceof NameExpr) { 206 | 207 | NameExpr ne = ((NameExpr) n.getScope()); 208 | 209 | if (variables.containsKey(ne.getName())) { 210 | n.setScope(variables.get(ne.getName())); 211 | refactoredVariables.add(ne.getName()); 212 | } 213 | } else { 214 | n.getScope().accept(this, arg); 215 | } 216 | 217 | } 218 | 219 | } 220 | 221 | @Override 222 | public void visit(ObjectCreationExpr n, VisitorContext arg) { 223 | 224 | if (n.getScope() != null) { 225 | 226 | if (n.getScope() instanceof NameExpr) { 227 | 228 | NameExpr ne = ((NameExpr) n.getScope()); 229 | 230 | if (variables.containsKey(ne.getName())) { 231 | n.setScope(variables.get(ne.getName())); 232 | refactoredVariables.add(ne.getName()); 233 | } 234 | } else { 235 | n.getScope().accept(this, arg); 236 | } 237 | } 238 | if (n.getTypeArgs() != null) { 239 | for (Type t : n.getTypeArgs()) { 240 | t.accept(this, arg); 241 | } 242 | } 243 | n.getType().accept(this, arg); 244 | if (n.getArgs() != null) { 245 | for (Expression e : n.getArgs()) { 246 | e.accept(this, arg); 247 | } 248 | } 249 | if (n.getAnonymousClassBody() != null) { 250 | for (BodyDeclaration member : n.getAnonymousClassBody()) { 251 | member.accept(this, arg); 252 | } 253 | } 254 | } 255 | 256 | public Map getVariableTypes() { 257 | return variableTypes; 258 | } 259 | 260 | public void setVariableTypes(Map variableTypes) { 261 | this.variableTypes = variableTypes; 262 | } 263 | 264 | } 265 | -------------------------------------------------------------------------------- /src/main/java/org/walkmod/refactor/visitors/MethodRefactor.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2013 Raquel Pau and Albert Coroleu. 3 | 4 | Walkmod is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Lesser General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | Walkmod is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Lesser General Public License for more details. 13 | 14 | You should have received a copy of the GNU Lesser General Public License 15 | along with Walkmod. If not, see .*/ 16 | package org.walkmod.refactor.visitors; 17 | 18 | import java.io.File; 19 | import java.lang.reflect.Method; 20 | import java.util.Collection; 21 | import java.util.HashMap; 22 | import java.util.Iterator; 23 | import java.util.LinkedList; 24 | import java.util.List; 25 | import java.util.Map; 26 | import java.util.Scanner; 27 | import java.util.Set; 28 | 29 | import org.apache.log4j.Logger; 30 | import org.walkmod.exceptions.InvalidTransformationRuleException; 31 | import org.walkmod.exceptions.WalkModException; 32 | import org.walkmod.javalang.ast.CompilationUnit; 33 | import org.walkmod.javalang.ast.MethodSymbolData; 34 | import org.walkmod.javalang.ast.SymbolData; 35 | import org.walkmod.javalang.ast.body.MethodDeclaration; 36 | import org.walkmod.javalang.ast.body.VariableDeclarator; 37 | import org.walkmod.javalang.ast.expr.AssignExpr; 38 | import org.walkmod.javalang.ast.expr.BinaryExpr; 39 | import org.walkmod.javalang.ast.expr.Expression; 40 | import org.walkmod.javalang.ast.expr.FieldAccessExpr; 41 | import org.walkmod.javalang.ast.expr.MethodCallExpr; 42 | import org.walkmod.javalang.ast.expr.ObjectCreationExpr; 43 | import org.walkmod.javalang.ast.expr.UnaryExpr; 44 | import org.walkmod.javalang.ast.stmt.BlockStmt; 45 | import org.walkmod.javalang.ast.stmt.ExpressionStmt; 46 | import org.walkmod.javalang.ast.stmt.IfStmt; 47 | import org.walkmod.javalang.ast.stmt.Statement; 48 | import org.walkmod.javalang.ast.stmt.SwitchEntryStmt; 49 | import org.walkmod.javalang.ast.type.Type; 50 | import org.walkmod.javalang.compiler.symbols.RequiresSemanticAnalysis; 51 | import org.walkmod.javalang.compiler.symbols.SymbolType; 52 | import org.walkmod.javalang.visitors.VoidVisitor; 53 | import org.walkmod.javalang.visitors.VoidVisitorAdapter; 54 | import org.walkmod.refactor.config.MethodRefactoringRule; 55 | import org.walkmod.refactor.config.RefactoringRulesDictionary; 56 | import org.walkmod.walkers.VisitorContext; 57 | 58 | import com.alibaba.fastjson.JSON; 59 | import com.alibaba.fastjson.JSONObject; 60 | 61 | @RequiresSemanticAnalysis 62 | public class MethodRefactor extends VoidVisitorAdapter { 63 | 64 | private RefactoringRulesDictionary refactoringRules; 65 | 66 | private Map inputRules; 67 | 68 | private ExpressionRefactor exprRefactor; 69 | 70 | private static final String UPDATED_STATEMENT_KEY = "updated_statement_key"; 71 | 72 | private static final String UPDATED_EXPRESSION_KEY = "updated_expression_key"; 73 | 74 | public static final String PREVIOUS_REQUIRED_STATEMENTS_KEY = "previous_required_statements"; 75 | 76 | public static final String FORWARD_REQUIRED_STATEMENTS_KEY = "forward_required_statements"; 77 | 78 | private static Logger LOG = Logger.getLogger(MethodRefactor.class); 79 | 80 | private ClassLoader classLoader = null; 81 | 82 | private Map> refactoringVisitors; 83 | 84 | private Map> auxRefactoringVisitors; 85 | 86 | private boolean setUp = false; 87 | 88 | public MethodRefactor() { 89 | } 90 | 91 | public void setClassLoader(ClassLoader classLoader) { 92 | this.classLoader = classLoader; 93 | } 94 | 95 | @Override 96 | public void visit(CompilationUnit unit, VisitorContext arg) { 97 | if (!setUp) { 98 | 99 | this.refactoringRules = new RefactoringRulesDictionary(classLoader); 100 | auxRefactoringVisitors = new HashMap>(); 101 | exprRefactor = new ExpressionRefactor(); 102 | 103 | refactoringRules.putRules(inputRules); 104 | 105 | if(refactoringVisitors != null){ 106 | Set keys = refactoringVisitors.keySet(); 107 | for(Method m: keys){ 108 | auxRefactoringVisitors.put(m.toString(), refactoringVisitors.get(m)); 109 | } 110 | } 111 | setUp = true; 112 | } 113 | 114 | super.visit(unit, arg); 115 | 116 | } 117 | 118 | public void visit(AssignExpr n, VisitorContext arg) { 119 | n.getTarget().accept(this, arg); 120 | 121 | n.getValue().accept(this, arg); 122 | 123 | if (arg.containsKey(UPDATED_EXPRESSION_KEY)) { 124 | n.setValue((Expression) arg.remove(UPDATED_EXPRESSION_KEY)); 125 | } 126 | 127 | } 128 | 129 | public void visit(VariableDeclarator n, VisitorContext arg) { 130 | n.getId().accept(this, arg); 131 | 132 | if (n.getInit() != null) { 133 | 134 | n.getInit().accept(this, arg); 135 | 136 | if (arg.containsKey(UPDATED_EXPRESSION_KEY)) { 137 | n.setInit((Expression) arg.remove(UPDATED_EXPRESSION_KEY)); 138 | } 139 | 140 | } 141 | } 142 | 143 | @Override 144 | public void visit(MethodDeclaration n, VisitorContext arg) { 145 | super.visit(n, arg); 146 | 147 | MethodSymbolData msd = n.getSymbolData(); 148 | if (msd != null) { 149 | if(refactoringVisitors != null){ 150 | 151 | VoidVisitor visitor = auxRefactoringVisitors.get(msd.getMethod().toString()); 152 | if(visitor != null){ 153 | n.accept(visitor, null); 154 | } 155 | } 156 | } 157 | } 158 | 159 | public void setRefactoringVisitors(Map> refactoringVisitors) { 160 | this.refactoringVisitors = refactoringVisitors; 161 | } 162 | 163 | @Override 164 | public void visit(BinaryExpr n, VisitorContext arg) { 165 | 166 | Expression right = n.getRight(); 167 | right.accept(this, arg); 168 | 169 | if (arg.containsKey(UPDATED_EXPRESSION_KEY)) { 170 | 171 | n.setRight((Expression) arg.remove(UPDATED_EXPRESSION_KEY)); 172 | 173 | } 174 | 175 | Expression left = n.getLeft(); 176 | left.accept(this, arg); 177 | if (arg.containsKey(UPDATED_EXPRESSION_KEY)) { 178 | n.setLeft((Expression) arg.remove(UPDATED_EXPRESSION_KEY)); 179 | 180 | } 181 | 182 | } 183 | 184 | @Override 185 | public void visit(UnaryExpr n, VisitorContext arg) { 186 | Expression e = n.getExpr(); 187 | e.accept(this, arg); 188 | 189 | if (arg.containsKey(UPDATED_EXPRESSION_KEY)) { 190 | 191 | n.setExpr((Expression) arg.get(UPDATED_EXPRESSION_KEY)); 192 | 193 | arg.remove(UPDATED_EXPRESSION_KEY); 194 | } 195 | } 196 | 197 | @Override 198 | public void visit(MethodCallExpr n, VisitorContext arg) { 199 | 200 | MethodSymbolData resultType = n.getSymbolData(); 201 | 202 | Class scopeClass = resultType.getMethod().getDeclaringClass(); 203 | SymbolType scopeST = new SymbolType(scopeClass); 204 | try { 205 | 206 | if (n.getScope() != null) { 207 | 208 | // resolving the scope 209 | n.getScope().accept(this, arg); 210 | 211 | // updating the scope if some refactor is applied 212 | if (arg.containsKey(UPDATED_EXPRESSION_KEY)) { 213 | n.setScope((Expression) arg.remove(UPDATED_EXPRESSION_KEY)); 214 | } 215 | 216 | } 217 | // searching the replacing method 218 | List args = n.getArgs(); 219 | 220 | SymbolType[] argClazzes = null; 221 | List refactoredArgs = new LinkedList(); 222 | 223 | if (args != null) { 224 | int i = 0; 225 | argClazzes = new SymbolType[args.size()]; 226 | 227 | // guardem els tipus dels parametres 228 | for (Expression e : args) { 229 | 230 | SymbolData aux = e.getSymbolData(); 231 | 232 | if (aux != null) { 233 | 234 | argClazzes[i] = (SymbolType) aux; 235 | } else { 236 | // e is a nullLiteralExpr 237 | argClazzes[i] = null; 238 | } 239 | // the systems applies the method refactoring in all its 240 | // args once the type is known 241 | e.accept(this, arg); 242 | 243 | if (arg.containsKey(UPDATED_EXPRESSION_KEY)) { 244 | refactoredArgs.add((Expression) arg.remove(UPDATED_EXPRESSION_KEY)); 245 | } else { 246 | refactoredArgs.add(e); 247 | } 248 | i++; 249 | 250 | } 251 | 252 | args = refactoredArgs; 253 | } else { 254 | argClazzes = new SymbolType[0]; 255 | } 256 | 257 | MethodRefactoringRule mrr = refactoringRules.getRefactoringRule(scopeST, n.getName(), argClazzes); 258 | 259 | // does exists some refactoring rule? 260 | if (mrr != null) { 261 | 262 | LOG.debug("refactoring [ " + n.toString() + " ]"); 263 | // changing the method's name 264 | n.setName(mrr.getMethodName()); 265 | 266 | Map variableMap = new HashMap(); 267 | Map variableTypes = new HashMap(); 268 | 269 | exprRefactor.setVariable(variableMap); 270 | exprRefactor.setVariableTypes(variableTypes); 271 | 272 | // updating args 273 | if (args != null && !args.isEmpty()) { 274 | 275 | List argExpr = mrr.getExpressionTreeArgs(); 276 | 277 | Iterator it = args.iterator(); 278 | int i = 0; 279 | for (String variable : mrr.getVariables()) { 280 | variableMap.put(variable, it.next()); 281 | variableTypes.put(variable, argClazzes[i]); 282 | i++; 283 | } 284 | 285 | variableMap.put(mrr.getImplicitVaribale(), n.getScope()); 286 | variableTypes.put(mrr.getImplicitVaribale(), scopeST); 287 | 288 | List argExprRefactored = new LinkedList(); 289 | 290 | for (Expression e : argExpr) { 291 | 292 | // changing the argument expression once it its 293 | // refactored 294 | 295 | e.accept(exprRefactor, arg); 296 | 297 | if (e.getData() != null) { 298 | Expression aux = (Expression) e.getData(); 299 | argExprRefactored.add(aux); 300 | 301 | } else { 302 | argExprRefactored.add(e); 303 | } 304 | 305 | } 306 | 307 | n.setArgs(argExprRefactored); 308 | 309 | } 310 | 311 | if (mrr.hasImplicitExpression()) { 312 | 313 | Expression implicitExpression = mrr.getImplicitTreeExpression(); 314 | 315 | implicitExpression.accept(exprRefactor, arg); 316 | 317 | if (implicitExpression.getData() != null) { 318 | implicitExpression = (Expression) implicitExpression.getData(); 319 | } 320 | 321 | n.setScope(implicitExpression); 322 | 323 | } 324 | Expression resultExpression = null; 325 | 326 | if (mrr.hasResultExpression()) { 327 | 328 | resultExpression = mrr.getResultTreeExpression(); 329 | 330 | Map map = exprRefactor.getVariable(); 331 | map.put(mrr.getResultVariable(), n); 332 | exprRefactor.setVariable(map); 333 | resultExpression.accept(exprRefactor, arg); 334 | 335 | if (resultExpression.getData() != null) { 336 | resultExpression = (Expression) resultExpression.getData(); 337 | } 338 | if (!exprRefactor.getRefactoredVariables().contains(mrr.getResultVariable())) { 339 | 340 | // it is necessary to apply the method refactor as 341 | // an statement and the result expression 342 | 343 | @SuppressWarnings("unchecked") 344 | Collection reqStmts = (Collection) arg.get(PREVIOUS_REQUIRED_STATEMENTS_KEY); 345 | 346 | if (reqStmts == null) { 347 | reqStmts = new LinkedList(); 348 | arg.put(PREVIOUS_REQUIRED_STATEMENTS_KEY, reqStmts); 349 | } 350 | ExpressionStmt stmt = new ExpressionStmt(n); 351 | reqStmts.add(stmt); 352 | } 353 | arg.put(UPDATED_EXPRESSION_KEY, resultExpression); 354 | } 355 | 356 | } 357 | 358 | } catch (Exception e) { 359 | throw new RuntimeException(e); 360 | } 361 | 362 | } 363 | 364 | @Override 365 | public void visit(FieldAccessExpr n, VisitorContext arg) { 366 | 367 | Expression scope = n.getScope(); 368 | 369 | if (scope != null) { 370 | n.getScope().accept(this, arg); 371 | if (arg.containsKey(UPDATED_EXPRESSION_KEY)) { 372 | n.setScope((Expression) arg.remove(UPDATED_EXPRESSION_KEY)); 373 | 374 | } 375 | } 376 | } 377 | 378 | public void visit(SwitchEntryStmt n, VisitorContext arg) { 379 | 380 | if (n.getLabel() != null) { 381 | n.getLabel().accept(this, arg); 382 | if (arg.containsKey(UPDATED_EXPRESSION_KEY)) { 383 | n.setLabel((Expression) arg.remove(UPDATED_EXPRESSION_KEY)); 384 | } 385 | } 386 | 387 | if (n.getStmts() != null) { 388 | 389 | List stmts = new LinkedList(); 390 | 391 | for (Statement s : n.getStmts()) { 392 | 393 | s.accept(this, arg); 394 | 395 | @SuppressWarnings("unchecked") 396 | Collection reqStmts = (Collection) arg.get(PREVIOUS_REQUIRED_STATEMENTS_KEY); 397 | if (reqStmts != null) { 398 | for (Statement ns : reqStmts) { 399 | stmts.add(ns); 400 | } 401 | reqStmts.clear(); 402 | } 403 | 404 | if (!arg.containsKey(UPDATED_STATEMENT_KEY)) { 405 | // is not an empty statement 406 | stmts.add(s); 407 | } else { 408 | if (arg.get(UPDATED_STATEMENT_KEY) != null) { 409 | stmts.add((Statement) arg.remove(UPDATED_STATEMENT_KEY)); 410 | } else { 411 | 412 | arg.remove(UPDATED_STATEMENT_KEY); 413 | } 414 | } 415 | 416 | @SuppressWarnings("unchecked") 417 | Collection forStmts = (Collection) arg.remove(FORWARD_REQUIRED_STATEMENTS_KEY); 418 | if (forStmts != null) { 419 | for (Statement ns : forStmts) { 420 | stmts.add(ns); 421 | } 422 | forStmts.clear(); 423 | } 424 | } 425 | n.setStmts(stmts); 426 | if (stmts.isEmpty()) { 427 | arg.put(UPDATED_STATEMENT_KEY, null); 428 | } 429 | } 430 | 431 | } 432 | 433 | public void setRefactoringConfigFile(String refactoringConfigFile) throws Exception { 434 | File file = new File(refactoringConfigFile); 435 | if (!file.exists()) { 436 | file = new File("src/main/walkmod/refactor/refactoring-methods.json"); 437 | } 438 | if (file.exists()) { 439 | 440 | if (file.canRead()) { 441 | 442 | String text = new Scanner(file).useDelimiter("\\A").next(); 443 | 444 | JSONObject o = JSON.parseObject(text); 445 | 446 | Map aux = new HashMap(); 447 | 448 | Set> entries = o.entrySet(); 449 | 450 | Iterator> it = entries.iterator(); 451 | 452 | while (it.hasNext()) { 453 | Map.Entry entry = it.next(); 454 | aux.put(entry.getKey(), entry.getValue().toString()); 455 | it.remove(); 456 | } 457 | setRefactoringRules(aux); 458 | } else { 459 | LOG.error("The refactoring config file [" + refactoringConfigFile + "] cannot be read"); 460 | } 461 | } else { 462 | LOG.error("The refactoring config file [" + refactoringConfigFile + "] does not exist"); 463 | } 464 | } 465 | 466 | public void setRefactoringRules(Map inputRules) throws InvalidTransformationRuleException { 467 | this.inputRules = inputRules; 468 | 469 | } 470 | 471 | public Map getRefactoringRules() { 472 | return inputRules; 473 | } 474 | 475 | @Override 476 | public void visit(BlockStmt n, VisitorContext arg) { 477 | 478 | if (n.getStmts() != null) { 479 | List stmts = new LinkedList(); 480 | for (Statement s : n.getStmts()) { 481 | 482 | s.accept(this, arg); 483 | 484 | @SuppressWarnings("unchecked") 485 | Collection reqStmts = (Collection) arg.get(PREVIOUS_REQUIRED_STATEMENTS_KEY); 486 | if (reqStmts != null) { 487 | for (Statement ns : reqStmts) { 488 | stmts.add(ns); 489 | } 490 | reqStmts.clear(); 491 | } 492 | 493 | if (!arg.containsKey(UPDATED_STATEMENT_KEY)) { 494 | // is not an empty statement 495 | stmts.add(s); 496 | } else { 497 | if (arg.get(UPDATED_STATEMENT_KEY) != null) { 498 | stmts.add((Statement) arg.remove(UPDATED_STATEMENT_KEY)); 499 | } else { 500 | 501 | arg.remove(UPDATED_STATEMENT_KEY); 502 | } 503 | } 504 | 505 | @SuppressWarnings("unchecked") 506 | Collection forStmts = (Collection) arg.remove(FORWARD_REQUIRED_STATEMENTS_KEY); 507 | if (forStmts != null) { 508 | for (Statement ns : forStmts) { 509 | stmts.add(ns); 510 | } 511 | forStmts.clear(); 512 | } 513 | } 514 | n.setStmts(stmts); 515 | if (stmts.isEmpty()) { 516 | arg.put(UPDATED_STATEMENT_KEY, null); 517 | } 518 | } 519 | 520 | } 521 | 522 | @Override 523 | public void visit(IfStmt n, VisitorContext arg) { 524 | n.getCondition().accept(this, arg); 525 | 526 | if (arg.containsKey(UPDATED_EXPRESSION_KEY)) { 527 | n.setCondition((Expression) arg.remove(UPDATED_EXPRESSION_KEY)); 528 | } 529 | 530 | n.getThenStmt().accept(this, arg); 531 | 532 | if (arg.containsKey(UPDATED_STATEMENT_KEY) && arg.get(UPDATED_STATEMENT_KEY) == null) { 533 | // when empty then statement is setted because a method is removed 534 | 535 | UnaryExpr notExpr = new UnaryExpr(n.getCondition(), UnaryExpr.Operator.not); 536 | n.setCondition(notExpr); 537 | n.setThenStmt(n.getElseStmt()); 538 | n.setElseStmt(null); 539 | 540 | if (n.getThenStmt() != null) { 541 | n.getThenStmt().accept(this, arg); 542 | } else { 543 | arg.put(UPDATED_STATEMENT_KEY, null); 544 | } 545 | 546 | } else { 547 | if (n.getElseStmt() != null) { 548 | n.getElseStmt().accept(this, arg); 549 | } 550 | } 551 | } 552 | 553 | @Override 554 | public void visit(ObjectCreationExpr n, VisitorContext arg) { 555 | 556 | SymbolData objectScope = n.getSymbolData(); 557 | 558 | if (n.getTypeArgs() != null) { 559 | for (Type t : n.getTypeArgs()) { 560 | t.accept(this, arg); 561 | } 562 | } 563 | n.getType().accept(this, arg); 564 | 565 | SymbolType[] argStr = null; 566 | 567 | List args = n.getArgs(); 568 | List refactoredArgs = new LinkedList(); 569 | if (args != null) { 570 | 571 | argStr = new SymbolType[n.getArgs().size()]; 572 | int i = 0; 573 | for (Expression e : args) { 574 | 575 | SymbolData eType = e.getSymbolData(); 576 | 577 | if (eType != null) { 578 | argStr[i] = (SymbolType) eType; 579 | } else { 580 | // null literal expression 581 | argStr[i] = null; 582 | } 583 | 584 | // Transforming the expression 585 | e.accept(this, arg); 586 | if (arg.containsKey(UPDATED_EXPRESSION_KEY)) { 587 | refactoredArgs.add((Expression) arg.remove(UPDATED_EXPRESSION_KEY)); 588 | } else { 589 | refactoredArgs.add(e); 590 | } 591 | 592 | i++; 593 | } 594 | 595 | n.setArgs(refactoredArgs); 596 | } 597 | try { 598 | MethodRefactoringRule mrr = refactoringRules.getRefactoringRule((SymbolType) objectScope, 599 | n.getType().getName(), argStr); 600 | 601 | if (mrr != null) { 602 | LOG.debug("refactoring [" + n.toString() + "]"); 603 | // changing the constructor's name 604 | String newConstructorName = mrr.getMethodName(); 605 | if (mrr.getScope() != null) { 606 | newConstructorName = mrr.getScope() + "." + newConstructorName; 607 | } 608 | 609 | Map variableMap = new HashMap(); 610 | 611 | exprRefactor.setVariable(variableMap); 612 | 613 | // actualizamos los args 614 | if (args != null && !args.isEmpty()) { 615 | 616 | List argExpr = mrr.getExpressionTreeArgs(); 617 | 618 | Iterator it = args.iterator(); 619 | 620 | for (String variable : mrr.getVariables()) { 621 | variableMap.put(variable, it.next()); 622 | } 623 | 624 | variableMap.put(mrr.getImplicitVaribale(), n.getScope()); 625 | 626 | List argExprRefactored = new LinkedList(); 627 | 628 | for (Expression e : argExpr) { 629 | 630 | // replacing the argument expression 631 | e.accept(exprRefactor, arg); 632 | 633 | if (e.getData() != null) { 634 | argExprRefactored.add((Expression) e.getData()); 635 | 636 | } else { 637 | argExprRefactored.add(e); 638 | } 639 | 640 | } 641 | 642 | n.setArgs(argExprRefactored); 643 | 644 | } 645 | 646 | if (mrr.hasImplicitExpression()) { 647 | 648 | Expression implicitExpression = mrr.getImplicitTreeExpression(); 649 | 650 | implicitExpression.accept(exprRefactor, arg); 651 | 652 | if (implicitExpression.getData() != null) { 653 | implicitExpression = (Expression) implicitExpression.getData(); 654 | } 655 | 656 | MethodCallExpr aux = new MethodCallExpr(); 657 | aux.setScope(implicitExpression); 658 | aux.setTypeArgs(n.getTypeArgs()); 659 | aux.setName(mrr.getMethodName()); 660 | aux.setArgs(n.getArgs()); 661 | arg.put(UPDATED_EXPRESSION_KEY, aux); 662 | 663 | } 664 | 665 | n.getType().setName(newConstructorName); 666 | } 667 | 668 | } catch (Exception e) { 669 | throw new WalkModException(e); 670 | } 671 | 672 | super.visit(n, arg); 673 | } 674 | 675 | @Override 676 | public void visit(ExpressionStmt n, VisitorContext arg) { 677 | 678 | n.getExpression().accept(this, arg); 679 | 680 | if (arg.containsKey(UPDATED_EXPRESSION_KEY) && arg.get(UPDATED_EXPRESSION_KEY) == null) { 681 | 682 | arg.put(UPDATED_STATEMENT_KEY, null); 683 | arg.remove(UPDATED_EXPRESSION_KEY); 684 | 685 | } else { 686 | if (arg.containsKey(UPDATED_EXPRESSION_KEY)) { 687 | n.setExpression((Expression) arg.remove(UPDATED_EXPRESSION_KEY)); 688 | } 689 | } 690 | 691 | } 692 | 693 | } 694 | -------------------------------------------------------------------------------- /src/main/license-header.txt: -------------------------------------------------------------------------------- 1 | 2 | Copyright (C) 2013 Raquel Pau and Albert Coroleu. 3 | 4 | Walkmod is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Lesser General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | Walkmod is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Lesser General Public License for more details. 13 | 14 | You should have received a copy of the GNU Lesser General Public License 15 | along with Walkmod. If not, see . -------------------------------------------------------------------------------- /src/main/resources/META-INF/walkmod/walkmod-refactor-plugin.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/test/java/org/walkmod/refactor/visitors/ClassOrInterfaceRefactorTest.java: -------------------------------------------------------------------------------- 1 | package org.walkmod.refactor.visitors; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | import junit.framework.Assert; 7 | 8 | import org.junit.Test; 9 | import org.walkmod.javalang.ASTManager; 10 | import org.walkmod.javalang.ast.CompilationUnit; 11 | import org.walkmod.javalang.ast.ImportDeclaration; 12 | import org.walkmod.javalang.ast.body.BodyDeclaration; 13 | import org.walkmod.javalang.ast.body.FieldDeclaration; 14 | import org.walkmod.refactor.visitors.ClassOrInterfaceRefactor; 15 | import org.walkmod.walkers.VisitorContext; 16 | 17 | public class ClassOrInterfaceRefactorTest { 18 | 19 | @Test 20 | public void testImportsRefactor() throws Exception { 21 | String code = "import java.util.List; public class Foo {}"; 22 | CompilationUnit cu = ASTManager.parse(code); 23 | 24 | ClassOrInterfaceRefactor coi = new ClassOrInterfaceRefactor(); 25 | 26 | Map refactorMap = new HashMap(); 27 | refactorMap.put("java.util.List", "java.util.Collection"); 28 | 29 | coi.setRefactoringRules(refactorMap); 30 | cu.accept(coi, new VisitorContext()); 31 | 32 | ImportDeclaration id = cu.getImports().get(0); 33 | String name = id.getName().toString(); 34 | Assert.assertEquals("java.util.Collection", name); 35 | 36 | } 37 | 38 | @Test 39 | public void testTypes() throws Exception { 40 | 41 | String code = "import java.util.List; public class Foo { private List list;}"; 42 | CompilationUnit cu = ASTManager.parse(code); 43 | 44 | ClassOrInterfaceRefactor coi = new ClassOrInterfaceRefactor(); 45 | 46 | Map refactorMap = new HashMap(); 47 | refactorMap.put("java.util.List", "java.util.Collection"); 48 | 49 | coi.setRefactoringRules(refactorMap); 50 | cu.accept(coi, new VisitorContext()); 51 | 52 | BodyDeclaration field = cu.getTypes().get(0).getMembers().get(0); 53 | 54 | FieldDeclaration fd = ((FieldDeclaration) field); 55 | 56 | Assert.assertEquals("Collection", fd.getType().toString()); 57 | } 58 | 59 | @Test 60 | public void testPackageClass() throws Exception { 61 | String code = "package bar; public class Foo { private c elem; }"; 62 | CompilationUnit cu = ASTManager.parse(code); 63 | 64 | ClassOrInterfaceRefactor coi = new ClassOrInterfaceRefactor(); 65 | 66 | Map refactorMap = new HashMap(); 67 | refactorMap.put("bar.c", "bar.C"); 68 | 69 | coi.setRefactoringRules(refactorMap); 70 | cu.accept(coi, new VisitorContext()); 71 | 72 | BodyDeclaration field = cu.getTypes().get(0).getMembers().get(0); 73 | 74 | FieldDeclaration fd = ((FieldDeclaration) field); 75 | 76 | Assert.assertEquals("C", fd.getType().toString()); 77 | 78 | } 79 | 80 | @Test 81 | public void testRefactoringConfiguration() throws Exception{ 82 | ClassOrInterfaceRefactor coi = new ClassOrInterfaceRefactor(); 83 | coi.setRefactoringConfigFile("src/test/resources/refactoring-class-config.json"); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/test/java/org/walkmod/refactor/visitors/MethodRefactorTest.java: -------------------------------------------------------------------------------- 1 | package org.walkmod.refactor.visitors; 2 | 3 | import java.lang.reflect.Method; 4 | import java.util.HashMap; 5 | import java.util.Map; 6 | 7 | import org.junit.Assert; 8 | import org.junit.Test; 9 | import org.walkmod.javalang.ast.CompilationUnit; 10 | import org.walkmod.javalang.ast.body.MethodDeclaration; 11 | import org.walkmod.javalang.ast.expr.MethodCallExpr; 12 | import org.walkmod.javalang.ast.expr.UnaryExpr; 13 | import org.walkmod.javalang.ast.stmt.IfStmt; 14 | import org.walkmod.javalang.test.SemanticTest; 15 | import org.walkmod.javalang.visitors.VoidVisitor; 16 | import org.walkmod.javalang.visitors.VoidVisitorAdapter; 17 | import org.walkmod.walkers.VisitorContext; 18 | 19 | 20 | public class MethodRefactorTest extends SemanticTest { 21 | 22 | public CompilationUnit getRefactoredSource(Map methodRules, String... code) throws Exception { 23 | 24 | CompilationUnit cu = compile(code); 25 | 26 | MethodRefactor coi = new MethodRefactor(); 27 | 28 | coi.setClassLoader(getClassLoader()); 29 | 30 | coi.setRefactoringRules(methodRules); 31 | 32 | cu.accept(coi, new VisitorContext()); 33 | 34 | return cu; 35 | 36 | } 37 | 38 | @Test 39 | public void testSimpleMethodCall() throws Exception { 40 | String code = "public class Foo { public void hi() { System.out.print(\"hello\");}}"; 41 | 42 | Map rules = new HashMap(); 43 | rules.put("java.io.PrintStream:print(java.lang.String text)", "java.io.PrintStream:println(text)"); 44 | 45 | CompilationUnit cu = getRefactoredSource(rules, code); 46 | 47 | MethodDeclaration md = (MethodDeclaration) cu.getTypes().get(0).getMembers().get(0); 48 | String stmt = md.getBody().getStmts().get(0).toString(); 49 | Assert.assertEquals("System.out.println(\"hello\");", stmt); 50 | 51 | } 52 | 53 | @Test 54 | public void testMultipleMethodCall() throws Exception { 55 | String code = "public class Foo { public void hi() { \"hello\".substring(0).substring(3);}}"; 56 | 57 | Map rules = new HashMap(); 58 | rules.put("java.lang.String:substring(int pos)", "java.lang.String:concat(\"a\")"); 59 | 60 | CompilationUnit cu = getRefactoredSource(rules, code); 61 | 62 | MethodDeclaration md = (MethodDeclaration) cu.getTypes().get(0).getMembers().get(0); 63 | String stmt = md.getBody().getStmts().get(0).toString(); 64 | Assert.assertEquals("\"hello\".concat(\"a\").concat(\"a\");", stmt); 65 | 66 | } 67 | 68 | @Test 69 | public void testSymbols() throws Exception { 70 | String code = "public class Foo { public void hi(String bar) { bar.substring(0).substring(3);}}"; 71 | 72 | Map rules = new HashMap(); 73 | rules.put("java.lang.String:substring(int pos)", "java.lang.String:concat(\"a\")"); 74 | 75 | CompilationUnit cu = getRefactoredSource(rules, code); 76 | 77 | MethodDeclaration md = (MethodDeclaration) cu.getTypes().get(0).getMembers().get(0); 78 | String stmt = md.getBody().getStmts().get(0).toString(); 79 | Assert.assertEquals("bar.concat(\"a\").concat(\"a\");", stmt); 80 | 81 | } 82 | 83 | @Test 84 | public void testResultTransformations() throws Exception { 85 | String code = "import java.io.File; public class A { public void hello(File file){ " + "Bar bar = new Bar(); " 86 | + "bar.open(file); " + "if(bar.isOpen()){}" + " }}"; 87 | 88 | String barCode = "import java.io.File; public class Bar { public void open(File file){} public boolean isOpen() {return false;}}"; 89 | Map rules = new HashMap(); 90 | rules.put("Bar:isOpen()", "Bar:isClosed():!result"); 91 | CompilationUnit cu = getRefactoredSource(rules, code, barCode); 92 | 93 | MethodDeclaration md = (MethodDeclaration) cu.getTypes().get(0).getMembers().get(0); 94 | IfStmt ifStmt = (IfStmt) md.getBody().getStmts().get(2); 95 | 96 | Assert.assertTrue((ifStmt.getCondition() instanceof UnaryExpr)); 97 | } 98 | 99 | @Test 100 | public void testResultTransformationsWithExistingParams() throws Exception { 101 | String code = "import java.io.File; public class A { public void hello(File file){ " + "Bar bar = new Bar(); " 102 | + "if(bar.isOpen(file)){}" + " }}"; 103 | 104 | String barCode = "import java.io.File; public class Bar { public boolean isOpen(File file){return false;}}"; 105 | Map rules = new HashMap(); 106 | rules.put("Bar:isOpen(java.io.File file)", "[file]:isOpen()"); 107 | CompilationUnit cu = getRefactoredSource(rules, code, barCode); 108 | 109 | MethodDeclaration md = (MethodDeclaration) cu.getTypes().get(0).getMembers().get(0); 110 | IfStmt ifStmt = (IfStmt) md.getBody().getStmts().get(1); 111 | 112 | Assert.assertTrue((ifStmt.getCondition() instanceof MethodCallExpr)); 113 | 114 | MethodCallExpr call = (MethodCallExpr) ifStmt.getCondition(); 115 | Assert.assertEquals("file", call.getScope().toString()); 116 | } 117 | 118 | @Test 119 | public void testResultTransformationsWithExistingParamsAndResult() throws Exception { 120 | String code = "import java.io.File; public class A { public void hello(File file){ " + "Bar bar = new Bar(); " 121 | + "if(bar.isOpen(file)){}" + " }}"; 122 | 123 | String barCode = "import java.io.File; public class Bar { public boolean isOpen(File file){return false;}}"; 124 | Map rules = new HashMap(); 125 | rules.put("Bar:isOpen(java.io.File file)", "Bar:prepare():file.isOpen()"); 126 | CompilationUnit cu = getRefactoredSource(rules, code, barCode); 127 | 128 | MethodDeclaration md = (MethodDeclaration) cu.getTypes().get(0).getMembers().get(0); 129 | Assert.assertEquals(3, md.getBody().getStmts().size()); 130 | 131 | IfStmt ifStmt = (IfStmt) md.getBody().getStmts().get(2); 132 | 133 | Assert.assertTrue((ifStmt.getCondition() instanceof MethodCallExpr)); 134 | 135 | MethodCallExpr call = (MethodCallExpr) ifStmt.getCondition(); 136 | Assert.assertEquals("file", call.getScope().toString()); 137 | } 138 | 139 | @Test 140 | public void testParsingConfigFile() throws Exception { 141 | 142 | MethodRefactor coi = new MethodRefactor(); 143 | coi.setRefactoringConfigFile("src/test/resources/refactoring-methods-config.json"); 144 | 145 | Assert.assertEquals(2, coi.getRefactoringRules().size()); 146 | 147 | } 148 | 149 | @Test 150 | public void testRefactoringVisitors() throws Exception { 151 | String code = "import java.io.File; public class Bar { public boolean isOpen(File file){return false;}}"; 152 | 153 | Map rules = new HashMap(); 154 | rules.put("Bar:isOpen(java.io.File file)", "Bar:isOpen()"); 155 | 156 | CompilationUnit cu = compile(code); 157 | 158 | MethodDeclaration md = (MethodDeclaration) cu.getTypes().get(0).getMembers().get(0); 159 | 160 | Map> refactoringVisitors = new HashMap>(); 161 | 162 | refactoringVisitors.put(md.getSymbolData().getMethod(), new VoidVisitorAdapter() { 163 | 164 | public void visit(MethodDeclaration md, VisitorContext ctx) { 165 | md.setParameters(null); 166 | } 167 | 168 | }); 169 | 170 | MethodRefactor coi = new MethodRefactor(); 171 | 172 | coi.setClassLoader(getClassLoader()); 173 | 174 | coi.setRefactoringRules(rules); 175 | 176 | coi.setRefactoringVisitors(refactoringVisitors); 177 | 178 | cu.accept(coi, new VisitorContext()); 179 | 180 | Assert.assertNull(md.getParameters()); 181 | } 182 | 183 | } 184 | -------------------------------------------------------------------------------- /src/test/resources/refactoring-class-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "java.util.List" : "java.util.Collection" 3 | } -------------------------------------------------------------------------------- /src/test/resources/refactoring-constants-to-enum.json: -------------------------------------------------------------------------------- 1 | { 2 | "edu.upc.dama.dex.core.Graph.EDGES_OUT" : "com.sparsity.dex.gdb.EdgesDirection.Outgoing", 3 | "edu.upc.dama.dex.core.Graph.EDGES_IN" : "com.sparsity.dex.gdb.EdgesDirection.Ingoing", 4 | "edu.upc.dama.dex.core.Graph.EDGES_BOTH" : "com.sparsity.dex.gdb.EdgesDirection.Any", 5 | "edu.upc.dama.dex.core.Graph.ATTR_KIND_BASIC" : "com.sparsity.dex.gdb.AttributeKind.Basic", 6 | "edu.upc.dama.dex.core.Graph.ATTR_KIND_INDEXED" : "com.sparsity.dex.gdb.AttributeKind.Indexed", 7 | "edu.upc.dama.dex.core.Graph.ATTR_KIND_UNIQUE": "com.sparsity.dex.gdb.AttributeKind.Unique", 8 | "edu.upc.dama.dex.core.Graph.OPERATION_EQ" : "com.sparsity.dex.gdb.Condition.Equal", 9 | "edu.upc.dama.dex.core.Graph.OPERATION_NE" : "com.sparsity.dex.gdb.Condition.NotEqual", 10 | "edu.upc.dama.dex.core.Graph.OPERATION_BETWEEN" : "com.sparsity.dex.gdb.Condition.Between", 11 | "edu.upc.dama.dex.core.Graph.OPERATION_GE" : "com.sparsity.dex.gdb.Condition.GreaterEqual", 12 | "edu.upc.dama.dex.core.Graph.OPERATION_GT" : "com.sparsity.dex.gdb.Condition.GreaterThan", 13 | "edu.upc.dama.dex.core.Graph.OPERATION_LE" : "com.sparsity.dex.gdb.Condition.LessEqual", 14 | "edu.upc.dama.dex.core.Graph.OPERATION_LT" : "com.sparsity.dex.gdb.Condition.LessThan", 15 | "edu.upc.dama.dex.core.Graph.OPERATION_LIKE" : "com.sparsity.dex.gdb.Condition.Like", 16 | "edu.upc.dama.dex.core.Graph.OPERATION_ILIKE" : "com.sparsity.dex.gdb.Condition.LikeNoCase", 17 | "edu.upc.dama.dex.core.Graph.OPERATION_ERE" : "com.sparsity.dex.gdb.Condition.RegExpr", 18 | "edu.upc.dama.dex.core.Graph.ORDER_ASCENDENT" : "com.sparsity.dex.gdb.Order.Ascendent", 19 | "edu.upc.dama.dex.core.Graph.ORDER_DESCENDENT" : "com.sparsity.dex.gdb.Order.Descendent", 20 | "edu.upc.dama.dex.core.Value.BOOL" : "com.sparsity.dex.gdb.DataType.Boolean", 21 | "edu.upc.dama.dex.core.Value.INT" : "com.sparsity.dex.gdb.DataType.Integer", 22 | "edu.upc.dama.dex.core.Value.Long" : "com.sparsity.dex.gdb.DataType.Long", 23 | "edu.upc.dama.dex.core.Value.DOUBLE" : "com.sparsity.dex.gdb.DataType.Double", 24 | "edu.upc.dama.dex.core.Value.STRING" : "com.sparsity.dex.gdb.DataType.String", 25 | "edu.upc.dama.dex.core.Value.TIMESTAMP" : "com.sparsity.dex.gdb.DataType.Timestamp", 26 | "edu.upc.dama.dex.core.Value.TEXT" : "com.sparsity.dex.gdb.DataType.Text" 27 | } -------------------------------------------------------------------------------- /src/test/resources/refactoring-methods-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "java.io.PrintStream:print(java.lang.String text)" : "java.io.PrintStream:println(text)", 3 | "java.lang.String:substring(int pos)" : "java.lang.String:concat(\"a\")" 4 | } --------------------------------------------------------------------------------