1 /*******************************************************************************
2 * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Common Public License v0.5
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/cpl-v05.html
9 * IBM Corporation - initial API and implementation
10 ******************************************************************************/
11 package net.sourceforge.phpdt.internal.compiler.lookup;
13 import net.sourceforge.phpdt.internal.compiler.ast.MethodDeclaration;
14 import net.sourceforge.phpdt.internal.compiler.ast.TypeDeclaration;
15 import net.sourceforge.phpdt.internal.compiler.problem.ProblemReporter;
16 import net.sourceforge.phpdt.internal.compiler.util.CharOperation;
17 import net.sourceforge.phpdt.internal.compiler.util.HashtableOfObject;
19 public final class MethodVerifier implements TagBits, TypeConstants {
20 SourceTypeBinding type;
21 HashtableOfObject inheritedMethods;
22 HashtableOfObject currentMethods;
23 ReferenceBinding runtimeException;
24 ReferenceBinding errorException;
26 Binding creation is responsible for reporting all problems with types:
27 - all modifier problems (duplicates & multiple visibility modifiers + incompatible combinations - abstract/final)
28 - plus invalid modifiers given the context (the verifier did not do this before)
29 - qualified name collisions between a type and a package (types in default packages are excluded)
30 - all type hierarchy problems:
31 - cycles in the superclass or superinterface hierarchy
32 - an ambiguous, invisible or missing superclass or superinterface
33 - extending a final class
34 - extending an interface instead of a class
35 - implementing a class instead of an interface
36 - implementing the same interface more than once (ie. duplicate interfaces)
38 - shadowing an enclosing type's source name
39 - defining a static class or interface inside a non-static nested class
40 - defining an interface as a local type (local types can only be classes)
44 | hasHierarchyProblem superclass current names interfaces interfacesByIndentity duplicateExists invalidType |
46 (type basicModifiers anyMask: AccModifierProblem | AccAlternateModifierProblem) ifTrue: [
47 self reportModifierProblemsOnType: type].
49 type controller isJavaDefaultPackage ifFalse: [
50 (nameEnvironment class doesPackageExistNamed: type javaQualifiedName) ifTrue: [
52 reportVerificationProblem: #CollidesWithPackage
53 args: (Array with: type javaQualifiedName)
57 hasHierarchyProblem := false.
61 (superclass := self superclassFor: type) ~~ nil ifTrue: [
62 superclass isBuilderClass ifTrue: [
63 superclass := superclass newClass].
64 superclass isJavaMissing
66 hasHierarchyProblem := true.
67 type javaSuperclassIsMissing ifTrue: [
69 reportVerificationProblem: #MissingSuperclass
70 args: (Array with: superclass javaQualifiedName with: superclass unmatchedDescriptor)
73 type javaSuperclassCreatesCycle ifTrue: [
75 reportVerificationProblem: #CyclicSuperclass
76 args: (Array with: superclass javaQualifiedName)
79 type javaSuperclassIsInterface ifTrue: [
81 reportVerificationProblem: #ClassCannotExtendAnInterface
82 args: (Array with: superclass javaQualifiedName)
86 "NOTE: If type is a Java class and its superclass is
87 a valid descriptor then it should NEVER be an interface."
89 superclass isJavaFinal ifTrue: [
91 reportVerificationProblem: #ClassCannotExtendFinalClass
96 type isJavaLocalType ifTrue: [
98 reportVerificationProblem: #CannotDefineLocalInterface
103 type isJavaNestedType ifTrue: [
104 (current := type) sourceName notEmpty ifTrue: [
106 [(current := current enclosingType) ~~ nil] whileTrue: [
107 names add: current sourceName].
109 (names includes: type sourceName) ifTrue: [
111 reportVerificationProblem: #NestedTypeCannotShadowTypeName
116 (type enclosingType isJavaNestedType and: [type enclosingType isJavaClass]) ifTrue: [
117 type enclosingType isJavaStatic ifFalse: [
120 type isJavaStatic ifTrue: [
122 reportVerificationProblem: #StaticClassCannotExistInNestedClass
128 reportVerificationProblem: #InterfaceCannotExistInNestedClass
133 (interfaces := newClass superinterfaces) notEmpty ifTrue: [
134 interfacesByIndentity := interfaces asSet.
135 duplicateExists := interfaces size ~~ interfacesByIndentity size.
137 interfacesByIndentity do: [:interface |
138 duplicateExists ifTrue: [
139 (interfaces occurrencesOf: interface) > 1 ifTrue: [
141 reportVerificationProblem: #InterfaceIsSpecifiedMoreThanOnce
142 args: (Array with: interface javaQualifiedName)
146 interface isJavaMissing ifTrue: [
147 hasHierarchyProblem := true.
148 interface basicClass == JavaInterfaceIsClass basicClass
151 reportVerificationProblem: #UsingClassWhereInterfaceIsRequired
152 args: (Array with: interface javaQualifiedName)
156 interface basicClass == JavaMissingInterface basicClass
159 reportVerificationProblem: #MissingInterface
160 args: (Array with: interface javaQualifiedName with: interface unmatchedDescriptor)
165 reportVerificationProblem: #CyclicSuperinterface
166 args: (Array with: interface javaQualifiedName)
170 hasHierarchyProblem ifFalse: [
171 "Search up the type's hierarchy for
172 1. missing superclass,
173 2. superclass cycle, or
174 3. superclass is interface."
175 (invalidType := newClass findFirstInvalidSupertypeSkipping: EsIdentitySet new) ~~ nil ifTrue: [
177 reportVerificationProblem: #HasHierarchyProblem
178 args: (Array with: invalidType javaReadableName)
182 reportModifierProblemsOnType: aType
184 (type basicModifiers anyMask: AccAlternateModifierProblem) ifTrue: [
185 (type basicModifiers anyMask: AccModifierProblem)
188 reportVerificationProblem: #OnlyOneVisibilityModifierAllowed
194 reportVerificationProblem: #DuplicateModifier
199 type isJavaInterface ifTrue: [
201 reportVerificationProblem: #IllegalModifierForInterface
206 (type basicModifiers allMask: AccAbstract | AccFinal) ifTrue: [
208 reportVerificationProblem: #IllegalModifierCombinationAbstractFinal
214 reportVerificationProblem: #IllegalModifierForClass
219 void reportModifierProblems() {
220 if (this.type.isAbstract() && this.type.isFinal())
221 this.problemReporter.illegalModifierCombinationAbstractFinal(this.type);
223 // Should be able to detect all 3 problems NOT just 1
224 if ((type.modifiers() & Modifiers.AccAlternateModifierProblem) == 0) {
225 if (this.type.isInterface())
226 this.problemReporter.illegalModifierForInterface(this.type);
228 this.problemReporter.illegalModifier(this.type);
230 if ((type.modifiers() & Modifiers.AccModifierProblem) != 0)
231 this.problemReporter.onlyOneVisibilityModifierAllowed(this.type);
233 this.problemReporter.duplicateModifier(this.type);
237 public MethodVerifier(LookupEnvironment environment) {
238 this.type = null; // Initialized with the public method verify(SourceTypeBinding)
239 this.inheritedMethods = null;
240 this.currentMethods = null;
241 this.runtimeException = null;
242 this.errorException = null;
244 private void checkAgainstInheritedMethods(MethodBinding currentMethod, MethodBinding[] methods, int length) {
245 for (int i = length; --i >= 0;) {
246 MethodBinding inheritedMethod = methods[i];
247 if (currentMethod.returnType != inheritedMethod.returnType) {
248 this.problemReporter(currentMethod).incompatibleReturnType(currentMethod, inheritedMethod);
249 } else if (currentMethod.isStatic() != inheritedMethod.isStatic()) { // Cannot override a static method or hide an instance method
250 this.problemReporter(currentMethod).staticAndInstanceConflict(currentMethod, inheritedMethod);
252 if (currentMethod.thrownExceptions != NoExceptions)
253 this.checkExceptions(currentMethod, inheritedMethod);
254 if (inheritedMethod.isFinal())
255 this.problemReporter(currentMethod).finalMethodCannotBeOverridden(currentMethod, inheritedMethod);
256 if (!this.isAsVisible(currentMethod, inheritedMethod))
257 this.problemReporter(currentMethod).visibilityConflict(currentMethod, inheritedMethod);
258 if (inheritedMethod.isViewedAsDeprecated())
259 if (!currentMethod.isViewedAsDeprecated())
260 this.problemReporter(currentMethod).overridesDeprecatedMethod(currentMethod, inheritedMethod);
266 Verify that newExceptions are all included in inheritedExceptions.
267 Assumes all exceptions are valid and throwable.
268 Unchecked exceptions (compatible with runtime & error) are ignored (see the spec on pg. 203).
271 private void checkExceptions(MethodBinding newMethod, MethodBinding inheritedMethod) {
272 ReferenceBinding[] newExceptions = newMethod.thrownExceptions;
273 ReferenceBinding[] inheritedExceptions = inheritedMethod.thrownExceptions;
274 for (int i = newExceptions.length; --i >= 0;) {
275 ReferenceBinding newException = newExceptions[i];
276 int j = inheritedExceptions.length;
277 while (--j > -1 && !this.isSameClassOrSubclassOf(newException, inheritedExceptions[j]));
279 if (!(newException.isCompatibleWith(this.runtimeException()) || newException.isCompatibleWith(this.errorException())))
280 this.problemReporter(newMethod).incompatibleExceptionInThrowsClause(this.type, newMethod, inheritedMethod, newException);
283 private void checkInheritedMethods(MethodBinding[] methods, int length) {
284 TypeBinding returnType = methods[0].returnType;
286 while ((--index > 0) && (returnType == methods[index].returnType));
287 if (index > 0) { // All inherited methods do NOT have the same vmSignature
288 this.problemReporter().inheritedMethodsHaveIncompatibleReturnTypes(this.type, methods, length);
292 MethodBinding concreteMethod = null;
293 if (!type.isInterface()){ // ignore concrete methods for interfaces
294 for (int i = length; --i >= 0;) // Remember that only one of the methods can be non-abstract
295 if (!methods[i].isAbstract()) {
296 concreteMethod = methods[i];
300 if (concreteMethod == null) {
301 if (this.type.isClass() && !this.type.isAbstract()) {
302 for (int i = length; --i >= 0;)
303 if (!mustImplementAbstractMethod(methods[i]))
304 return; // in this case, we have already reported problem against the concrete superclass
306 TypeDeclaration typeDeclaration = this.type.scope.referenceContext;
307 if (typeDeclaration != null) {
308 MethodDeclaration missingAbstractMethod = typeDeclaration.addMissingAbstractMethodFor(methods[0]);
309 missingAbstractMethod.scope.problemReporter().abstractMethodMustBeImplemented(this.type, methods[0]);
311 this.problemReporter().abstractMethodMustBeImplemented(this.type, methods[0]);
317 MethodBinding[] abstractMethods = new MethodBinding[length - 1];
319 for (int i = length; --i >= 0;)
320 if (methods[i] != concreteMethod)
321 abstractMethods[index++] = methods[i];
323 // Remember that interfaces can only define public instance methods
324 if (concreteMethod.isStatic())
325 // Cannot inherit a static method which is specified as an instance method by an interface
326 this.problemReporter().staticInheritedMethodConflicts(type, concreteMethod, abstractMethods);
327 if (!concreteMethod.isPublic())
328 // Cannot reduce visibility of a public method specified by an interface
329 this.problemReporter().inheritedMethodReducesVisibility(type, concreteMethod, abstractMethods);
330 if (concreteMethod.thrownExceptions != NoExceptions)
331 for (int i = abstractMethods.length; --i >= 0;)
332 this.checkExceptions(concreteMethod, abstractMethods[i]);
335 For each inherited method identifier (message pattern - vm signature minus the return type)
336 if current method exists
337 if current's vm signature does not match an inherited signature then complain
338 else compare current's exceptions & visibility against each inherited method
340 if inherited methods = 1
341 if inherited is abstract && type is NOT an interface or abstract, complain
343 if vm signatures do not match complain
345 find the concrete implementation amongst the abstract methods (can only be 1)
347 it must be a public instance method
348 compare concrete's exceptions against each abstract method
350 complain about missing implementation only if type is NOT an interface or abstract
353 private void checkMethods() {
354 boolean mustImplementAbstractMethods = this.type.isClass() && !this.type.isAbstract();
355 char[][] methodSelectors = this.inheritedMethods.keyTable;
356 for (int s = methodSelectors.length; --s >= 0;) {
357 if (methodSelectors[s] != null) {
358 MethodBinding[] current = (MethodBinding[]) this.currentMethods.get(methodSelectors[s]);
359 MethodBinding[] inherited = (MethodBinding[]) this.inheritedMethods.valueTable[s];
362 MethodBinding[] matchingInherited = new MethodBinding[inherited.length];
363 if (current != null) {
364 for (int i = 0, length1 = current.length; i < length1; i++) {
365 while (index >= 0) matchingInherited[index--] = null; // clear the previous contents of the matching methods
366 MethodBinding currentMethod = current[i];
367 for (int j = 0, length2 = inherited.length; j < length2; j++) {
368 if (inherited[j] != null && currentMethod.areParametersEqual(inherited[j])) {
369 matchingInherited[++index] = inherited[j];
370 inherited[j] = null; // do not want to find it again
374 this.checkAgainstInheritedMethods(currentMethod, matchingInherited, index + 1); // pass in the length of matching
377 for (int i = 0, length = inherited.length; i < length; i++) {
378 while (index >= 0) matchingInherited[index--] = null; // clear the previous contents of the matching methods
379 if (inherited[i] != null) {
380 matchingInherited[++index] = inherited[i];
381 for (int j = i + 1; j < length; j++) {
382 if (inherited[j] != null && inherited[i].areParametersEqual(inherited[j])) {
383 matchingInherited[++index] = inherited[j];
384 inherited[j] = null; // do not want to find it again
389 this.checkInheritedMethods(matchingInherited, index + 1); // pass in the length of matching
391 if (mustImplementAbstractMethods && index == 0 && matchingInherited[0].isAbstract())
392 if (mustImplementAbstractMethod(matchingInherited[0])) {
393 TypeDeclaration typeDeclaration = this.type.scope.referenceContext;
394 if (typeDeclaration != null) {
395 MethodDeclaration missingAbstractMethod = typeDeclaration.addMissingAbstractMethodFor(matchingInherited[0]);
396 missingAbstractMethod.scope.problemReporter().abstractMethodMustBeImplemented(this.type, matchingInherited[0]);
398 this.problemReporter().abstractMethodMustBeImplemented(this.type, matchingInherited[0]);
407 Binding creation is responsible for reporting:
408 - all modifier problems (duplicates & multiple visibility modifiers + incompatible combinations)
409 - plus invalid modifiers given the context... examples:
410 - interface methods can only be public
411 - abstract methods can only be defined by abstract classes
412 - collisions... 2 methods with identical vmSelectors
413 - multiple methods with the same message pattern but different return types
414 - ambiguous, invisible or missing return/argument/exception types
415 - check the type of any array is not void
416 - check that each exception type is Throwable or a subclass of it
418 private void computeInheritedMethods() {
419 this.inheritedMethods = new HashtableOfObject(51); // maps method selectors to an array of methods... must search to match paramaters & return type
420 ReferenceBinding[][] interfacesToVisit = new ReferenceBinding[5][];
421 int lastPosition = 0;
422 interfacesToVisit[lastPosition] = type.superInterfaces();
424 ReferenceBinding superType;
425 if (this.type.isClass()) {
426 superType = this.type.superclass();
427 } else { // check interface methods against Object
428 superType = this.type.scope.getJavaLangObject();
430 MethodBinding[] nonVisibleDefaultMethods = null;
431 int nonVisibleCount = 0;
433 while (superType != null) {
434 if (superType.isValidBinding()) {
435 ReferenceBinding[] itsInterfaces = superType.superInterfaces();
436 if (itsInterfaces != NoSuperInterfaces) {
437 if (++lastPosition == interfacesToVisit.length)
438 System.arraycopy(interfacesToVisit, 0, interfacesToVisit = new ReferenceBinding[lastPosition * 2][], 0, lastPosition);
439 interfacesToVisit[lastPosition] = itsInterfaces;
442 MethodBinding[] methods = superType.methods();
443 nextMethod : for (int m = methods.length; --m >= 0;) {
444 MethodBinding method = methods[m];
445 if (!(method.isPrivate() || method.isConstructor() || method.isDefaultAbstract())) { // look at all methods which are NOT private or constructors or default abstract
446 MethodBinding[] existingMethods = (MethodBinding[]) this.inheritedMethods.get(method.selector);
447 if (existingMethods != null)
448 for (int i = 0, length = existingMethods.length; i < length; i++)
449 if (method.returnType == existingMethods[i].returnType)
450 if (method.areParametersEqual(existingMethods[i]))
452 if (nonVisibleDefaultMethods != null)
453 for (int i = 0; i < nonVisibleCount; i++)
454 if (method.returnType == nonVisibleDefaultMethods[i].returnType)
455 if (CharOperation.equals(method.selector, nonVisibleDefaultMethods[i].selector))
456 if (method.areParametersEqual(nonVisibleDefaultMethods[i]))
459 if (!(method.isDefault() && (method.declaringClass.fPackage != type.fPackage))) { // ignore methods which have default visibility and are NOT defined in another package
460 if (existingMethods == null)
461 existingMethods = new MethodBinding[1];
463 System.arraycopy(existingMethods, 0,
464 (existingMethods = new MethodBinding[existingMethods.length + 1]), 0, existingMethods.length - 1);
465 existingMethods[existingMethods.length - 1] = method;
466 this.inheritedMethods.put(method.selector, existingMethods);
468 if (nonVisibleDefaultMethods == null)
469 nonVisibleDefaultMethods = new MethodBinding[10];
470 else if (nonVisibleCount == nonVisibleDefaultMethods.length)
471 System.arraycopy(nonVisibleDefaultMethods, 0,
472 (nonVisibleDefaultMethods = new MethodBinding[nonVisibleCount * 2]), 0, nonVisibleCount);
473 nonVisibleDefaultMethods[nonVisibleCount++] = method;
475 if (method.isAbstract() && !this.type.isAbstract()) // non visible abstract methods cannot be overridden so the type must be defined abstract
476 this.problemReporter().abstractMethodCannotBeOverridden(this.type, method);
478 MethodBinding[] current = (MethodBinding[]) this.currentMethods.get(method.selector);
479 if (current != null) { // non visible methods cannot be overridden so a warning is issued
480 foundMatch : for (int i = 0, length = current.length; i < length; i++) {
481 if (method.returnType == current[i].returnType) {
482 if (method.areParametersEqual(current[i])) {
483 this.problemReporter().overridesPackageDefaultMethod(current[i], method);
492 superType = superType.superclass();
496 for (int i = 0; i <= lastPosition; i++) {
497 ReferenceBinding[] interfaces = interfacesToVisit[i];
498 for (int j = 0, length = interfaces.length; j < length; j++) {
499 superType = interfaces[j];
500 if ((superType.tagBits & InterfaceVisited) == 0) {
501 superType.tagBits |= InterfaceVisited;
502 if (superType.isValidBinding()) {
503 ReferenceBinding[] itsInterfaces = superType.superInterfaces();
504 if (itsInterfaces != NoSuperInterfaces) {
505 if (++lastPosition == interfacesToVisit.length)
506 System.arraycopy(interfacesToVisit, 0, interfacesToVisit = new ReferenceBinding[lastPosition * 2][], 0, lastPosition);
507 interfacesToVisit[lastPosition] = itsInterfaces;
510 MethodBinding[] methods = superType.methods();
511 for (int m = methods.length; --m >= 0;) { // Interface methods are all abstract public
512 MethodBinding method = methods[m];
513 MethodBinding[] existingMethods = (MethodBinding[]) this.inheritedMethods.get(method.selector);
514 if (existingMethods == null)
515 existingMethods = new MethodBinding[1];
517 System.arraycopy(existingMethods, 0,
518 (existingMethods = new MethodBinding[existingMethods.length + 1]), 0, existingMethods.length - 1);
519 existingMethods[existingMethods.length - 1] = method;
520 this.inheritedMethods.put(method.selector, existingMethods);
527 // bit reinitialization
528 for (int i = 0; i <= lastPosition; i++) {
529 ReferenceBinding[] interfaces = interfacesToVisit[i];
530 for (int j = 0, length = interfaces.length; j < length; j++)
531 interfaces[j].tagBits &= ~InterfaceVisited;
535 computeInheritedMethodMembers
538 "Compute all of the members for the type that are inherited from its supertypes.
540 All of the methods implemented in the supertype hierarchy that are not overridden.
541 PROBLEM: Currently we do not remove overridden methods in the interface hierarchy.
542 This could cause a non-existent exception error to be detected."
544 | supertype allSuperinterfaces methodsSeen interfacesSeen |
545 inheritedMethodMembers := LookupTable new: 50.
546 allSuperinterfaces := OrderedCollection new.
548 type isJavaClass ifTrue: [
550 methodsSeen := EsIdentitySet new: 20.
551 [(supertype := self superclassFor: supertype) == nil] whileFalse: [
552 (supertype isBuilderClass or: [supertype isValidDescriptor]) ifTrue: [
553 allSuperinterfaces addAll: (self superinterfacesFor: supertype).
554 supertype javaUserDefinedMethodsDo: [:method |
555 (method isJavaPrivate or: [method isJavaConstructor]) ifFalse: [
556 (method isJavaDefault and: [method declaringClass package symbol ~= type package symbol]) ifFalse: [
557 (methodsSeen includes: method selector) ifFalse: [
558 methodsSeen add: method selector.
559 (inheritedMethodMembers
560 at: (self methodSignatureFor: method selector)
561 ifAbsentPut: [OrderedCollection new: 3])
564 allSuperinterfaces addAll: (self superinterfacesFor: type).
565 interfacesSeen := EsIdentitySet new: allSuperinterfaces size * 2.
566 [allSuperinterfaces notEmpty] whileTrue: [
567 supertype := allSuperinterfaces removeFirst.
568 (interfacesSeen includes: supertype) ifFalse: [
569 interfacesSeen add: supertype.
570 (supertype isBuilderClass or: [supertype isValidDescriptor]) ifTrue: [
571 allSuperinterfaces addAll: (self superinterfacesFor: supertype).
572 supertype javaUserDefinedMethodsDo: [:method | "Interface methods are all abstract public."
573 (inheritedMethodMembers
574 at: (self methodSignatureFor: method selector)
575 ifAbsentPut: [OrderedCollection new: 3])
578 private void computeMethods() {
579 MethodBinding[] methods = type.methods();
580 int size = methods.length;
581 this.currentMethods = new HashtableOfObject(size == 0 ? 1 : size); // maps method selectors to an array of methods... must search to match paramaters & return type
582 for (int m = size; --m >= 0;) {
583 MethodBinding method = methods[m];
584 if (!(method.isConstructor() || method.isDefaultAbstract())) { // keep all methods which are NOT constructors or default abstract
585 MethodBinding[] existingMethods = (MethodBinding[]) this.currentMethods.get(method.selector);
586 if (existingMethods == null)
587 existingMethods = new MethodBinding[1];
589 System.arraycopy(existingMethods, 0,
590 (existingMethods = new MethodBinding[existingMethods.length + 1]), 0, existingMethods.length - 1);
591 existingMethods[existingMethods.length - 1] = method;
592 this.currentMethods.put(method.selector, existingMethods);
596 private ReferenceBinding errorException() {
597 if (errorException == null)
598 this.errorException = this.type.scope.getJavaLangError();
599 return errorException;
601 private boolean isAsVisible(MethodBinding newMethod, MethodBinding inheritedMethod) {
602 if (inheritedMethod.modifiers == newMethod.modifiers) return true;
604 if (newMethod.isPublic()) return true; // Covers everything
605 if (inheritedMethod.isPublic()) return false;
607 if (newMethod.isProtected()) return true;
608 if (inheritedMethod.isProtected()) return false;
610 return !newMethod.isPrivate(); // The inheritedMethod cannot be private since it would not be visible
612 private boolean isSameClassOrSubclassOf(ReferenceBinding testClass, ReferenceBinding superclass) {
614 if (testClass == superclass) return true;
615 } while ((testClass = testClass.superclass()) != null);
618 private boolean mustImplementAbstractMethod(MethodBinding abstractMethod) {
619 // if the type's superclass is an abstract class, then all abstract methods must be implemented
620 // otherwise, skip it if the type's superclass must implement any of the inherited methods
621 ReferenceBinding superclass = this.type.superclass();
622 ReferenceBinding declaringClass = abstractMethod.declaringClass;
623 if (declaringClass.isClass()) {
624 while (superclass.isAbstract() && superclass != declaringClass)
625 superclass = superclass.superclass(); // find the first concrete superclass or the abstract declaringClass
627 if (this.type.implementsInterface(declaringClass, false))
628 return !this.type.isAbstract();
629 while (superclass.isAbstract() && !superclass.implementsInterface(declaringClass, false))
630 superclass = superclass.superclass(); // find the first concrete superclass or the superclass which implements the interface
632 return superclass.isAbstract(); // if it is a concrete class then we have already reported problem against it
634 private ProblemReporter problemReporter() {
635 return this.type.scope.problemReporter();
637 private ProblemReporter problemReporter(MethodBinding currentMethod) {
638 ProblemReporter reporter = problemReporter();
639 if (currentMethod.declaringClass == type) // only report against the currentMethod if its implemented by the type
640 reporter.referenceContext = currentMethod.sourceMethod();
643 private ReferenceBinding runtimeException() {
644 if (runtimeException == null)
645 this.runtimeException = this.type.scope.getJavaLangRuntimeException();
646 return runtimeException;
648 public void verify(SourceTypeBinding type) {
650 this.computeMethods();
651 this.computeInheritedMethods();
654 private void zzFieldProblems() {
657 Binding creation is responsible for reporting all problems with fields:
658 - all modifier problems (duplicates & multiple visibility modifiers + incompatible combinations - final/volatile)
659 - plus invalid modifiers given the context (the verifier did not do this before)
660 - include initializers in the modifier checks even though bindings are not created
661 - collisions... 2 fields with same name
662 - interfaces cannot define initializers
663 - nested types cannot define static fields
664 - with the type of the field:
665 - void is not a valid type (or for an array)
666 - an ambiguous, invisible or missing type
671 (toSearch := newClass fields) notEmpty ifTrue: [
672 newClass fromJavaClassFile
674 toSearch do: [:field |
675 field isJavaInitializer ifFalse: [
676 self verifyFieldType: field]]]
678 toSearch do: [:field |
679 field isJavaInitializer
680 ifTrue: [self verifyFieldInitializer: field]
681 ifFalse: [self verifyField: field]]]]
683 verifyFieldInitializer: field
688 reportVerificationProblem: #InterfacesCannotHaveInitializers
695 field modifiers == AccStatic ifFalse: [
697 reportVerificationProblem: #IllegalModifierForStaticInitializer
702 field modifiers == 0 ifFalse: [
704 reportVerificationProblem: #IllegalModifierForInitializer
711 (field basicModifiers anyMask: AccAlternateModifierProblem | AccModifierProblem) ifTrue: [
712 self reportModifierProblemsOnField: field].
714 field isJavaStatic ifTrue: [
715 type isJavaStatic ifFalse: [
716 (type isJavaNestedType and: [type isJavaClass]) ifTrue: [
718 reportVerificationProblem: #NestedClassCannotHaveStaticField
723 self verifyFieldType: field
725 verifyFieldType: field
727 | descriptor fieldType |
728 "8.3 (Class) 9.3 (Interface)"
729 "Optimize the base type case"
732 field typeName = 'V' ifTrue: [ "$NON-NLS$"
734 reportVerificationProblem: #IllegalTypeForField
735 args: (Array with: JavaVoid)
739 descriptor := field asDescriptorIn: nameEnvironment.
740 (fieldType := descriptor type) isValidDescriptor
742 (fieldType isArrayType and: [fieldType leafComponentType isVoidType]) ifTrue: [
744 reportVerificationProblem: #InvalidArrayType
745 args: (Array with: fieldType javaReadableName)
750 reportVerificationProblem: #UnboundTypeForField
751 args: (Array with: fieldType javaReadableName with: fieldType leafComponentType)
755 reportModifierProblemsOnField: field
757 (field basicModifiers anyMask: AccAlternateModifierProblem) ifTrue: [
758 (field basicModifiers anyMask: AccModifierProblem)
761 reportVerificationProblem: #OnlyOneVisibilityModifierAllowed
763 severity: ErrorInfo::ConflictingModifier
767 reportVerificationProblem: #DuplicateModifier
769 severity: ErrorInfo::ConflictingModifier
772 type isJavaInterface ifTrue: [
774 reportVerificationProblem: #IllegalModifierForInterfaceField
779 (field basicModifiers allMask: AccFinal | AccVolatile) ifTrue: [
781 reportVerificationProblem: #IllegalModifierCombinationFinalVolatile
787 reportVerificationProblem: #IllegalModifierForField
792 void reportModifierProblems(FieldBinding field) {
793 if (field.isFinal() && field.isVolatile())
794 this.problemReporter.illegalModifierCombinationFinalVolatile(field);
796 // Should be able to detect all 3 problems NOT just 1
797 if ((type.modifiers() & Modifiers.AccAlternateModifierProblem) == 0) {
798 if (this.type.isInterface())
799 this.problemReporter.illegalModifierForInterfaceField(field);
801 this.problemReporter.illegalModifier(field);
803 if ((field.modifiers & Modifiers.AccModifierProblem) != 0)
804 this.problemReporter.onlyOneVisibilityModifierAllowed(field);
806 this.problemReporter.duplicateModifier(field);
810 private void zzImportProblems() {
813 Binding creation is responsible for reporting all problems with imports:
814 - on demand imports which refer to missing packages
815 - with single type imports:
816 - resolves to an ambiguous, invisible or missing type
817 - conflicts with the type's source name
818 - has the same simple name as another import
820 Note: VAJ ignored duplicate imports (only one was kept)
824 | importsBySimpleName nameEnvClass imports cl first |
825 importsBySimpleName := LookupTable new.
826 nameEnvClass := nameEnvironment class.
829 type imports do: [:import |
832 (nameEnvClass doesPackageExistNamed: import javaPackageName) ifFalse: [
833 (nameEnvClass findJavaClassNamedFrom: import javaPackageName) == nil ifTrue: [
835 reportVerificationProblem: #OnDemandImportRefersToMissingPackage
836 args: (Array with: import asString)
837 severity: ErrorInfo::ImportVerification
840 (imports := importsBySimpleName at: import javaSimpleName ifAbsent: []) == nil
842 importsBySimpleName at: import javaSimpleName put: (Array with: import)]
844 (imports includes: import) ifFalse: [
845 importsBySimpleName at: import javaSimpleName put: imports, (Array with: import)]].
847 "Ignore any imports which are simple names - we will treat these as no-ops."
849 import javaPackageName notEmpty ifTrue: [
850 cl := nameEnvClass findJavaClassNamedFrom: import asString.
852 (cl ~~ nil and: [cl isJavaPublic or: [cl controller symbol == type controller symbol]]) ifFalse: [
854 reportVerificationProblem: #SingleTypeImportRefersToInvisibleType
855 args: (Array with: import asString)
856 severity: ErrorInfo::ImportVerification
859 importsBySimpleName notEmpty ifTrue: [
860 importsBySimpleName keysAndValuesDo: [:simpleName :matching |
863 simpleName = type sourceName ifTrue: [
864 matching first javaReadableName = type javaReadableName ifFalse: [
866 reportVerificationProblem: #SingleTypeImportConflictsWithType
872 reportVerificationProblem: #SingleTypeImportsHaveSameSimpleName
873 args: (Array with: simpleName)
877 private void zzTypeProblems() {