private void checkFinalFieldAccess(Expression expression) {
    if (!(expression instanceof VariableExpression) && !(expression instanceof PropertyExpression))
      return;
    Variable v = null;
    if (expression instanceof VariableExpression) {
      VariableExpression ve = (VariableExpression) expression;
      v = ve.getAccessedVariable();
    } else {
      PropertyExpression propExp = ((PropertyExpression) expression);
      Expression objectExpression = propExp.getObjectExpression();
      if (objectExpression instanceof VariableExpression) {
        VariableExpression varExp = (VariableExpression) objectExpression;
        if (varExp.isThisExpression()) {
          v = currentClass.getDeclaredField(propExp.getPropertyAsString());
        }
      }
    }
    if (v instanceof FieldNode) {
      FieldNode fn = (FieldNode) v;

      /*
       *  if it is static final but not accessed inside a static constructor, or,
       *  if it is an instance final but not accessed inside a instance constructor, it is an error
       */
      boolean isFinal = fn.isFinal();
      boolean isStatic = fn.isStatic();
      boolean error =
          isFinal && ((isStatic && !inStaticConstructor) || (!isStatic && !inConstructor));

      if (error)
        addError(
            "cannot modify"
                + (isStatic ? " static" : "")
                + " final field '"
                + fn.getName()
                + "' outside of "
                + (isStatic ? "static initialization block." : "constructor."),
            expression);
    }
  }
  protected Expression transformMethodCallExpression(MethodCallExpression mce) {
    Expression args = transform(mce.getArguments());
    Expression method = transform(mce.getMethod());
    Expression object = transform(mce.getObjectExpression());
    boolean isExplicitThisOrSuper = false;
    boolean isExplicitSuper = false;
    if (object instanceof VariableExpression) {
      VariableExpression ve = (VariableExpression) object;
      isExplicitThisOrSuper =
          !mce.isImplicitThis() && (ve.isThisExpression() || ve.isSuperExpression());
      isExplicitSuper = ve.isSuperExpression();
    }

    if (mce.isImplicitThis() || isExplicitThisOrSuper) {
      if (mce.isImplicitThis()) {
        Expression ret = findStaticMethodImportFromModule(method, args);
        if (ret != null) {
          setSourcePosition(ret, mce);
          return ret;
        }
        if (method instanceof ConstantExpression && !inLeftExpression) {
          // could be a closure field
          String methodName = (String) ((ConstantExpression) method).getValue();
          ret = findStaticFieldOrPropAccessorImportFromModule(methodName);
          if (ret != null) {
            ret = new MethodCallExpression(ret, "call", args);
            setSourcePosition(ret, mce);
            return ret;
          }
        }
      } else if (currentMethod != null && currentMethod.isStatic() && isExplicitSuper) {
        MethodCallExpression ret =
            new MethodCallExpression(
                new ClassExpression(currentClass.getSuperClass()), method, args);
        setSourcePosition(ret, mce);
        return ret;
      }

      if (method instanceof ConstantExpression) {
        ConstantExpression ce = (ConstantExpression) method;
        Object value = ce.getValue();
        if (value instanceof String) {
          String methodName = (String) value;
          boolean lookForPossibleStaticMethod = !methodName.equals("call");
          if (currentMethod != null && !currentMethod.isStatic()) {
            if (currentClass.hasPossibleMethod(methodName, args)) {
              lookForPossibleStaticMethod = false;
            }
          }
          if (!inClosure
              && (inSpecialConstructorCall
                  || (lookForPossibleStaticMethod
                      && currentClass.hasPossibleStaticMethod(methodName, args)))) {
            StaticMethodCallExpression smce =
                new StaticMethodCallExpression(currentClass, methodName, args);
            setSourcePosition(smce, mce);
            return smce;
          }
        }
      }
    }

    MethodCallExpression result = new MethodCallExpression(object, method, args);
    result.setSafe(mce.isSafe());
    result.setImplicitThis(mce.isImplicitThis());
    result.setSpreadSafe(mce.isSpreadSafe());
    result.setMethodTarget(mce.getMethodTarget());
    // GROOVY-6757
    result.setGenericsTypes(mce.getGenericsTypes());
    setSourcePosition(result, mce);
    return result;
  }