JavaResolver.st
author Claus Gittinger <cg@exept.de>
Thu, 24 Nov 2011 13:02:05 +0100
changeset 2330 b189800c0d92
parent 2231 8655662e7cc6
child 2353 fa7400d022a0
permissions -rw-r--r--
automatically generated by browser

"
 COPYRIGHT (c) 1996-2011 by Claus Gittinger
 COPYRIGHT (c) 2010-2011 by Jan Vrany, Jan Kurs and Marcel Hlopko
                            SWING Research Group, Czech Technical University in Prague

 Parts of the code written by Claus Gittinger are under following
 license:

 This software is furnished under a license and may be used
 only in accordance with the terms of that license and with the
 inclusion of the above copyright notice.   This software may not
 be provided or otherwise made available to, or used by, any
 other person.  No title to or ownership of the software is
 hereby transferred.

 Parts of the code written at SWING Reasearch Group [1] are MIT licensed:

 Permission is hereby granted, free of charge, to any person
 obtaining a copy of this software and associated documentation
 files (the 'Software'), to deal in the Software without
 restriction, including without limitation the rights to use,
 copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the
 Software is furnished to do so, subject to the following
 conditions:

 The above copyright notice and this permission notice shall be
 included in all copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 OTHER DEALINGS IN THE SOFTWARE.

 [1] Code written at SWING Research Group contain a signature
     of one of the above copright owners.
"
"{ Package: 'stx:libjava' }"

Object subclass:#JavaResolver
	instanceVariableNames:'exceptionThrower'
	classVariableNames:'uniqueInstance'
	poolDictionaries:''
	category:'Languages-Java-Reader-Support-new'
!

!JavaResolver class methodsFor:'documentation'!

copyright
"
 COPYRIGHT (c) 1996-2011 by Claus Gittinger
 COPYRIGHT (c) 2010-2011 by Jan Vrany, Jan Kurs and Marcel Hlopko
                            SWING Research Group, Czech Technical University in Prague

 Parts of the code written by Claus Gittinger are under following
 license:

 This software is furnished under a license and may be used
 only in accordance with the terms of that license and with the
 inclusion of the above copyright notice.   This software may not
 be provided or otherwise made available to, or used by, any
 other person.  No title to or ownership of the software is
 hereby transferred.

 Parts of the code written at SWING Reasearch Group [1] are MIT licensed:

 Permission is hereby granted, free of charge, to any person
 obtaining a copy of this software and associated documentation
 files (the 'Software'), to deal in the Software without
 restriction, including without limitation the rights to use,
 copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the
 Software is furnished to do so, subject to the following
 conditions:

 The above copyright notice and this permission notice shall be
 included in all copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 OTHER DEALINGS IN THE SOFTWARE.

 [1] Code written at SWING Research Group contain a signature
     of one of the above copright owners.

"
! !

!JavaResolver class methodsFor:'initialization'!

initialize
    uniqueInstance := JavaResolver new.
    uniqueInstance exceptionThrower: JavaVM.

    "/has methods at: and at: put: 
    "/uniqueInstance resolvedClasses: Java.

    "Modified: / 10-04-2011 / 10:23:43 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 13-04-2011 / 14:07:35 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
! !

!JavaResolver class methodsFor:'instance creation'!

uniqueInstance
    ^uniqueInstance.

    "Created: / 08-04-2011 / 17:36:37 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
    "Modified: / 11-04-2011 / 19:06:49 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
! !

!JavaResolver methodsFor:'accessing'!

exceptionThrower
    ^ exceptionThrower
!

exceptionThrower:something
    exceptionThrower := something.
! !

!JavaResolver methodsFor:'class resolving'!

checkIfPrimitiveArrayRef: aJavaClassRef andWrap: result 

    ^ (JavaDescriptor readFromString: aJavaClassRef name) javaClass.

    "Created: / 23-05-2011 / 21:12:04 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!

resolveClassIndentifiedByRef: aJavaClassRef init: doInit 
    | classLoader  result |

    self validateClassRef: aJavaClassRef.
    result := self lookupClassIfAlreadyResolved: aJavaClassRef javaClassName.
