diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java index 3bf770c620a7..2b2c35859f9d 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java @@ -285,9 +285,9 @@ public class JavaCompletionContributor extends CompletionContributor { result.stopHere(); } - private void addExpressionVariants(@NotNull CompletionParameters parameters, PsiElement position, CompletionResultSet result) { + private static void addExpressionVariants(@NotNull CompletionParameters parameters, PsiElement position, CompletionResultSet result) { if (JavaSmartCompletionContributor.INSIDE_EXPRESSION.accepts(position) && - !JavaCompletionData.AFTER_DOT.accepts(position)) { + !JavaCompletionData.AFTER_DOT.accepts(position) && !SmartCastProvider.shouldSuggestCast(parameters)) { JavaCompletionData.addExpectedTypeMembers(parameters, result); if (SameSignatureCallParametersProvider.IN_CALL_ARGUMENT.accepts(position)) { new SameSignatureCallParametersProvider().addCompletions(parameters, new ProcessingContext(), result); @@ -481,7 +481,7 @@ public class JavaCompletionContributor extends CompletionContributor { private static void completeAnnotationAttributeName(CompletionResultSet result, PsiElement insertedElement, CompletionParameters parameters) { PsiNameValuePair pair = PsiTreeUtil.getParentOfType(insertedElement, PsiNameValuePair.class); - PsiAnnotationParameterList parameterList = (PsiAnnotationParameterList)ObjectUtils.assertNotNull(pair).getParent(); + PsiAnnotationParameterList parameterList = (PsiAnnotationParameterList)assertNotNull(pair).getParent(); PsiAnnotation anno = (PsiAnnotation)parameterList.getParent(); boolean showClasses = psiElement().afterLeaf("(").accepts(insertedElement); PsiClass annoClass = null; diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaSmartCompletionContributor.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaSmartCompletionContributor.java index d4eede0babc6..af8266714ee8 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaSmartCompletionContributor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaSmartCompletionContributor.java @@ -129,7 +129,7 @@ public class JavaSmartCompletionContributor extends CompletionContributor { public JavaSmartCompletionContributor() { - extend(CompletionType.SMART, SmartCastProvider.INSIDE_TYPECAST_TYPE, new SmartCastProvider()); + extend(CompletionType.SMART, SmartCastProvider.TYPECAST_TYPE_CANDIDATE, new SmartCastProvider()); extend(CompletionType.SMART, SameSignatureCallParametersProvider.IN_CALL_ARGUMENT, new SameSignatureCallParametersProvider()); @@ -172,6 +172,8 @@ public class JavaSmartCompletionContributor extends CompletionContributor { extend(CompletionType.SMART, psiElement(), new CompletionProvider() { @Override protected void addCompletions(@NotNull final CompletionParameters parameters, final ProcessingContext context, @NotNull final CompletionResultSet result) { + if (SmartCastProvider.shouldSuggestCast(parameters)) return; + final PsiElement element = parameters.getPosition(); final PsiReference reference = element.getContainingFile().findReferenceAt(parameters.getOffset()); if (reference != null) { @@ -215,6 +217,8 @@ public class JavaSmartCompletionContributor extends CompletionContributor { extend(CompletionType.SMART, INSIDE_EXPRESSION, new ExpectedTypeBasedCompletionProvider() { @Override protected void addCompletions(final CompletionParameters params, final CompletionResultSet result, final Collection _infos) { + if (SmartCastProvider.shouldSuggestCast(params)) return; + Consumer noTypeCheck = decorateWithoutTypeCheck(result, _infos); THashSet mergedInfos = new THashSet(_infos, EXPECTED_TYPE_INFO_STRATEGY); @@ -525,16 +529,10 @@ public class JavaSmartCompletionContributor extends CompletionContributor { } PsiElement lastElement = context.getFile().findElementAt(context.getStartOffset() - 1); - if (lastElement != null && lastElement.getText().equals("(")) { - final PsiElement parent = lastElement.getParent(); - if (parent instanceof PsiTypeCastExpression) { - context.setDummyIdentifier(""); - return; - } - if (parent instanceof PsiParenthesizedExpression) { - context.setDummyIdentifier(CompletionUtil.DUMMY_IDENTIFIER_TRIMMED + ")" + CompletionUtil.DUMMY_IDENTIFIER_TRIMMED + " "); // to handle type cast - return; - } + if (lastElement != null && lastElement.getText().equals("(") && lastElement.getParent() instanceof PsiParenthesizedExpression) { + // don't trim dummy identifier or we won't be able to determine the type of the expression after '(' + // which is needed to insert correct cast + return; } context.setDummyIdentifier(CompletionUtil.DUMMY_IDENTIFIER_TRIMMED); } diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/SmartCastProvider.java b/java/java-impl/src/com/intellij/codeInsight/completion/SmartCastProvider.java index 66e402a89bd3..135f641f229b 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/SmartCastProvider.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/SmartCastProvider.java @@ -11,8 +11,7 @@ import com.intellij.featureStatistics.FeatureUsageTracker; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.ScrollType; -import com.intellij.patterns.PlatformPatterns; -import com.intellij.patterns.PsiElementPattern; +import com.intellij.patterns.ElementPattern; import com.intellij.psi.*; import com.intellij.psi.codeStyle.CommonCodeStyleSettings; import com.intellij.psi.impl.source.PostprocessReformattingAspect; @@ -22,20 +21,38 @@ import com.intellij.util.ProcessingContext; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import static com.intellij.patterns.PlatformPatterns.psiElement; + /** * @author peter */ class SmartCastProvider extends CompletionProvider { - static final PsiElementPattern.Capture INSIDE_TYPECAST_TYPE = PlatformPatterns.psiElement().afterLeaf( - PlatformPatterns.psiElement().withText("(").withParent( - PsiTypeCastExpression.class)); + static final ElementPattern TYPECAST_TYPE_CANDIDATE = psiElement().afterLeaf("("); + + static boolean shouldSuggestCast(CompletionParameters parameters) { + PsiElement position = parameters.getPosition(); + PsiElement parent = getParenthesisOwner(position); + if (parent instanceof PsiTypeCastExpression) return true; + if (parent instanceof PsiParenthesizedExpression) { + return parameters.getOffset() == position.getTextRange().getStartOffset(); + } + return false; + } + + private static PsiElement getParenthesisOwner(PsiElement position) { + PsiElement lParen = PsiTreeUtil.prevVisibleLeaf(position); + return lParen == null || !lParen.textMatches("(") ? null : lParen.getParent(); + } @Override protected void addCompletions(@NotNull final CompletionParameters parameters, final ProcessingContext context, @NotNull final CompletionResultSet result) { + if (!shouldSuggestCast(parameters)) return; + + PsiElement position = parameters.getPosition(); + PsiElement parenthesisOwner = getParenthesisOwner(position); + final boolean overwrite = parenthesisOwner instanceof PsiTypeCastExpression; + for (final ExpectedTypeInfo info : JavaSmartCompletionContributor.getExpectedTypes(parameters)) { - final PsiElement originalPosition = parameters.getOriginalPosition(); - final boolean overwrite = INSIDE_TYPECAST_TYPE.accepts(originalPosition); - PsiType type = info.getDefaultType(); if (type instanceof PsiWildcardType) { type = ((PsiWildcardType)type).getBound(); @@ -45,42 +62,34 @@ class SmartCastProvider extends CompletionProvider { continue; } - result.addElement(createSmartCastElement(parameters, overwrite, type)); if (type instanceof PsiPrimitiveType) { - final PsiType castedType = getCastedExpressionType(originalPosition); + final PsiType castedType = getCastedExpressionType(parenthesisOwner); if (castedType != null && !(castedType instanceof PsiPrimitiveType)) { - final PsiClassType boxedType = ((PsiPrimitiveType)type).getBoxedType(originalPosition); + final PsiClassType boxedType = ((PsiPrimitiveType)type).getBoxedType(position); if (boxedType != null) { - result.addElement(createSmartCastElement(parameters, overwrite, boxedType)); + type = boxedType; } } } + result.addElement(createSmartCastElement(parameters, overwrite, type)); } } @Nullable - private static PsiType getCastedExpressionType(PsiElement originalPosition) { - if (INSIDE_TYPECAST_TYPE.accepts(originalPosition)) { - final PsiTypeCastExpression cast = PsiTreeUtil.getParentOfType(originalPosition, PsiTypeCastExpression.class); - if (cast != null) { - final PsiExpression operand = cast.getOperand(); - return operand == null ? null : operand.getType(); - } + private static PsiType getCastedExpressionType(PsiElement parenthesisOwner) { + if (parenthesisOwner instanceof PsiTypeCastExpression) { + final PsiExpression operand = ((PsiTypeCastExpression)parenthesisOwner).getOperand(); + return operand == null ? null : operand.getType(); } - final PsiParenthesizedExpression parens = PsiTreeUtil.getParentOfType(originalPosition, PsiParenthesizedExpression.class, true, PsiStatement.class); - if (parens != null) { - final PsiExpression rightSide = parens.getExpression(); - if (rightSide != null) { - return rightSide.getType(); - } - PsiElement next = parens.getNextSibling(); + + if (parenthesisOwner instanceof PsiParenthesizedExpression) { + PsiElement next = parenthesisOwner.getNextSibling(); while (next != null && (next instanceof PsiEmptyExpressionImpl || next instanceof PsiErrorElement || next instanceof PsiWhiteSpace)) { next = next.getNextSibling(); } if (next instanceof PsiExpression) { return ((PsiExpression)next).getType(); } - return null; } return null; }