All Downloads are FREE. Search and download functionalities are using the official Maven repository.

jbase.validation.JbaseValidator Maven / Gradle / Ivy

There is a newer version: 0.12.2
Show newest version
/**
 * generated by Xtext
 */
package jbase.validation;

import com.google.common.base.Objects;
import com.google.inject.Inject;
import java.util.ArrayList;
import java.util.List;
import jbase.controlflow.JbaseSureReturnComputer;
import jbase.jbase.JbasePackage;
import jbase.jbase.XJAdditionalXVariableDeclaration;
import jbase.jbase.XJArrayAccess;
import jbase.jbase.XJArrayConstructorCall;
import jbase.jbase.XJArrayLiteral;
import jbase.jbase.XJBranchingStatement;
import jbase.jbase.XJBreakStatement;
import jbase.jbase.XJCharLiteral;
import jbase.jbase.XJConstructorCall;
import jbase.jbase.XJContinueStatement;
import jbase.jbase.XJJvmFormalParameter;
import jbase.jbase.XJSemicolonStatement;
import jbase.jbase.XJTryWithResourcesStatement;
import jbase.jbase.XJTryWithResourcesVariableDeclaration;
import jbase.scoping.featurecalls.JbaseOperatorMapping;
import jbase.util.JbaseModelUtil;
import jbase.util.JbaseNodeModelUtil;
import jbase.validation.AbstractJbaseValidator;
import jbase.validation.JbaseInitializedVariableFinder;
import jbase.validation.JbaseIssueCodes;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.xtext.common.types.JvmConstructor;
import org.eclipse.xtext.common.types.JvmFormalParameter;
import org.eclipse.xtext.common.types.JvmIdentifiableElement;
import org.eclipse.xtext.common.types.JvmOperation;
import org.eclipse.xtext.common.types.JvmType;
import org.eclipse.xtext.util.Wrapper;
import org.eclipse.xtext.validation.Check;
import org.eclipse.xtext.xbase.XAbstractFeatureCall;
import org.eclipse.xtext.xbase.XAbstractWhileExpression;
import org.eclipse.xtext.xbase.XBasicForLoopExpression;
import org.eclipse.xtext.xbase.XBlockExpression;
import org.eclipse.xtext.xbase.XConstructorCall;
import org.eclipse.xtext.xbase.XExpression;
import org.eclipse.xtext.xbase.XFeatureCall;
import org.eclipse.xtext.xbase.XMemberFeatureCall;
import org.eclipse.xtext.xbase.XSwitchExpression;
import org.eclipse.xtext.xbase.XVariableDeclaration;
import org.eclipse.xtext.xbase.XbasePackage;
import org.eclipse.xtext.xbase.jvmmodel.ILogicalContainerProvider;
import org.eclipse.xtext.xbase.lib.Conversions;
import org.eclipse.xtext.xbase.lib.Extension;
import org.eclipse.xtext.xbase.lib.Functions.Function1;
import org.eclipse.xtext.xbase.lib.IterableExtensions;
import org.eclipse.xtext.xbase.typesystem.IBatchTypeResolver;
import org.eclipse.xtext.xbase.typesystem.IResolvedTypes;
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.validation.IssueCodes;
import org.eclipse.xtext.xbase.validation.ProxyAwareUIStrings;
import org.eclipse.xtext.xtype.XImportDeclaration;

/**
 * @author Lorenzo Bettini
 */
@SuppressWarnings("all")
public class JbaseValidator extends AbstractJbaseValidator {
  private final static XbasePackage xbasePackage = XbasePackage.eINSTANCE;
  
  private final static JbasePackage jbasePackage = JbasePackage.eINSTANCE;
  
  @Inject
  @Extension
  private JbaseNodeModelUtil _jbaseNodeModelUtil;
  
  @Inject
  @Extension
  private JbaseModelUtil _jbaseModelUtil;
  
  @Inject
  private ILogicalContainerProvider logicalContainerProvider;
  
  @Inject
  private IBatchTypeResolver batchTypeResolver;
  
  @Inject
  private JbaseSureReturnComputer sureReturnComputer;
  
  @Inject
  private JbaseInitializedVariableFinder initializedVariableFinder;
  
  @Inject
  private ProxyAwareUIStrings proxyAwareUIStrings;
  
