@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); }