private static boolean isSwitchOnString(SwitchStatement first) {
    SwitchStatement second = null;
    List<StatEdge> edges = first.getSuccessorEdges(StatEdge.TYPE_REGULAR);
    if (edges.size() == 1 && edges.get(0).getDestination() instanceof SwitchStatement) {
      second = (SwitchStatement)edges.get(0).getDestination();
    }
    AssignmentExprent nullAssign = null;

    // if we're the only thing in an if statement,
    if (first.getParent() instanceof IfStatement) {
      if (!first.hasSuccessor(StatEdge.TYPE_REGULAR)) {
        IfStatement parent = (IfStatement) first.getParent();
        Exprent ifCond = parent.getHeadexprent().getCondition();
        // and it's a null check with `else` branch,
        if (parent.iftype == IfStatement.IFTYPE_IFELSE && ifCond instanceof FunctionExprent) {
          FunctionExprent func = (FunctionExprent)ifCond;
          if (func.getFuncType() == FunctionType.NE && func.getLstOperands().size() == 2) {
            Exprent right = func.getLstOperands().get(1);
            if (right instanceof ConstExprent && right.getExprType() == VarType.VARTYPE_NULL) {
              // and the `else` only assigns a variable,
              Statement elseStat = parent.getElsestat();
              if (elseStat instanceof BasicBlockStatement && elseStat.getExprents().size() == 1) {
                Exprent assign = elseStat.getExprents().get(0);
                if (assign instanceof AssignmentExprent) {
                  nullAssign = (AssignmentExprent)assign;
                  // then we're probably a nullable string-switch
                  edges = parent.getSuccessorEdges(StatEdge.TYPE_REGULAR);
                  if (edges.size() == 1 && edges.get(0).getDestination() instanceof SwitchStatement) {
                    second = (SwitchStatement)edges.get(0).getDestination();
                  }
                }
              }
            }
          }
        }
      }
    }

    if (second != null) {
      Exprent firstValue = ((SwitchHeadExprent)first.getHeadexprent()).getValue();
      Exprent secondValue = ((SwitchHeadExprent)second.getHeadexprent()).getValue();

      if (firstValue instanceof InvocationExprent && secondValue instanceof VarExprent && first.getCaseStatements().get(0) instanceof IfStatement) {
        InvocationExprent invExpr = (InvocationExprent)firstValue;
        VarExprent varExpr = (VarExprent) secondValue;
        if (nullAssign != null && !nullAssign.getLeft().equals(varExpr)) {
          return false; // wrong assignment across `if`
        }

        if (invExpr.getName().equals("hashCode") && invExpr.getClassname().equals("java/lang/String")) {
          boolean matches = true;

          for (int i = 0; matches && i < first.getCaseStatements().size(); ++i) {
            if (!first.getCaseEdges().get(i).contains(first.getDefaultEdge())) {
              Statement curr = first.getCaseStatements().get(i);
              while (matches && curr != null) {
                if (curr instanceof IfStatement) {
                  IfStatement ifStat = (IfStatement)curr;
                  Exprent condition = ifStat.getHeadexprent().getCondition();

                  if (condition instanceof FunctionExprent && ((FunctionExprent)condition).getFuncType() == FunctionType.NE) {
                    condition = ((FunctionExprent)condition).getLstOperands().get(0);
                  }

                  if (condition instanceof InvocationExprent) {
                    InvocationExprent condInvocation = (InvocationExprent)condition;

                    if (condInvocation.getName().equals("equals") && condInvocation.getInstance().equals(invExpr.getInstance())) {
                      List<Exprent> block = ifStat.getIfstat().getExprents();

                      if (block != null && block.size() == 1 && block.get(0) instanceof AssignmentExprent) {
                        AssignmentExprent assign = (AssignmentExprent)block.get(0);

                        if (assign.getRight() instanceof ConstExprent && varExpr.equals(assign.getLeft())) {

                          curr = ifStat.getElsestat();
                          continue;
                        }
                      }
                    }
                  }
                }

                matches = false;
              }
            }
          }

          return matches;
        }
      }
    }

    return false;
  }
Switch on string gets compiled into two sequential switch statements.
  The first is a switch on the hashcode of the string with the case statement
  being the actual if equal to string literal check. Hashcode collisions result in
  an else if chain. The body of the if block sets the switch variable for the
  following switch.

  The second switch block has the case statements of the original switch on string.

  byte b1 = -1;
  switch (stringVar.hashcode()) {
    case -390932093:
       if (stringVar.equals("foo") {
         b1 = 0;
       }
  }

  switch(b1) {
    case 0 :
       // code for case "foo"
  }
src/org/jetbrains/java/decompiler/modules/decompiler/SwitchHelper.java