  @Override
  protected void checkAssignment(final XExpression expression, final EStructuralFeature feature, final boolean simpleAssignment) {
    if ((expression instanceof XJArrayAccess)) {
      return;
    }
    if ((expression instanceof XAbstractFeatureCall)) {
      final JvmIdentifiableElement assignmentFeature = ((XAbstractFeatureCall)expression).getFeature();
      if ((assignmentFeature instanceof JvmFormalParameter)) {
        final XJJvmFormalParameter originalParam = this._jbaseModelUtil.getOriginalParam(((JvmFormalParameter)assignmentFeature));
        if (((originalParam == null) || (!originalParam.isFinal()))) {
          return;
        }
      }
    }
    super.checkAssignment(expression, feature, simpleAssignment);
  }
  
  /**
   * In case of an additional variable declaration we must use the container of
   * the containing variable declaration, otherwise additional variables will always be
   * detected as unused; similarly if the container is a semicolon statement which
   * contains a variable declaration
   */
  @Override
  protected boolean isLocallyUsed(final EObject target, final EObject containerToFindUsage) {
    if (((target instanceof XJAdditionalXVariableDeclaration) && 
      (containerToFindUsage instanceof XVariableDeclaration))) {
      return this.isLocallyUsed(target, containerToFindUsage.eContainer());
    }
    if ((containerToFindUsage instanceof XJSemicolonStatement)) {
      return this.isLocallyUsed(target, ((XJSemicolonStatement)containerToFindUsage).eContainer());
    }
    return super.isLocallyUsed(target, containerToFindUsage);
  }
  
  @Check
  public void checkContinue(final XJContinueStatement st) {
    this.checkBranchingStatementInternal(st, 
      "a loop", 
      "continue", 
      XAbstractWhileExpression.class, 
      XBasicForLoopExpression.class);
  }
  
  @Check
  public void checkBreak(final XJBreakStatement st) {
    this.checkBranchingStatementInternal(st, 
      "a loop or a switch", 
      "break", 
      XAbstractWhileExpression.class, 
      XBasicForLoopExpression.class, 
      XSwitchExpression.class);
  }
  
  private void checkBranchingStatementInternal(final XJBranchingStatement st, final String errorDetails, final String instruction, final Class... validContainers) {
    final Wrapper container = Wrapper.wrap(st.eContainer());
    while ((container.get() != null)) {
      {
        final Function1, Boolean> _function = new Function1, Boolean>() {
          @Override
          public Boolean apply(final Class c) {
            return Boolean.valueOf(c.isInstance(container.get()));
          }
        };
        boolean _exists = IterableExtensions.>exists(((Iterable>)Conversions.doWrapArray(validContainers)), _function);
        if (_exists) {
          return;
        }
        container.set(container.get().eContainer());
      }
    }
    this.error(
      ((instruction + " cannot be used outside of ") + errorDetails), st, 
      null, 
      JbaseIssueCodes.INVALID_BRANCHING_STATEMENT);
  }
  
  @Check
  public void checkMissingSemicolon(final XJSemicolonStatement e) {
    String _semicolon = e.getSemicolon();
    boolean _tripleEquals = (_semicolon == null);
    if (_tripleEquals) {
      this.errorMissingSemicolon(e.getExpression());
    }
  }
  
  @Check
  public void checkMissingSemicolon(final XImportDeclaration e) {
    this.checkMissingSemicolonInternal(e);
  }
  
  @Check
  public void checkTryWithResources(final XJTryWithResourcesStatement e) {
    final EList resourceDeclarations = e.getResourceDeclarations();
    final int numOfResources = resourceDeclarations.size();
    if ((numOfResources == 0)) {
      this.error(
        "Syntax error on token \"(\", Resources expected after this token", e, JbaseValidator.jbasePackage.getXJTryWithResourcesStatement_OpenParenthesis(), 
        JbaseIssueCodes.MISSING_RESOURCES);
    } else {
      Iterable _take = IterableExtensions.take(resourceDeclarations, (numOfResources - 1));
      for (final XJTryWithResourcesVariableDeclaration r : _take) {
        String _semicolon = r.getSemicolon();
        boolean _tripleEquals = (_semicolon == null);
        if (_tripleEquals) {
          this.errorMissingSemicolon(r);
        }
      }
    }
  }
  
