View Javadoc
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  
26  package sun.tools.java;
27  
28  import 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  
42  public
43  class 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 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 methodList = (List) 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 (((MemberDefinition) 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 methodList = (List) 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 (((MemberDefinition) 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 matches = lookupName(name);
164         MemberDefinition candidate;
165 
166         while (matches.hasNext()) {
167             candidate = (MemberDefinition) 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 lookupName(Identifier name) {
182         // Find the List containing all methods of this name, and
183         // return that List's Iterator.
184         List methodList = (List) 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 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 {
202             Iterator hashIter = lookupMap.values().iterator();
203             Iterator listIter = Collections.emptyIterator();
204 
205             public boolean hasNext() {
206                 if (listIter.hasNext()) {
207                     return true;
208                 } else {
209                     if (hashIter.hasNext()) {
210                         listIter = ((List) hashIter.next())
211                             .iterator();
212 
213                         // The following should be always true.
214                         if (listIter.hasNext()) {
215                             return true;
216                         } else {
217                             throw new
218                                 CompilerError("iterator() in MethodSet");
219                         }
220                     }
221                 }
222 
223                 // We've run out of Lists.
224                 return false;
225             }
226 
227             public Object next() {
228                 return listIter.next();
229             }
230 
231             public void remove() {
232                 throw new UnsupportedOperationException();
233             }
234         }
235         // end MethodIterator
236         //----------------------------------------------------------
237 
238         // A one-liner.
239         return new MethodIterator();
240     }
241 
242     /**
243      * After freeze() is called, the MethodSet becomes (mostly)
244      * immutable.  Any calls to add() or addMeet() lead to
245      * CompilerErrors.  Note that the entries themselves are still
246      * (unfortunately) open for mischievous and wanton modification.
247      */
248     public void freeze() {
249         frozen = true;
250     }
251 
252     /**
253      * Tells whether freeze() has been called on this MethodSet.
254      */
255     public boolean isFrozen() {
256         return frozen;
257     }
258 
259     /**
260      * Returns a (big) string representation of this MethodSet
261      */
262     public String toString() {
263         int len = size();
264         StringBuffer buf = new StringBuffer();
265         Iterator all = iterator();
266         buf.append("{");
267 
268         while (all.hasNext()) {
269             buf.append(all.next().toString());
270             len--;
271             if (len > 0) {
272                 buf.append(", ");
273             }
274         }
275         buf.append("}");
276         return buf.toString();
277     }
278 }