@Override
  public String handleEmptyLookup(
      @NotNull final CompletionParameters parameters, final Editor editor) {
    if (!(parameters.getOriginalFile() instanceof PsiJavaFile)) return null;

    final String ad = advertise(parameters);
    final String suffix = ad == null ? "" : "; " + StringUtil.decapitalize(ad);
    if (parameters.getCompletionType() == CompletionType.SMART) {
      if (!ApplicationManager.getApplication().isUnitTestMode()) {

        final Project project = parameters.getPosition().getProject();
        final PsiFile file = parameters.getOriginalFile();

        PsiExpression expression =
            PsiTreeUtil.getContextOfType(parameters.getPosition(), PsiExpression.class, true);
        if (expression != null && expression.getParent() instanceof PsiExpressionList) {
          int lbraceOffset = expression.getParent().getTextRange().getStartOffset();
          ShowParameterInfoHandler.invoke(project, editor, file, lbraceOffset, null);
        }

        if (expression instanceof PsiLiteralExpression) {
          return LangBundle.message("completion.no.suggestions") + suffix;
        }

        if (expression instanceof PsiInstanceOfExpression) {
          final PsiInstanceOfExpression instanceOfExpression = (PsiInstanceOfExpression) expression;
          if (PsiTreeUtil.isAncestor(
              instanceOfExpression.getCheckType(), parameters.getPosition(), false)) {
            return LangBundle.message("completion.no.suggestions") + suffix;
          }
        }
      }

      final Set<PsiType> expectedTypes = JavaCompletionUtil.getExpectedTypes(parameters);
      if (expectedTypes != null) {
        PsiType type = expectedTypes.size() == 1 ? expectedTypes.iterator().next() : null;
        if (type != null) {
          final PsiType deepComponentType = type.getDeepComponentType();
          if (deepComponentType instanceof PsiClassType) {
            if (((PsiClassType) deepComponentType).resolve() != null) {
              return CompletionBundle.message(
                      "completion.no.suggestions.of.type", type.getPresentableText())
                  + suffix;
            }
            return CompletionBundle.message("completion.unknown.type", type.getPresentableText())
                + suffix;
          }
          if (!PsiType.NULL.equals(type)) {
            return CompletionBundle.message(
                    "completion.no.suggestions.of.type", type.getPresentableText())
                + suffix;
          }
        }
      }
    }
    return LangBundle.message("completion.no.suggestions") + suffix;
  }
 private static boolean instanceofExpressionsAreEquivalent(
     PsiInstanceOfExpression instanceOfExpression1,
     PsiInstanceOfExpression instanceOfExpression2) {
   final PsiExpression operand1 = instanceOfExpression1.getOperand();
   final PsiExpression operand2 = instanceOfExpression2.getOperand();
   if (!expressionsAreEquivalent(operand1, operand2)) {
     return false;
   }
   final PsiTypeElement typeElement1 = instanceOfExpression1.getCheckType();
   final PsiTypeElement typeElement2 = instanceOfExpression2.getCheckType();
   return typeElementsAreEquivalent(typeElement1, typeElement2);
 }
 @Override
 protected final void doFix(Project project, ProblemDescriptor descriptor)
     throws IncorrectOperationException {
   final PsiElement element = descriptor.getPsiElement();
   final PsiTypeElement castTypeElement;
   final PsiReferenceExpression reference;
   if (element instanceof PsiTypeCastExpression) {
     final PsiTypeCastExpression typeCastExpression = (PsiTypeCastExpression) element;
     castTypeElement = typeCastExpression.getCastType();
     final PsiExpression operand = typeCastExpression.getOperand();
     if (!(operand instanceof PsiReferenceExpression)) {
       return;
     }
     reference = (PsiReferenceExpression) operand;
   } else if (element instanceof PsiMethodCallExpression) {
     final PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression) element;
     final PsiReferenceExpression methodExpression = methodCallExpression.getMethodExpression();
     final PsiExpression qualifier = methodExpression.getQualifierExpression();
     if (!(qualifier instanceof PsiClassObjectAccessExpression)) {
       return;
     }
     final PsiClassObjectAccessExpression classObjectAccessExpression =
         (PsiClassObjectAccessExpression) qualifier;
     castTypeElement = classObjectAccessExpression.getOperand();
     final PsiExpressionList argumentList = methodCallExpression.getArgumentList();
     final PsiExpression[] arguments = argumentList.getExpressions();
     if (arguments.length != 1) {
       return;
     }
     final PsiExpression argument = arguments[0];
     if (!(argument instanceof PsiReferenceExpression)) {
       return;
     }
     reference = (PsiReferenceExpression) argument;
   } else {
     return;
   }
   if (castTypeElement == null) {
     return;
   }
   final PsiInstanceOfExpression conflictingInstanceof =
       InstanceOfUtils.getConflictingInstanceof(castTypeElement.getType(), reference, element);
   final PsiTypeElement instanceofTypeElement = conflictingInstanceof.getCheckType();
   if (instanceofTypeElement == null) {
     return;
   }
   final PsiElement newElement = replace(castTypeElement, instanceofTypeElement);
   final JavaCodeStyleManager codeStyleManager = JavaCodeStyleManager.getInstance(project);
   codeStyleManager.shortenClassReferences(newElement);
 }
 @Override
 public void visitMethodCallExpression(PsiMethodCallExpression expression) {
   super.visitMethodCallExpression(expression);
   final PsiReferenceExpression methodExpression = expression.getMethodExpression();
   final String methodName = methodExpression.getReferenceName();
   if (!"cast".equals(methodName)) {
     return;
   }
   final PsiMethod method = expression.resolveMethod();
   if (method == null) {
     return;
   }
   final PsiClass containingClass = method.getContainingClass();
   if (containingClass == null) {
     return;
   }
   final String qualifiedName = containingClass.getQualifiedName();
   if (!"java.lang.Class".equals(qualifiedName)) {
     return;
   }
   final PsiExpression qualifier = methodExpression.getQualifierExpression();
   if (!(qualifier instanceof PsiClassObjectAccessExpression)) {
     return;
   }
   final PsiClassObjectAccessExpression classObjectAccessExpression =
       (PsiClassObjectAccessExpression) qualifier;
   final PsiTypeElement operand = classObjectAccessExpression.getOperand();
   final PsiType castType = operand.getType();
   if (!(castType instanceof PsiClassType)) {
     return;
   }
   final PsiExpressionList argumentList = expression.getArgumentList();
   final PsiExpression[] arguments = argumentList.getExpressions();
   if (arguments.length != 1) {
     return;
   }
   final PsiExpression argument = arguments[0];
   if (!(argument instanceof PsiReferenceExpression)) {
     return;
   }
   final PsiReferenceExpression referenceExpression = (PsiReferenceExpression) argument;
   final PsiInstanceOfExpression conflictingInstanceof =
       InstanceOfUtils.getConflictingInstanceof(castType, referenceExpression, expression);
   if (conflictingInstanceof == null) {
     return;
   }
   final PsiTypeElement instanceofTypeElement = conflictingInstanceof.getCheckType();
   registerError(expression, referenceExpression, operand, instanceofTypeElement);
 }
 @Nullable
 private static PsiReferenceExpression getReferenceFromInstanceofExpression(
     PsiExpression expression) {
   if (expression instanceof PsiParenthesizedExpression) {
     final PsiParenthesizedExpression parenthesizedExpression =
         (PsiParenthesizedExpression) expression;
     return getReferenceFromInstanceofExpression(parenthesizedExpression.getExpression());
   } else if (expression instanceof PsiInstanceOfExpression) {
     final PsiInstanceOfExpression instanceOfExpression = (PsiInstanceOfExpression) expression;
     final PsiExpression operand =
         ParenthesesUtils.stripParentheses(instanceOfExpression.getOperand());
     if (!(operand instanceof PsiReferenceExpression)) {
       return null;
     }
     return (PsiReferenceExpression) operand;
   } else if (expression instanceof PsiPolyadicExpression) {
     final PsiPolyadicExpression polyadicExpression = (PsiPolyadicExpression) expression;
     final IElementType tokenType = polyadicExpression.getOperationTokenType();
     if (JavaTokenType.OROR != tokenType) {
       return null;
     }
     final PsiExpression[] operands = polyadicExpression.getOperands();
     final PsiReferenceExpression referenceExpression =
         getReferenceFromInstanceofExpression(operands[0]);
     if (referenceExpression == null) {
       return null;
     }
     for (int i = 1, operandsLength = operands.length; i < operandsLength; i++) {
       if (!referencesEqual(
           referenceExpression, getReferenceFromInstanceofExpression(operands[i]))) {
         return null;
       }
     }
     return referenceExpression;
   } else {
     return null;
   }
 }
 @Override
 public void visitTypeCastExpression(@NotNull PsiTypeCastExpression expression) {
   super.visitTypeCastExpression(expression);
   final PsiTypeElement castType = expression.getCastType();
   if (castType == null) {
     return;
   }
   final PsiType type = castType.getType();
   final PsiExpression operand = expression.getOperand();
   if (!(operand instanceof PsiReferenceExpression)) {
     return;
   }
   final PsiReferenceExpression referenceExpression = (PsiReferenceExpression) operand;
   final PsiInstanceOfExpression conflictingInstanceof =
       InstanceOfUtils.getConflictingInstanceof(type, referenceExpression, expression);
   if (conflictingInstanceof == null) {
     return;
   }
   final PsiTypeElement instanceofTypeElement = conflictingInstanceof.getCheckType();
   if (instanceofTypeElement == null) {
     return;
   }
   registerError(expression, referenceExpression, castType, instanceofTypeElement);
 }
 private boolean checkCondition(
     @Nullable PsiExpression condition,
     @NotNull PsiStatement context,
     List<PsiExpression> notUpdated) {
   if (condition == null) {
     return false;
   }
   if (PsiUtil.isConstantExpression(condition) || PsiKeyword.NULL.equals(condition.getText())) {
     return true;
   }
   if (condition instanceof PsiInstanceOfExpression) {
     final PsiInstanceOfExpression instanceOfExpression = (PsiInstanceOfExpression) condition;
     final PsiExpression operand = instanceOfExpression.getOperand();
     return checkCondition(operand, context, notUpdated);
   } else if (condition instanceof PsiParenthesizedExpression) {
     // catch stuff like "while ((x)) { ... }"
     final PsiExpression expression = ((PsiParenthesizedExpression) condition).getExpression();
     return checkCondition(expression, context, notUpdated);
   } else if (condition instanceof PsiPolyadicExpression) {
     // while (value != x) { ... }
     // while (value != (x + y)) { ... }
     // while (b1 && b2) { ... }
     final PsiPolyadicExpression polyadicExpression = (PsiPolyadicExpression) condition;
     for (PsiExpression operand : polyadicExpression.getOperands()) {
       if (!checkCondition(operand, context, notUpdated)) {
         return false;
       }
     }
     return true;
   } else if (condition instanceof PsiReferenceExpression) {
     final PsiReferenceExpression referenceExpression = (PsiReferenceExpression) condition;
     final PsiElement element = referenceExpression.resolve();
     if (element instanceof PsiField) {
       final PsiField field = (PsiField) element;
       final PsiType type = field.getType();
       if (field.hasModifierProperty(PsiModifier.FINAL) && type.getArrayDimensions() == 0) {
         if (field.hasModifierProperty(PsiModifier.STATIC)) {
           return true;
         }
         final PsiExpression qualifier = referenceExpression.getQualifierExpression();
         if (qualifier == null) {
           return true;
         } else if (checkCondition(qualifier, context, notUpdated)) {
           return true;
         }
       }
     } else if (element instanceof PsiVariable) {
       final PsiVariable variable = (PsiVariable) element;
       if (variable.hasModifierProperty(PsiModifier.FINAL)) {
         // final variables cannot be updated, don't bother to
         // flag them
         return true;
       } else if (element instanceof PsiLocalVariable || element instanceof PsiParameter) {
         if (!VariableAccessUtils.variableIsAssigned(variable, context)) {
           notUpdated.add(referenceExpression);
           return true;
         }
       }
     }
   } else if (condition instanceof PsiPrefixExpression) {
     final PsiPrefixExpression prefixExpression = (PsiPrefixExpression) condition;
     final IElementType tokenType = prefixExpression.getOperationTokenType();
     if (JavaTokenType.EXCL.equals(tokenType)
         || JavaTokenType.PLUS.equals(tokenType)
         || JavaTokenType.MINUS.equals(tokenType)) {
       final PsiExpression operand = prefixExpression.getOperand();
       return checkCondition(operand, context, notUpdated);
     }
   } else if (condition instanceof PsiArrayAccessExpression) {
     // Actually the contents of the array could change nevertheless
     // if it is accessed through a different reference like this:
     //   int[] local_ints = new int[]{1, 2};
     //   int[] other_ints = local_ints;
     //   while (local_ints[0] > 0) { other_ints[0]--; }
     //
     // Keep this check?
     final PsiArrayAccessExpression accessExpression = (PsiArrayAccessExpression) condition;
     final PsiExpression indexExpression = accessExpression.getIndexExpression();
     return checkCondition(indexExpression, context, notUpdated)
         && checkCondition(accessExpression.getArrayExpression(), context, notUpdated);
   } else if (condition instanceof PsiConditionalExpression) {
     final PsiConditionalExpression conditionalExpression = (PsiConditionalExpression) condition;
     final PsiExpression thenExpression = conditionalExpression.getThenExpression();
     final PsiExpression elseExpression = conditionalExpression.getElseExpression();
     if (thenExpression == null || elseExpression == null) {
       return false;
     }
     return checkCondition(conditionalExpression.getCondition(), context, notUpdated)
         && checkCondition(thenExpression, context, notUpdated)
         && checkCondition(elseExpression, context, notUpdated);
   } else if (condition instanceof PsiThisExpression) {
     return true;
   } else if (condition instanceof PsiMethodCallExpression && !ignoreIterators) {
     final PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression) condition;
     if (!IteratorUtils.isCallToHasNext(methodCallExpression)) {
       return false;
     }
     final PsiReferenceExpression methodExpression = methodCallExpression.getMethodExpression();
     final PsiExpression qualifierExpression = methodExpression.getQualifierExpression();
     if (qualifierExpression instanceof PsiReferenceExpression) {
       final PsiReferenceExpression referenceExpression =
           (PsiReferenceExpression) qualifierExpression;
       final PsiElement element = referenceExpression.resolve();
       if (!(element instanceof PsiVariable)) {
         return false;
       }
       final PsiVariable variable = (PsiVariable) element;
       if (!IteratorUtils.containsCallToScannerNext(context, variable, true)) {
         notUpdated.add(qualifierExpression);
         return true;
       }
     } else {
       if (!IteratorUtils.containsCallToScannerNext(context, null, true)) {
         notUpdated.add(methodCallExpression);
         return true;
       }
     }
   }
   return false;
 }
 private static void removeParensFromInstanceOfExpression(
     @NotNull PsiInstanceOfExpression instanceofExpression, boolean ignoreClarifyingParentheses) {
   final PsiExpression operand = instanceofExpression.getOperand();
   removeParentheses(operand, ignoreClarifyingParentheses);
 }