"/    result notNil ifTrue:[ 
"/        "/wrap result with array(s) if needed and return it
"/        "/FIXME: Marcel, can you have a look? Is that correct?
"/        ^self checkIfArrayRef: aJavaClassRef andWrap: result 
"/    ].
     "
     To resolve an unresolved symbolic reference from D to a class or interface C denoted by N,
     the following steps are performed:
     The defining class loader of D is used to create a class or interface denoted by N.
     This class or interface is C. Any exception that can be thrown as a result of failure
     of class or interface creation can thus be thrown as a result of failure of class and
     interface resolution. The details of the process are given in Section 5.3.
    "
    result isNil ifTrue:[
        classLoader := aJavaClassRef classLoader.
        classLoader isNil ifTrue: [ 
            result := self loadUnresolvedClass: aJavaClassRef
        ] ifFalse: [
            result := self loadUnresolvedClass: aJavaClassRef
                           withJavaClassLoader: classLoader. 
        ].
    ].
    result ifNil: [ self breakPoint: #mh ].

    result isJavaPrimitiveType ifTrue: [ 
        ^ self checkIfPrimitiveArrayRef: aJavaClassRef andWrap: result 
    ].
    doInit ifTrue:[result classInit].
     "
     If C is an array class and its element type is a reference type, then the symbolic reference
     to the class or interface representing the element type is resolved by invoking the algorithm
     in Section 5.4.3.1 recursively."
    result := self checkIfArrayRef: aJavaClassRef andWrap: result.
     "Finally, access permissions to C are checked:
     If C is not accessible (5.4.4) to D, class or interface resolution throws an IllegalAccessError.
     This condition can occur, for example, if C is a class that was originally declared to be
     public but was changed to be non-public after D was compiled.
     
     If steps 1 and 2 succeed but step 3 fails, C is still valid and usable. Nevertheless, resolution
     fails, and D is prohibited from accessing C."


     "JV@2011-08-10: HACK FOR SAXON DEMO!!!!!!"
    "(self checkPermissionsFrom: aJavaClassRef owner to: result)"true
        ifTrue: [ ^ result ]
        ifFalse: [ self throwIllegalAccessError ].

    "Created: / 11-04-2011 / 19:07:19 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
    "Modified: / 23-05-2011 / 21:11:32 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
    "Created: / 12-08-2011 / 22:19:51 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!JavaResolver methodsFor:'class resolving helpers'!

checkIfArrayRef: aJavaClassRef andWrap: result 
 "/wrap result with array(s) if needed and return it
    ^ aJavaClassRef isJavaArrayClassRef 
        ifFalse: [ result ]
        ifTrue: [ self wrapJavaClass: result withArrayAsSpecifiedIn: aJavaClassRef ]

    "Modified: / 11-04-2011 / 19:31:43 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!

checkPermissionsFrom: refOwner to: resolvedClass 
    "
     A class or interface C is accessible to a class or interface D if and only if either of the following conditions are true:
            C is public.
            C and D are members of the same runtime package (§5.3).
     Finally, access permissions to C are checked:
     If C is not accessible (§5.4.4) to D, class or interface resolution throws an IllegalAccessError.
     This condition can occur, for example, if C is a class that was originally declared to be
     public but was changed to be non-public after D was compiled.
     At run time, a class or interface is determined not by its name alone,
     but by a pair: its fully qualified name and its defining class loader.
     Each such class or interface belongs to a single runtime package. The runtime
     package of a class or interface is determined by the package name and
     defining class loader of the class or interface."
    
    resolvedClass isPublic ifTrue: [ ^ true ].
    resolvedClass classLoader = refOwner classLoader ifFalse: [ ^ false ].
    ^ refOwner javaPackage = resolvedClass javaPackage.

    "Created: / 11-04-2011 / 19:35:21 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
    "Modified: / 13-04-2011 / 23:13:39 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!

loadUnresolvedClass: aJavaClassRef 
    | nm |

    nm := aJavaClassRef javaClassName.
    nm size == 1 
        and: [ JavaDescriptor baseTypes at: nm first ifPresent: [:cls | ^ cls ] ].
    ^ Java classForName: aJavaClassRef javaClassName.

    "Created: / 11-04-2011 / 19:27:10 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
    "Modified: / 22-05-2011 / 17:58:19 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 23-05-2011 / 21:06:25 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!

loadUnresolvedClass: aJavaClassRef withJavaClassLoader: classLoader 
    | jClass clc |

    "JV@2011-08-12: HACK HACK HACK!!!!!!"        
    (clc := Java at:'java.lang.ClassLoader') notNil ifTrue:[
        (classLoader == (clc instVarNamed: #scl)) ifTrue:[
            ^self loadUnresolvedClass: aJavaClassRef                        
        ]
    ].

    jClass := classLoader 
                perform: #'loadClass(Ljava/lang/String;)Ljava/lang/Class;'
                with: (Java as_String: (aJavaClassRef name)).
    ^JavaVM reflection classForJavaClassObject: jClass.

    "Modified: / 18-05-2011 / 14:52:39 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
    "Modified: / 12-08-2011 / 09:14:58 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

lookupClassIfAlreadyResolved: javaClassName 

    ^Java at: javaClassName

    "Modified: / 13-04-2011 / 14:05:25 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
    "Modified: / 06-08-2011 / 16:44:03 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

validateClassRef: aJavaClassRef 
    self assert: aJavaClassRef isJavaRef.
    self assert: aJavaClassRef isJavaClassRef .

    "Modified: / 23-05-2011 / 21:04:00 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!

wrapJavaClass:aJavaClass withArrayAsSpecifiedIn:aJavaClassRef 
    "wraps aJavaClass with as many array dimensions as needed (zero means no array)"
    
    |arrayClass|

    aJavaClassRef isJavaArrayClassRef ifFalse:[ ^ aJavaClass ].
    aJavaClassRef arrayDimensions timesRepeat:
            [ arrayClass := aJavaClass.
            arrayClass := arrayClass javaArrayClass. ].
    ^ arrayClass.

    "Created: / 08-04-2011 / 18:40:00 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
    "Modified: / 22-05-2011 / 17:48:49 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 23-05-2011 / 21:06:41 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
! !

!JavaResolver methodsFor:'common helpers'!

checkPermissionsForMethodOrField: aJavaMethodOrField from: accessingJavaClass to: resolvedJavaClass 
    "A class or interface C is accessible to a class or interface D if 
     and only if either of the following conditions are true:
     C is public.
     C and D are members of the same runtime package (§5.3).
     A field or method R is accessible to a class or interface D if and only
     if any of the following conditions is true:
     R is public.
     R is protected and is declared in a class C, and D is either a subclass
     of C or C itself.
     R is either protected or package private (that is, neither public nor
     protected nor private), and is declared by a class in the same runtime
     package as D.
     R is private and is declared in D.
     This discussion of access control omits a related restriction on the target
     of a protected field access or method invocation (the target must be of class
     D or a subtype of D). That requirement is checked as part of the verification
     process (§5.4.1); it is not part of link-time access control."
    
    (self checkPermissionsFrom: accessingJavaClass to: resolvedJavaClass) ifFalse: [
        ^ false
    ].
    aJavaMethodOrField isPublic ifTrue: [
        ^ true
    ].
    ((aJavaMethodOrField isProtected 
        and: [
            resolvedJavaClass javaComponentClass 
                equalsOrIsSubclassOf: aJavaMethodOrField javaClass
        ]) 
            and: [
                accessingJavaClass javaComponentClass 
                    equalsOrIsSubclassOf: aJavaMethodOrField javaClass
            ]) 
            ifTrue: [ ^ true ].
    ((aJavaMethodOrField isPrivate not 
        and: [ resolvedJavaClass javaPackage = accessingJavaClass javaPackage ]) 
            and: [ resolvedJavaClass classLoader = accessingJavaClass classLoader ]) 
            ifTrue: [ ^ true ].
    (aJavaMethodOrField isPrivate 
        and: [ aJavaMethodOrField javaClass name = accessingJavaClass name ]) 
            ifTrue: [ ^ true ].
    ^ false.

    "Created: / 14-04-2011 / 14:19:33 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
    "Modified: / 04-06-2011 / 20:49:30 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
! !

!JavaResolver methodsFor:'exceptions'!

throwAbstractMethodError
    exceptionThrower throwAbstractMethodError.

    "Created: / 11-04-2011 / 20:19:42 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
    "Modified: / 13-04-2011 / 14:07:46 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!

throwIllegalAccessError
    exceptionThrower throwIllegalAccessError.

    "Created: / 11-04-2011 / 19:39:16 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
    "Modified: / 13-04-2011 / 23:06:58 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!

throwIncompatibleClassChangeError
    exceptionThrower throwIncompatibleClassChangeError.

    "Created: / 11-04-2011 / 20:02:01 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
    "Modified: / 13-04-2011 / 14:07:54 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!

throwNoSuchFieldException
    exceptionThrower throwNoSuchFieldException.

    "Created: / 11-04-2011 / 21:35:02 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
    "Modified: / 13-04-2011 / 14:07:57 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!

throwNoSuchMethodError
    exceptionThrower throwNoSuchMethodError.

    "Created: / 11-04-2011 / 20:19:41 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
    "Modified: / 13-04-2011 / 14:08:01 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
! !

!JavaResolver methodsFor:'field resolving'!

resolveFieldIndentifiedByRef: aJavaFieldRef 
    | result  class |

    self validateFieldRef: aJavaFieldRef.
    result := self lookupFieldIfAlreadyResolved: aJavaFieldRef.
    result ifNotNil: [ ^ result ].
    class := aJavaFieldRef classRef resolve.
    class ifNil: [ self halt: 'should not happen - tell mh' ].
    result := class lookupFieldByNameAndType: aJavaFieldRef nameAndType.
    result ifNil: [ self throwNoSuchFieldException ].
    (self 
        checkPermissionsForField: result
        from: aJavaFieldRef classRef owner
        to: class) ifFalse: [ self throwIllegalAccessError ].
    ^ result.

    "
     To resolve an unresolved symbolic reference from D to a field in a class
     or interface C, the symbolic reference to C given by the field reference
     must first be resolved (§5.4.3.1). Therefore, any exception that can be
     thrown as a result of failure of resolution of a class or interface reference
     can be thrown as a result of failure of field resolution. If the reference
     to C can be successfully resolved, an exception relating to the failure of
     resolution of the field reference itself can be thrown.
     When resolving a field reference, field resolution first attempts to look
     up the referenced field in C and its superclasses:

     If C declares a field with the name and descriptor specified by the field
     reference, field lookup succeeds. The declared field is the result of the
     field lookup.

     Otherwise, field lookup is applied recursively to the direct superinterfaces
     of the specified class or interface C.

     Otherwise, if C has a superclass S, field lookup is applied recursively to S.

     Otherwise, field lookup fails.
     If field lookup fails, field resolution throws a NoSuchFieldError. Otherwise,
     if field lookup succeeds but the referenced field is not accessible (§5.4.4)
     to D, field resolution throws an IllegalAccessError.
     Otherwise, let <E, L1> be the class or interface in which the referenced
     field is actually declared and let L2 be the defining loader of D. Let T be
     the name of the type of the referenced field. The Java virtual machine must
     impose the loading constraint that TL1=TL2(§5.3.4)."

    "Created: / 11-04-2011 / 21:15:20 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
    "Modified: / 13-04-2011 / 11:57:24 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!

resolveStaticFieldIndentifiedByRef: aJavaFieldRef 
    | result  class |

    self validateFieldRef: aJavaFieldRef.
    result := self lookupFieldIfAlreadyResolved: aJavaFieldRef.
    result ifNotNil: [ ^ result ].
    class := aJavaFieldRef classRef resolve.
    class ifNil: [ self halt: 'should not happen - tell mh' ].
    result := class lookupStaticFieldByNameAndType: aJavaFieldRef nameAndType.
    result ifNil: [ self throwNoSuchFieldException ].
    (self 
        checkPermissionsForField: result
        from: aJavaFieldRef classRef owner
        to: class) ifFalse: [ self throwIllegalAccessError ].
    ^ result.

    "
     To resolve an unresolved symbolic reference from D to a field in a class
     or interface C, the symbolic reference to C given by the field reference
     must first be resolved (§5.4.3.1). Therefore, any exception that can be
     thrown as a result of failure of resolution of a class or interface reference
     can be thrown as a result of failure of field resolution. If the reference
     to C can be successfully resolved, an exception relating to the failure of
     resolution of the field reference itself can be thrown.
     When resolving a field reference, field resolution first attempts to look
     up the referenced field in C and its superclasses:

     If C declares a field with the name and descriptor specified by the field
     reference, field lookup succeeds. The declared field is the result of the
     field lookup.

     Otherwise, field lookup is applied recursively to the direct superinterfaces
     of the specified class or interface C.

     Otherwise, if C has a superclass S, field lookup is applied recursively to S.

     Otherwise, field lookup fails.
     If field lookup fails, field resolution throws a NoSuchFieldError. Otherwise,
     if field lookup succeeds but the referenced field is not accessible (§5.4.4)
     to D, field resolution throws an IllegalAccessError.
     Otherwise, let <E, L1> be the class or interface in which the referenced
     field is actually declared and let L2 be the defining loader of D. Let T be
     the name of the type of the referenced field. The Java virtual machine must
     impose the loading constraint that TL1=TL2(§5.3.4)."

    "Created: / 28-04-2011 / 22:31:34 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
! !

!JavaResolver methodsFor:'field resolving helpers'!

checkPermissionsForField: aJavaField from: accessingJavaClass to: resolvedJavaClass 
    "A class or interface C is accessible to a class or interface D if and only 
     if either of the following conditions are true:
     C is public.
     C and D are members of the same runtime package (5.3).
     A field or method R is accessible to a class or interface D if and only
     if any of the following conditions is true:
     R is public.
     R is protected and is declared in a class C, and D is either a subclass of
     C or C itself.
     R is either protected or package private (that is, neither public nor protected
     nor private), and is declared by a class in the same runtime package as D.
     R is private and is declared in D.
     This discussion of access control omits a related restriction on the target of
     a protected field access or method invocation (the target must be of class D or
     a subtype of D). That requirement is checked as part of the verification process
     (5.4.1); it is not part of link-time access control."
    
    ^ self 
        checkPermissionsForMethodOrField: aJavaField from: accessingJavaClass
        to: resolvedJavaClass.

    "Created: / 11-04-2011 / 21:46:29 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
    "Modified: / 14-04-2011 / 14:21:05 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!

lookupFieldIfAlreadyResolved: aJavaFieldRef 
    ^ nil.

    "Created: / 11-04-2011 / 21:16:45 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
    "Modified: / 13-04-2011 / 11:57:13 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!

validateFieldRef: aJavaFieldRef 
    aJavaFieldRef isJavaRef ifFalse:[self halt:'I expected Java Ref'].
    aJavaFieldRef isJavaFieldRef ifFalse:[self halt:'I expected Java Field Ref'].

    "Created: / 11-04-2011 / 21:16:44 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
! !

!JavaResolver methodsFor:'interface method resolving'!

resolveInterfaceMethodIdentifiedByRef: aJavaInterfaceMethodRef 
    | result  class |

    self validateInterfaceMethodRef: aJavaInterfaceMethodRef.
    result := self 
                lookupInterfaceMethodIfAlreadyResolved: aJavaInterfaceMethodRef.
    result ifNotNil: [ ^ result ].
    class := aJavaInterfaceMethodRef classRef resolve.
    class ifNil: [ self halt: 'should not happen - tell mh' ].
    class isInterface ifFalse: [ self throwIncompatibleClassChangeError ].
    result := class 
                lookupMethodByNameAndType: aJavaInterfaceMethodRef nameAndType.
    result ifNil: [ self throwNoSuchMethodError ].
    (self 
        checkPermissionsForMethod: result
        from: aJavaInterfaceMethodRef classRef owner
        to: class) ifFalse: [ self throwIllegalAccessError ].
^ result.
     "
     To resolve an unresolved symbolic reference from D to an interface method in an
     interface C, the symbolic reference to C given by the interface method reference is
     first resolved (§5.4.3.1). Therefore, any exceptions that can be thrown as a result
     of failure of resolution of an interface reference can be thrown as a result of
     failure of interface method resolution. If the reference to C can be successfully
     resolved, exceptions relating to the resolution of the interface method reference
     itself can be thrown.
     When resolving an interface method reference:
     
     If C is not an interface, interface method resolution throws an IncompatibleClassChangeError.""Otherwise, if the referenced method does not have the same name and descriptor as
     a method in C or in one of the superinterfaces of C, or in class Object, interface
     method resolution throws a NoSuchMethodError.
     Otherwise, let <E, L1> be the interface in which the referenced interface method is
     actually declared and let L2 be the defining loader of D. Let T0 be the name of
     the type returned by the referenced method, and let T1, ..., Tn be the names of the
     argument types of the referenced method. The Java virtual machine must impose the
     loading constraints TiL1 = TiL2 for i = 0 to n (§5.3.4)."

    "Modified: / 23-05-2011 / 17:56:24 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
! !

!JavaResolver methodsFor:'interface method resolving helpers'!

lookupInterfaceMethodIfAlreadyResolved: aJavaInterfaceMethodRef 
    ^  nil.

    "Created: / 13-04-2011 / 11:53:36 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!

validateInterfaceMethodRef: aJavaInterfaceMethodRef 
        aJavaInterfaceMethodRef isJavaRef 
        ifFalse: [ self halt: 'I expected JavaRef instance as an argument' ].
    aJavaInterfaceMethodRef isJavaInterfaceMethodRef 
                ifFalse: [ self halt: 'I expected JavaMethodRef instance as an argument' ].

    "Created: / 13-04-2011 / 11:53:34 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
! !

!JavaResolver methodsFor:'method resolving'!

resolveMethodIndentifiedByRef: aJavaMethodRef 
    | result  class |

    self validateMethodRef: aJavaMethodRef.
    result := self lookupMethodIfAlreadyResolved: aJavaMethodRef.
    result ifNotNil: [ ^ result ].
    class := aJavaMethodRef classRef resolve.
    class ifNil: [ self error: 'should not happen - tell mh' ].
    "Array types responds to all method of class java.lang.Object"
    class isJavaArrayClass ifTrue:[
        class := Java classForName:'java.lang.Object'.
    ].


     "
     To resolve an unresolved symbolic reference from D to a method in
     a class C, the symbolic reference to C given by the method reference
     is first resolved (§5.4.3.1). Therefore, any exceptions that can be
     thrown due to resolution of a class reference can be thrown as a result
     of method resolution. If the reference to C can be successfully resolved,
     exceptions relating to the resolution of the method reference itself
     can be thrown.
     When resolving a method reference:
     
     Method resolution checks whether C is a class or an interface.
     If C is an interface, method resolution throws an IncompatibleClassChangeError."
    class isInterface ifTrue: [ self throwIncompatibleClassChangeError ].
     "Method resolution attempts to look up the referenced method in C and its
     superclasses:
     If C declares a method with the name and descriptor specified by the method
     reference, method lookup succeeds.
     Otherwise, if C has a superclass, step 2 of method lookup is recursively
     invoked on the direct superclass of C.
     
     Otherwise, method lookup attempts to locate the referenced method in any of
     the superinterfaces of the specified class C.
     If any superinterface of C declares a method with the name and descriptor
     specified by the method reference, method lookup succeeds.
     Otherwise, method lookup fails.
     If method lookup fails, method resolution throws a NoSuchMethodError. If method
     lookup succeeds and the method is abstract, but C is not abstract, method resolution
     throws an AbstractMethodError. Otherwise, if the referenced method is not accessible
     (§5.4.4) to D, method resolution throws an IllegalAccessError."
    result := class lookupMethodByNameAndType: aJavaMethodRef nameAndType.
    result ifNil: [ self throwNoSuchMethodError ].
    (result isAbstract and:[result javaClass isInterface not and:[ class isAbstract not ]]) 
        ifTrue: [ self throwAbstractMethodError ].
    true "FIXME does not work with saxon demo - q&d hack t make esug demo work" "(self 
        checkPermissionsForMethod: result
        from: aJavaMethodRef classRef owner
        to: class)" ifFalse: [ self throwIllegalAccessError ].
    ^ result.

    "Otherwise, let <E, L1> be the class or interface in which the referenced method is
     actually declared and let L2 be the defining loader of D. Let T0 be the name of
     the type returned by the referenced method, and let T1, ..., Tn be the names of
     the argument types of the referenced method. The Java virtual machine must impose
     the loading constraints TiL1=TiL2 for i = 0 to n (§5.3.4)."

    "Created: / 11-04-2011 / 19:45:34 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
    "Modified: / 14-04-2011 / 00:01:34 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
    "Modified: / 10-08-2011 / 22:44:14 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 19-08-2011 / 14:33:56 / cg"
!

resolveStaticMethodIndentifiedByRef: aJavaMethodRef 
    | result  class |

    self validateMethodRef: aJavaMethodRef.
    result := self lookupMethodIfAlreadyResolved: aJavaMethodRef.
    result ifNotNil: [ ^ result ].
    class := aJavaMethodRef classRef resolve.
    class ifNil: [ self halt: 'should not happen - tell mh' ].
     "
     To resolve an unresolved symbolic reference from D to a method in
     a class C, the symbolic reference to C given by the method reference
     is first resolved (§5.4.3.1). Therefore, any exceptions that can be
     thrown due to resolution of a class reference can be thrown as a result
     of method resolution. If the reference to C can be successfully resolved,
     exceptions relating to the resolution of the method reference itself
     can be thrown.
     When resolving a method reference:
     
     Method resolution checks whether C is a class or an interface.
     If C is an interface, method resolution throws an IncompatibleClassChangeError."
    class isInterface ifTrue: [ self throwIncompatibleClassChangeError ].
     "Method resolution attempts to look up the referenced method in C and its
     superclasses:
     If C declares a method with the name and descriptor specified by the method
     reference, method lookup succeeds.
     Otherwise, if C has a superclass, step 2 of method lookup is recursively
     invoked on the direct superclass of C.
     
     Otherwise, method lookup attempts to locate the referenced method in any of
     the superinterfaces of the specified class C.
     If any superinterface of C declares a method with the name and descriptor
     specified by the method reference, method lookup succeeds.
     Otherwise, method lookup fails.
     If method lookup fails, method resolution throws a NoSuchMethodError. If method
     lookup succeeds and the method is abstract, but C is not abstract, method resolution
     throws an AbstractMethodError. Otherwise, if the referenced method is not accessible
     (§5.4.4) to D, method resolution throws an IllegalAccessError."
    result := class lookupStaticMethodByNameAndType: aJavaMethodRef nameAndType.
    result ifNil: [ self throwNoSuchMethodError ].
    (result isAbstract and: [ class isAbstract not ]) 
        ifTrue: [ self throwAbstractMethodError ].
    (self 
        checkPermissionsForMethod: result
        from: aJavaMethodRef classRef owner
        to: class) ifFalse: [ self throwIllegalAccessError ].
    ^ result.

    "Otherwise, let <E, L1> be the class or interface in which the referenced method is
     actually declared and let L2 be the defining loader of D. Let T0 be the name of
     the type returned by the referenced method, and let T1, ..., Tn be the names of
     the argument types of the referenced method. The Java virtual machine must impose
     the loading constraints TiL1=TiL2 for i = 0 to n (§5.3.4)."

    "Created: / 28-04-2011 / 22:50:04 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
! !

!JavaResolver methodsFor:'method resolving helpers'!

checkPermissionsForMethod: aJavaMethod from: accessingJavaClass to: resolvedJavaClass 
    "A class or interface C is accessible to a class or interface D if 
     and only if either of the following conditions are true:
     C is public.
     C and D are members of the same runtime package (§5.3).
     A field or method R is accessible to a class or interface D if and only
     if any of the following conditions is true:
     R is public.
     R is protected and is declared in a class C, and D is either a subclass
     of C or C itself.
     R is either protected or package private (that is, neither public nor
     protected nor private), and is declared by a class in the same runtime
     package as D.
     R is private and is declared in D.
     This discussion of access control omits a related restriction on the target
     of a protected field access or method invocation (the target must be of class
     D or a subtype of D). That requirement is checked as part of the verification
     process (§5.4.1); it is not part of link-time access control."

    "JV@2011-05-24: Temporary hack, since access checking
     is somewhat broken. Marcle should fix it :-)"
    OperatingSystem getLoginName = 'jv' ifTrue:[^true].
    
  ^ self checkPermissionsForMethodOrField: aJavaMethod from: accessingJavaClass to: resolvedJavaClass.

    "Created: / 11-04-2011 / 20:20:12 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
    "Modified: / 14-04-2011 / 14:20:27 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
    "Modified: / 24-05-2011 / 14:06:09 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

lookupMethodIfAlreadyResolved: aJavaMethodRef 
    ^ nil.

    "Created: / 11-04-2011 / 19:50:38 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
    "Modified: / 13-04-2011 / 11:57:00 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!

validateMethodRef: aJavaMethodRef 
    aJavaMethodRef isJavaRef ifFalse:[self halt: 'I expected JavaRef instance as an argument'].
    aJavaMethodRef isJavaMethodRef ifFalse: [self halt: 'I expected JavaMethodRef instance as an argument'].

    "Created: / 11-04-2011 / 19:47:25 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
! !

!JavaResolver class methodsFor:'documentation'!

version
    ^ '$Header: /cvs/stx/stx/libjava/JavaResolver.st,v 1.3 2011-11-24 11:24:31 cg Exp $'
!

version_CVS
    ^ '$Header: /cvs/stx/stx/libjava/JavaResolver.st,v 1.3 2011-11-24 11:24:31 cg Exp $'
!

version_SVN
    ^ '§Id: JavaResolver.st,v 1.1 2011/08/18 19:06:53 vrany Exp §'
! !

JavaResolver initialize!