@Override public List<LightweightTypeReference> getIllegallyDeclaredExceptions() { if (getDeclaration().getExceptions().isEmpty()) return Collections.emptyList(); List<IResolvedOperation> overriddenAndImplemented = getOverriddenAndImplementedMethods(); if (overriddenAndImplemented.isEmpty()) return Collections.emptyList(); List<LightweightTypeReference> exceptions = getResolvedExceptions(); List<LightweightTypeReference> result = Lists.newArrayListWithCapacity(exceptions.size()); for(LightweightTypeReference exception: exceptions) { if (!exception.isSubtypeOf(RuntimeException.class) && !exception.isSubtypeOf(Error.class)) { if (isIllegallyDeclaredException(exception, overriddenAndImplemented)) { result.add(exception); } } } return result; }
@Override public List<IResolvedOperation> getOverriddenAndImplementedMethods() { if (validOverrides != null) return validOverrides; List<JvmOperation> candidates = getOverriddenAndImplementedMethodCandidates(); if (candidates.isEmpty()) return Collections.emptyList(); List<IResolvedOperation> result = Lists.newArrayListWithCapacity(candidates.size()); for(JvmOperation candidate: candidates) { // we know that our candidates are computed from the hierarchy // thus there is no need to check the declarator for inheritance IOverrideCheckResult checkResult = getOverrideTester().isSubsignature(this, candidate, false); if (checkResult.isOverridingOrImplementing()) { result.add(createResolvedOperationInHierarchy(candidate, checkResult)); } } return validOverrides = Collections.unmodifiableList(result); }
protected OverrideTester getOverrideTester() { return getBottom().getOverrideTester(); }
@Override public LightweightTypeReference getResolvedReturnType() { if (returnType != null) return returnType; return returnType = getResolvedReference(getDeclaration().getReturnType()); }
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); } }
protected boolean isMatchingTypeParameters(AbstractResolvedOperation overriding, AbstractResolvedOperation overridden) { int overridingTypeParameterCount = overriding.getTypeParameters().size(); if (overridingTypeParameterCount != overridden.getTypeParameters().size()) { for(LightweightTypeReference overridingParameterType: overriding.getResolvedParameterTypes()) { if (overridingParameterType.hasTypeArguments()) return false; TypeParameterSubstitutor<?> substitutor = overridden.getSubstitutor(); ITypeReferenceOwner owner = overriding.getContextType().getOwner(); for(int i = 0; i < overridingTypeParameterCount; i++) { JvmTypeParameter overridingTypeParameter = overriding.getTypeParameters().get(i); JvmTypeParameter overriddenTypeParameter = overridden.getTypeParameters().get(i); List<LightweightTypeReference> overridingSuperTypes = owner.newParameterizedTypeReference(overridingTypeParameter).getSuperTypes(); List<LightweightTypeReference> overriddenSuperTypes = owner.newParameterizedTypeReference(overriddenTypeParameter).getSuperTypes();
JvmOperation declaration = overriding.getDeclaration(); if (declaration == overridden) { return new LazyOverrideCheckResult(overriding, overridden, OverrideCheckDetails.CURRENT); return new LazyOverrideCheckResult(overriding, overridden, OverrideCheckDetails.SAME_DECLARATOR); ITypeReferenceOwner owner = overriding.getContextType().getOwner(); LightweightTypeReference currentDeclarator = null; if (checkInheritance) { return new LazyOverrideCheckResult(overriding, overridden, OverrideCheckDetails.STATIC_MISMATCH); AbstractResolvedOperation overriddenInHierarchy = new ResolvedOperationInHierarchy(overridden, overriding.getBottom()); if (parameterCount != 0 && !isMatchingParameterList(overriding, overriddenInHierarchy)) { return new LazyOverrideCheckResult(overriding, overridden, OverrideCheckDetails.PARAMETER_TYPE_MISMATCH);
@Override protected boolean isRawTypeInheritance() { if (getDeclaration().isStatic()) { return false; } return super.isRawTypeInheritance(); }
@Override public IResolvedOperation getOverriddenMethod() { if (!getDeclaration().isAbstract() && getDeclaration().getVisibility() != JvmVisibility.PRIVATE) { List<IResolvedOperation> overriddenAndImplemented = getOverriddenAndImplementedMethods(); for(IResolvedOperation candidate: overriddenAndImplemented) { if (!candidate.getDeclaration().isAbstract()) { return candidate; } } } return null; }
protected boolean isConflictingDefaultImplementation(AbstractResolvedOperation overriding, AbstractResolvedOperation overridden) { JvmOperation ridingDecl = overriding.getDeclaration(); JvmOperation riddenDecl = overridden.getDeclaration(); if (isInterface(ridingDecl.getDeclaringType()) && isInterface(riddenDecl.getDeclaringType()) && (!ridingDecl.isAbstract() || !riddenDecl.isAbstract())) { LightweightTypeReference ridingTypeRef = overriding.getResolvedDeclarator(); LightweightTypeReference riddenTypeRef = overridden.getResolvedDeclarator(); return !riddenTypeRef.isAssignableFrom(ridingTypeRef); } return false; }
@Override public List<JvmOperation> getOverriddenAndImplementedMethodCandidates() { if (overrideCandidates != null) return overrideCandidates; // here we are only interested in the raw type thus the declarator is not substituted // the found operation will be put in the right context by clients, e.g. #getOverriddenAndImplementedMethods ParameterizedTypeReference currentDeclarator = getContextType().getOwner().newParameterizedTypeReference(getDeclaration().getDeclaringType()); List<LightweightTypeReference> superTypes = currentDeclarator.getSuperTypes(); List<JvmOperation> result = Lists.newArrayListWithCapacity(5); for(LightweightTypeReference superType: superTypes) { if (superType.getType() instanceof JvmDeclaredType) { JvmDeclaredType declaredSuperType = (JvmDeclaredType) superType.getType(); if (declaredSuperType != null) { Iterable<JvmFeature> equallyNamedFeatures = declaredSuperType.findAllFeaturesByName(getDeclaration().getSimpleName()); for(JvmFeature equallyNamedFeature: equallyNamedFeatures) { if (equallyNamedFeature instanceof JvmOperation) { result.add((JvmOperation) equallyNamedFeature); } } } } } return overrideCandidates = Collections.unmodifiableList(result); }
OverrideTester overrideTester = candidate.getOverrideTester(); IOverrideCheckResult checkResult = overrideTester.isSubsignature(candidate, operation, false); if (checkResult.getDetails().contains(OverrideCheckDetails.DEFAULT_IMPL_CONFLICT)) { ConflictingDefaultOperation resolvedOperation = createConflictingOperation(conflictingOperations.get(0).getDeclaration()); resolvedOperation.getConflictingOperations().add(createResolvedOperation(operation)); for (AbstractResolvedOperation conflictingOp : conflictingOperations) { processedOperations.remove(simpleName, conflictingOp); if (conflictingOp.getDeclaration() != resolvedOperation.getDeclaration()) { resolvedOperation.getConflictingOperations().add(conflictingOp);
protected boolean isMatchingParameterList(AbstractResolvedOperation overriding, AbstractResolvedOperation overridden) { List<LightweightTypeReference> overridingParameterTypes = overriding.getResolvedParameterTypes(); List<LightweightTypeReference> overriddenParameterTypes = overridden.getResolvedParameterTypes(); boolean testErasure = false; for(int i = 0; i < overridingParameterTypes.size(); i++) { String overridingParameterTypeIdentifier = overridingParameterType.getJavaIdentifier(); if (!overridingParameterTypeIdentifier.equals(overriddenParameterType.getJavaIdentifier())) { if (!overriding.getTypeParameters().isEmpty()) { return false;
protected EnumSet<OverrideCheckDetails> getAllDetails(AbstractResolvedOperation overriding, JvmOperation overridden, OverrideCheckDetails primary) { EnumSet<OverrideCheckDetails> result = EnumSet.of(primary); AbstractResolvedOperation overriddenInHierarchy = new ResolvedOperationInHierarchy(overridden, overriding.getBottom()); switch(primary) { case CURRENT: if (!overriding.getResolvedParameterTypes().isEmpty() && !isMatchingParameterList(overriding, overriddenInHierarchy)) { result.add(OverrideCheckDetails.PARAMETER_TYPE_MISMATCH); return result;
@Override public IOverrideCheckResult isOverridingOrImplementing(final JvmOperation operation) { return getOverrideTester().isSubsignature(this, operation, true); }
protected boolean isSameErasure(AbstractResolvedOperation overriding, AbstractResolvedOperation overridden) { List<LightweightTypeReference> overridingParameterTypes = overriding.getResolvedParameterTypes(); List<LightweightTypeReference> overriddenParameterTypes = overridden.getResolvedParameterTypes(); if (overridingParameterTypes.size() != overriddenParameterTypes.size()) { return false; } for(int i = 0; i < overridingParameterTypes.size(); i++) { LightweightTypeReference overridingParameterType = overridingParameterTypes.get(i); LightweightTypeReference overriddenParameterType = overriddenParameterTypes.get(i); String erasedOverridingParameterTypeIdentifier = overridingParameterType.getRawTypeReference().getJavaIdentifier(); String erasedOverriddenParameterTypeIdentifier = overriddenParameterType.getRawTypeReference().getJavaIdentifier(); if (!erasedOverridingParameterTypeIdentifier.equals(erasedOverriddenParameterTypeIdentifier)) { return false; } } return true; }
protected void addExceptionDetails(AbstractResolvedOperation overriding, AbstractResolvedOperation overridden, EnumSet<OverrideCheckDetails> result) { List<LightweightTypeReference> exceptions = overriding.getResolvedExceptions(); if (exceptions.isEmpty()) { return; } List<LightweightTypeReference> inheritedExceptions = overridden.getResolvedExceptions(); for(LightweightTypeReference exception: exceptions) { if (!exception.isSubtypeOf(RuntimeException.class) && !exception.isSubtypeOf(Error.class)) { boolean isDeclared = false; for(LightweightTypeReference inheritedException: inheritedExceptions) { if (inheritedException.isAssignableFrom(exception)) { isDeclared = true; break; } } if (!isDeclared) { result.add(OverrideCheckDetails.EXCEPTION_MISMATCH); return; } } } }
protected List<IResolvedOperation> computeAllOperations() { JvmType rawType = getRawType(); if (!(rawType instanceof JvmDeclaredType)) { return Collections.emptyList(); } Multimap<String, AbstractResolvedOperation> processedOperations = LinkedHashMultimap.create(); for (IResolvedOperation resolvedOperation : getDeclaredOperations()) { processedOperations.put(resolvedOperation.getDeclaration().getSimpleName(), (AbstractResolvedOperation) resolvedOperation); } if (targetVersion.isAtLeast(JavaVersion.JAVA8)) { computeAllOperationsFromSortedSuperTypes((JvmDeclaredType) rawType, processedOperations); } else { Set<JvmType> processedTypes = Sets.newHashSet(rawType); computeAllOperationsFromSuperTypes((JvmDeclaredType) rawType, processedOperations, processedTypes); } // make sure the declared operations are the first in the list List<IResolvedOperation> result = new ArrayList<IResolvedOperation>(processedOperations.size()); result.addAll(getDeclaredOperations()); for (AbstractResolvedOperation operation : processedOperations.values()) { if (operation.getDeclaration().getDeclaringType() != rawType) { result.add(operation); } } return Collections.unmodifiableList(result); }
protected EnumSet<OverrideCheckDetails> getComputedDetails() { return thisOperation.getOverrideTester().getAllDetails(thisOperation, givenOperation, primaryDetail); }
protected void addAdditionalDetails(AbstractResolvedOperation overriding, AbstractResolvedOperation overridden, EnumSet<OverrideCheckDetails> result) { addReturnTypeDetails(overriding, overridden, result); addExceptionDetails(overriding, overridden, result); JvmOperation overridingDecl = overriding.getDeclaration(); JvmOperation overriddenDecl = overridden.getDeclaration(); if (isMorePrivateThan(overridingDecl.getVisibility(), overriddenDecl.getVisibility())) { result.add(OverrideCheckDetails.REDUCED_VISIBILITY); } if (overriddenDecl.isFinal()) { result.add(OverrideCheckDetails.IS_FINAL); } if (overridingDecl.isVarArgs() != overriddenDecl.isVarArgs()) { result.add(OverrideCheckDetails.VAR_ARG_MISMATCH); } if (isConflictingDefaultImplementation(overriding, overridden)) { result.add(OverrideCheckDetails.DEFAULT_IMPL_CONFLICT); } if (!overridingDecl.isSynchronized() && overriddenDecl.isSynchronized()) { result.add(OverrideCheckDetails.SYNCHRONIZED_MISMATCH); } }