Skip to content

Commit

Permalink
checkExceptions in JvmGenericTypeValidator
Browse files Browse the repository at this point in the history
  • Loading branch information
LorenzoBettini committed Feb 5, 2024
1 parent c8d728b commit 8d76826
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 43 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,13 @@

import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.xtend.core.jvmmodel.DispatchHelper;
import org.eclipse.xtend.core.xtend.XtendField;
import org.eclipse.xtend.core.xtend.XtendFunction;
import org.eclipse.xtend.core.xtend.XtendMember;
import org.eclipse.xtend.core.xtend.XtendTypeDeclaration;
import org.eclipse.xtext.common.types.JvmGenericType;
import org.eclipse.xtext.common.types.JvmOperation;
import org.eclipse.xtext.common.types.JvmType;
import org.eclipse.xtext.common.types.JvmTypeReference;
import org.eclipse.xtext.xbase.annotations.xAnnotations.XAnnotation;
Expand All @@ -32,6 +34,7 @@

import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
import com.google.inject.Inject;

/**
* A specialization of {@link JvmGenericTypeValidator} to deal with specific features of Xtend.
Expand All @@ -40,6 +43,8 @@
* @author Sebastian Zarnekow - Author of the original Java code in XtendValidator extracted here.
*/
public class XtendJvmGenericTypeValidator extends JvmGenericTypeValidator {
@Inject
private DispatchHelper dispatchHelper;

@Override
protected void checkMemberNamesAreUnique(JvmGenericType genericType) {
Expand Down Expand Up @@ -139,4 +144,17 @@ protected EStructuralFeature returnTypeFeature(EObject member, IResolvedOperatio
return XTEND_FIELD__TYPE;
return returnTypeFeature;
}

/**
* Dispatcher {@link JvmOperation}s must not be checked by the {@link JvmGenericTypeValidator}.
*/
@Override
protected boolean isAssociatedToSource(EObject element) {
if (element instanceof JvmOperation) {
JvmOperation op = (JvmOperation) element;
if (dispatchHelper.isDispatcherFunction(op))
return false;
}
return super.isAssociatedToSource(element);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
import org.eclipse.emf.ecore.EAttribute;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.xtend.core.jvmmodel.DispatchHelper;
import org.eclipse.xtend.core.jvmmodel.IXtendJvmAssociations;
Expand Down Expand Up @@ -111,9 +110,7 @@
import org.eclipse.xtext.xbase.typesystem.IResolvedTypes;
import org.eclipse.xtext.xbase.typesystem.override.IResolvedOperation;
import org.eclipse.xtext.xbase.typesystem.override.OverrideHelper;
import org.eclipse.xtext.xbase.typesystem.references.ITypeReferenceOwner;
import org.eclipse.xtext.xbase.typesystem.references.LightweightTypeReference;
import org.eclipse.xtext.xbase.typesystem.references.StandardTypeReferenceOwner;
import org.eclipse.xtext.xbase.validation.ImplicitReturnFinder;
import org.eclipse.xtext.xbase.validation.ImplicitReturnFinder.Acceptor;
import org.eclipse.xtext.xbase.validation.ProxyAwareUIStrings;
Expand All @@ -131,7 +128,6 @@
import com.google.common.collect.Iterables;
import com.google.common.collect.Multimap;
import com.google.common.collect.Multimaps;
import com.google.common.collect.Sets;
import com.google.inject.Inject;

/**
Expand Down Expand Up @@ -1038,14 +1034,6 @@ public void checkLocalUsageOfDeclaredXtendFunction(XtendFunction function){
}
}

@Check
public void checkDeclaredExceptions(XtendConstructor constructor){
JvmConstructor jvmConstructor = associations.getInferredConstructor(constructor);
if (jvmConstructor != null) {
checkExceptions(constructor, jvmConstructor.getExceptions(), XtendPackage.Literals.XTEND_EXECUTABLE__EXCEPTIONS);
}
}

@Check
public void checkTypeParameterForwardReferences(XtendClass xtendClass) {
doCheckTypeParameterForwardReference(xtendClass.getTypeParameters());
Expand All @@ -1067,36 +1055,7 @@ public void checkTypeParametersAreUnsupported(XtendConstructor constructor){
error("Type parameters are not supported for constructors", XtendPackage.Literals.XTEND_EXECUTABLE__TYPE_PARAMETERS, INSIGNIFICANT_INDEX, CONSTRUCTOR_TYPE_PARAMS_NOT_SUPPORTED);
}
}

@Check
public void checkDeclaredExceptions(XtendFunction function){
JvmOperation jvmOperation = associations.getDirectlyInferredOperation(function);
if (jvmOperation != null) {
checkExceptions(function,jvmOperation.getExceptions(), XtendPackage.Literals.XTEND_EXECUTABLE__EXCEPTIONS);
}
}

private void checkExceptions(EObject context, List<JvmTypeReference> exceptions, EReference reference) {
Set<String> declaredExceptionNames = Sets.newHashSet();
JvmTypeReference throwableType = getServices().getTypeReferences().getTypeForName(Throwable.class, context);
if (throwableType == null) {
return;
}
ITypeReferenceOwner owner = new StandardTypeReferenceOwner(getServices(), context);
LightweightTypeReference throwableReference = owner.toLightweightTypeReference(throwableType);
for(int i = 0; i < exceptions.size(); i++) {
JvmTypeReference exception = exceptions.get(i);
// throwables may not carry generics thus the raw comparison is sufficient
if (exception.getType() != null && !exception.getType().eIsProxy()) {
if(!throwableReference.isAssignableFrom(exception.getType()))
error("No exception of type " + exception.getSimpleName() + " can be thrown; an exception type must be a subclass of Throwable",
reference, i, EXCEPTION_NOT_THROWABLE);
if(!declaredExceptionNames.add(exception.getQualifiedName()))
error("Exception " + exception.getSimpleName() + " is declared twice", reference, i, EXCEPTION_DECLARED_TWICE);
}
}
}


@Check
public void checkLeftHandSideIsVariable(XAssignment assignment){
String concreteSyntaxFeatureName = assignment.getConcreteSyntaxFeatureName();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,10 @@
import org.eclipse.xtext.xbase.typesystem.override.IResolvedOperation;
import org.eclipse.xtext.xbase.typesystem.override.OverrideHelper;
import org.eclipse.xtext.xbase.typesystem.override.ResolvedFeatures;
import org.eclipse.xtext.xbase.typesystem.references.ITypeReferenceOwner;
import org.eclipse.xtext.xbase.typesystem.references.LightweightTypeReference;
import org.eclipse.xtext.xbase.typesystem.references.StandardTypeReferenceOwner;
import org.eclipse.xtext.xbase.typesystem.util.CommonTypeComputationServices;
import org.eclipse.xtext.xbase.typesystem.util.ContextualVisibilityHelper;
import org.eclipse.xtext.xbase.typesystem.util.IVisibilityHelper;
import org.eclipse.xtext.xbase.typesystem.util.RecursionGuard;
Expand Down Expand Up @@ -100,6 +103,9 @@ public class JvmGenericTypeValidator extends AbstractDeclarativeValidator {
@Inject
private ILogicalContainerProvider containerProvider;

@Inject
private CommonTypeComputationServices services;

@Override
public void register(EValidatorRegistrar registrar) {
// library validator is not registered for a specific language
Expand All @@ -121,7 +127,7 @@ protected void checkJvmGenericTypes(List<? extends EObject> contents) {
.forEach(this::checkJvmGenericType);
}

private boolean isAssociatedToSource(EObject e) {
protected boolean isAssociatedToSource(EObject e) {
return !associations.getSourceElements(e).isEmpty();
}

Expand Down Expand Up @@ -433,6 +439,41 @@ protected void checkJvmExecutable(JvmExecutable executable) {
+ executable.getSimpleName(), sourceParameterType, null, INVALID_USE_OF_TYPE);
}
}
checkExceptions(sourceExecutable, executable);
}

protected void checkExceptions(EObject sourceExecutable, JvmExecutable executable) {
List<JvmTypeReference> exceptions = executable.getExceptions();
if (exceptions.isEmpty())
return;
Set<String> declaredExceptionNames = Sets.newHashSet();
JvmTypeReference throwableType = getServices().getTypeReferences().getTypeForName(Throwable.class, executable);
if (throwableType == null) {
return;
}
ITypeReferenceOwner owner = new StandardTypeReferenceOwner(getServices(), executable);
LightweightTypeReference throwableReference = owner.toLightweightTypeReference(throwableType);
for(int i = 0; i < exceptions.size(); i++) {
JvmTypeReference exception = exceptions.get(i);
// throwables may not carry generics thus the raw comparison is sufficient
if (exception.getType() != null && !exception.getType().eIsProxy()) {
var sourceException = associations.getPrimarySourceElement(exception);
if (sourceException == null)
continue;
var containingFeature = sourceException.eContainingFeature();
if(!throwableReference.isAssignableFrom(exception.getType()))
error("No exception of type " + exception.getSimpleName() +
" can be thrown; an exception type must be a subclass of Throwable",
sourceExecutable, containingFeature, i, EXCEPTION_NOT_THROWABLE);
if(!declaredExceptionNames.add(exception.getQualifiedName()))
error("Exception " + exception.getSimpleName() + " is declared twice",
sourceExecutable, containingFeature, i, EXCEPTION_DECLARED_TWICE);
}
}
}

protected CommonTypeComputationServices getServices() {
return services;
}

/**
Expand Down

0 comments on commit 8d76826

Please sign in to comment.