  @Check
  public void checkAutoCloseableResource(final XJTryWithResourcesVariableDeclaration e) {
    final LightweightTypeReference declaredType = this.getActualType(e.getType().getType());
    CommonTypeComputationServices _services = this.getServices();
    final LightweightTypeReference autoCloseable = new StandardTypeReferenceOwner(_services, e).toLightweightTypeReference(this.getServices().getTypeReferences().getTypeForName(AutoCloseable.class, e));
    boolean _isAssignableFrom = autoCloseable.isAssignableFrom(declaredType);
    boolean _not = (!_isAssignableFrom);
    if (_not) {
      this.error(
        (("The resource type " + declaredType) + " does not implement java.lang.AutoCloseable"), e, JbaseValidator.xbasePackage.getXVariableDeclaration_Type(), 
        JbaseIssueCodes.NOT_AUTO_CLOSEABLE);
    }
  }
  
  private void checkMissingSemicolonInternal(final EObject e) {
    boolean _hasSemicolon = this._jbaseNodeModelUtil.hasSemicolon(e);
    boolean _not = (!_hasSemicolon);
    if (_not) {
      this.errorMissingSemicolon(e);
    }
  }
  
  private void errorMissingSemicolon(final EObject e) {
    this.error(
      "Syntax error, insert \";\" to complete Statement", e, null, JbaseIssueCodes.MISSING_SEMICOLON);
  }
  
  @Check
  public void checkMissingParentheses(final XFeatureCall call) {
    this.checkMissingParenthesesInternal(call, call.isExplicitOperationCall());
  }
  
  @Check
  public void checkMissingParentheses(final XMemberFeatureCall call) {
    this.checkMissingParenthesesInternal(call, call.isExplicitOperationCall());
  }
  
  @Check
  public void checkMissingParentheses(final XConstructorCall call) {
    boolean _isExplicitConstructorCall = call.isExplicitConstructorCall();
    boolean _not = (!_isExplicitConstructorCall);
    if (_not) {
      this.error(
        "Syntax error, insert \"()\" to complete Expression", call, 
        JbaseValidator.xbasePackage.getXConstructorCall_Constructor(), 
        JbaseIssueCodes.MISSING_PARENTHESES);
    }
  }
  
  @Check
  public void checkConstructorCallRawType(final XJConstructorCall call) {
    boolean _isRawType = this._jbaseModelUtil.isRawType(call);
    if (_isRawType) {
      final JvmConstructor constructor = call.getConstructor();
      EObject _eContainer = constructor.eContainer();
      final JvmType constructorType = ((JvmType) _eContainer);
      StringBuilder message = new StringBuilder(64);
      message.append(constructorType.getSimpleName());
      message.append(" is a raw type. References to generic type ");
      message = this.proxyAwareUIStrings.appendTypeSignature(constructorType, message);
      message.append(" should be parameterized");
      this.warning(
        message.toString(), 
        JbaseValidator.xbasePackage.getXConstructorCall_Constructor(), 
        IssueCodes.RAW_TYPE);
    }
  }
  
  @Check
  public void checkArrayConstructor(final XJArrayConstructorCall cons) {
    final XJArrayLiteral arrayLiteral = cons.getArrayLiteral();
    final EList dimensionExpressions = cons.getIndexes();
    if ((dimensionExpressions.isEmpty() && (arrayLiteral == null))) {
      this.error(
        "Constructor must provide either dimension expressions or an array initializer", cons, 
        null, 
        JbaseIssueCodes.ARRAY_CONSTRUCTOR_EITHER_DIMENSION_EXPRESSION_OR_INITIALIZER);
    } else {
      if (((!dimensionExpressions.isEmpty()) && (arrayLiteral != null))) {
        this.error(
          "Cannot define dimension expressions when an array initializer is provided", cons, 
          null, 
          JbaseIssueCodes.ARRAY_CONSTRUCTOR_BOTH_DIMENSION_EXPRESSION_AND_INITIALIZER);
      } else {
        final ArrayList dimensionsAndIndexes = this._jbaseModelUtil.arrayDimensionIndexAssociations(cons);
        boolean foundEmptyDimension = false;
        for (final XExpression d : dimensionsAndIndexes) {
          if ((d == null)) {
            foundEmptyDimension = true;
          } else {
            if (foundEmptyDimension) {
              this.error(
                "Cannot specify an array dimension after an empty dimension", d, 
                null, 
                JbaseIssueCodes.ARRAY_CONSTRUCTOR_DIMENSION_EXPRESSION_AFTER_EMPTY_DIMENSION);
              return;
            }
          }
        }
      }
    }
  }
  
