static List<Extension> getApplicableExtensionMethods(
     EclipseNode typeNode, Annotation ann, TypeBinding receiverType) {
   List<Extension> extensions = new ArrayList<Extension>();
   if ((typeNode != null) && (ann != null) && (receiverType != null)) {
     BlockScope blockScope = ((TypeDeclaration) typeNode.get()).initializerScope;
     EclipseNode annotationNode = typeNode.getNodeFor(ann);
     AnnotationValues<ExtensionMethod> annotation =
         createAnnotation(ExtensionMethod.class, annotationNode);
     boolean suppressBaseMethods = false;
     try {
       suppressBaseMethods = annotation.getInstance().suppressBaseMethods();
     } catch (AnnotationValueDecodeFail fail) {
       fail.owner.setError(fail.getMessage(), fail.idx);
     }
     for (Object extensionMethodProvider : annotation.getActualExpressions("value")) {
       if (extensionMethodProvider instanceof ClassLiteralAccess) {
         TypeBinding binding =
             ((ClassLiteralAccess) extensionMethodProvider).type.resolveType(blockScope);
         if (binding == null) continue;
         if (!binding.isClass() && !binding.isEnum()) continue;
         Extension e = new Extension();
         e.extensionMethods =
             getApplicableExtensionMethodsDefinedInProvider(
                 typeNode, (ReferenceBinding) binding, receiverType);
         e.suppressBaseMethods = suppressBaseMethods;
         extensions.add(e);
       }
     }
   }
   return extensions;
 }
  /**
   * Convert a JDT annotation value as obtained from ElementValuePair.getValue() (e.g., IntConstant,
   * FieldBinding, etc.) to the type expected by a reflective method invocation (e.g., int, an enum
   * constant, etc.).
   *
   * @return a value of type {@code expectedType}, or a dummy value of that type if the actual value
   *     cannot be converted.
   */
  private Object convertJDTValueToReflectionType(
      Object jdtValue, TypeBinding actualType, Class<?> expectedType) {
    if (expectedType.isPrimitive() || String.class.equals(expectedType)) {
      if (jdtValue instanceof Constant) {
        if (boolean.class.equals(expectedType)) {
          return ((Constant) jdtValue).booleanValue();
        } else if (byte.class.equals(expectedType)) {
          return ((Constant) jdtValue).byteValue();
        } else if (char.class.equals(expectedType)) {
          return ((Constant) jdtValue).charValue();
        } else if (double.class.equals(expectedType)) {
          return ((Constant) jdtValue).doubleValue();
        } else if (float.class.equals(expectedType)) {
          return ((Constant) jdtValue).floatValue();
        } else if (int.class.equals(expectedType)) {
          return ((Constant) jdtValue).intValue();
        } else if (long.class.equals(expectedType)) {
          return ((Constant) jdtValue).longValue();
        } else if (short.class.equals(expectedType)) {
          return ((Constant) jdtValue).shortValue();
        } else if (String.class.equals(expectedType)) {
          return ((Constant) jdtValue).stringValue();
        }
      }
      // Primitive or string is expected, but our actual value cannot be coerced into one.
      // TODO: if the actual value is an array of primitives, should we unpack the first one?
      return Factory.getMatchingDummyValue(expectedType);
    } else if (expectedType.isEnum()) {
      Object returnVal = null;
      if (actualType != null && actualType.isEnum() && jdtValue instanceof FieldBinding) {

        FieldBinding binding = (FieldBinding) jdtValue;
        try {
          Field returnedField = null;
          returnedField = expectedType.getField(new String(binding.name));
          if (null != returnedField) {
            returnVal = returnedField.get(null);
          }
        } catch (NoSuchFieldException nsfe) {
          // return null
        } catch (IllegalAccessException iae) {
          // return null
        }
      }
      return null == returnVal ? Factory.getMatchingDummyValue(expectedType) : returnVal;
    } else if (expectedType.isAnnotation()) {
      // member value is expected to be an annotation type.  Wrap it in an Annotation proxy.
      if (actualType.isAnnotationType() && jdtValue instanceof AnnotationBinding) {
        AnnotationMirrorImpl annoMirror =
            (AnnotationMirrorImpl)
                _env.getFactory().newAnnotationMirror((AnnotationBinding) jdtValue);
        return Proxy.newProxyInstance(
            expectedType.getClassLoader(), new Class[] {expectedType}, annoMirror);
      } else {
        // No way to cast a non-annotation value to an annotation type; return null to caller
        return null;
      }
    } else {
      return Factory.getMatchingDummyValue(expectedType);
    }
  }
 /**
  * Convert an array of JDT types as obtained from ElementValuePair.getValue() (e.g., an Object[]
  * containing IntConstant elements) to the type expected by a reflective method invocation (e.g.,
  * int[]).
  *
  * <p>This does not handle arrays of Class, but it does handle primitives, enum constants, and
  * types such as String.
  *
  * @param jdtValue the actual value returned by ElementValuePair.getValue() or
  *     MethodBinding.getDefault()
  * @param jdtType the return type of the annotation method binding
  * @param expectedType the type that the invoker of the method is expecting; must be an array type
  * @return an Object which is, e.g., an int[]; or null, if an array cannot be created.
  */
 private Object convertJDTArrayToReflectionArray(
     Object jdtValue, TypeBinding jdtType, Class<?> expectedType) {
   assert null != expectedType && expectedType.isArray();
   if (!jdtType.isArrayType()) {
     // the compiler says that the type binding isn't an array type; this probably means
     // that there's some sort of syntax error.
     return null;
   }
   Object[] jdtArray;
   // See bug 261969: it's legal to pass a solo element for an array-typed value
   if (jdtValue != null && !(jdtValue instanceof Object[])) {
     // Create an array of the expected type
     jdtArray = (Object[]) Array.newInstance(jdtValue.getClass(), 1);
     jdtArray[0] = jdtValue;
   } else {
     jdtArray = (Object[]) jdtValue;
   }
   TypeBinding jdtLeafType = jdtType.leafComponentType();
   Class<?> expectedLeafType = expectedType.getComponentType();
   final int length = jdtArray.length;
   final Object returnArray = Array.newInstance(expectedLeafType, length);
   for (int i = 0; i < length; ++i) {
     Object jdtElementValue = jdtArray[i];
     if (expectedLeafType.isPrimitive() || String.class.equals(expectedLeafType)) {
       if (jdtElementValue instanceof Constant) {
         if (boolean.class.equals(expectedLeafType)) {
           Array.setBoolean(returnArray, i, ((Constant) jdtElementValue).booleanValue());
         } else if (byte.class.equals(expectedLeafType)) {
           Array.setByte(returnArray, i, ((Constant) jdtElementValue).byteValue());
         } else if (char.class.equals(expectedLeafType)) {
           Array.setChar(returnArray, i, ((Constant) jdtElementValue).charValue());
         } else if (double.class.equals(expectedLeafType)) {
           Array.setDouble(returnArray, i, ((Constant) jdtElementValue).doubleValue());
         } else if (float.class.equals(expectedLeafType)) {
           Array.setFloat(returnArray, i, ((Constant) jdtElementValue).floatValue());
         } else if (int.class.equals(expectedLeafType)) {
           Array.setInt(returnArray, i, ((Constant) jdtElementValue).intValue());
         } else if (long.class.equals(expectedLeafType)) {
           Array.setLong(returnArray, i, ((Constant) jdtElementValue).longValue());
         } else if (short.class.equals(expectedLeafType)) {
           Array.setShort(returnArray, i, ((Constant) jdtElementValue).shortValue());
         } else if (String.class.equals(expectedLeafType)) {
           Array.set(returnArray, i, ((Constant) jdtElementValue).stringValue());
         }
       } else {
         // Primitive or string is expected, but our actual value cannot be coerced into one.
         // TODO: if the actual value is an array of primitives, should we unpack the first one?
         Factory.setArrayMatchingDummyValue(returnArray, i, expectedLeafType);
       }
     } else if (expectedLeafType.isEnum()) {
       Object returnVal = null;
       if (jdtLeafType != null
           && jdtLeafType.isEnum()
           && jdtElementValue instanceof FieldBinding) {
         FieldBinding binding = (FieldBinding) jdtElementValue;
         try {
           Field returnedField = null;
           returnedField = expectedLeafType.getField(new String(binding.name));
           if (null != returnedField) {
             returnVal = returnedField.get(null);
           }
         } catch (NoSuchFieldException nsfe) {
           // return null
         } catch (IllegalAccessException iae) {
           // return null
         }
       }
       Array.set(returnArray, i, returnVal);
     } else if (expectedLeafType.isAnnotation()) {
       // member value is expected to be an annotation type.  Wrap it in an Annotation proxy.
       Object returnVal = null;
       if (jdtLeafType.isAnnotationType() && jdtElementValue instanceof AnnotationBinding) {
         AnnotationMirrorImpl annoMirror =
             (AnnotationMirrorImpl)
                 _env.getFactory().newAnnotationMirror((AnnotationBinding) jdtElementValue);
         returnVal =
             Proxy.newProxyInstance(
                 expectedLeafType.getClassLoader(), new Class[] {expectedLeafType}, annoMirror);
       }
       Array.set(returnArray, i, returnVal);
     } else {
       Array.set(returnArray, i, null);
     }
   }
   return returnArray;
 }