]> git.uio.no Git - ifi-stolz-refaktor.git/blame - case-study/jdt-before/core extension/org/eclipse/jdt/internal/corext/dom/LinkedNodeFinder.java
Some talks, mostly identical.
[ifi-stolz-refaktor.git] / case-study / jdt-before / core extension / org / eclipse / jdt / internal / corext / dom / LinkedNodeFinder.java
CommitLineData
1b2798f6
EK
1/*******************************************************************************
2 * Copyright (c) 2000, 2011 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors:
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11package org.eclipse.jdt.internal.corext.dom;
12
13import java.util.ArrayList;
14
15import org.eclipse.jdt.core.compiler.IProblem;
16import org.eclipse.jdt.core.dom.ASTNode;
17import org.eclipse.jdt.core.dom.ASTVisitor;
18import org.eclipse.jdt.core.dom.BreakStatement;
19import org.eclipse.jdt.core.dom.CompilationUnit;
20import org.eclipse.jdt.core.dom.ContinueStatement;
21import org.eclipse.jdt.core.dom.IBinding;
22import org.eclipse.jdt.core.dom.IMethodBinding;
23import org.eclipse.jdt.core.dom.ITypeBinding;
24import org.eclipse.jdt.core.dom.IVariableBinding;
25import org.eclipse.jdt.core.dom.LabeledStatement;
26import org.eclipse.jdt.core.dom.NodeFinder;
27import org.eclipse.jdt.core.dom.SimpleName;
28
29
30/**
31 * Find all nodes connected to a given binding or node. e.g. Declaration of a field and all references.
32 * For types this includes also the constructor declaration, for methods also overridden methods
33 * or methods overriding (if existing in the same AST), for constructors also the type and all other constructors.
34 */
35
36public class LinkedNodeFinder {
37
38 private LinkedNodeFinder() {
39 }
40
41
42 /**
43 * Find all nodes connected to the given binding. e.g. Declaration of a field and all references.
44 * For types this includes also the constructor declaration, for methods also overridden methods
45 * or methods overriding (if existing in the same AST)
46 * @param root The root of the AST tree to search
47 * @param binding The binding of the searched nodes
48 * @return Return
49 */
50 public static SimpleName[] findByBinding(ASTNode root, IBinding binding) {
51 ArrayList<SimpleName> res= new ArrayList<SimpleName>();
52 BindingFinder nodeFinder= new BindingFinder(binding, res);
53 root.accept(nodeFinder);
54 return res.toArray(new SimpleName[res.size()]);
55 }
56
57 /**
58 * Find all nodes connected to the given name node. If the node has a binding then all nodes connected
59 * to this binding are returned. If the node has no binding, then all nodes that also miss a binding and have
60 * the same name are returned.
61 * @param root The root of the AST tree to search
62 * @param name The node to find linked nodes for
63 * @return Return
64 */
65 public static SimpleName[] findByNode(ASTNode root, SimpleName name) {
66 IBinding binding = name.resolveBinding();
67 if (binding != null) {
68 return findByBinding(root, binding);
69 }
70 SimpleName[] names= findByProblems(root, name);
71 if (names != null) {
72 return names;
73 }
74 int parentKind= name.getParent().getNodeType();
75 if (parentKind == ASTNode.LABELED_STATEMENT || parentKind == ASTNode.BREAK_STATEMENT || parentKind == ASTNode.CONTINUE_STATEMENT) {
76 ArrayList<SimpleName> res= new ArrayList<SimpleName>();
77 LabelFinder nodeFinder= new LabelFinder(name, res);
78 root.accept(nodeFinder);
79 return res.toArray(new SimpleName[res.size()]);
80 }
81 return new SimpleName[] { name };
82 }
83
84
85
86 private static final int FIELD= 1;
87 private static final int METHOD= 2;
88 private static final int TYPE= 4;
89 private static final int LABEL= 8;
90 private static final int NAME= FIELD | TYPE;
91
92 private static int getProblemKind(IProblem problem) {
93 switch (problem.getID()) {
94 case IProblem.UndefinedField:
95 return FIELD;
96 case IProblem.UndefinedMethod:
97 return METHOD;
98 case IProblem.UndefinedLabel:
99 return LABEL;
100 case IProblem.UndefinedName:
101 case IProblem.UnresolvedVariable:
102 return NAME;
103 case IProblem.UndefinedType:
104 return TYPE;
105 }
106 return 0;
107 }
108
109 private static int getNameNodeProblemKind(IProblem[] problems, SimpleName nameNode) {
110 int nameOffset= nameNode.getStartPosition();
111 int nameInclEnd= nameOffset + nameNode.getLength() - 1;
112
113 for (int i= 0; i < problems.length; i++) {
114 IProblem curr= problems[i];
115 if (curr.getSourceStart() == nameOffset && curr.getSourceEnd() == nameInclEnd) {
116 int kind= getProblemKind(curr);
117 if (kind != 0) {
118 return kind;
119 }
120 }
121 }
122 return 0;
123 }
124
125
126 public static SimpleName[] findByProblems(ASTNode parent, SimpleName nameNode) {
127 ArrayList<SimpleName> res= new ArrayList<SimpleName>();
128
129 ASTNode astRoot = parent.getRoot();
130 if (!(astRoot instanceof CompilationUnit)) {
131 return null;
132 }
133
134 IProblem[] problems= ((CompilationUnit) astRoot).getProblems();
135 int nameNodeKind= getNameNodeProblemKind(problems, nameNode);
136 if (nameNodeKind == 0) { // no problem on node
137 return null;
138 }
139
140 int bodyStart= parent.getStartPosition();
141 int bodyEnd= bodyStart + parent.getLength();
142
143 String name= nameNode.getIdentifier();
144
145 for (int i= 0; i < problems.length; i++) {
146 IProblem curr= problems[i];
147 int probStart= curr.getSourceStart();
148 int probEnd= curr.getSourceEnd() + 1;
149
150 if (probStart > bodyStart && probEnd < bodyEnd) {
151 int currKind= getProblemKind(curr);
152 if ((nameNodeKind & currKind) != 0) {
153 ASTNode node= NodeFinder.perform(parent, probStart, (probEnd - probStart));
154 if (node instanceof SimpleName && name.equals(((SimpleName) node).getIdentifier())) {
155 res.add((SimpleName) node);
156 }
157 }
158 }
159 }
160 return res.toArray(new SimpleName[res.size()]);
161 }
162
163 private static class LabelFinder extends ASTVisitor {
164
165 private SimpleName fLabel;
166 private ASTNode fDefiningLabel;
167 private ArrayList<SimpleName> fResult;
168
169 public LabelFinder(SimpleName label, ArrayList<SimpleName> result) {
170 super(true);
171 fLabel= label;
172 fResult= result;
173 fDefiningLabel= null;
174 }
175
176 private boolean isSameLabel(SimpleName label) {
177 return label != null && fLabel.getIdentifier().equals(label.getIdentifier());
178 }
179
180 @Override
181 public boolean visit(BreakStatement node) {
182 SimpleName label= node.getLabel();
183 if (fDefiningLabel != null && isSameLabel(label) && ASTNodes.isParent(label, fDefiningLabel)) {
184 fResult.add(label);
185 }
186 return false;
187 }
188
189 @Override
190 public boolean visit(ContinueStatement node) {
191 SimpleName label= node.getLabel();
192 if (fDefiningLabel != null && isSameLabel(label) && ASTNodes.isParent(label, fDefiningLabel)) {
193 fResult.add(label);
194 }
195 return false;
196 }
197
198 @Override
199 public boolean visit(LabeledStatement node) {
200 if (fDefiningLabel == null) {
201 SimpleName label= node.getLabel();
202 if (fLabel == label || isSameLabel(label) && ASTNodes.isParent(fLabel, node)) {
203 fDefiningLabel= node;
204 fResult.add(label);
205 }
206 }
207 node.getBody().accept(this);
208 return false;
209 }
210 }
211
212 private static class BindingFinder extends ASTVisitor {
213
214 private IBinding fBinding;
215 private ArrayList<SimpleName> fResult;
216
217 public BindingFinder(IBinding binding, ArrayList<SimpleName> result) {
218 super(true);
219 fBinding= getDeclaration(binding);
220 fResult= result;
221 }
222
223 @Override
224 public boolean visit(SimpleName node) {
225 IBinding binding= node.resolveBinding();
226 if (binding == null) {
227 return false;
228 }
229 binding= getDeclaration(binding);
230
231 if (fBinding == binding) {
232 fResult.add(node);
233 } else if (binding.getKind() != fBinding.getKind()) {
234 return false;
235 } else if (binding.getKind() == IBinding.METHOD) {
236 IMethodBinding curr= (IMethodBinding) binding;
237 IMethodBinding methodBinding= (IMethodBinding) fBinding;
238 if (methodBinding.overrides(curr) || curr.overrides(methodBinding)) {
239 fResult.add(node);
240 }
241 }
242 return false;
243 }
244
245 private static IBinding getDeclaration(IBinding binding) {
246 if (binding instanceof ITypeBinding) {
247 return ((ITypeBinding) binding).getTypeDeclaration();
248 } else if (binding instanceof IMethodBinding) {
249 IMethodBinding methodBinding= (IMethodBinding) binding;
250 if (methodBinding.isConstructor()) { // link all constructors with their type
251 return methodBinding.getDeclaringClass().getTypeDeclaration();
252 } else {
253 return methodBinding.getMethodDeclaration();
254 }
255 } else if (binding instanceof IVariableBinding) {
256 return ((IVariableBinding) binding).getVariableDeclaration();
257 }
258 return binding;
259 }
260 }
261}