package com.jetbrains.lang.dart.ide.hierarchy.call; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.jetbrains.lang.dart.analyzer.DartAnalysisServerService; import com.jetbrains.lang.dart.psi.DartComponent; import com.jetbrains.lang.dart.psi.DartComponentName; import com.jetbrains.lang.dart.psi.DartRecursiveVisitor; import com.jetbrains.lang.dart.psi.DartReferenceExpression; import com.jetbrains.lang.dart.resolve.DartResolver; import org.dartlang.analysis.server.protocol.ElementKind; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; import java.util.List; import static com.jetbrains.lang.dart.analyzer.DartServerData.DartNavigationRegion; import static com.jetbrains.lang.dart.analyzer.DartServerData.DartNavigationTarget; public class DartCalleeTreeStructure extends DartCallHierarchyTreeStructure { public DartCalleeTreeStructure(Project project, PsiElement element, String currentScopeType) { super(project, element, currentScopeType); } private static void getCallees(@NotNull PsiElement element, @NotNull List<PsiElement> results) { DartComponentName name = (DartComponentName)element; DartComponent decl = (DartComponent)name.getParent(); PsiFile file = decl.getContainingFile(); if (file == null) return; VirtualFile vFile = file.getVirtualFile(); List<DartNavigationRegion> navRegions = DartAnalysisServerService.getInstance(element.getProject()).analysis_getNavigation(vFile, decl.getTextOffset(), decl.getTextLength()); if (navRegions == null) return; resolveReferences(decl, navRegions, results); } private static void resolveReferences(@NotNull DartComponent component, @NotNull List<DartNavigationRegion> regions, @NotNull List<PsiElement> results) { component.acceptChildren(new DartRecursiveVisitor() { @Override public void visitReferenceExpression(@NotNull DartReferenceExpression reference) { int offset = reference.getTextOffset(); List<DartNavigationTarget> targets = getRegionAt(offset, regions); for (DartNavigationTarget target : targets) { if (isExecutable(target)) { PsiElement element = getDeclaration(target, reference); if (element != null) { results.add(element); } } } super.visitReferenceExpression(reference); } }); } private static boolean isExecutable(DartNavigationTarget target) { String kind = target.getKind(); return ElementKind.METHOD.equals(kind) || ElementKind.FUNCTION.equals(kind) || ElementKind.GETTER.equals(kind) || ElementKind.SETTER.equals(kind) || ElementKind.CONSTRUCTOR.equals(kind); } private static PsiElement getDeclaration(DartNavigationTarget target, PsiElement reference) { PsiElement found = DartResolver.getElementForNavigationTarget(reference.getProject(), target); return found == null ? null : found.getParent(); } @NotNull private static List<DartNavigationTarget> getRegionAt(int offset, @NotNull List<DartNavigationRegion> regions) { for (DartNavigationRegion region : regions) { int targetStart = region.getOffset(); int targetEnd = targetStart + region.getLength(); if (offset >= targetStart && offset <= targetEnd) { return region.getTargets(); } } return new ArrayList<>(0); } @NotNull @Override protected List<PsiElement> getChildren(@NotNull PsiElement element) { final List<PsiElement> list = new ArrayList<>(); getCallees(element, list); return list; } }