blob: 66e402a89bd3d2648b0e48200c1c80ecc7b4f6e7 [file] [log] [blame]
package com.intellij.codeInsight.completion;
import com.intellij.codeInsight.ExpectedTypeInfo;
import com.intellij.codeInsight.TailType;
import com.intellij.codeInsight.completion.simple.RParenthTailType;
import com.intellij.codeInsight.lookup.AutoCompletionPolicy;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupElementDecorator;
import com.intellij.codeInsight.lookup.PsiTypeLookupItem;
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.psi.*;
import com.intellij.psi.codeStyle.CommonCodeStyleSettings;
import com.intellij.psi.impl.source.PostprocessReformattingAspect;
import com.intellij.psi.impl.source.tree.java.PsiEmptyExpressionImpl;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.ProcessingContext;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* @author peter
*/
class SmartCastProvider extends CompletionProvider<CompletionParameters> {
static final PsiElementPattern.Capture<PsiElement> INSIDE_TYPECAST_TYPE = PlatformPatterns.psiElement().afterLeaf(
PlatformPatterns.psiElement().withText("(").withParent(
PsiTypeCastExpression.class));
@Override
protected void addCompletions(@NotNull final CompletionParameters parameters, final ProcessingContext context, @NotNull final CompletionResultSet result) {
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();
}
if (type == null || type == PsiType.VOID) {
continue;
}
result.addElement(createSmartCastElement(parameters, overwrite, type));
if (type instanceof PsiPrimitiveType) {
final PsiType castedType = getCastedExpressionType(originalPosition);
if (castedType != null && !(castedType instanceof PsiPrimitiveType)) {
final PsiClassType boxedType = ((PsiPrimitiveType)type).getBoxedType(originalPosition);
if (boxedType != null) {
result.addElement(createSmartCastElement(parameters, overwrite, boxedType));
}
}
}
}
}
@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();
}
}
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();
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;
}
private static LookupElement createSmartCastElement(final CompletionParameters parameters, final boolean overwrite, final PsiType type) {
return AutoCompletionPolicy.ALWAYS_AUTOCOMPLETE.applyPolicy(new LookupElementDecorator<PsiTypeLookupItem>(
PsiTypeLookupItem.createLookupItem(type, parameters.getPosition())) {
@Override
public void handleInsert(InsertionContext context) {
FeatureUsageTracker.getInstance().triggerFeatureUsed("editing.completion.smarttype.casting");
final Editor editor = context.getEditor();
final Document document = editor.getDocument();
if (overwrite) {
document.deleteString(context.getSelectionEndOffset(),
context.getOffsetMap().getOffset(CompletionInitializationContext.IDENTIFIER_END_OFFSET));
}
final CommonCodeStyleSettings csSettings = context.getCodeStyleSettings();
final int oldTail = context.getTailOffset();
context.setTailOffset(RParenthTailType.addRParenth(editor, oldTail, csSettings.SPACE_WITHIN_CAST_PARENTHESES));
getDelegate().handleInsert(CompletionUtil.newContext(context, getDelegate(), context.getStartOffset(), oldTail));
PostprocessReformattingAspect.getInstance(context.getProject()).doPostponedFormatting();
if (csSettings.SPACE_AFTER_TYPE_CAST) {
context.setTailOffset(TailType.insertChar(editor, context.getTailOffset(), ' '));
}
editor.getCaretModel().moveToOffset(context.getTailOffset());
editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
}
});
}
}