/* * Copyright (c) 2013, the Dart project authors. * * Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except * in compliance with the License. You may obtain a copy of the License at * * http://www.eclipse.org/legal/epl-v10.html * * Unless required by applicable law or agreed to in writing, software distributed under the License * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express * or implied. See the License for the specific language governing permissions and limitations under * the License. */ package com.google.dart.tools.internal.search.ui; import com.google.common.collect.Lists; import com.google.common.collect.Sets; import com.google.dart.engine.ast.AstNode; import com.google.dart.engine.ast.MethodInvocation; import com.google.dart.engine.ast.PrefixedIdentifier; import com.google.dart.engine.ast.PropertyAccess; import com.google.dart.engine.ast.SimpleIdentifier; import com.google.dart.engine.element.ClassElement; import com.google.dart.engine.element.CompilationUnitElement; import com.google.dart.engine.element.Element; import com.google.dart.engine.element.FieldElement; import com.google.dart.engine.element.MethodElement; import com.google.dart.engine.element.PropertyAccessorElement; import com.google.dart.engine.search.SearchEngine; import com.google.dart.engine.search.SearchMatch; import com.google.dart.engine.source.Source; import com.google.dart.tools.core.DartCore; import com.google.dart.tools.ui.DartToolsPlugin; import com.google.dart.tools.ui.actions.AbstractDartSelectionAction_OLD; import com.google.dart.tools.ui.instrumentation.UIInstrumentationBuilder; import com.google.dart.tools.ui.internal.actions.ActionUtil; import com.google.dart.tools.ui.internal.search.SearchMessages; import com.google.dart.tools.ui.internal.text.DartHelpContextIds; import com.google.dart.tools.ui.internal.text.editor.DartEditor; import com.google.dart.tools.ui.internal.text.editor.DartSelection; import com.google.dart.tools.ui.internal.util.ExceptionHandler; import org.eclipse.core.resources.IProject; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.swt.widgets.Event; import org.eclipse.ui.IWorkbenchSite; import org.eclipse.ui.PlatformUI; import java.util.Iterator; import java.util.List; import java.util.Set; /** * Finds declarations of the {@link Element}s similar to selected in the workspace. * * @coverage dart.editor.ui.search */ public class FindDeclarationsAction extends AbstractDartSelectionAction_OLD { /** * Asks {@link SearchView} to execute query and display results. */ public static void doSearch(final String name) { try { final SearchEngine searchEngine = DartCore.getProjectManager().newSearchEngine(); SearchView view = (SearchView) DartToolsPlugin.showView(SearchView.ID); if (view == null) { return; } view.showPage(new SearchMatchPage(view, "Searching for '" + name + "' declarations...") { @Override protected boolean canUseFilterPotential() { return false; } @Override protected IProject getCurrentProject() { return FindReferencesAction.findCurrentProject(); } @Override protected String getQueryElementName() { return name; } @Override protected String getQueryKindName() { return "declarations"; } @Override protected List<SearchMatch> runQuery() { List<SearchMatch> declarations = searchEngine.searchDeclarations(name, null, null); for (Iterator<SearchMatch> iter = declarations.iterator(); iter.hasNext();) { SearchMatch searchMatch = iter.next(); Element declaringElement = searchMatch.getElement(); Element enclosingElement = declaringElement.getEnclosingElement(); // OK, top-level or class member if (enclosingElement instanceof CompilationUnitElement || enclosingElement instanceof ClassElement) { continue; } // local element, remove iter.remove(); } declarations = getUniqueMatches(declarations); return declarations; } }); } catch (Throwable e) { ExceptionHandler.handle(e, "Find Declarations", "Exception during search."); } } /** * When one {@link Source} (one file) is used in more than one context, {@link SearchEngine} will * return separate {@link SearchMatch} for each context. But we want to show {@link Source} only * once. */ static List<SearchMatch> getUniqueMatches(List<SearchMatch> matches) { Set<SearchMatch> uniqueMatches = Sets.newHashSet(); for (SearchMatch match : matches) { uniqueMatches.add(match); } return Lists.newArrayList(uniqueMatches); } static boolean isInvocationNameOrPropertyAccessSelected(DartSelection selection) { AstNode node = getSelectionNode(selection); if (!(node instanceof SimpleIdentifier)) { return false; } SimpleIdentifier name = (SimpleIdentifier) node; AstNode parent = name.getParent(); // method name if (parent instanceof MethodInvocation) { MethodInvocation invocation = (MethodInvocation) parent; return invocation.getMethodName() == name && invocation.getRealTarget() != null; } // property name if (parent instanceof PropertyAccess) { PropertyAccess access = (PropertyAccess) parent; return access.getPropertyName() == name && access.getRealTarget() != null; } // property name (cannot be distinguished from prefixed) if (parent instanceof PrefixedIdentifier) { PrefixedIdentifier prefixed = (PrefixedIdentifier) parent; return prefixed.getIdentifier() == name; } // we don't know this node return false; } /** * @return {@code true} if given {@link DartSelection} looks valid. */ private static boolean isValidSelection(DartSelection selection) { // If we know the exact Element, no need to search for singleton declarations Element element = getSelectionElement(selection); if (element != null) { return element instanceof MethodElement || element instanceof FieldElement || element instanceof PropertyAccessorElement; } // we want to search only method and property declarations return isInvocationNameOrPropertyAccessSelected(selection); } public FindDeclarationsAction(DartEditor editor) { super(editor); } public FindDeclarationsAction(IWorkbenchSite site) { super(site); } @Override public void selectionChanged(DartSelection selection) { setEnabled(isValidSelection(selection)); } @Override public void selectionChanged(IStructuredSelection selection) { Element element = getSelectionElement(selection); setEnabled(element != null); } @Override protected void doRun(DartSelection selection, Event event, UIInstrumentationBuilder instrumentation) { // may be resolved element Element element = ActionUtil.getActionElement(selection); if (element != null) { String name = element.getName(); doSearch(name); } // may be identifier AstNode node = getSelectionNode(selection); if (node instanceof SimpleIdentifier) { String name = ((SimpleIdentifier) node).getName(); doSearch(name); } } @Override protected void doRun(IStructuredSelection selection, Event event, UIInstrumentationBuilder instrumentation) { Element element = getSelectionElement(selection); if (element != null) { String name = element.getDisplayName(); doSearch(name); } } @Override protected void init() { setText(SearchMessages.Search_FindDeclarationsAction_label); setToolTipText(SearchMessages.Search_FindDeclarationsAction_tooltip); PlatformUI.getWorkbench().getHelpSystem().setHelp( this, DartHelpContextIds.FIND_DECLARATIONS_IN_WORKSPACE_ACTION); } }