/** * Same as {@link LightweightTypeReference#isSubtypeOf(Class)} but does not accept synonym types as subtypes. */ protected boolean isSubtypeButNotSynonym(LightweightTypeReference expectation, Class<?> clazz) { if (expectation.isType(clazz)) { return true; } ITypeReferenceOwner owner = expectation.getOwner(); JvmType declaredType = owner.getServices().getTypeReferences().findDeclaredType(clazz, owner.getContextResourceSet()); if (declaredType == null) { return false; } LightweightTypeReference superType = owner.newParameterizedTypeReference(declaredType); // don't allow synonyms, e.g. Iterable is not considered to be a supertype of Functions.Function0 boolean result = superType.isAssignableFrom(expectation.getRawTypeReference(), new TypeConformanceComputationArgument(false, false, true, true, false, false)); return result; }
protected int compareDeclaredTypes(LightweightTypeReference left, LightweightTypeReference right, boolean leftResolved, boolean rightResolved) { int rightToLeftConformance = left.internalIsAssignableFrom(right, new TypeConformanceComputationArgument()); if ((rightToLeftConformance & ConformanceFlags.SUCCESS) != 0) { if (!right.isAssignableFrom(left) && (!leftResolved || !rightResolved || ((rightToLeftConformance & ConformanceFlags.RAW_TYPE_CONVERSION) == 0))) { return 1; } } else { int leftToRightConformance = right.internalIsAssignableFrom(left, new TypeConformanceComputationArgument()); if ((leftToRightConformance & ConformanceFlags.SUCCESS) != 0 && (!leftResolved || !rightResolved || ((leftToRightConformance & ConformanceFlags.RAW_TYPE_CONVERSION) == 0))) { return -1; } } return 0; }
@Check public void checkInstanceOf(XInstanceOfExpression instanceOfExpression) { LightweightTypeReference leftType = getActualType(instanceOfExpression.getExpression()); final LightweightTypeReference rightType = toLightweightTypeReference(instanceOfExpression.getType(), true); if (leftType == null || rightType == null || rightType.getType() == null || rightType.getType().eIsProxy()) { return; } if (containsTypeArgs(rightType)) { error("Cannot perform instanceof check against parameterized type " + getNameOfTypes(rightType), null, ValidationMessageAcceptor.INSIGNIFICANT_INDEX, INVALID_INSTANCEOF); return; } if (leftType.isAny() || leftType.isUnknown()) { return; // null / unknown is ok } if (rightType.isPrimitive()) { error("Cannot perform instanceof check against primitive type " + this.getNameOfTypes(rightType), null, ValidationMessageAcceptor.INSIGNIFICANT_INDEX, INVALID_INSTANCEOF); return; } if (leftType.isPrimitive() || rightType.isArray() && !(leftType.isArray() || leftType.isType(Object.class) || leftType.isType(Cloneable.class) || leftType.isType(Serializable.class)) || isFinal(rightType) && !memberOfTypeHierarchy(rightType, leftType) || isFinal(leftType) && !memberOfTypeHierarchy(leftType, rightType)) { error("Incompatible conditional operand types " + this.getNameOfTypes(leftType)+" and "+this.getNameOfTypes(rightType), null, ValidationMessageAcceptor.INSIGNIFICANT_INDEX, INVALID_INSTANCEOF); return; } if (!isIgnored(OBSOLETE_INSTANCEOF) && rightType.isAssignableFrom(leftType, new TypeConformanceComputationArgument(false, false, true, true, false, false))) { addIssueToState(OBSOLETE_INSTANCEOF, "The expression of type " + getNameOfTypes(leftType) + " is already of type " + canonicalName(rightType), null); } }
@Override protected LightweightTypeReference deferredBindTypeArgument(ITypeExpectation expectation, LightweightTypeReference type) { LightweightTypeReference result = super.deferredBindTypeArgument(expectation, type); LightweightTypeReference expectedType = expectation.getExpectedType(); if (expectedType != null && getConstructorCall().getTypeArguments().isEmpty() && !result.isRawType() && !getDeclaredTypeParameters().isEmpty()) { if (!expectedType.isAssignableFrom(result, new TypeConformanceComputationArgument())) { LightweightTypeReference rawFeatureType = result.getRawTypeReference(); if (expectedType.isAssignableFrom(rawFeatureType)) { result = rawFeatureType; getTypeParameterMapping().clear(); } } } return result; }
protected int getConformanceFlags(TypeData typeData, boolean recompute) { int flags = typeData.getConformanceFlags(); if (recompute) { if ((flags & ConformanceFlags.SEALED) != 0) { ConformanceFlags.sanityCheck(flags); return flags; } flags &= ~(ConformanceFlags.INCOMPATIBLE | ConformanceFlags.SUCCESS); flags |= ConformanceFlags.UNCHECKED; } if ((flags & ConformanceFlags.UNCHECKED) != 0) { LightweightTypeReference actualType = typeData.getActualType(); ITypeExpectation expectation = typeData.getExpectation(); LightweightTypeReference expectedType = expectation.getExpectedType(); if (expectedType != null) { int conformanceResult = expectedType.getUpperBoundSubstitute().internalIsAssignableFrom( actualType, new TypeConformanceComputationArgument()); flags |= conformanceResult | ConformanceFlags.CHECKED; flags &= ~ConformanceFlags.UNCHECKED; } else { flags &= ~ConformanceFlags.UNCHECKED; flags |= ConformanceFlags.CHECKED_SUCCESS; } } ConformanceFlags.sanityCheck(flags); typeData.setConformanceFlags(flags); return flags; }
@Override protected Map<JvmTypeParameter, LightweightMergedBoundTypeArgument> getDeclaratorParameterMapping() { final Wrapper<Map<JvmTypeParameter, LightweightMergedBoundTypeArgument>> receiverTypeParameterMapping = Wrapper.wrap(Collections.<JvmTypeParameter, LightweightMergedBoundTypeArgument>emptyMap()); XExpression receiver = getReceiver(); if (receiver != null) { LightweightTypeReference receiverType = getReceiverType(); if (receiverType == null) { throw new IllegalStateException("Cannot determine type of receiver "+ getReceiver()); } JvmIdentifiableElement feature = getFeature(); if (feature instanceof JvmFeature) { JvmDeclaredType declaringType = ((JvmFeature) feature).getDeclaringType(); final LightweightTypeReference declaringTypeReference = receiverType.getOwner().newParameterizedTypeReference(declaringType); final TypeConformanceComputationArgument rawConformanceCheck = new TypeConformanceComputationArgument(true, false, false, false, false, false); if (declaringTypeReference.isAssignableFrom(receiverType, rawConformanceCheck)) { receiverTypeParameterMapping.set(new DeclaratorTypeArgumentCollector().getTypeParameterMapping(receiverType)); } else { CommonTypeComputationServices services = receiverType.getOwner().getServices(); SynonymTypesProvider synonymProvider = services.getSynonymTypesProvider(); synonymProvider.collectSynonymTypes(receiverType, new SynonymTypesProvider.Acceptor() { @Override protected boolean accept(LightweightTypeReference synonym, int hints) { if (declaringTypeReference.isAssignableFrom(synonym, rawConformanceCheck)) { receiverTypeParameterMapping.set(new DeclaratorTypeArgumentCollector().getTypeParameterMapping(synonym)); return false; } return true; } }); } } else { receiverTypeParameterMapping.set(new DeclaratorTypeArgumentCollector().getTypeParameterMapping(receiverType)); } } return receiverTypeParameterMapping.get(); }
/** * Returns true if the existing hints would allow to resolve to the given reference. */ public boolean canResolveTo(LightweightTypeReference reference) { if (internalIsResolved()) return reference.isAssignableFrom(resolvedTo, new TypeConformanceComputationArgument(false, true, true, true, false, false /* TODO do we need to support synonmys here? */)); List<LightweightBoundTypeArgument> hints = getAllHints(); if (!hints.isEmpty() && hasSignificantHints(hints)) { return canResolveTo(reference, hints); } return false; }
protected void addReturnTypeDetails(AbstractResolvedOperation overriding, AbstractResolvedOperation overridden, EnumSet<OverrideCheckDetails> result) { LightweightTypeReference overridingReturnType = overriding.getResolvedReturnType(); LightweightTypeReference overriddenReturnType = overridden.getResolvedReturnType(); TypeConformanceComputationArgument conformanceArgument = new TypeConformanceComputationArgument(false, false, false, false, false, false); if (!overriddenReturnType.isAssignableFrom(overridingReturnType, conformanceArgument)) { if (overriding.getTypeParameters().isEmpty() && !overridden.getTypeParameters().isEmpty()) { TypeConformanceComputationArgument rawConformanceArgument = new TypeConformanceComputationArgument(true, false, false, false, false, false); if (!overriddenReturnType.isAssignableFrom(overridingReturnType, rawConformanceArgument)) { result.add(OverrideCheckDetails.RETURN_MISMATCH); } else { result.add(OverrideCheckDetails.UNCHECKED_CONVERSION_REQUIRED); if (overridingReturnType.getRawTypeReference().getType() != overriddenReturnType.getRawTypeReference().getType()) { result.add(OverrideCheckDetails.COVARIANT_RETURN); } } } else { result.add(OverrideCheckDetails.RETURN_MISMATCH); } } else if (!overriddenReturnType.getJavaIdentifier().equals(overridingReturnType.getJavaIdentifier())) { if (!overridden.isRawTypeInheritance() && overriding.getTypeParameters().isEmpty() && !overridden.getTypeParameters().isEmpty()) { if (overridden.getTypeParameters().contains(overridden.getDeclaration().getReturnType().getType())) { result.add(OverrideCheckDetails.UNCHECKED_CONVERSION_REQUIRED); } } result.add(OverrideCheckDetails.COVARIANT_RETURN); } }
public boolean isPossibleMergeResult(List<LightweightBoundTypeArgument> allArguments, LightweightTypeReference candidate) { if (allArguments.isEmpty()) return false; if (allArguments.size() == 1 && !candidate.isWildcard()) { LightweightBoundTypeArgument singleArgument = allArguments.get(0); if (VarianceInfo.OUT.equals(singleArgument.getActualVariance()) && singleArgument.getActualVariance().equals(singleArgument.getDeclaredVariance())) { LightweightTypeReference singleReference = singleArgument.getTypeReference(); if (singleReference.isResolved()) return candidate.isAssignableFrom(singleReference, new TypeConformanceComputationArgument()); } } LightweightMergedBoundTypeArgument merged = merge(allArguments, candidate.getOwner()); if (merged == null) return false; VarianceInfo variance = merged.getVariance(); LightweightTypeReference type = merged.getTypeReference(); if (variance == null || type == null) { return false; } switch(variance) { case INVARIANT: { int result = candidate.internalIsAssignableFrom(type, new TypeConformanceComputationArgument(false, true, true, true, false, false)); if ((result & ConformanceFlags.SUCCESS) != 0 && (result & ConformanceFlags.RAW_TYPE_CONVERSION) == 0) { return true; } return false; } case OUT: return type.isAssignableFrom(candidate, new TypeConformanceComputationArgument()); case IN: return candidate.isAssignableFrom(type, new TypeConformanceComputationArgument()); default: throw new IllegalStateException("Unknown variance info: " + variance); } }
protected boolean isConformantReturnTypes(final String leftExpression, final String rightExpression, boolean ignoreGenerics) throws Exception { XExpression leftParse = parseHelper.parse(leftExpression); IResolvedTypes leftTypes = typeResolver.resolveTypes(leftParse); XExpression rightParse = parseHelper.parse(rightExpression, leftParse.eResource().getResourceSet()); LightweightTypeReference leftType = leftTypes.getActualType(leftParse); IResolvedTypes rightTypes = typeResolver.resolveTypes(rightParse); LightweightTypeReference rightType = rightTypes.getActualType(rightParse); if (rightType == null) { throw new IllegalStateException("rightType may not be null"); } boolean conformant = leftType.isAssignableFrom(rightType, new TypeConformanceComputationArgument(ignoreGenerics, false, true, true, false, true)); return conformant; }
/** * Checks that type of a default expression of a formal parameter actually matches the declared type. * * @param parameter * to check */ @Check public void checkFormalParameterTypeConformance(final FormalParameter parameter) { JvmTypeReference jvmType = parameter.getType(); XExpression value = parameter.getRight(); if (jvmType == null || value == null) { return; } LightweightTypeReference declaredType = toLightweightTypeReference(jvmType); LightweightTypeReference valueType = getActualType(value); if (!declaredType.isAssignableFrom(valueType, new TypeConformanceComputationArgument())) { error(Messages.CheckJavaValidator_FormalParameterType_Incompatibility, value, null, IssueCodes.FORMAL_PARAMETER_TYPE); } }
protected boolean memberOfTypeHierarchy(LightweightTypeReference type, LightweightTypeReference potentialMember) { return potentialMember.isAssignableFrom(type, new TypeConformanceComputationArgument(false, false, false, true, false, false)); }
/** * Determines if this type reference denotes the same or a supertype of * the given {@code reference}. */ public boolean isAssignableFrom(LightweightTypeReference reference) { TypeConformanceComputationArgument argument = new TypeConformanceComputationArgument(); return isAssignableFrom(reference, argument); }
public boolean isAssignableFrom(LightweightTypeReference reference, TypeConformanceComputationArgument argument) { int result = internalIsAssignableFrom(reference, argument); return (result & ConformanceFlags.INCOMPATIBLE) == 0; }
public int internalIsAssignableFrom(LightweightTypeReference reference, TypeConformanceComputationArgument argument) { TypeConformanceComputer conformanceCompouter = getOwner().getServices().getTypeConformanceComputer(); int result = conformanceCompouter.isConformant(this, reference, argument); return result; }