Skip to main content
summaryrefslogtreecommitdiffstats
blob: 6cda282e332277e8297cb345ff161760a37f1301 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
/*******************************************************************************
 * Copyright (c) 2000, 2004 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials 
 * are made available under the terms of the Common Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/cpl-v10.html
 * 
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package org.eclipse.jdt.internal.compiler.lookup;

import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.internal.compiler.env.IDependent;

/*
Not all fields defined by this type (& its subclasses) are initialized when it is created.
Some are initialized only when needed.

Accessors have been provided for some public fields so all TypeBindings have the same API...
but access public fields directly whenever possible.
Non-public fields have accessors which should be used everywhere you expect the field to be initialized.

null is NOT a valid value for a non-public field... it just means the field is not initialized.
*/

abstract public class ReferenceBinding extends TypeBinding implements IDependent {
	public char[][] compoundName;
	public char[] sourceName;
	public int modifiers;
	public PackageBinding fPackage;

	char[] fileName;
	char[] constantPoolName;
	char[] signature;

public FieldBinding[] availableFields() {
	return fields();
}

public MethodBinding[] availableMethods() {
	return methods();
}	
/* Answer true if the receiver can be instantiated
*/

public boolean canBeInstantiated() {
	return !(isAbstract() || isInterface());
}
/* Answer true if the receiver is visible to the invocationPackage.
*/

public final boolean canBeSeenBy(PackageBinding invocationPackage) {
	if (isPublic()) return true;
	if (isPrivate()) return false;

	// isProtected() or isDefault()
	return invocationPackage == fPackage;
}
/* Answer true if the receiver is visible to the receiverType and the invocationType.
*/

public final boolean canBeSeenBy(ReferenceBinding receiverType, SourceTypeBinding invocationType) {
	if (isPublic()) return true;

	if (invocationType == this && invocationType == receiverType) return true;

	if (isProtected()) {

		// answer true if the invocationType is the declaringClass or they are in the same package
		// OR the invocationType is a subclass of the declaringClass
		//    AND the invocationType is the invocationType or its subclass
		//    OR the type is a static method accessed directly through a type
		//    OR previous assertions are true for one of the enclosing type
		if (invocationType == this) return true;
		if (invocationType.fPackage == fPackage) return true;

		ReferenceBinding currentType = invocationType;
		ReferenceBinding declaringClass = enclosingType(); // protected types always have an enclosing one
		if (declaringClass == null) return false; // could be null if incorrect top-level protected type
		//int depth = 0;
		do {
			if (declaringClass == invocationType) return true;
			if (declaringClass.isSuperclassOf(currentType)) return true;
			//depth++;
			currentType = currentType.enclosingType();
		} while (currentType != null);
		return false;
	}

	if (isPrivate()) {
		// answer true if the receiverType is the receiver or its enclosingType
		// AND the invocationType and the receiver have a common enclosingType
		if (!(receiverType == this || receiverType == enclosingType())) return false;
		
		if (invocationType != this) {
			ReferenceBinding outerInvocationType = invocationType;
			ReferenceBinding temp = outerInvocationType.enclosingType();
			while (temp != null) {
				outerInvocationType = temp;
				temp = temp.enclosingType();
			}

			ReferenceBinding outerDeclaringClass = this;
			temp = outerDeclaringClass.enclosingType();
			while (temp != null) {
				outerDeclaringClass = temp;
				temp = temp.enclosingType();
			}
			if (outerInvocationType != outerDeclaringClass) return false;
		}
		return true;
	}

	// isDefault()
	if (invocationType.fPackage != fPackage) return false;

	ReferenceBinding type = receiverType;
	ReferenceBinding declaringClass = enclosingType() == null ? this : enclosingType();
	do {
		if (declaringClass == type) return true;
		if (fPackage != type.fPackage) return false;
	} while ((type = type.superclass()) != null);
	return false;
}
/* 
 * Answer true if the receiver is visible to the type provided by the scope.
 */

public final boolean canBeSeenBy(Scope scope) {
	
	if (isPublic()) return true;

	if (scope.kind == Scope.COMPILATION_UNIT_SCOPE){
		return this.canBeSeenBy(((CompilationUnitScope)scope).fPackage);
	}
	
	SourceTypeBinding invocationType = scope.enclosingSourceType();
	if (invocationType == this) return true;

	if (isProtected()) {
		// answer true if the invocationType is the declaringClass or they are in the same package
		// OR the invocationType is a subclass of the declaringClass
		//    AND the invocationType is the invocationType or its subclass
		//    OR the type is a static method accessed directly through a type
		//    OR previous assertions are true for one of the enclosing type
		if (invocationType.fPackage == fPackage) return true;

		ReferenceBinding currentType = invocationType;
		ReferenceBinding declaringClass = enclosingType(); // protected types always have an enclosing one
		if (declaringClass == null) return false; // could be null if incorrect top-level protected type
		// int depth = 0;
		do {
			if (declaringClass == invocationType) return true;
			if (declaringClass.isSuperclassOf(currentType)) return true;
			// depth++;
			currentType = currentType.enclosingType();
		} while (currentType != null);
		return false;
	}
	if (isPrivate()) {
		// answer true if the receiver and the invocationType have a common enclosingType
		// already know they are not the identical type
		ReferenceBinding outerInvocationType = invocationType;
		ReferenceBinding temp = outerInvocationType.enclosingType();
		while (temp != null) {
			outerInvocationType = temp;
			temp = temp.enclosingType();
		}

		ReferenceBinding outerDeclaringClass = this;
		temp = outerDeclaringClass.enclosingType();
		while (temp != null) {
			outerDeclaringClass = temp;
			temp = temp.enclosingType();
		}
		return outerInvocationType == outerDeclaringClass;
	}

	// isDefault()
	return invocationType.fPackage == fPackage;
}
public void computeId() {
	if (compoundName.length != 3) {
		if (compoundName.length == 4 && CharOperation.equals(JAVA_LANG_REFLECT_CONSTRUCTOR, compoundName))
			id = T_JavaLangReflectConstructor;
		return;
	}

	if (!CharOperation.equals(JAVA, compoundName[0]))
		return;

	// remaining types MUST be in java.*.*
	if (!CharOperation.equals(LANG, compoundName[1])) {
		if (CharOperation.equals(JAVA_IO_PRINTSTREAM, compoundName))
			id = T_JavaIoPrintStream;
		else if (CharOperation.equals(JAVA_IO_SERIALIZABLE, compoundName))
		    id = T_JavaIoSerializable;
		return;
	}

	// remaining types MUST be in java.lang.*
	char[] typeName = compoundName[2];
	if (typeName.length == 0) return; // just to be safe
	switch (typeName[0]) {
		case 'A' :
			if (CharOperation.equals(typeName, JAVA_LANG_ASSERTIONERROR[2]))
				id = T_JavaLangAssertionError;
			return;
		case 'B' :
			if (CharOperation.equals(typeName, JAVA_LANG_BOOLEAN[2]))
				id = T_JavaLangBoolean;
			else if (CharOperation.equals(typeName, JAVA_LANG_BYTE[2]))
				id = T_JavaLangByte;
			return;
		case 'C' :
			if (CharOperation.equals(typeName, JAVA_LANG_CHARACTER[2]))
				id = T_JavaLangCharacter;
			else if (CharOperation.equals(typeName, JAVA_LANG_CLASS[2]))
				id = T_JavaLangClass;
			else if (CharOperation.equals(typeName, JAVA_LANG_CLASSNOTFOUNDEXCEPTION[2]))
				id = T_JavaLangClassNotFoundException;
			else if (CharOperation.equals(typeName, JAVA_LANG_CLONEABLE[2]))
			    id = T_JavaLangCloneable;
			return;
		case 'D' :
			if (CharOperation.equals(typeName, JAVA_LANG_DOUBLE[2]))
				id = T_JavaLangDouble;
			return;
		case 'E' :
			if (CharOperation.equals(typeName, JAVA_LANG_ERROR[2]))
				id = T_JavaLangError;
			else if (CharOperation.equals(typeName, JAVA_LANG_EXCEPTION[2]))
				id = T_JavaLangException;
			return;
		case 'F' :
			if (CharOperation.equals(typeName, JAVA_LANG_FLOAT[2]))
				id = T_JavaLangFloat;
			return;
		case 'I' :
			if (CharOperation.equals(typeName, JAVA_LANG_INTEGER[2]))
				id = T_JavaLangInteger;
			return;
		case 'L' :
			if (CharOperation.equals(typeName, JAVA_LANG_LONG[2]))
				id = T_JavaLangLong;
			return;
		case 'N' :
			if (CharOperation.equals(typeName, JAVA_LANG_NOCLASSDEFERROR[2]))
				id = T_JavaLangNoClassDefError;
			return;
		case 'O' :
			if (CharOperation.equals(typeName, JAVA_LANG_OBJECT[2]))
				id = T_JavaLangObject;
			return;
		case 'S' :
			if (CharOperation.equals(typeName, JAVA_LANG_STRING[2]))
				id = T_JavaLangString;
			else if (CharOperation.equals(typeName, JAVA_LANG_STRINGBUFFER[2]))
				id = T_JavaLangStringBuffer;
			else if (CharOperation.equals(typeName, JAVA_LANG_SYSTEM[2]))
				id = T_JavaLangSystem;
			else if (CharOperation.equals(typeName, JAVA_LANG_SHORT[2]))
				id = T_JavaLangShort;
			return;
		case 'T' :
			if (CharOperation.equals(typeName, JAVA_LANG_THROWABLE[2]))
				id = T_JavaLangThrowable;
			return;
		case 'V' :
			if (CharOperation.equals(typeName, JAVA_LANG_VOID[2]))
				id = T_JavaLangVoid;
			return;
	}
}
/* Answer the receiver's constant pool name.
*
* NOTE: This method should only be used during/after code gen.
*/

public char[] constantPoolName() /* java/lang/Object */ {
	if (constantPoolName != null) 	return constantPoolName;
	return constantPoolName = CharOperation.concatWith(compoundName, '/');
}
String debugName() {
	return (compoundName != null) ? new String(readableName()) : "UNNAMED TYPE"; //$NON-NLS-1$
}
public final int depth() {
	int depth = 0;
	ReferenceBinding current = this;
	while ((current = current.enclosingType()) != null)
		depth++;
	return depth;
}
/* Answer the receiver's enclosing type... null if the receiver is a top level type.
*/

public ReferenceBinding enclosingType() {
	return null;
}
public final ReferenceBinding enclosingTypeAt(int relativeDepth) {
	ReferenceBinding current = this;
	while (relativeDepth-- > 0 && current != null)
		current = current.enclosingType();
	return current;
}
public int fieldCount() {
	return fields().length;
}
public FieldBinding[] fields() {
	return NoFields;
}
public final int getAccessFlags() {
	return modifiers & AccJustFlag;
}
public MethodBinding getExactConstructor(TypeBinding[] argumentTypes) {
	return null;
}
public MethodBinding getExactMethod(char[] selector, TypeBinding[] argumentTypes) {
	return null;
}
public FieldBinding getField(char[] fieldName, boolean needResolve) {
	return null;
}
/**
 * Answer the file name which defines the type.
 *
 * The path part (optional) must be separated from the actual
 * file proper name by a java.io.File.separator.
 *
 * The proper file name includes the suffix extension (e.g. ".java")
 *
 * e.g. "c:/com/ibm/compiler/java/api/Compiler.java" 
 */

public char[] getFileName() {
	return fileName;
}
public ReferenceBinding getMemberType(char[] typeName) {
	ReferenceBinding[] memberTypes = memberTypes();
	for (int i = memberTypes.length; --i >= 0;)
		if (CharOperation.equals(memberTypes[i].sourceName, typeName))
			return memberTypes[i];
	return null;
}
public MethodBinding[] getMethods(char[] selector) {
	return NoMethods;
}
public PackageBinding getPackage() {
	return fPackage;
}
public boolean hasMemberTypes() {
    return false;
}
/* Answer true if the receiver implements anInterface or is identical to anInterface.
* If searchHierarchy is true, then also search the receiver's superclasses.
*
* NOTE: Assume that anInterface is an interface.
*/

public boolean implementsInterface(ReferenceBinding anInterface, boolean searchHierarchy) {
	if (this == anInterface)
		return true;

	ReferenceBinding[][] interfacesToVisit = new ReferenceBinding[5][];
	int lastPosition = -1;
	ReferenceBinding currentType = this;
	do {
		ReferenceBinding[] itsInterfaces = currentType.superInterfaces();
		if (itsInterfaces != NoSuperInterfaces) {
			if (++lastPosition == interfacesToVisit.length)
				System.arraycopy(interfacesToVisit, 0, interfacesToVisit = new ReferenceBinding[lastPosition * 2][], 0, lastPosition);
			interfacesToVisit[lastPosition] = itsInterfaces;
		}
	} while (searchHierarchy && (currentType = currentType.superclass()) != null);
			
	for (int i = 0; i <= lastPosition; i++) {
		ReferenceBinding[] interfaces = interfacesToVisit[i];
		for (int j = 0, length = interfaces.length; j < length; j++) {
			if ((currentType = interfaces[j]) == anInterface)
				return true;

			ReferenceBinding[] itsInterfaces = currentType.superInterfaces();
			if (itsInterfaces != NoSuperInterfaces) {
				if (++lastPosition == interfacesToVisit.length)
					System.arraycopy(interfacesToVisit, 0, interfacesToVisit = new ReferenceBinding[lastPosition * 2][], 0, lastPosition);
				interfacesToVisit[lastPosition] = itsInterfaces;
			}
		}
	}
	return false;
}
// Internal method... assume its only sent to classes NOT interfaces

boolean implementsMethod(MethodBinding method) {
	ReferenceBinding type = this;
	while (type != null) {
		MethodBinding[] methods = type.getMethods(method.selector);
		for (int i = methods.length; --i >= 0;)
			if (methods[i].areParametersEqual(method))
				return true;
		type = type.superclass();
	}
	return false;
}
/* Answer true if the receiver is an abstract type
*/

public final boolean isAbstract() {
	return (modifiers & AccAbstract) != 0;
}
public final boolean isAnonymousType() {
	return (tagBits & IsAnonymousType) != 0;
}
public final boolean isBinaryBinding() {
	return (tagBits & IsBinaryBinding) != 0;
}
public final boolean isClass() {
	return (modifiers & AccInterface) == 0;
}
/* Answer true if the receiver type can be assigned to the argument type (right)
*/
	
public boolean isCompatibleWith(TypeBinding right) {
	if (right == this)
		return true;
	if (right.id == T_Object)
		return true;
	if (!(right instanceof ReferenceBinding))
		return false;

	ReferenceBinding referenceBinding = (ReferenceBinding) right;
	if (referenceBinding.isInterface())
		return implementsInterface(referenceBinding, true);
	if (isInterface())  // Explicit conversion from an interface to a class is not allowed
		return false;
	return referenceBinding.isSuperclassOf(this);
}
/* Answer true if the receiver has default visibility
*/

public final boolean isDefault() {
	return (modifiers & (AccPublic | AccProtected | AccPrivate)) == 0;
}
/* Answer true if the receiver is a deprecated type
*/

public final boolean isDeprecated() {
	return (modifiers & AccDeprecated) != 0;
}
/* Answer true if the receiver is final and cannot be subclassed
*/

public final boolean isFinal() {
	return (modifiers & AccFinal) != 0;
}
public final boolean isInterface() {
	return (modifiers & AccInterface) != 0;
}
public final boolean isLocalType() {
	return (tagBits & IsLocalType) != 0;
}
public final boolean isMemberType() {
	return (tagBits & IsMemberType) != 0;
}
public final boolean isNestedType() {
	return (tagBits & IsNestedType) != 0;
}
/* Answer true if the receiver has private visibility
*/

public final boolean isPrivate() {
	return (modifiers & AccPrivate) != 0;
}
/* Answer true if the receiver has private visibility and is used locally
*/

public final boolean isPrivateUsed() {
	return (modifiers & AccPrivateUsed) != 0;
}
/* Answer true if the receiver has protected visibility
*/

public final boolean isProtected() {
	return (modifiers & AccProtected) != 0;
}
/* Answer true if the receiver has public visibility
*/

public final boolean isPublic() {
	return (modifiers & AccPublic) != 0;
}
/* Answer true if the receiver is a static member type (or toplevel)
 */

public final boolean isStatic() {
	return (modifiers & (AccStatic | AccInterface)) != 0 ||
		    (tagBits & IsNestedType) == 0;
}
/* Answer true if all float operations must adher to IEEE 754 float/double rules
*/

public final boolean isStrictfp() {
	return (modifiers & AccStrictfp) != 0;
}
/* Answer true if the receiver is in the superclass hierarchy of aType
*
* NOTE: Object.isSuperclassOf(Object) -> false
*/

public boolean isSuperclassOf(ReferenceBinding type) {
	do {
		if (this == (type = type.superclass())) return true;
	} while (type != null);

	return false;
}
/* Answer true if the receiver is deprecated (or any of its enclosing types)
*/

public final boolean isViewedAsDeprecated() {
	return (modifiers & AccDeprecated) != 0 ||
		(modifiers & AccDeprecatedImplicitly) != 0;
}
public ReferenceBinding[] memberTypes() {
	return NoMemberTypes;
}
public MethodBinding[] methods() {
	return NoMethods;
}
/**
* Answer the source name for the type.
* In the case of member types, as the qualified name from its top level type.
* For example, for a member type N defined inside M & A: "A.M.N".
*/

public char[] qualifiedSourceName() {
	if (isMemberType())
		return CharOperation.concat(enclosingType().qualifiedSourceName(), sourceName(), '.');
	return sourceName();
}

public char[] readableName() /*java.lang.Object*/ {
	if (isMemberType())
		return CharOperation.concat(enclosingType().readableName(), sourceName, '.');
	return CharOperation.concatWith(compoundName, '.');
}

public char[] shortReadableName() /*Object*/ {
	if (isMemberType())
		return CharOperation.concat(enclosingType().shortReadableName(), sourceName, '.');
	return sourceName;
}

/* Answer the receiver's signature.
*
* NOTE: This method should only be used during/after code gen.
*/

public char[] signature() /* Ljava/lang/Object; */ {
	if (signature != null)
		return signature;

	return signature = CharOperation.concat('L', constantPoolName(), ';');
}
public char[] sourceName() {
	return sourceName;
}
public ReferenceBinding superclass() {
	return null;
}
public ReferenceBinding[] superInterfaces() {
	return NoSuperInterfaces;
}
public ReferenceBinding[] syntheticEnclosingInstanceTypes() {
	if (isStatic()) return null;

	ReferenceBinding enclosingType = enclosingType();
	if (enclosingType == null)
		return null;
	return new ReferenceBinding[] {enclosingType};
}
public SyntheticArgumentBinding[] syntheticOuterLocalVariables() {
	return null;		// is null if no enclosing instances are required
}
MethodBinding[] unResolvedMethods() { // for the MethodVerifier so it doesn't resolve types
	return methods();
}
}

Back to the top