// checks (3) and (1)
  private Expression genObjOperation(Context ctx, MClass srcClass, Expression srcExpr)
      throws SemanticException {
    Expression res = null;

    // find operation
    String opname = fOp.getText();
    MOperation op = srcClass.operation(opname, true);
    if (op != null) {
      // check for isQuery operation with OCL body
      if (!op.hasExpression())
        throw new SemanticException(
            fOp,
            "Operation `"
                + srcClass.name()
                + "::"
                + op.signature()
                + "' cannot be used in OCL expression "
                + "(only side effect-free operations with a return type and an OCL expression as body may be used).");

      try {
        // constructor performs additional checks
        res = new ExpObjOp(op, fArgExprs);
      } catch (ExpInvalidException ex) {
        throw new SemanticException(
            fOp, "In operation call `" + srcClass.name() + "::" + opname + "': " + ex.getMessage());
      }
    } else {
      // try standard operation
      res = genStdOperation(ctx, fOp, opname, fArgExprs);
    }
    return res;
  }
  /** Handles shorthand notation for collect and expands to an explicit collect expression. */
  private Expression collectShorthandWithArgs(String opname, Expression srcExpr)
      throws SemanticException {
    Expression res = null;
    // c.op()  201 (5) with implicit (3,1)
    CollectionType cType = (CollectionType) srcExpr.type();
    Type elemType = cType.elemType();
    if (elemType.isObjectType()) {
      MClass srcClass = ((ObjectType) elemType).cls();
      MOperation op = srcClass.operation(opname, true);
      if (op != null) {
        // check for isQuery operation with OCL body
        if (!op.hasExpression())
          throw new SemanticException(
              fOp,
              "Operation `"
                  + srcClass.name()
                  + "::"
                  + op.signature()
                  + "' cannot be used in OCL expression "
                  + "(only side effect-free operations with a return type and an OCL expression as body may be used).");

        // transform c.op(...) into c->collect($e | $e.op(...))
        ExpVariable eVar = new ExpVariable("$e", elemType);
        fArgExprs[0] = eVar;
        try {
          // constructor performs additional checks
          res = new ExpObjOp(op, fArgExprs);
        } catch (ExpInvalidException ex) {
          throw new SemanticException(
              fOp,
              "In operation call `" + srcClass.name() + "::" + opname + "': " + ex.getMessage());
        }
        res = genImplicitCollect(srcExpr, res, elemType);
      }
    }
    if (res == null) {
      // try (1) predefined OCL operation
      res = collectShorthandStdOp(opname, srcExpr, cType, elemType);
    }
    return res;
  }
  /** Handles shorthand notation for collect and expands to an explicit collect expression. */
  private Expression collectShorthandStdOp(
      String opname, Expression srcExpr, Type cType, Type elemType) throws SemanticException {
    Expression res = null;
    // (1) predefined OCL operation

    // find operation on element type
    Type[] params = new Type[fArgExprs.length];
    params[0] = elemType;
    for (int i = 1; i < fArgExprs.length; i++) params[i] = fArgExprs[i].type();
    if (!ExpStdOp.exists(opname, params)) {
      String msg =
          "Undefined operation `"
              + elemType
              + "."
              + opname
              + "' in shorthand notation for collect.";
      // maybe the user just confused . with ->, check for
      // operation on collection and give a hint.
      params[0] = cType;
      if (ExpStdOp.exists(opname, params))
        msg +=
            " However, there is an operation `"
                + cType
                + "->"
                + opname
                + "'. Maybe you wanted to use `->' instead of `.'?";
      throw new SemanticException(fOp, msg);
    }
    // transform c.op(...) into c->collect($e | $e.op(...))
    fArgExprs[0] = new ExpVariable("$e", elemType);
    try {
      Expression eOp = ExpStdOp.create(opname, fArgExprs);
      res = genImplicitCollect(srcExpr, eOp, elemType);
    } catch (ExpInvalidException ex) {
      // shouldn't fail because we already checked the
      // existence above
      throw new RuntimeException("collectShorthand failed: " + ex.getMessage());
    }
    return res;
  }