| /******************************************************************************* |
| * Copyright (c) 2000, 2006 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.jdt.internal.ui.search; |
| |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.List; |
| |
| import org.eclipse.jface.text.BadLocationException; |
| import org.eclipse.jface.text.IDocument; |
| import org.eclipse.jface.text.IRegion; |
| |
| import org.eclipse.search.ui.text.Match; |
| |
| import org.eclipse.jdt.core.IJavaElement; |
| import org.eclipse.jdt.core.dom.ASTNode; |
| import org.eclipse.jdt.core.dom.ASTVisitor; |
| import org.eclipse.jdt.core.dom.Assignment; |
| import org.eclipse.jdt.core.dom.ClassInstanceCreation; |
| import org.eclipse.jdt.core.dom.CompilationUnit; |
| import org.eclipse.jdt.core.dom.Expression; |
| import org.eclipse.jdt.core.dom.FieldAccess; |
| import org.eclipse.jdt.core.dom.IBinding; |
| import org.eclipse.jdt.core.dom.IMethodBinding; |
| import org.eclipse.jdt.core.dom.ITypeBinding; |
| import org.eclipse.jdt.core.dom.IVariableBinding; |
| import org.eclipse.jdt.core.dom.ImportDeclaration; |
| import org.eclipse.jdt.core.dom.MethodInvocation; |
| import org.eclipse.jdt.core.dom.Modifier; |
| import org.eclipse.jdt.core.dom.Name; |
| import org.eclipse.jdt.core.dom.ParameterizedType; |
| import org.eclipse.jdt.core.dom.PostfixExpression; |
| import org.eclipse.jdt.core.dom.PrefixExpression; |
| import org.eclipse.jdt.core.dom.QualifiedName; |
| import org.eclipse.jdt.core.dom.SimpleName; |
| import org.eclipse.jdt.core.dom.SimpleType; |
| import org.eclipse.jdt.core.dom.SingleVariableDeclaration; |
| import org.eclipse.jdt.core.dom.Type; |
| import org.eclipse.jdt.core.dom.VariableDeclarationFragment; |
| import org.eclipse.jdt.core.dom.PrefixExpression.Operator; |
| |
| import org.eclipse.jdt.internal.corext.dom.ASTNodes; |
| import org.eclipse.jdt.internal.corext.dom.Bindings; |
| import org.eclipse.jdt.internal.corext.dom.NodeFinder; |
| |
| public class OccurrencesFinder extends ASTVisitor implements IOccurrencesFinder { |
| |
| public static final String IS_WRITEACCESS= "writeAccess"; //$NON-NLS-1$ |
| public static final String IS_VARIABLE= "variable"; //$NON-NLS-1$ |
| |
| private CompilationUnit fRoot; |
| private Name fSelectedNode; |
| private IBinding fTarget; |
| private List fUsages= new ArrayList/*<ASTNode>*/(); |
| private List fWriteUsages= new ArrayList/*<ASTNode>*/(); |
| private boolean fTargetIsStaticMethodImport; |
| |
| public OccurrencesFinder(IBinding target) { |
| super(true); |
| fTarget= target; |
| } |
| |
| public OccurrencesFinder() { |
| super(true); |
| } |
| |
| public String initialize(CompilationUnit root, int offset, int length) { |
| return initialize(root, NodeFinder.perform(root, offset, length)); |
| } |
| |
| public String initialize(CompilationUnit root, ASTNode node) { |
| if (!(node instanceof Name)) |
| return SearchMessages.OccurrencesFinder_no_element; |
| fRoot= root; |
| fSelectedNode= (Name)node; |
| fTarget= fSelectedNode.resolveBinding(); |
| if (fTarget == null) |
| return SearchMessages.OccurrencesFinder_no_binding; |
| fTarget= getBindingDeclaration(fTarget); |
| |
| fTargetIsStaticMethodImport= isStaticImport(fSelectedNode.getParent()); |
| return null; |
| } |
| |
| public List perform() { |
| fRoot.accept(this); |
| return fUsages; |
| } |
| |
| public void collectOccurrenceMatches(IJavaElement element, IDocument document, Collection resultingMatches) { |
| boolean isVariable= fTarget instanceof IVariableBinding; |
| HashMap lineToGroup= new HashMap(); |
| |
| for (Iterator iter= fUsages.iterator(); iter.hasNext();) { |
| ASTNode node= (ASTNode) iter.next(); |
| int startPosition= node.getStartPosition(); |
| int length= node.getLength(); |
| try { |
| boolean isWriteAccess= fWriteUsages.contains(node); |
| int line= document.getLineOfOffset(startPosition); |
| Integer lineInteger= new Integer(line); |
| OccurrencesGroupKey groupKey= (OccurrencesGroupKey) lineToGroup.get(lineInteger); |
| if (groupKey == null) { |
| IRegion region= document.getLineInformation(line); |
| String lineContents= document.get(region.getOffset(), region.getLength()).trim(); |
| groupKey= new OccurrencesGroupKey(element, line, lineContents, isWriteAccess, isVariable); |
| lineToGroup.put(lineInteger, groupKey); |
| } else if (isWriteAccess) { |
| // a line with read an write access is considered as write access: |
| groupKey.setWriteAccess(true); |
| } |
| Match match= new Match(groupKey, startPosition, length); |
| resultingMatches.add(match); |
| } catch (BadLocationException e) { |
| //nothing |
| } |
| } |
| } |
| |
| /* |
| * @see org.eclipse.jdt.internal.ui.search.IOccurrencesFinder#getJobLabel() |
| */ |
| public String getJobLabel() { |
| return SearchMessages.OccurrencesFinder_searchfor ; |
| } |
| |
| public String getElementName() { |
| if (fSelectedNode != null) { |
| return ASTNodes.asString(fSelectedNode); |
| } |
| return null; |
| } |
| |
| public String getUnformattedPluralLabel() { |
| return SearchMessages.OccurrencesFinder_label_plural; |
| } |
| |
| public String getUnformattedSingularLabel() { |
| return SearchMessages.OccurrencesFinder_label_singular; |
| } |
| |
| public boolean visit(QualifiedName node) { |
| final IBinding binding= node.resolveBinding(); |
| if (binding instanceof IVariableBinding && ((IVariableBinding)binding).isField()) { |
| SimpleName name= node.getName(); |
| return !match(name, fUsages, name.resolveBinding()); |
| } |
| if (binding instanceof IMethodBinding) { |
| if (isStaticImport(node)) { |
| SimpleName name= node.getName(); |
| return !matchStaticImport(name, fUsages, (IMethodBinding)binding); |
| } |
| } |
| return !match(node, fUsages, binding); |
| } |
| |
| private static boolean isStaticImport(ASTNode node) { |
| if (!(node instanceof QualifiedName)) |
| return false; |
| |
| ASTNode parent= ((QualifiedName)node).getParent(); |
| return parent instanceof ImportDeclaration && ((ImportDeclaration)parent).isStatic(); |
| } |
| |
| public boolean visit(MethodInvocation node) { |
| if (fTargetIsStaticMethodImport) |
| return !matchStaticImport(node.getName(), fUsages, node.resolveMethodBinding()); |
| |
| return true; |
| } |
| |
| public boolean visit(SimpleName node) { |
| return !match(node, fUsages, node.resolveBinding()); |
| } |
| |
| /* |
| * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.ConstructorInvocation) |
| */ |
| public boolean visit(ClassInstanceCreation node) { |
| // match with the constructor and the type. |
| Type type= node.getType(); |
| if (type instanceof ParameterizedType) { |
| type= ((ParameterizedType) type).getType(); |
| } |
| if (type instanceof SimpleType) { |
| Name name= ((SimpleType) type).getName(); |
| if (name instanceof QualifiedName) |
| name= ((QualifiedName)name).getName(); |
| match(name, fUsages, node.resolveConstructorBinding()); |
| } |
| return super.visit(node); |
| } |
| |
| public boolean visit(Assignment node) { |
| Expression lhs= node.getLeftHandSide(); |
| SimpleName name= getSimpleName(lhs); |
| if (name != null) |
| match(name, fWriteUsages, name.resolveBinding()); |
| lhs.accept(this); |
| node.getRightHandSide().accept(this); |
| return false; |
| } |
| |
| public boolean visit(SingleVariableDeclaration node) { |
| match(node.getName(), fWriteUsages, node.resolveBinding()); |
| return super.visit(node); |
| } |
| |
| public boolean visit(VariableDeclarationFragment node) { |
| if (node.getParent().getNodeType() == ASTNode.FIELD_DECLARATION || node.getInitializer() != null) |
| match(node.getName(), fWriteUsages, node.resolveBinding()); |
| return super.visit(node); |
| } |
| |
| public boolean visit(PrefixExpression node) { |
| PrefixExpression.Operator operator= node.getOperator(); |
| if (operator == Operator.INCREMENT || operator == Operator.DECREMENT) { |
| Expression operand= node.getOperand(); |
| SimpleName name= getSimpleName(operand); |
| if (name != null) |
| match(name, fWriteUsages, name.resolveBinding()); |
| } |
| return super.visit(node); |
| } |
| |
| public boolean visit(PostfixExpression node) { |
| Expression operand= node.getOperand(); |
| SimpleName name= getSimpleName(operand); |
| if (name != null) |
| match(name, fWriteUsages, name.resolveBinding()); |
| return super.visit(node); |
| } |
| |
| private boolean match(Name node, List result, IBinding binding) { |
| if (binding != null && Bindings.equals(getBindingDeclaration(binding), fTarget)) { |
| result.add(node); |
| return true; |
| } |
| return false; |
| } |
| |
| private boolean matchStaticImport(Name node, List result, IMethodBinding binding) { |
| if (binding == null || node == null || !(fTarget instanceof IMethodBinding) || !Modifier.isStatic(binding.getModifiers())) |
| return false; |
| |
| IMethodBinding targetMethodBinding= (IMethodBinding)fTarget; |
| if ((fTargetIsStaticMethodImport || Modifier.isStatic(targetMethodBinding.getModifiers())) && (targetMethodBinding.getDeclaringClass().getTypeDeclaration() == binding.getDeclaringClass().getTypeDeclaration())) { |
| if (node.getFullyQualifiedName().equals(targetMethodBinding.getName())) { |
| result.add(node); |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| private SimpleName getSimpleName(Expression expression) { |
| if (expression instanceof SimpleName) |
| return ((SimpleName)expression); |
| else if (expression instanceof QualifiedName) |
| return (((QualifiedName) expression).getName()); |
| else if (expression instanceof FieldAccess) |
| return ((FieldAccess)expression).getName(); |
| return null; |
| } |
| |
| private IBinding getBindingDeclaration(IBinding binding) { |
| switch (binding.getKind()) { |
| case IBinding.TYPE : |
| return ((ITypeBinding)binding).getTypeDeclaration(); |
| case IBinding.METHOD : |
| return ((IMethodBinding)binding).getMethodDeclaration(); |
| case IBinding.VARIABLE : |
| return ((IVariableBinding)binding).getVariableDeclaration(); |
| default: |
| return binding; |
| } |
| } |
| } |