Fix bug #672
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / compiler / lookup / PackageBinding.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2003 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials 
4  * are made available under the terms of the Common Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/cpl-v10.html
7  * 
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  *******************************************************************************/
11 package net.sourceforge.phpdt.internal.compiler.lookup;
12
13 import net.sourceforge.phpdt.core.compiler.CharOperation;
14 import net.sourceforge.phpdt.internal.compiler.util.HashtableOfPackage;
15 import net.sourceforge.phpdt.internal.compiler.util.HashtableOfType;
16
17 public class PackageBinding extends Binding implements TypeConstants {
18         public char[][] compoundName;
19
20         PackageBinding parent;
21
22         LookupEnvironment environment;
23
24         HashtableOfType knownTypes;
25
26         HashtableOfPackage knownPackages;
27
28         protected PackageBinding() {
29         }
30
31         public PackageBinding(char[][] compoundName, PackageBinding parent,
32                         LookupEnvironment environment) {
33                 this.compoundName = compoundName;
34                 this.parent = parent;
35                 this.environment = environment;
36                 this.knownTypes = null; // initialized if used... class counts can be
37                                                                 // very large 300-600
38                 this.knownPackages = new HashtableOfPackage(3); // sub-package counts
39                                                                                                                 // are typically 0-3
40         }
41
42         public PackageBinding(char[] topLevelPackageName,
43                         LookupEnvironment environment) {
44                 this(new char[][] { topLevelPackageName }, null, environment);
45         }
46
47         /*
48          * Create the default package.
49          */
50
51         public PackageBinding(LookupEnvironment environment) {
52                 this(CharOperation.NO_CHAR_CHAR, null, environment);
53         }
54
55         private void addNotFoundPackage(char[] simpleName) {
56                 knownPackages.put(simpleName, LookupEnvironment.TheNotFoundPackage);
57         }
58
59         private void addNotFoundType(char[] simpleName) {
60                 if (knownTypes == null)
61                         knownTypes = new HashtableOfType(25);
62                 knownTypes.put(simpleName, LookupEnvironment.TheNotFoundType);
63         }
64
65         void addPackage(PackageBinding element) {
66                 knownPackages.put(
67                                 element.compoundName[element.compoundName.length - 1], element);
68         }
69
70         void addType(ReferenceBinding element) {
71                 if (knownTypes == null)
72                         knownTypes = new HashtableOfType(25);
73                 knownTypes.put(element.compoundName[element.compoundName.length - 1],
74                                 element);
75         }
76
77         /*
78          * API Answer the receiver's binding type from Binding.BindingID.
79          */
80
81         public final int bindingType() {
82                 return PACKAGE;
83         }
84
85         private PackageBinding findPackage(char[] name) {
86                 if (!environment.isPackage(this.compoundName, name))
87                         return null;
88
89                 char[][] compoundName = CharOperation.arrayConcat(this.compoundName,
90                                 name);
91                 PackageBinding newPackageBinding = new PackageBinding(compoundName,
92                                 this, environment);
93                 addPackage(newPackageBinding);
94                 return newPackageBinding;
95         }
96
97         /*
98          * Answer the subpackage named name; ask the oracle for the package if its
99          * not in the cache. Answer null if it could not be resolved.
100          * 
101          * NOTE: This should only be used when we know there is NOT a type with the
102          * same name.
103          */
104
105         PackageBinding getPackage(char[] name) {
106                 PackageBinding binding = getPackage0(name);
107                 if (binding != null) {
108                         if (binding == LookupEnvironment.TheNotFoundPackage)
109                                 return null;
110                         else
111                                 return binding;
112                 }
113                 if ((binding = findPackage(name)) != null)
114                         return binding;
115
116                 // not found so remember a problem package binding in the cache for
117                 // future lookups
118                 addNotFoundPackage(name);
119                 return null;
120         }
121
122         /*
123          * Answer the subpackage named name if it exists in the cache. Answer
124          * theNotFoundPackage if it could not be resolved the first time it was
125          * looked up, otherwise answer null.
126          * 
127          * NOTE: Senders must convert theNotFoundPackage into a real problem package
128          * if its to returned.
129          */
130
131         PackageBinding getPackage0(char[] name) {
132                 return knownPackages.get(name);
133         }
134
135         /*
136          * Answer the type named name; ask the oracle for the type if its not in the
137          * cache. Answer a NotVisible problem type if the type is not visible from
138          * the invocationPackage. Answer null if it could not be resolved.
139          * 
140          * NOTE: This should only be used by source types/scopes which know there is
141          * NOT a package with the same name.
142          */
143
144         ReferenceBinding getType(char[] name) {
145                 ReferenceBinding binding = getType0(name);
146                 if (binding == null) {
147                         if ((binding = environment.askForType(this, name)) == null) {
148                                 // not found so remember a problem type binding in the cache for
149                                 // future lookups
150                                 addNotFoundType(name);
151                                 return null;
152                         }
153                 }
154
155                 if (binding == LookupEnvironment.TheNotFoundType)
156                         return null;
157                 if (binding instanceof UnresolvedReferenceBinding)
158                         binding = ((UnresolvedReferenceBinding) binding)
159                                         .resolve(environment);
160                 if (binding.isNestedType())
161                         return new ProblemReferenceBinding(name, InternalNameProvided);
162                 return binding;
163         }
164
165         /*
166          * Answer the type named name if it exists in the cache. Answer
167          * theNotFoundType if it could not be resolved the first time it was looked
168          * up, otherwise answer null.
169          * 
170          * NOTE: Senders must convert theNotFoundType into a real problem reference
171          * type if its to returned.
172          */
173
174         ReferenceBinding getType0(char[] name) {
175                 if (knownTypes == null)
176                         return null;
177                 return knownTypes.get(name);
178         }
179
180         /*
181          * Answer the package or type named name; ask the oracle if it is not in the
182          * cache. Answer null if it could not be resolved.
183          * 
184          * When collisions exist between a type name & a package name, answer the
185          * package. Treat the type as if it does not exist... a problem was already
186          * reported when the type was defined.
187          * 
188          * NOTE: no visibility checks are performed. THIS SHOULD ONLY BE USED BY
189          * SOURCE TYPES/SCOPES.
190          */
191
192         public Binding getTypeOrPackage(char[] name) {
193                 PackageBinding packageBinding = getPackage0(name);
194                 if (packageBinding != null
195                                 && packageBinding != LookupEnvironment.TheNotFoundPackage)
196                         return packageBinding;
197
198                 ReferenceBinding typeBinding = getType0(name);
199                 if (typeBinding != null
200                                 && typeBinding != LookupEnvironment.TheNotFoundType) {
201                         if (typeBinding instanceof UnresolvedReferenceBinding)
202                                 typeBinding = ((UnresolvedReferenceBinding) typeBinding)
203                                                 .resolve(environment);
204                         if (typeBinding.isNestedType())
205                                 return new ProblemReferenceBinding(name, InternalNameProvided);
206                         return typeBinding;
207                 }
208
209                 // always look for the name as a sub-package if its not a known type
210                 if (packageBinding == null
211                                 && (packageBinding = findPackage(name)) != null)
212                         return packageBinding;
213                 if (typeBinding == null) {
214                         // if no package was found, find the type named name relative to the
215                         // receiver
216                         if ((typeBinding = environment.askForType(this, name)) != null) {
217                                 if (typeBinding.isNestedType())
218                                         return new ProblemReferenceBinding(name,
219                                                         InternalNameProvided);
220                                 return typeBinding;
221                         }
222
223                         // Since name could not be found, add problem bindings
224                         // to the collections so it will be reported as an error next time.
225                         addNotFoundPackage(name);
226                         addNotFoundType(name);
227                 } else {
228                         if (packageBinding == LookupEnvironment.TheNotFoundPackage)
229                                 packageBinding = null;
230                         if (typeBinding == LookupEnvironment.TheNotFoundType)
231                                 typeBinding = null;
232                 }
233
234                 if (packageBinding != null)
235                         return packageBinding;
236                 else
237                         return typeBinding;
238         }
239
240         public char[] readableName() /* java.lang */{
241                 return CharOperation.concatWith(compoundName, '.');
242         }
243
244         public String toString() {
245                 if (compoundName == CharOperation.NO_CHAR_CHAR)
246                         return "The Default Package"; //$NON-NLS-1$
247                 else
248                         return "package " + ((compoundName != null) ? CharOperation.toString(compoundName) : "UNNAMED"); //$NON-NLS-1$ //$NON-NLS-2$
249         }
250 }