1/* 2 * Copyright (c) 1997, 2003, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26package sun.tools.java; 27 28import java.util.*; 29 30/** 31 * The MethodSet structure is used to store methods for a class. 32 * It maintains the invariant that it never stores two methods 33 * with the same signature. MethodSets are able to lookup 34 * all methods with a given name and the unique method with a given 35 * signature (name, args). 36 * 37 * WARNING: The contents of this source file are not part of any 38 * supported API. Code that depends on them does so at its own risk: 39 * they are subject to change or removal without notice. 40 */ 41 42public 43class MethodSet { 44 45 /** 46 * A Map containing Lists of MemberDefinitions. The Lists 47 * contain methods which share the same name. 48 */ 49 private final Map<Identifier,List<MemberDefinition>> lookupMap; 50 51 /** 52 * The number of methods stored in the MethodSet. 53 */ 54 private int count; 55 56 /** 57 * Is this MethodSet currently frozen? See freeze() for more details. 58 */ 59 private boolean frozen; 60 61 /** 62 * Creates a brand new MethodSet 63 */ 64 public MethodSet() { 65 frozen = false; 66 lookupMap = new HashMap<>(); 67 count = 0; 68 } 69 70 /** 71 * Returns the number of distinct methods stored in the MethodSet. 72 */ 73 public int size() { 74 return count; 75 } 76 77 /** 78 * Adds `method' to the MethodSet. No method of the same signature 79 * should be already defined. 80 */ 81 public void add(MemberDefinition method) { 82 // Check for late additions. 83 if (frozen) { 84 throw new CompilerError("add()"); 85 } 86 87 // todo: Check for method?? 88 89 Identifier name = method.getName(); 90 91 // Get a List containing all methods of this name. 92 List<MemberDefinition> methodList = lookupMap.get(name); 93 94 if (methodList == null) { 95 // There is no method with this name already. 96 // Create a List, and insert it into the hash. 97 methodList = new ArrayList<>(); 98 lookupMap.put(name, methodList); 99 } 100 101 // Make sure that no method with the same signature has already 102 // been added to the MethodSet. 103 int size = methodList.size(); 104 for (int i = 0; i < size; i++) { 105 if ((methodList.get(i)) 106 .getType().equalArguments(method.getType())) { 107 throw new CompilerError("duplicate addition"); 108 } 109 } 110 111 // We add the method to the appropriate list. 112 methodList.add(method); 113 count++; 114 } 115 116 /** 117 * Adds `method' to the MethodSet, replacing any previous definition 118 * with the same signature. 119 */ 120 public void replace(MemberDefinition method) { 121 // Check for late additions. 122 if (frozen) { 123 throw new CompilerError("replace()"); 124 } 125 126 // todo: Check for method?? 127 128 Identifier name = method.getName(); 129 130 // Get a List containing all methods of this name. 131 List<MemberDefinition> methodList = lookupMap.get(name); 132 133 if (methodList == null) { 134 // There is no method with this name already. 135 // Create a List, and insert it into the hash. 136 methodList = new ArrayList<>(); 137 lookupMap.put(name, methodList); 138 } 139 140 // Replace the element which has the same signature as 141 // `method'. 142 int size = methodList.size(); 143 for (int i = 0; i < size; i++) { 144 if ((methodList.get(i)) 145 .getType().equalArguments(method.getType())) { 146 methodList.set(i, method); 147 return; 148 } 149 } 150 151 // We add the method to the appropriate list. 152 methodList.add(method); 153 count++; 154 } 155 156 /** 157 * If the MethodSet contains a method with the same signature 158 * then lookup() returns it. Otherwise, this method returns null. 159 */ 160 public MemberDefinition lookupSig(Identifier name, Type type) { 161 // Go through all methods of the same name and see if any 162 // have the right signature. 163 Iterator<MemberDefinition> matches = lookupName(name); 164 MemberDefinition candidate; 165 166 while (matches.hasNext()) { 167 candidate = matches.next(); 168 if (candidate.getType().equalArguments(type)) { 169 return candidate; 170 } 171 } 172 173 // No match. 174 return null; 175 } 176 177 /** 178 * Returns an Iterator of all methods contained in the 179 * MethodSet which have a given name. 180 */ 181 public Iterator<MemberDefinition> lookupName(Identifier name) { 182 // Find the List containing all methods of this name, and 183 // return that List's Iterator. 184 List<MemberDefinition> methodList = lookupMap.get(name); 185 if (methodList == null) { 186 // If there is no method of this name, return a bogus, empty 187 // Iterator. 188 return Collections.emptyIterator(); 189 } 190 return methodList.iterator(); 191 } 192 193 /** 194 * Returns an Iterator of all methods in the MethodSet 195 */ 196 public Iterator<MemberDefinition> iterator() { 197 198 //---------------------------------------------------------- 199 // The inner class MethodIterator is used to create our 200 // Iterator of all methods in the MethodSet. 201 class MethodIterator implements Iterator<MemberDefinition> { 202 Iterator<List<MemberDefinition>> hashIter = lookupMap.values().iterator(); 203 Iterator<MemberDefinition> listIter = Collections.emptyIterator(); 204 205 public boolean hasNext() { 206 if (listIter.hasNext()) { 207 return true; 208 } else { 209 if (hashIter.hasNext()) { 210 listIter = hashIter.next().iterator(); 211 212 // The following should be always true. 213 if (listIter.hasNext()) { 214 return true; 215 } else { 216 throw new 217 CompilerError("iterator() in MethodSet"); 218 } 219 } 220 } 221 222 // We've run out of Lists. 223 return false; 224 } 225 226 public MemberDefinition next() { 227 return listIter.next(); 228 } 229 230 public void remove() { 231 throw new UnsupportedOperationException(); 232 } 233 } 234 // end MethodIterator 235 //---------------------------------------------------------- 236 237 // A one-liner. 238 return new MethodIterator(); 239 } 240 241 /** 242 * After freeze() is called, the MethodSet becomes (mostly) 243 * immutable. Any calls to add() or addMeet() lead to 244 * CompilerErrors. Note that the entries themselves are still 245 * (unfortunately) open for mischievous and wanton modification. 246 */ 247 public void freeze() { 248 frozen = true; 249 } 250 251 /** 252 * Tells whether freeze() has been called on this MethodSet. 253 */ 254 public boolean isFrozen() { 255 return frozen; 256 } 257 258 /** 259 * Returns a (big) string representation of this MethodSet 260 */ 261 public String toString() { 262 int len = size(); 263 StringBuilder sb = new StringBuilder(); 264 Iterator<MemberDefinition> all = iterator(); 265 sb.append("{"); 266 267 while (all.hasNext()) { 268 sb.append(all.next().toString()); 269 len--; 270 if (len > 0) { 271 sb.append(", "); 272 } 273 } 274 sb.append("}"); 275 return sb.toString(); 276 } 277} 278