如何在eclipse插件中修改函数体?

时间:2014-10-21 17:18:58

标签: java eclipse-plugin eclipse-jdt

我设法创建了一个弹出菜单并获得IMethod,但我不知道如何修改该方法。对于此示例,假设我想在单击按钮时将文本system.out.println("Hello, world!");添加到现有方法的底部。

我目前的情况如下:

import org.eclipse.jface.action.IAction;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IObjectActionDelegate;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.jdt.core.IMethod;

public class HelloWorldAction implements IObjectActionDelegate {

    private Shell shell;

    private IMethod currentMethod;

    /**
     * Constructor for Action1.
     */
    public HelloWorldAction() {
        super();
    }

    /**
     * @see IObjectActionDelegate#setActivePart(IAction, IWorkbenchPart)
     */
    public void setActivePart(IAction action, IWorkbenchPart targetPart) {
        shell = targetPart.getSite().getShell();
    }

    /**
     * @see IActionDelegate#run(IAction)
     */
    public void run(IAction action) {
        //TODO: preform the actions.
    }

    /**
     * @see IActionDelegate#selectionChanged(IAction, ISelection)
     */
    public void selectionChanged(IAction action, ISelection selection) {
        if (!(selection instanceof IStructuredSelection)) {
            action.setEnabled(false);
            return;
        }
        IStructuredSelection sel = (IStructuredSelection) selection;

        if (!(sel.getFirstElement() instanceof IMethod)) {
            //Only handles IMethods.
            action.setEnabled(false);
            return;
        }

        action.setEnabled(true);
        this.currentMethod = (IMethod) sel.getFirstElement();
    }
}

我坚持修改currentMethod。我已经看过this help page on modifying code,但我不知道如何获得DocumentAST,或者真正需要IMethod所需的任何内容。这样做的正确方法是什么?

2 个答案:

答案 0 :(得分:1)

根据Eclipse API

  

修改编译单元Java源代码的最简单修改   可以使用Java元素API完成。

     

例如,您可以从编译单元查询类型。一旦您   拥有IType,你可以使用createField等协议,   createInitializer,createMethod或createType以添加源代码   成员的类型。关于的源代码和信息   成员的位置以这些方法提供。

我会尝试使用:

currentMethod.getCompilationUnit().getTypes()[0].createMethod(" hello world code goes here ",null,true,null); 
//not sure if progress monitor can be null, please check

根据Eclipse API

  

IMethod createMethod(字符串内容,                        IJavaElement兄弟,                        布尔力,                        IProgressMonitor监视器)                        抛出JavaModelException

     

使用给定内容创建并返回此类型的方法或构造函数。   可选地,新元素可以在指定之前定位   兄弟。如果未指定兄弟,则将附加元素   这种类型。

     

可能已存在具有相同签名的方法   这个类型。 force参数的值会影响分辨率   这样的冲突:

     

true - 在这种情况下,使用新内容

创建方法      

false - 在这种情况下会抛出JavaModelException

如果您正在寻找,请告诉我。

答案 1 :(得分:1)

我已经弄明白了。

以下内容基于the example of using AST from the documentation将文本System.out.println("Hello" + " world");追加到现有函数的末尾。

import org.eclipse.jface.action.IAction;
import org.eclipse.jface.text.Document;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.text.edits.TextEdit;
import org.eclipse.ui.IObjectActionDelegate;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.dom.*;
import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;

public class HelloWorldAction implements IObjectActionDelegate {

    private Shell shell;

    private IMethod currentMethod;

    /**
     * Constructor for Action1.
     */
    public AddFace2() {
        super();
    }

    /**
     * @see IObjectActionDelegate#setActivePart(IAction, IWorkbenchPart)
     */
    public void setActivePart(IAction action, IWorkbenchPart targetPart) {
        shell = targetPart.getSite().getShell();
    }

    /**
     * @see IActionDelegate#run(IAction)
     */
    public void run(IAction action) {
        //Following is based off of the sample at http://help.eclipse.org/indigo/index.jsp?topic=%2Forg.eclipse.jdt.doc.isv%2Fguide%2Fjdt_api_manip.htm

        try {
            ICompilationUnit cu = currentMethod.getCompilationUnit(); 
            String source = cu.getSource();
            Document document= new Document(source);


            //Get the compilation unit for traversing AST
            final ASTParser parser = ASTParser.newParser(AST.JLS8);
            parser.setSource(currentMethod.getCompilationUnit());
            parser.setResolveBindings(true);

            final CompilationUnit compilationUnit = (CompilationUnit) parser.createAST(null);

            // record modification - to be later written with ASTRewrite
            compilationUnit.recordModifications();

            // Get AST node for IMethod
            int methodIndex = currentMethod.getCompilationUnit().getSource().indexOf(currentMethod.getSource());

            //Convert to a MethodDeclaration.
            MethodDeclaration methodASTNode = (MethodDeclaration)NodeFinder.perform(compilationUnit.getRoot(), methodIndex, currentMethod.getSource().length());

            ASTRewrite rewrite = ASTRewrite.create(compilationUnit.getAST());

            Block blockOld = methodASTNode.getBody();

            //Create a copy of the old block.
            AST blockAST = AST.newAST(AST.JLS8);
            Block block = (Block) Block.copySubtree(blockAST, blockOld);

            //Add "System.out.println("hello" + " world");".
            MethodInvocation methodInvocation = blockAST.newMethodInvocation();

            QualifiedName name =  blockAST.newQualifiedName(
                    blockAST.newSimpleName("System"),
                    blockAST.newSimpleName("out"));

            methodInvocation.setExpression(name);
            methodInvocation.setName(blockAST.newSimpleName("println")); 
            InfixExpression infixExpression = blockAST.newInfixExpression();
            infixExpression.setOperator(InfixExpression.Operator.PLUS);
            StringLiteral literal = blockAST.newStringLiteral();
            literal.setLiteralValue("Hello");
            infixExpression.setLeftOperand(literal);
            literal = blockAST.newStringLiteral();
            literal.setLiteralValue(" world");
            infixExpression.setRightOperand(literal);
            methodInvocation.arguments().add(infixExpression);
            ExpressionStatement expressionStatement = blockAST.newExpressionStatement(methodInvocation);
            block.statements().add(expressionStatement);

            rewrite.replace(blockOld, block, null);


            // computation of the text edits
            TextEdit edits = rewrite.rewriteAST(document, cu.getJavaProject().getOptions(true));

            // computation of the new source code
            edits.apply(document);
            String newSource = document.get();

            // update of the compilation unit
            cu.getBuffer().setContents(newSource);

        } catch (Exception e) {
            throw new RuntimeException(e);
        }


    }

    /**
     * @see IActionDelegate#selectionChanged(IAction, ISelection)
     */
    public void selectionChanged(IAction action, ISelection selection) {
        if (!(selection instanceof IStructuredSelection)) {
            action.setEnabled(false);
            return;
        }
        IStructuredSelection sel = (IStructuredSelection) selection;

        if (!(sel.getFirstElement() instanceof IMethod)) {
            //Only handles IMethods.
            action.setEnabled(false);
            return;
        }

        action.setEnabled(true);
        this.currentMethod = (IMethod) sel.getFirstElement();
    }

}