Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Refactor parameter names programmatically

Using eclipse's jdt refactoring framework, I am trying to convert two different code bases to the same names. They are almost identical codebases except that names are different. Function/Field/Class renaming works fine, but when it comes to parameters it yells at me that the workbench is not created yet. However i'm trying to do this in a headless manor.

private void refactor(String task, IJavaElement element, String new_name) throws CoreException
{
    RefactoringStatus status = new RefactoringStatus();

    RefactoringContribution contrib = RefactoringCore.getRefactoringContribution(task);
    RenameJavaElementDescriptor rnDesc = (RenameJavaElementDescriptor)contrib.createDescriptor();
    rnDesc.setFlags(JavaRefactoringDescriptor.JAR_MIGRATION | JavaRefactoringDescriptor.JAR_REFACTORING);
    rnDesc.setProject(element.getJavaProject().getProject().getName());
    rnDesc.setUpdateReferences(true);
    rnDesc.setJavaElement(element);
    rnDesc.setNewName(new_name);

    Refactoring ref = rnDesc.createRefactoring(status);

    ref.checkInitialConditions(NULL_MON);
    ref.checkFinalConditions(NULL_MON);

    Change change = ref.createChange(NULL_MON);
    change.perform(NULL_MON);
}

This works fine:

for (IMethod method : type.getMethods())
{
    refactor(IJavaRefactorings.RENAME_METHOD, method, {new name});
}

This does not:

for (IMethod method : type.getMethods())
{
    for (ILocalVariable param : method.getParameters())
    {
        refactor(IJavaRefactorings.RENAME_LOCAL_VARIABLE, param, {new name});
    }
}

And the error, not really helpful as I said I need to do this in a headless manor {so can't make workbench}

java.lang.IllegalStateException: Workbench has not been created yet.
    at org.eclipse.ui.PlatformUI.getWorkbench(PlatformUI.java:92)
    at org.eclipse.jdt.internal.ui.javaeditor.ASTProvider.install(ASTProvider.java:245)
    at org.eclipse.jdt.internal.ui.javaeditor.ASTProvider.<init>(ASTProvider.java:236)
    at org.eclipse.jdt.internal.ui.JavaPlugin.getASTProvider(JavaPlugin.java:710)
    at org.eclipse.jdt.ui.SharedASTProvider.getAST(SharedASTProvider.java:128)
    at org.eclipse.jdt.internal.corext.refactoring.util.RefactoringASTParser.parseWithASTProvider(RefactoringASTParser.java:119)
    at org.eclipse.jdt.internal.corext.refactoring.rename.RenameLocalVariableProcessor.initAST(RenameLocalVariableProcessor.java:231)
    at org.eclipse.jdt.internal.corext.refactoring.rename.RenameLocalVariableProcessor.checkInitialConditions(RenameLocalVariableProcessor.java:218)
    at org.eclipse.ltk.core.refactoring.participants.ProcessorBasedRefactoring.checkInitialConditions(ProcessorBasedRefactoring.java:203)

UPDATE: Made some progress, now I can refactor functions that are not overrides. But any function that overrides another or an interface screws up:

F_ARGUMENTS = JavaRefactoringDescriptor.class.getDeclaredField("fArguments");
F_ARGUMENTS.setAccessible(true);

private void refactor(IMethod method, String[] names) throws CoreException
{
    /* My attempt to fix the interface issues, causes duplicate functions instead of renaming the parameters
    IMethod parent = null;
    if (method.getDeclaringType().isInterface())
    {
        parent = MethodChecks.overridesAnotherMethod(method, method.getDeclaringType().newSupertypeHierarchy(NULL_MON));
    }
    else if (MethodChecks.isVirtual(method))
    {
        ITypeHierarchy hierarchy = method.getDeclaringType().newTypeHierarchy(NULL_MON);
        parent = MethodChecks.isDeclaredInInterface(method, hierarchy, NULL_MON);
        if (parent == null)
        {
            parent = MethodChecks.overridesAnotherMethod(method, hierarchy);
        }
    }

    parent = (parent == null ? method : parent);
    if (!method.equals(parent))
    {
        refactor(parent, names);
        return;
    }*/

    String task = IJavaRefactorings.CHANGE_METHOD_SIGNATURE;
    RefactoringStatus status = new RefactoringStatus();

    ChangeMethodSignatureRefactoringContribution contrib = (ChangeMethodSignatureRefactoringContribution)RefactoringCore.getRefactoringContribution(task);
    ChangeMethodSignatureDescriptor desc = (ChangeMethodSignatureDescriptor)contrib.createDescriptor();
    desc.setFlags(JavaRefactoringDescriptor.JAR_MIGRATION |
                  JavaRefactoringDescriptor.JAR_REFACTORING |
                  RefactoringDescriptor.MULTI_CHANGE |
                  RefactoringDescriptor.STRUCTURAL_CHANGE);

    Map<String, String> args = null;
    try
    {
        args = (Map<String, String>)F_ARGUMENTS.get(desc);
    }
    catch (Exception e)
    {
        e.printStackTrace();
    }

    String project = method.getJavaProject().getProject().getName();

    desc.setProject(method.getJavaProject().getProject().getName());

    args.put("input", JavaRefactoringDescriptorUtil.elementToHandle(project, method));
    args.put("name", method.getElementName());
    args.put("deprecate", "false");
    args.put("delegate", "true");        

    boolean changed = false;
    int x = 0;
    for (ILocalVariable param : method.getParameters())
    {
        if (!param.getElementName().equals(names[x]))
        {
            changed = true;
        }
        String type = "String"; //Doesn't seem to actually matter as long as they are both the same
        String info = type + " " + param.getElementName() + " " + x + " " + 
                      type + " " + names[x] + " false";
        args.put("parameter" + (x + 1), info);
        x++;
    }
    if (changed)
    {
        refactor(desc.createRefactoring(status));
    }
}
like image 944
LexManos Avatar asked Nov 03 '22 06:11

LexManos


1 Answers

This is what I came up with:

ChangeSignatureProcessor changeSignatureProcessor = new ChangeSignatureProcessor((IMethod) node.resolveBinding().getJavaElement());

ParameterInfo info=new ParameterInfo("FormContext", "formContext", ParameterInfo.INDEX_FOR_ADDED);
info.setDefaultValue("formContext");
changeSignatureProcessor.getParameterInfos().add(0,info);

RefactoringStatus status = new RefactoringStatus();
CheckConditionsContext context= new CheckConditionsContext();
context.add(new ValidateEditChecker(null));
context.add(new ResourceChangeChecker());

changeSignatureProcessor.checkInitialConditions(monitor);
changeSignatureProcessor.checkFinalConditions(monitor,context);

changeSignatureProcessor.createChange(monitor).perform(monitor);
like image 71
ruediste Avatar answered Nov 09 '22 14:11

ruediste