void VisitArraySubscriptExpr(clang::ArraySubscriptExpr *AS) {
      // find array name and size
      clang::DeclRefExpr *DR;
      if (!(DR = clang::dyn_cast<clang::DeclRefExpr>(
                      AS->getBase()->IgnoreImpCasts()))) {
          printf("Can't handle complex array expressions:\n\t%s\n",
                  toString(AS));
          exit(1);
      }
  
      const char *arr = DR->getDecl()->getNameAsString().c_str();
      int size = variables.arraySize(arr);
  
      clang::Expr *ind = AS->getIdx();
      // Both size and index are literals. No need for abstraction:
      if (clang::IntegerLiteral *IL =
              clang::dyn_cast<clang::IntegerLiteral>(ind)) {
          int val = (int)*IL->getValue().getRawData();
          if (val < 0 || val >= size) {
              printf("** Index out of bounds error: Array %s, size %d, index "
                      "%d\n", arr, size, val);
              printf("\t%s\n", toString(AS));
              error = true;
          }
      // Size is a literal but the index is an abstract value:
      } else if (clang::DeclRefExpr *DR =
              clang::dyn_cast<clang::DeclRefExpr>(ind->IgnoreImpCasts())) {
          char *varInd = variables.find(
                  DR->getDecl()->getNameAsString().c_str());
          if (!blkApronCtx->isIndexInBound(varInd, size)) {
              printf("** Index out of bounds error: Index %s, Array %s, size "
                      "%d\n", toString(DR), arr, size);
              error = true;
          }
      } else {
          printf("Can't handle compound expressions as array indexes:\n\t%s\n",
                  toString(AS));
          exit(1);
      }
//      else if (clang::ImplicitCastExpr *CE =
//              clang::dyn_cast<clang::ImplicitCastExpr>(ind)) {
//        Visit(CE);
//        char *indVar = variables.getLastVar();
//        analysisCtx->addArrayIndex(indVar, size);
//      }
//      variables.toggleCollectingVars(false);
    }