@Override
  public String generateDescription() {
    if (!argType.isPointerType()) {
      return format(
          "Operand '%s' of operator %s has type '%s' but expecting a pointer type",
          ASTWriter.writeToString(argExpr), op, argType);
    }

    return format(
        "Invalid operand '%s' of type '%s' for operator %s",
        ASTWriter.writeToString(argExpr), argType, op);
  }
  @Override
  public String generateDescription() {
    if (!condType.isGeneralizedScalarType()) {
      return format(
          "Condition operand '%s' for operator ?: has type '%s' but expecting a scalar type",
          ASTWriter.writeToString(condExpr), condType);
    } else if (trueType.isFieldTagType() && falseType.isFieldTagType()) {
      return format(
          "Middle and last operand for operator ?: are structures or unions of incompatible types '%s' and '%s'",
          trueType, falseType);
    } else if (trueType.isVoid() && !falseType.isVoid()) {
      return format(
          "Last operand '%s' for operator ?: has type '%s' but expecting 'void' as the middle operand has such type",
          ASTWriter.writeToString(falseExpr), falseType);
    } else if (!trueType.isVoid() && falseType.isVoid()) {
      return format(
          "Middle operand '%s' for operator ?: has type '%s' but expecting 'void' as the last operand has such type",
          ASTWriter.writeToString(trueExpr), trueType);
    } else if (trueType.isPointerType() && falseType.isPointerType()) {

      final PointerType truePtrType = (PointerType) trueType,
          falsePtrType = (PointerType) falseType;
      final Type trueRefType = truePtrType.getReferencedType(),
          falseRefType = falsePtrType.getReferencedType();

      if (trueRefType.isVoid() && !falseRefType.isObjectType()) {
        return format(
            "Last operand '%s' for operator ?: points not to an object and thus cannot be combined with a middle operand of type '%s'",
            ASTWriter.writeToString(falseExpr), trueType);
      } else if (!trueRefType.isObjectType() && falseRefType.isVoid()) {
        return format(
            "Middle operand '%s' for operator ?: points not to an object and thus cannot be combined with a last operand of type '%s'",
            ASTWriter.writeToString(trueExpr), falseType);
      }
    }

    return format(
        "Invalid middle and last operands of types '%s' and '%s' for operator ?:",
        trueType, falseType);
  }
  @Override
  public String generateDescription() {
    if (!argType.isFunctionType() && !isLvalue) {
      return format(
          "Cannot use expression '%s' as the operand for operator %s because it "
              + "is neither an lvalue nor a function designator",
          ASTWriter.writeToString(argExpr), op);
    } else if (argType.isObjectType() && isLvalue) {
      if (isBitField) {
        return format(
            "Cannot use expression '%s' as the operand for operator %s because it "
                + "designates a bit-field",
            ASTWriter.writeToString(argExpr), op);
      } else if (inRegister) {
        return format(
            "Cannot use expression '%s' as the operand for operator %s because it "
                + "designates an object in a register",
            ASTWriter.writeToString(argExpr), op);
      }
    }

    return format("Invalid operand '%s' for operator %s", ASTWriter.writeToString(argExpr), op);
  }