package com.redhat.ceylon.eclipse.code.resolve; import static com.redhat.ceylon.eclipse.code.editor.Navigation.getJavaElement; import static com.redhat.ceylon.eclipse.util.Nodes.findNode; import static com.redhat.ceylon.eclipse.util.Nodes.getIdentifyingNode; import static com.redhat.ceylon.eclipse.util.Nodes.getReferencedModel; import static com.redhat.ceylon.eclipse.util.InteropUtils.toJavaString; import static com.redhat.ceylon.model.typechecker.model.ModelUtil.getNativeDeclaration; import static com.redhat.ceylon.model.typechecker.model.ModelUtil.getNativeHeader; import static org.eclipse.jdt.internal.ui.javaeditor.EditorUtility.openInEditor; import static org.eclipse.jdt.internal.ui.javaeditor.EditorUtility.revealInEditor; import java.util.List; import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.ITextViewer; import org.eclipse.jface.text.Region; import org.eclipse.jface.text.hyperlink.IHyperlink; import org.eclipse.jface.text.hyperlink.IHyperlinkDetector; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.PartInitException; import com.redhat.ceylon.common.Backend; import com.redhat.ceylon.compiler.typechecker.tree.Node; import com.redhat.ceylon.compiler.typechecker.tree.Tree; import com.redhat.ceylon.eclipse.code.parse.CeylonParseController; import com.redhat.ceylon.ide.common.model.CeylonBinaryUnit; import com.redhat.ceylon.ide.common.model.EditedSourceFile; import com.redhat.ceylon.ide.common.model.ExternalSourceFile; import com.redhat.ceylon.ide.common.model.IJavaModelAware; import com.redhat.ceylon.ide.common.model.ProjectSourceFile; import com.redhat.ceylon.model.typechecker.model.Declaration; import com.redhat.ceylon.model.typechecker.model.Referenceable; import com.redhat.ceylon.model.typechecker.model.Unit; public class JavaHyperlinkDetector implements IHyperlinkDetector { private CeylonParseController pc; public JavaHyperlinkDetector(CeylonParseController pc) { this.pc = pc; } private final class JavaElementLink implements IHyperlink { private final IJavaElement elem; private final Node id; private JavaElementLink(IJavaElement elem, Node id) { this.elem = elem; this.id = id; } @Override public void open() { try { IEditorPart part = openInEditor(elem, true); if (part!=null) { revealInEditor(part, elem); } } catch (PartInitException e) { e.printStackTrace(); } } @Override public String getTypeLabel() { return null; } @Override public String getHyperlinkText() { return "Declaration \u2014 native Java"; } @Override public IRegion getHyperlinkRegion() { return new Region(id.getStartIndex(), id.getDistance()); } } @Override public IHyperlink[] detectHyperlinks(ITextViewer tv, IRegion region, boolean csmh) { if (pc==null) { return null; } Tree.CompilationUnit rootNode = pc.getLastCompilationUnit(); if (rootNode==null) { return null; } else { Node node = findNode(rootNode, pc.getTokens(), region.getOffset(), region.getOffset() + region.getLength()); if (node==null) { return null; } else { Node id = getIdentifyingNode(node); Referenceable ref = getReferencedModel(node); if (ref instanceof Declaration) { Declaration dec = (Declaration) ref; Unit declarationUnit = dec.getUnit(); if (!(declarationUnit instanceof IJavaModelAware)) { if (declarationUnit instanceof ExternalSourceFile) { final ExternalSourceFile externalSourceFile = (ExternalSourceFile)declarationUnit; Declaration binaryDeclaration = externalSourceFile.retrieveBinaryDeclaration(dec); if (binaryDeclaration != null) { dec = binaryDeclaration; declarationUnit = binaryDeclaration.getUnit(); } else { return null; } } else { boolean hasFoundAJavaImplementation = false; if (dec.isNative()) { if (declarationUnit instanceof EditedSourceFile) { ProjectSourceFile projectSourceFile = ((EditedSourceFile)declarationUnit).getOriginalSourceFile(); if (projectSourceFile != null) { Declaration modelDeclaration = null; Declaration modelHeaderDeclaration = getNativeHeader(projectSourceFile.getPackage(), dec.getName()); if (modelHeaderDeclaration != null) { List<Declaration> overloads = modelHeaderDeclaration.getOverloads(); if (overloads != null) { for (Declaration packageDeclarationOverload: overloads) { if (packageDeclarationOverload.equals(dec)) { modelDeclaration = packageDeclarationOverload; break; } } } } if (modelDeclaration != null) { dec = modelDeclaration; declarationUnit = projectSourceFile; } } } Declaration javaOverload = getNativeDeclaration(dec, Backend.Java.asSet()); if (javaOverload != null && javaOverload.getUnit() instanceof IJavaModelAware) { dec = javaOverload; declarationUnit = dec.getUnit(); hasFoundAJavaImplementation = true; } if (!hasFoundAJavaImplementation) { return null; } } } } if (declarationUnit instanceof CeylonBinaryUnit) { CeylonBinaryUnit ceylonBinaryUnit = (CeylonBinaryUnit) declarationUnit; String path = toJavaString(ceylonBinaryUnit.getSourceRelativePath()); if (! JavaCore.isJavaLikeFileName(path)) { return null; } } try { IJavaElement element = getJavaElement(dec); if (element==null) { return null; } else { return new IHyperlink[] { new JavaElementLink(element, id) }; } } catch (JavaModelException jme) { jme.printStackTrace(); return null; } } else { return null; } } } } }