我将鼠标悬停在String文字上时,需要创建一个显示工具提示的Eclipse插件。
但仅当该字符串文字是特殊方法的第一个参数时。

这是我用来测试插件的Test.java文件:

package test;

public class Test {
    public static void main(String[] args) {
        String hello = "Hello";
        String world = Translator.get("Test.worldLabel");
        System.out.println(hello + " " + world);
    }
}

我创建了一个实现IJavaEditorTextHover的类,并且需要编译当前编辑的Java文件以计算光标是否悬停在需要翻译的String上。
  • 悬停“Hello”将无济于事。
  • 悬停在“Test.worldLabel”上将显示我的工具提示,因为该文字包含在Translator.get()方法调用中。

  • 最初,我使用了这个(170位于“Test.worldLabel”内部):
    ITypeRoot typeRoot = (ITypeRoot)
        JavaUI.getEditorInputJavaElement(editorPart.getEditorInput());
    
    JavaElement foundElement = (JavaElement) typeRoot.getElementAt(170);
    

    但是foundElement包含整个main()方法:它的粒度不够细。

    然后,我认为正确的方法是:
    private static ASTNode parse(ICompilationUnit unit, int position) {
        ASTParser parser = ASTParser.newParser(AST.JLS3);
        parser.setKind(ASTParser.K_COMPILATION_UNIT);
        parser.setSource(unit);
        parser.setResolveBindings(true);
        parser.setIgnoreMethodBodies(false);
        // TODO Future optimisation: parser.setFocalPosition(position);
        return parser.createAST((IProgressMonitor) null); // parse
    }
    

    在我的IJavaEditorTextHover.getHoverInfo(...)实现中:
    ICompilationUnit compilationUnit = (ICompilationUnit)
        JavaUI.getEditorInputJavaElement(editor.getEditorInput())
    int position = 170/*hoverRegion.getOffset()*/;
    ASTNode ast = parse(compilationUnit, position);
    

    现在,这是我的问题:

    如何从这个ast节点获取如何在源代码中的位置170(“Test.worldLabel”字符串)上表示StringLiteral的ASTNode?

    奖励问题:我选择了正确的解决方案吗?基于性能。

    编辑:
    好吧,这是我找到的解决方案:
    private StringLiteral findStringLiteralAtPosition(final ASTNode parent, final int position) {
    
        final List<StringLiteral> stringLiterals = new ArrayList<StringLiteral>();
    
        parent.accept(new ASTVisitor() {
            @Override
            public boolean visit(StringLiteral stringLiteral) {
                int start = stringLiteral.getStartPosition();
                int end = start + stringLiteral.getLength();
                if (start <= position && position <= end) {
                    stringLiterals.add(stringLiteral);
                }
                return super.visit(stringLiteral);
            }
        });
    
        return (stringLiterals.size() > 0 ? stringLiterals.get(0) : null);
    }
    

    可以接缝吗?
    还是更简单或更高效的方法?

    最佳答案

    一种解决方案将根本不使用偏移逻辑。
    您可以使用节点父检查来概括解决方案。

    这是一个示例代码:

    public boolean visit(StringLiteral stringLiteral) {
    
            // Check if parent is a method inovacation.
            if (stringLiteral.getParent().getNodeType() == ASTNode.METHOD_INVOCATION) {
    
                  // get the parent method inovacation.
                  MethodInvocation miNode = (MethodInvocation) stringLiteral.getParent();
    
                  //To do: null and empty check on argument list.
    
                  // Check if is the special method and this is the 1st argument
                  if (miNode.getName().toString().equals("SpecialMethod")
                            && miNode.arguments().get(0).toString().equals(stringLiteral.toString())) {
    
                        System.out.println("Found it : " + stringLiteral.toString());
                  }
            }
    
            return true;
        }
    

    10-06 05:02
    查看更多