/plug-ins/helios/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MemberDeclarationVisitor.java

https://github.com/vazexqi/CodingSpectator · Java · 327 lines · 265 code · 35 blank · 27 comment · 90 complexity · bd0983a9b63868eea9e980fe0972d37b MD5 · raw file

  1. /*******************************************************************************
  2. * Copyright (c) 2000, 2009 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. *******************************************************************************/
  11. package org.eclipse.jdt.internal.core.search.matching;
  12. import org.eclipse.core.runtime.CoreException;
  13. import org.eclipse.jdt.core.IAnnotatable;
  14. import org.eclipse.jdt.core.IJavaElement;
  15. import org.eclipse.jdt.core.compiler.CharOperation;
  16. import org.eclipse.jdt.internal.compiler.ASTVisitor;
  17. import org.eclipse.jdt.internal.compiler.ast.ASTNode;
  18. import org.eclipse.jdt.internal.compiler.ast.Annotation;
  19. import org.eclipse.jdt.internal.compiler.ast.Argument;
  20. import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration;
  21. import org.eclipse.jdt.internal.compiler.ast.MarkerAnnotation;
  22. import org.eclipse.jdt.internal.compiler.ast.NormalAnnotation;
  23. import org.eclipse.jdt.internal.compiler.ast.QualifiedNameReference;
  24. import org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference;
  25. import org.eclipse.jdt.internal.compiler.ast.SingleMemberAnnotation;
  26. import org.eclipse.jdt.internal.compiler.ast.SingleNameReference;
  27. import org.eclipse.jdt.internal.compiler.ast.SingleTypeReference;
  28. import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
  29. import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
  30. import org.eclipse.jdt.internal.compiler.util.HashtableOfIntValues;
  31. import org.eclipse.jdt.internal.core.search.matching.MatchLocator.WrappedCoreException;
  32. /**
  33. * Specific visitor of field or method declaration which can identify and store the local and other
  34. * elements of one or several matching nodes.
  35. * <p>
  36. * This visitor can also peek up local or anonymous type declaration and restart a new
  37. * {@link MatchLocator} traverse on this type.
  38. * </p>
  39. */
  40. class MemberDeclarationVisitor extends ASTVisitor {
  41. // Matches information
  42. private final MatchLocator locator;
  43. private final IJavaElement enclosingElement;
  44. private final MatchingNodeSet nodeSet;
  45. private final ASTNode[] matchingNodes;
  46. private final ASTNode matchingNode;
  47. // Local type storage
  48. HashtableOfIntValues occurrencesCounts= new HashtableOfIntValues(); // key = class name (char[]), value = occurrenceCount (int)
  49. int nodesCount= 0;
  50. // Local and other elements storage
  51. private Annotation annotation;
  52. private LocalDeclaration localDeclaration;
  53. IJavaElement localElement;
  54. IJavaElement[] localElements, otherElements;
  55. IJavaElement[][] allOtherElements;
  56. int ptr= -1;
  57. int[] ptrs;
  58. public MemberDeclarationVisitor(IJavaElement element, ASTNode[] nodes, MatchingNodeSet set, MatchLocator locator) {
  59. this.enclosingElement= element;
  60. this.nodeSet= set;
  61. this.locator= locator;
  62. if (nodes == null) {
  63. this.matchingNode= null;
  64. this.matchingNodes= null;
  65. } else {
  66. this.nodesCount= nodes.length;
  67. if (nodes.length == 1) {
  68. this.matchingNode= nodes[0];
  69. this.matchingNodes= null;
  70. } else {
  71. this.matchingNode= null;
  72. this.matchingNodes= nodes;
  73. this.localElements= new IJavaElement[this.nodesCount];
  74. this.ptrs= new int[this.nodesCount];
  75. this.allOtherElements= new IJavaElement[this.nodesCount][];
  76. }
  77. }
  78. }
  79. public void endVisit(Argument argument, BlockScope scope) {
  80. this.localDeclaration= null;
  81. }
  82. public void endVisit(LocalDeclaration declaration, BlockScope scope) {
  83. this.localDeclaration= null;
  84. }
  85. public void endVisit(MarkerAnnotation markerAnnotation, BlockScope unused) {
  86. this.annotation= null;
  87. }
  88. public void endVisit(NormalAnnotation normalAnnotation, BlockScope unused) {
  89. this.annotation= null;
  90. }
  91. public void endVisit(SingleMemberAnnotation singleMemberAnnotation, BlockScope unused) {
  92. this.annotation= null;
  93. }
  94. IJavaElement getLocalElement(int idx) {
  95. if (this.nodesCount == 1) {
  96. return this.localElement;
  97. }
  98. if (this.localElements != null) {
  99. return this.localElements[idx];
  100. }
  101. return null;
  102. }
  103. IJavaElement[] getOtherElements(int idx) {
  104. if (this.nodesCount == 1) {
  105. if (this.otherElements != null) {
  106. int length= this.otherElements.length;
  107. if (this.ptr < (length - 1)) {
  108. System.arraycopy(this.otherElements, 0, this.otherElements= new IJavaElement[this.ptr + 1], 0, this.ptr + 1);
  109. }
  110. }
  111. return this.otherElements;
  112. }
  113. IJavaElement[] elements= this.allOtherElements == null ? null : this.allOtherElements[idx];
  114. if (elements != null) {
  115. int length= elements.length;
  116. if (this.ptrs[idx] < (length - 1)) {
  117. System.arraycopy(elements, 0, elements= this.allOtherElements[idx]= new IJavaElement[this.ptrs[idx] + 1], 0, this.ptrs[idx] + 1);
  118. }
  119. }
  120. return elements;
  121. }
  122. private int matchNode(ASTNode reference) {
  123. if (this.matchingNode != null) {
  124. if (this.matchingNode == reference)
  125. return 0;
  126. } else {
  127. int length= this.matchingNodes.length;
  128. for (int i= 0; i < length; i++) {
  129. if (this.matchingNodes[i] == reference) { // == is intentional
  130. return i;
  131. }
  132. }
  133. }
  134. return -1;
  135. }
  136. /*
  137. * Store the handle for the reference of the given index (e.g. peek in #matchingNodes
  138. * or #matchingNode).
  139. * Note that for performance reason, matching node and associated handles are
  140. * not stored in array when there's only one reference to identify.
  141. */
  142. private void storeHandle(int idx) {
  143. if (this.localDeclaration == null)
  144. return;
  145. IJavaElement handle= this.locator.createHandle(this.localDeclaration, this.enclosingElement);
  146. if (this.nodesCount == 1) {
  147. if (this.localElement == null) {
  148. if (this.annotation == null) {
  149. this.localElement= handle;
  150. } else {
  151. IJavaElement annotHandle= this.locator.createHandle(this.annotation, (IAnnotatable)handle);
  152. if (annotHandle == null) {
  153. annotHandle= this.locator.createHandle(this.annotation, (IAnnotatable)this.enclosingElement);
  154. }
  155. this.localElement= annotHandle == null ? handle : annotHandle;
  156. }
  157. } else {
  158. if (++this.ptr == 0) {
  159. this.otherElements= new IJavaElement[10];
  160. } else {
  161. int length= this.otherElements.length;
  162. if (this.ptr == length) {
  163. System.arraycopy(this.otherElements, 0, this.otherElements= new IJavaElement[length + 10], 0, length);
  164. }
  165. }
  166. if (this.annotation == null) {
  167. this.otherElements[this.ptr]= handle;
  168. } else {
  169. IJavaElement annotHandle= this.locator.createHandle(this.annotation, (IAnnotatable)handle);
  170. if (annotHandle == null) {
  171. annotHandle= this.locator.createHandle(this.annotation, (IAnnotatable)this.enclosingElement);
  172. }
  173. this.otherElements[this.ptr]= annotHandle == null ? handle : annotHandle;
  174. }
  175. }
  176. } else {
  177. if (this.localElements[idx] == null) {
  178. if (this.annotation == null) {
  179. this.localElements[idx]= handle;
  180. } else {
  181. IJavaElement annotHandle= this.locator.createHandle(this.annotation, (IAnnotatable)handle);
  182. if (annotHandle == null) {
  183. annotHandle= this.locator.createHandle(this.annotation, (IAnnotatable)this.enclosingElement);
  184. }
  185. this.localElements[idx]= annotHandle == null ? handle : annotHandle;
  186. }
  187. this.ptrs[idx]= -1;
  188. } else {
  189. int oPtr= ++this.ptrs[idx];
  190. if (oPtr == 0) {
  191. this.allOtherElements[idx]= new IJavaElement[10];
  192. } else {
  193. int length= this.allOtherElements[idx].length;
  194. if (oPtr == length) {
  195. System.arraycopy(this.allOtherElements[idx], 0, this.allOtherElements[idx]= new IJavaElement[length + 10], 0, length);
  196. }
  197. }
  198. if (this.annotation == null) {
  199. this.allOtherElements[idx][oPtr]= handle;
  200. } else {
  201. IJavaElement annotHandle= this.locator.createHandle(this.annotation, (IAnnotatable)handle);
  202. if (annotHandle == null) {
  203. annotHandle= this.locator.createHandle(this.annotation, (IAnnotatable)this.enclosingElement);
  204. }
  205. this.allOtherElements[idx][oPtr]= annotHandle == null ? handle : annotHandle;
  206. }
  207. }
  208. }
  209. }
  210. public boolean visit(Argument argument, BlockScope scope) {
  211. this.localDeclaration= argument;
  212. return true;
  213. }
  214. public boolean visit(LocalDeclaration declaration, BlockScope scope) {
  215. this.localDeclaration= declaration;
  216. return true;
  217. }
  218. public boolean visit(MarkerAnnotation markerAnnotation, BlockScope unused) {
  219. this.annotation= markerAnnotation;
  220. return true;
  221. }
  222. public boolean visit(NormalAnnotation normalAnnotation, BlockScope unused) {
  223. this.annotation= normalAnnotation;
  224. return true;
  225. }
  226. public boolean visit(QualifiedNameReference nameReference, BlockScope unused) {
  227. if (this.nodesCount > 0) {
  228. int idx= matchNode(nameReference);
  229. if (idx >= 0) {
  230. storeHandle(idx);
  231. }
  232. }
  233. return false;
  234. }
  235. public boolean visit(QualifiedTypeReference typeReference, BlockScope unused) {
  236. if (this.nodesCount > 0) {
  237. int idx= matchNode(typeReference);
  238. if (idx >= 0) {
  239. storeHandle(idx);
  240. }
  241. }
  242. return false;
  243. }
  244. public boolean visit(SingleMemberAnnotation singleMemberAnnotation, BlockScope unused) {
  245. this.annotation= singleMemberAnnotation;
  246. return true;
  247. }
  248. public boolean visit(SingleNameReference nameReference, BlockScope unused) {
  249. if (this.nodesCount > 0) {
  250. int idx= matchNode(nameReference);
  251. if (idx >= 0) {
  252. storeHandle(idx);
  253. }
  254. }
  255. return false;
  256. }
  257. public boolean visit(SingleTypeReference typeReference, BlockScope unused) {
  258. if (this.nodesCount > 0) {
  259. int idx= matchNode(typeReference);
  260. if (idx >= 0) {
  261. storeHandle(idx);
  262. }
  263. }
  264. return false;
  265. }
  266. public boolean visit(TypeDeclaration typeDeclaration, BlockScope unused) {
  267. try {
  268. char[] simpleName;
  269. if ((typeDeclaration.bits & ASTNode.IsAnonymousType) != 0) {
  270. simpleName= CharOperation.NO_CHAR;
  271. } else {
  272. simpleName= typeDeclaration.name;
  273. }
  274. int occurrenceCount= this.occurrencesCounts.get(simpleName);
  275. if (occurrenceCount == HashtableOfIntValues.NO_VALUE) {
  276. occurrenceCount= 1;
  277. } else {
  278. occurrenceCount= occurrenceCount + 1;
  279. }
  280. this.occurrencesCounts.put(simpleName, occurrenceCount);
  281. if ((typeDeclaration.bits & ASTNode.IsAnonymousType) != 0) {
  282. this.locator.reportMatching(typeDeclaration, this.enclosingElement, -1, this.nodeSet, occurrenceCount);
  283. } else {
  284. Integer level= (Integer)this.nodeSet.matchingNodes.removeKey(typeDeclaration);
  285. this.locator.reportMatching(typeDeclaration, this.enclosingElement, level != null ? level.intValue() : -1, this.nodeSet, occurrenceCount);
  286. }
  287. return false; // don't visit members as this was done during reportMatching(...)
  288. } catch (CoreException e) {
  289. throw new WrappedCoreException(e);
  290. }
  291. }
  292. }