Search in sources :

Example 6 with ElementValuePair

use of org.eclipse.jdt.internal.compiler.lookup.ElementValuePair in project bazel-jdt-java-toolchain by salesforce.

the class MemberValuePair method resolveTypeExpecting.

public void resolveTypeExpecting(final BlockScope scope, final TypeBinding requiredType) {
    if (this.compilerElementPair != null) {
        return;
    }
    if (this.value == null) {
        this.compilerElementPair = new ElementValuePair(this.name, this.value, this.binding);
        return;
    }
    if (requiredType == null) {
        // fault tolerance: keep resolving
        if (this.value instanceof ArrayInitializer) {
            this.value.resolveTypeExpecting(scope, null);
        } else {
            this.value.resolveType(scope);
        }
        this.compilerElementPair = new ElementValuePair(this.name, this.value, this.binding);
        return;
    }
    // needed in case of generic method invocation - looks suspect, generic method invocation here ???
    this.value.setExpectedType(requiredType);
    final TypeBinding valueType;
    if (this.value instanceof ArrayInitializer) {
        ArrayInitializer initializer = (ArrayInitializer) this.value;
        valueType = initializer.resolveTypeExpecting(scope, this.binding.returnType);
    } else if (this.value instanceof ArrayAllocationExpression) {
        scope.problemReporter().annotationValueMustBeArrayInitializer(this.binding.declaringClass, this.name, this.value);
        this.value.resolveType(scope);
        // no need to pursue
        valueType = null;
    } else {
        valueType = this.value.resolveType(scope);
        // https://bugs.eclipse.org/bugs/show_bug.cgi?id=248897
        ASTVisitor visitor = new ASTVisitor() {

            @Override
            public boolean visit(SingleNameReference reference, BlockScope scop) {
                if (reference.binding instanceof LocalVariableBinding) {
                    ((LocalVariableBinding) reference.binding).useFlag = LocalVariableBinding.USED;
                }
                return true;
            }
        };
        this.value.traverse(visitor, scope);
    }
    this.compilerElementPair = new ElementValuePair(this.name, this.value, this.binding);
    if (valueType == null)
        return;
    final TypeBinding leafType = requiredType.leafComponentType();
    // the next check may need deferring:
    final boolean[] shouldExit = { false };
    Runnable check = new Runnable() {

        @Override
        public void run() {
            if (!(MemberValuePair.this.value.isConstantValueOfTypeAssignableToType(valueType, requiredType) || valueType.isCompatibleWith(requiredType))) {
                if (!(requiredType.isArrayType() && requiredType.dimensions() == 1 && (MemberValuePair.this.value.isConstantValueOfTypeAssignableToType(valueType, leafType) || valueType.isCompatibleWith(leafType)))) {
                    if (leafType.isAnnotationType() && !valueType.isAnnotationType()) {
                        scope.problemReporter().annotationValueMustBeAnnotation(MemberValuePair.this.binding.declaringClass, MemberValuePair.this.name, MemberValuePair.this.value, leafType);
                    } else {
                        scope.problemReporter().typeMismatchError(valueType, requiredType, MemberValuePair.this.value, null);
                    }
                    // TODO may allow to proceed to find more errors at once
                    shouldExit[0] = true;
                }
            } else {
                scope.compilationUnitScope().recordTypeConversion(requiredType.leafComponentType(), valueType.leafComponentType());
                MemberValuePair.this.value.computeConversion(scope, requiredType, valueType);
            }
        }
    };
    // ... now or later?
    if (!scope.deferCheck(check)) {
        check.run();
        if (shouldExit[0])
            return;
    }
    // annotation methods can only return base types, String, Class, enum type, annotation types and arrays of these
    checkAnnotationMethodType: {
        switch(leafType.erasure().id) {
            case T_byte:
            case T_short:
            case T_char:
            case T_int:
            case T_long:
            case T_float:
            case T_double:
            case T_boolean:
            case T_JavaLangString:
                if (this.value instanceof ArrayInitializer) {
                    ArrayInitializer initializer = (ArrayInitializer) this.value;
                    final Expression[] expressions = initializer.expressions;
                    if (expressions != null) {
                        for (int i = 0, max = expressions.length; i < max; i++) {
                            Expression expression = expressions[i];
                            // fault-tolerance
                            if (expression.resolvedType == null)
                                continue;
                            if (expression.constant == Constant.NotAConstant) {
                                scope.problemReporter().annotationValueMustBeConstant(this.binding.declaringClass, this.name, expressions[i], false);
                            }
                        }
                    }
                } else if (this.value.constant == Constant.NotAConstant) {
                    if (valueType.isArrayType()) {
                        scope.problemReporter().annotationValueMustBeArrayInitializer(this.binding.declaringClass, this.name, this.value);
                    } else {
                        scope.problemReporter().annotationValueMustBeConstant(this.binding.declaringClass, this.name, this.value, false);
                    }
                }
                break checkAnnotationMethodType;
            case T_JavaLangClass:
                if (this.value instanceof ArrayInitializer) {
                    ArrayInitializer initializer = (ArrayInitializer) this.value;
                    final Expression[] expressions = initializer.expressions;
                    if (expressions != null) {
                        for (int i = 0, max = expressions.length; i < max; i++) {
                            Expression currentExpression = expressions[i];
                            if (!(currentExpression instanceof ClassLiteralAccess)) {
                                scope.problemReporter().annotationValueMustBeClassLiteral(this.binding.declaringClass, this.name, currentExpression);
                            }
                        }
                    }
                } else if (!(this.value instanceof ClassLiteralAccess)) {
                    scope.problemReporter().annotationValueMustBeClassLiteral(this.binding.declaringClass, this.name, this.value);
                }
                break checkAnnotationMethodType;
        }
        if (leafType.isEnum()) {
            if (this.value instanceof NullLiteral) {
                scope.problemReporter().annotationValueMustBeConstant(this.binding.declaringClass, this.name, this.value, true);
            } else if (this.value instanceof ArrayInitializer) {
                ArrayInitializer initializer = (ArrayInitializer) this.value;
                final Expression[] expressions = initializer.expressions;
                if (expressions != null) {
                    for (int i = 0, max = expressions.length; i < max; i++) {
                        Expression currentExpression = expressions[i];
                        if (currentExpression instanceof NullLiteral) {
                            scope.problemReporter().annotationValueMustBeConstant(this.binding.declaringClass, this.name, currentExpression, true);
                        } else if (currentExpression instanceof NameReference) {
                            NameReference nameReference = (NameReference) currentExpression;
                            final Binding nameReferenceBinding = nameReference.binding;
                            if (nameReferenceBinding.kind() == Binding.FIELD) {
                                FieldBinding fieldBinding = (FieldBinding) nameReferenceBinding;
                                if (!fieldBinding.declaringClass.isEnum()) {
                                    scope.problemReporter().annotationValueMustBeConstant(this.binding.declaringClass, this.name, currentExpression, true);
                                }
                            }
                        }
                    }
                }
            } else if (this.value instanceof NameReference) {
                NameReference nameReference = (NameReference) this.value;
                final Binding nameReferenceBinding = nameReference.binding;
                if (nameReferenceBinding.kind() == Binding.FIELD) {
                    FieldBinding fieldBinding = (FieldBinding) nameReferenceBinding;
                    if (!fieldBinding.declaringClass.isEnum()) {
                        if (!fieldBinding.type.isArrayType()) {
                            scope.problemReporter().annotationValueMustBeConstant(this.binding.declaringClass, this.name, this.value, true);
                        } else {
                            scope.problemReporter().annotationValueMustBeArrayInitializer(this.binding.declaringClass, this.name, this.value);
                        }
                    }
                }
            } else {
                scope.problemReporter().annotationValueMustBeConstant(this.binding.declaringClass, this.name, this.value, true);
            }
            break checkAnnotationMethodType;
        }
        if (leafType.isAnnotationType()) {
            if (!valueType.leafComponentType().isAnnotationType()) {
                // check annotation type and also reject null literal
                scope.problemReporter().annotationValueMustBeAnnotation(this.binding.declaringClass, this.name, this.value, leafType);
            } else if (this.value instanceof ArrayInitializer) {
                ArrayInitializer initializer = (ArrayInitializer) this.value;
                final Expression[] expressions = initializer.expressions;
                if (expressions != null) {
                    for (int i = 0, max = expressions.length; i < max; i++) {
                        Expression currentExpression = expressions[i];
                        if (currentExpression instanceof NullLiteral || !(currentExpression instanceof Annotation)) {
                            scope.problemReporter().annotationValueMustBeAnnotation(this.binding.declaringClass, this.name, currentExpression, leafType);
                        }
                    }
                }
            } else if (!(this.value instanceof Annotation)) {
                scope.problemReporter().annotationValueMustBeAnnotation(this.binding.declaringClass, this.name, this.value, leafType);
            }
            break checkAnnotationMethodType;
        }
    }
}
Also used : Binding(org.eclipse.jdt.internal.compiler.lookup.Binding) MethodBinding(org.eclipse.jdt.internal.compiler.lookup.MethodBinding) LocalVariableBinding(org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding) TypeBinding(org.eclipse.jdt.internal.compiler.lookup.TypeBinding) FieldBinding(org.eclipse.jdt.internal.compiler.lookup.FieldBinding) TypeBinding(org.eclipse.jdt.internal.compiler.lookup.TypeBinding) ASTVisitor(org.eclipse.jdt.internal.compiler.ASTVisitor) LocalVariableBinding(org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding) ElementValuePair(org.eclipse.jdt.internal.compiler.lookup.ElementValuePair) BlockScope(org.eclipse.jdt.internal.compiler.lookup.BlockScope) FieldBinding(org.eclipse.jdt.internal.compiler.lookup.FieldBinding)

Aggregations

ElementValuePair (org.eclipse.jdt.internal.compiler.lookup.ElementValuePair)6 MethodBinding (org.eclipse.jdt.internal.compiler.lookup.MethodBinding)6 ReferenceBinding (org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding)3 TypeBinding (org.eclipse.jdt.internal.compiler.lookup.TypeBinding)3 LinkedHashMap (java.util.LinkedHashMap)2 AnnotationValue (javax.lang.model.element.AnnotationValue)2 ExecutableElement (javax.lang.model.element.ExecutableElement)2 AnnotationBinding (org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding)2 ArrayList (java.util.ArrayList)1 ASTVisitor (org.eclipse.jdt.internal.compiler.ASTVisitor)1 BaseTypeBinding (org.eclipse.jdt.internal.compiler.lookup.BaseTypeBinding)1 Binding (org.eclipse.jdt.internal.compiler.lookup.Binding)1 BlockScope (org.eclipse.jdt.internal.compiler.lookup.BlockScope)1 FieldBinding (org.eclipse.jdt.internal.compiler.lookup.FieldBinding)1 LocalVariableBinding (org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding)1 ParameterizedTypeBinding (org.eclipse.jdt.internal.compiler.lookup.ParameterizedTypeBinding)1