  @Check
  public void checkCharacterLiteral(final XJCharLiteral c) {
    final int lenght = c.getValue().length();
    if ((lenght > 1)) {
      this.error(
        "Invalid character constant", c, null, 
        JbaseIssueCodes.INVALID_CHARACTER_CONSTANT);
    }
  }
  
  private void checkMissingParenthesesInternal(final XAbstractFeatureCall call, final boolean explicitOpCall) {
    if ((((call.getFeature() instanceof JvmOperation) && (!explicitOpCall)) && 
      (!Objects.equal(call.getFeature().getSimpleName(), JbaseOperatorMapping.ARRAY_LENGTH)))) {
      this.error(
        "Syntax error, insert \"()\" to complete method call", call, 
        JbaseValidator.xbasePackage.getXAbstractFeatureCall_Feature(), 
        JbaseIssueCodes.MISSING_PARENTHESES);
    }
  }
  
  @Check
  public void checkVarArgComesLast(final XJJvmFormalParameter param) {
    boolean _isVarArgs = param.isVarArgs();
    if (_isVarArgs) {
      Object _eGet = param.eContainer().eGet(param.eContainingFeature());
      final List params = ((List) _eGet);
      XJJvmFormalParameter _last = IterableExtensions.last(params);
      boolean _notEquals = (!Objects.equal(param, _last));
      if (_notEquals) {
        this.error(
          "A vararg must be the last parameter.", param, 
          JbaseValidator.jbasePackage.getXJJvmFormalParameter_VarArgs(), 
          JbaseIssueCodes.INVALID_USE_OF_VAR_ARGS);
      }
    }
  }
  
  /**
   * This can be explicitly called on an XBlockExpression which represents
   * the body of an inferred JvmOperation; it will check that,
   * if the corresponding Java method is not void, a return
   * is specified in all possible paths.
   */
  protected void checkMissingReturn(final XBlockExpression body) {
    final JvmIdentifiableElement jvmOperation = this.logicalContainerProvider.getLogicalContainer(body);
    final IResolvedTypes types = this.batchTypeResolver.resolveTypes(body);
    boolean _isPrimitiveVoid = types.getActualType(jvmOperation).isPrimitiveVoid();
    if (_isPrimitiveVoid) {
      return;
    }
    final XExpression lastExpression = IterableExtensions.last(body.getExpressions());
    if ((lastExpression == null)) {
      this.errorMissingReturnStatement(body);
      return;
    }
    boolean _isSureReturn = this.sureReturnComputer.isSureReturn(lastExpression);
    boolean _not = (!_isSureReturn);
    if (_not) {
      this.errorMissingReturnStatement(lastExpression);
    }
  }
  
  /**
   * This can be explicitly called on an XBlockExpression which represents
   * the body of an inferred JvmOperation; it will check that
   * variable references refer to variables that are surely initialized,
   * according to the Java semantics.  This should be called only on
   * top block expressions, as stated above.
   */
  protected void checkVariableInitialization(final XBlockExpression e) {
    final JbaseInitializedVariableFinder.NotInitializedAcceptor _function = new JbaseInitializedVariableFinder.NotInitializedAcceptor() {
      @Override
      public void accept(final XAbstractFeatureCall ref) {
        String _string = ref.toString();
        String _plus = ("The local variable " + _string);
        String _plus_1 = (_plus + " may not have been initialized");
        JbaseValidator.this.error(_plus_1, ref, 
          JbaseValidator.xbasePackage.getXAbstractFeatureCall_Feature(), 
          JbaseIssueCodes.NOT_INITIALIZED_VARIABLE);
      }
    };
    this.initializedVariableFinder.detectNotInitialized(e, _function);
  }
  
  protected void errorMissingReturnStatement(final XExpression e) {
    XExpression source = e;
    if ((e instanceof XJSemicolonStatement)) {
      source = ((XJSemicolonStatement)e).getExpression();
    }
    this.error("Missing return", source, null, JbaseIssueCodes.MISSING_RETURN);
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy