001: /*******************************************************************************
002: * Copyright (c) 2000, 2006 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.jdt.internal.core.search.matching;
011:
012: import java.util.ArrayList;
013:
014: import org.eclipse.jdt.core.search.SearchMatch;
015: import org.eclipse.jdt.core.search.SearchPattern;
016: import org.eclipse.jdt.internal.compiler.ast.*;
017: import org.eclipse.jdt.internal.compiler.util.HashtableOfLong;
018: import org.eclipse.jdt.internal.compiler.util.SimpleLookupTable;
019: import org.eclipse.jdt.internal.compiler.util.SimpleSet;
020: import org.eclipse.jdt.internal.core.util.Util;
021:
022: /**
023: * A set of matches and possible matches, which need to be resolved.
024: */
025: public class MatchingNodeSet {
026:
027: /**
028: * Map of matching ast nodes that don't need to be resolved to their accuracy level.
029: * Each node is removed as it is reported.
030: */
031: SimpleLookupTable matchingNodes = new SimpleLookupTable(3); // node -> accuracy
032: private HashtableOfLong matchingNodesKeys = new HashtableOfLong(3); // sourceRange -> node
033: static Integer EXACT_MATCH = new Integer(SearchMatch.A_ACCURATE);
034: static Integer POTENTIAL_MATCH = new Integer(
035: SearchMatch.A_INACCURATE);
036: static Integer ERASURE_MATCH = new Integer(
037: SearchPattern.R_ERASURE_MATCH);
038:
039: /**
040: * Tell whether locators need to resolve or not for current matching node set.
041: */
042: public boolean mustResolve;
043:
044: /**
045: * Set of possible matching ast nodes. They need to be resolved
046: * to determine if they really match the search pattern.
047: */
048: SimpleSet possibleMatchingNodesSet = new SimpleSet(7);
049: private HashtableOfLong possibleMatchingNodesKeys = new HashtableOfLong(
050: 7);
051:
052: public MatchingNodeSet(boolean mustResolvePattern) {
053: super ();
054: mustResolve = mustResolvePattern;
055: }
056:
057: public int addMatch(ASTNode node, int matchLevel) {
058: int maskedLevel = matchLevel & PatternLocator.MATCH_LEVEL_MASK;
059: switch (maskedLevel) {
060: case PatternLocator.INACCURATE_MATCH:
061: if (matchLevel != maskedLevel) {
062: addTrustedMatch(
063: node,
064: new Integer(
065: SearchMatch.A_INACCURATE
066: + (matchLevel & PatternLocator.FLAVORS_MASK)));
067: } else {
068: addTrustedMatch(node, POTENTIAL_MATCH);
069: }
070: break;
071: case PatternLocator.POSSIBLE_MATCH:
072: addPossibleMatch(node);
073: break;
074: case PatternLocator.ERASURE_MATCH:
075: if (matchLevel != maskedLevel) {
076: addTrustedMatch(
077: node,
078: new Integer(
079: SearchPattern.R_ERASURE_MATCH
080: + (matchLevel & PatternLocator.FLAVORS_MASK)));
081: } else {
082: addTrustedMatch(node, ERASURE_MATCH);
083: }
084: break;
085: case PatternLocator.ACCURATE_MATCH:
086: if (matchLevel != maskedLevel) {
087: addTrustedMatch(
088: node,
089: new Integer(
090: SearchMatch.A_ACCURATE
091: + (matchLevel & PatternLocator.FLAVORS_MASK)));
092: } else {
093: addTrustedMatch(node, EXACT_MATCH);
094: }
095: break;
096: }
097: return matchLevel;
098: }
099:
100: public void addPossibleMatch(ASTNode node) {
101: // remove existing node at same position from set
102: // (case of recovery that created the same node several time
103: // see http://bugs.eclipse.org/bugs/show_bug.cgi?id=29366)
104: long key = (((long) node.sourceStart) << 32) + node.sourceEnd;
105: ASTNode existing = (ASTNode) this .possibleMatchingNodesKeys
106: .get(key);
107: if (existing != null
108: && existing.getClass().equals(node.getClass()))
109: this .possibleMatchingNodesSet.remove(existing);
110:
111: // add node to set
112: this .possibleMatchingNodesSet.add(node);
113: this .possibleMatchingNodesKeys.put(key, node);
114: }
115:
116: public void addTrustedMatch(ASTNode node, boolean isExact) {
117: addTrustedMatch(node, isExact ? EXACT_MATCH : POTENTIAL_MATCH);
118:
119: }
120:
121: void addTrustedMatch(ASTNode node, Integer level) {
122: // remove existing node at same position from set
123: // (case of recovery that created the same node several time
124: // see http://bugs.eclipse.org/bugs/show_bug.cgi?id=29366)
125: long key = (((long) node.sourceStart) << 32) + node.sourceEnd;
126: ASTNode existing = (ASTNode) this .matchingNodesKeys.get(key);
127: if (existing != null
128: && existing.getClass().equals(node.getClass()))
129: this .matchingNodes.removeKey(existing);
130:
131: // map node to its accuracy level
132: this .matchingNodes.put(node, level);
133: this .matchingNodesKeys.put(key, node);
134: }
135:
136: protected boolean hasPossibleNodes(int start, int end) {
137: Object[] nodes = this .possibleMatchingNodesSet.values;
138: for (int i = 0, l = nodes.length; i < l; i++) {
139: ASTNode node = (ASTNode) nodes[i];
140: if (node != null && start <= node.sourceStart
141: && node.sourceEnd <= end)
142: return true;
143: }
144: nodes = this .matchingNodes.keyTable;
145: for (int i = 0, l = nodes.length; i < l; i++) {
146: ASTNode node = (ASTNode) nodes[i];
147: if (node != null && start <= node.sourceStart
148: && node.sourceEnd <= end)
149: return true;
150: }
151: return false;
152: }
153:
154: /**
155: * Returns the matching nodes that are in the given range in the source order.
156: */
157: protected ASTNode[] matchingNodes(int start, int end) {
158: ArrayList nodes = null;
159: Object[] keyTable = this .matchingNodes.keyTable;
160: for (int i = 0, l = keyTable.length; i < l; i++) {
161: ASTNode node = (ASTNode) keyTable[i];
162: if (node != null && start <= node.sourceStart
163: && node.sourceEnd <= end) {
164: if (nodes == null)
165: nodes = new ArrayList();
166: nodes.add(node);
167: }
168: }
169: if (nodes == null)
170: return null;
171:
172: ASTNode[] result = new ASTNode[nodes.size()];
173: nodes.toArray(result);
174:
175: // sort nodes by source starts
176: Util.Comparer comparer = new Util.Comparer() {
177: public int compare(Object o1, Object o2) {
178: return ((ASTNode) o1).sourceStart
179: - ((ASTNode) o2).sourceStart;
180: }
181: };
182: Util.sort(result, comparer);
183: return result;
184: }
185:
186: public Object removePossibleMatch(ASTNode node) {
187: long key = (((long) node.sourceStart) << 32) + node.sourceEnd;
188: ASTNode existing = (ASTNode) this .possibleMatchingNodesKeys
189: .get(key);
190: if (existing == null)
191: return null;
192:
193: this .possibleMatchingNodesKeys.put(key, null);
194: return this .possibleMatchingNodesSet.remove(node);
195: }
196:
197: public Object removeTrustedMatch(ASTNode node) {
198: long key = (((long) node.sourceStart) << 32) + node.sourceEnd;
199: ASTNode existing = (ASTNode) this .matchingNodesKeys.get(key);
200: if (existing == null)
201: return null;
202:
203: this .matchingNodesKeys.put(key, null);
204: return this .matchingNodes.removeKey(node);
205: }
206:
207: public String toString() {
208: // TODO (jerome) should show both tables
209: StringBuffer result = new StringBuffer();
210: result.append("Exact matches:"); //$NON-NLS-1$
211: Object[] keyTable = this .matchingNodes.keyTable;
212: Object[] valueTable = this .matchingNodes.valueTable;
213: for (int i = 0, l = keyTable.length; i < l; i++) {
214: ASTNode node = (ASTNode) keyTable[i];
215: if (node == null)
216: continue;
217: result.append("\n\t"); //$NON-NLS-1$
218: switch (((Integer) valueTable[i]).intValue()) {
219: case SearchMatch.A_ACCURATE:
220: result.append("ACCURATE_MATCH: "); //$NON-NLS-1$
221: break;
222: case SearchMatch.A_INACCURATE:
223: result.append("INACCURATE_MATCH: "); //$NON-NLS-1$
224: break;
225: case SearchPattern.R_ERASURE_MATCH:
226: result.append("ERASURE_MATCH: "); //$NON-NLS-1$
227: break;
228: }
229: node.print(0, result);
230: }
231:
232: result.append("\nPossible matches:"); //$NON-NLS-1$
233: Object[] nodes = this .possibleMatchingNodesSet.values;
234: for (int i = 0, l = nodes.length; i < l; i++) {
235: ASTNode node = (ASTNode) nodes[i];
236: if (node == null)
237: continue;
238: result.append("\nPOSSIBLE_MATCH: "); //$NON-NLS-1$
239: node.print(0, result);
240: }
241: return result.toString();
242: }
243: }
|