Project Coin multi-catch support

This commit is contained in:
Roman Shevchenko
2011-02-14 18:23:54 +01:00
parent a6f30214e6
commit 68ce5423cb
34 changed files with 809 additions and 112 deletions

View File

@@ -559,6 +559,10 @@ public class GenericsHighlightUtil {
return false; return false;
} }
if (rType instanceof PsiDisjunctionType || lType instanceof PsiDisjunctionType) {
return false;
}
if (lType instanceof PsiCapturedWildcardType || rType instanceof PsiCapturedWildcardType) { if (lType instanceof PsiCapturedWildcardType || rType instanceof PsiCapturedWildcardType) {
return false; return false;
} }

View File

@@ -29,9 +29,9 @@ import com.intellij.codeInsight.daemon.impl.quickfix.*;
import com.intellij.codeInsight.highlighting.HighlightUsagesDescriptionLocation; import com.intellij.codeInsight.highlighting.HighlightUsagesDescriptionLocation;
import com.intellij.codeInsight.intention.IntentionAction; import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.codeInsight.intention.QuickFixFactory; import com.intellij.codeInsight.intention.QuickFixFactory;
import com.intellij.codeInspection.IntentionProvider;
import com.intellij.codeInsight.quickfix.ChangeVariableTypeQuickFixProvider; import com.intellij.codeInsight.quickfix.ChangeVariableTypeQuickFixProvider;
import com.intellij.codeInsight.quickfix.UnresolvedReferenceQuickFixProvider; import com.intellij.codeInsight.quickfix.UnresolvedReferenceQuickFixProvider;
import com.intellij.codeInspection.IntentionProvider;
import com.intellij.lang.StdLanguages; import com.intellij.lang.StdLanguages;
import com.intellij.lang.findUsages.LanguageFindUsages; import com.intellij.lang.findUsages.LanguageFindUsages;
import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.diagnostic.Logger;
@@ -854,27 +854,66 @@ public class HighlightUtil {
@Nullable @Nullable
static HighlightInfo checkExceptionThrownInTry(PsiParameter parameter) { static HighlightInfo checkExceptionThrownInTry(final PsiParameter parameter) {
PsiElement declarationScope = parameter.getDeclarationScope(); final PsiElement declarationScope = parameter.getDeclarationScope();
if (!(declarationScope instanceof PsiCatchSection)) return null; if (!(declarationScope instanceof PsiCatchSection)) return null;
PsiTryStatement statement = ((PsiCatchSection)declarationScope).getTryStatement();
Collection<PsiClassType> classes = ExceptionUtil.collectUnhandledExceptions(statement.getTryBlock(), statement.getTryBlock());
PsiType caughtType = parameter.getType(); final PsiTryStatement statement = ((PsiCatchSection)declarationScope).getTryStatement();
if (!(caughtType instanceof PsiClassType)) return null; final PsiCodeBlock tryBlock = statement.getTryBlock();
if (ExceptionUtil.isUncheckedExceptionOrSuperclass((PsiClassType)caughtType)) return null; assert tryBlock != null : statement;
final Collection<PsiClassType> thrownTypes = ExceptionUtil.collectUnhandledExceptions(tryBlock, tryBlock);
for (PsiClassType exceptionType : classes) { final PsiType caughtType = parameter.getType();
if (caughtType instanceof PsiClassType) {
return checkSimpleCatchParameter(parameter, thrownTypes, (PsiClassType)caughtType);
}
else if (caughtType instanceof PsiDisjunctionType) {
return checkMultiCatchParameter(parameter, thrownTypes);
}
return null;
}
@Nullable
private static HighlightInfo checkSimpleCatchParameter(final PsiParameter parameter,
final Collection<PsiClassType> thrownTypes,
final PsiClassType caughtType) {
if (ExceptionUtil.isUncheckedExceptionOrSuperclass(caughtType)) return null;
for (PsiClassType exceptionType : thrownTypes) {
if (exceptionType.isAssignableFrom(caughtType) || caughtType.isAssignableFrom(exceptionType)) return null; if (exceptionType.isAssignableFrom(caughtType) || caughtType.isAssignableFrom(exceptionType)) return null;
} }
String description = JavaErrorMessages.message("exception.never.thrown.try", formatType(caughtType)); final String description = JavaErrorMessages.message("exception.never.thrown.try", formatType(caughtType));
HighlightInfo errorResult = HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, parameter, description); final HighlightInfo errorResult = HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, parameter, description);
QuickFixAction.registerQuickFixAction(errorResult, new DeleteCatchFix(parameter)); QuickFixAction.registerQuickFixAction(errorResult, new DeleteCatchFix(parameter));
return errorResult; return errorResult;
} }
@Nullable
private static HighlightInfo checkMultiCatchParameter(final PsiParameter parameter, final Collection<PsiClassType> thrownTypes) {
for (PsiTypeElement typeElement : PsiTreeUtil.getChildrenOfTypeAsList(parameter.getTypeElement(), PsiTypeElement.class)) {
final PsiType catchType = typeElement.getType();
if (catchType instanceof PsiClassType && ExceptionUtil.isUncheckedExceptionOrSuperclass((PsiClassType)catchType)) continue;
boolean used = false;
for (PsiClassType exceptionType : thrownTypes) {
if (exceptionType.isAssignableFrom(catchType) || catchType.isAssignableFrom(exceptionType)) {
used = true;
break;
}
}
if (used) continue;
final String description = JavaErrorMessages.message("exception.never.thrown.try", formatType(catchType));
final HighlightInfo errorResult = HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, typeElement, description);
QuickFixAction.registerQuickFixAction(errorResult, new DeleteMultiCatchFix(typeElement));
return errorResult;
}
return null;
}
@Nullable @Nullable
static HighlightInfo checkNotAStatement(PsiStatement statement) { static HighlightInfo checkNotAStatement(PsiStatement statement) {
@@ -1596,36 +1635,81 @@ public class HighlightUtil {
@Nullable @Nullable
public static HighlightInfo checkExceptionAlreadyCaught(PsiJavaCodeReferenceElement element, PsiElement resolved) { public static HighlightInfo checkExceptionAlreadyCaught(final PsiJavaCodeReferenceElement element, final PsiElement resolved) {
if (!(resolved instanceof PsiClass)) return null; if (!(resolved instanceof PsiClass)) return null;
PsiClass catchClass = (PsiClass)resolved;
if (!(element.getParent() instanceof PsiTypeElement)) return null; if (!(element.getParent() instanceof PsiTypeElement)) return null;
PsiElement catchParameter = element.getParent().getParent(); PsiElement catchParameter = element.getParent().getParent();
boolean isInMultiCatch = false;
if (catchParameter instanceof PsiTypeElement && ((PsiTypeElement)catchParameter).getType() instanceof PsiDisjunctionType) {
isInMultiCatch = true;
catchParameter = catchParameter.getParent();
}
if (!(catchParameter instanceof PsiParameter) || !(((PsiParameter)catchParameter).getDeclarationScope() instanceof PsiCatchSection)) { if (!(catchParameter instanceof PsiParameter) || !(((PsiParameter)catchParameter).getDeclarationScope() instanceof PsiCatchSection)) {
return null; return null;
} }
PsiCatchSection catchSection = (PsiCatchSection)((PsiParameter)catchParameter).getDeclarationScope();
PsiTryStatement statement = catchSection.getTryStatement(); final PsiClass catchClass = (PsiClass)resolved;
PsiCatchSection[] catchSections = statement.getCatchSections(); final PsiCatchSection catchSection = (PsiCatchSection)((PsiParameter)catchParameter).getDeclarationScope();
int i = ArrayUtil.find(catchSections, catchSection); final PsiCatchSection[] allCatchSections = catchSection.getTryStatement().getCatchSections();
for (i--; i >= 0; i--) { final int startFrom = ArrayUtil.find(allCatchSections, catchSection) - (isInMultiCatch ? 0 : 1); // check the same multi-catch section
PsiCatchSection section = catchSections[i]; for (int i = startFrom; i >= 0; i--) {
PsiType type = section.getCatchType(); final PsiCatchSection upperCatchSection = allCatchSections[i];
PsiClass upCatchClass = PsiUtil.resolveClassInType(type); final PsiType upperCatchType = upperCatchSection.getCatchType();
if (upCatchClass == null) continue; final boolean highlight = upperCatchType instanceof PsiDisjunctionType
if (InheritanceUtil.isInheritorOrSelf(catchClass, upCatchClass, true)) { ? checkMultiCatchSection(catchSection, element.getParent(), catchClass, upperCatchSection)
String description = JavaErrorMessages : checkSimpleCatchSection(catchClass, upperCatchType);
.message("exception.already.caught", PsiFormatUtil.formatClass(catchClass, PsiFormatUtilBase.SHOW_NAME | if (highlight) {
PsiFormatUtilBase.SHOW_FQ_NAME)); final String className = PsiFormatUtil.formatClass(catchClass, PsiFormatUtilBase.SHOW_NAME | PsiFormatUtilBase.SHOW_FQ_NAME);
HighlightInfo highlightInfo = HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, element, description); final String description = JavaErrorMessages.message("exception.already.caught", className);
QuickFixAction.registerQuickFixAction(highlightInfo, new MoveCatchUpFix(catchSection, section)); final HighlightInfo result = HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, element, description);
QuickFixAction.registerQuickFixAction(highlightInfo, new DeleteCatchFix((PsiParameter)catchParameter));
return highlightInfo; if (catchSection != upperCatchSection) {
QuickFixAction.registerQuickFixAction(result, new MoveCatchUpFix(catchSection, upperCatchSection));
}
if (isInMultiCatch) {
QuickFixAction.registerQuickFixAction(result, new DeleteMultiCatchFix((PsiTypeElement)element.getParent()));
}
else {
QuickFixAction.registerQuickFixAction(result, new DeleteCatchFix((PsiParameter)catchParameter));
}
return result;
} }
} }
return null; return null;
} }
private static boolean checkSimpleCatchSection(final PsiClass catchClass, final PsiType upperCatchType) {
final PsiClass upperCatchClass = PsiUtil.resolveClassInType(upperCatchType);
return upperCatchClass != null && InheritanceUtil.isInheritorOrSelf(catchClass, upperCatchClass, true);
}
private static boolean checkMultiCatchSection(final PsiCatchSection catchSection,
final PsiElement catchTypeElement,
final PsiClass catchClass,
final PsiCatchSection upperCatchSection) {
final PsiManager manager = upperCatchSection.getManager();
final PsiParameter parameter = upperCatchSection.getParameter();
assert parameter != null : upperCatchSection;
final List<PsiTypeElement> typeElements = PsiTreeUtil.getChildrenOfTypeAsList(parameter.getTypeElement(), PsiTypeElement.class);
boolean skipElements = manager.areElementsEquivalent(catchSection, upperCatchSection);
for (int i = typeElements.size() - 1; i >= 0; i--) {
final PsiTypeElement typeElement = typeElements.get(i);
if (skipElements) {
if (manager.areElementsEquivalent(typeElement, catchTypeElement)) skipElements = false;
continue;
}
final PsiClass upperCatchClass = PsiUtil.resolveClassInType(typeElement.getType());
if (upperCatchClass != null && InheritanceUtil.isInheritorOrSelf(catchClass, upperCatchClass, true)) return true;
}
return false;
}
@Nullable @Nullable
public static HighlightInfo checkTernaryOperatorConditionIsBoolean(PsiExpression expression) { public static HighlightInfo checkTernaryOperatorConditionIsBoolean(PsiExpression expression) {

View File

@@ -0,0 +1,98 @@
/*
* Copyright 2000-2011 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.codeInsight.daemon.impl.quickfix;
import com.intellij.codeInsight.CodeInsightUtilBase;
import com.intellij.codeInsight.daemon.QuickFixBundle;
import com.intellij.codeInsight.daemon.impl.analysis.HighlightUtil;
import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull;
import java.util.List;
public class DeleteMultiCatchFix implements IntentionAction {
private final PsiTypeElement myTypeElement;
public DeleteMultiCatchFix(final PsiTypeElement typeElement) {
myTypeElement = typeElement;
}
@NotNull
@Override
public String getText() {
return QuickFixBundle.message("delete.catch.text", HighlightUtil.formatType(myTypeElement.getType()));
}
@NotNull
@Override
public String getFamilyName() {
return QuickFixBundle.message("delete.catch.family");
}
@Override
public boolean isAvailable(@NotNull final Project project, final Editor editor, final PsiFile file) {
return myTypeElement != null &&
myTypeElement.isValid() &&
PsiManager.getInstance(project).isInProject(myTypeElement.getContainingFile());
}
@Override
public void invoke(@NotNull final Project project, final Editor editor, final PsiFile file) throws IncorrectOperationException {
if (!CodeInsightUtilBase.prepareFileForWrite(myTypeElement.getContainingFile())) return;
final PsiElement parentType = myTypeElement.getParent();
if (!(parentType instanceof PsiTypeElement)) return;
final PsiElement first;
final PsiElement last;
final PsiElement right = PsiTreeUtil.skipSiblingsForward(myTypeElement, PsiWhiteSpace.class, PsiComment.class);
if (right instanceof PsiJavaToken && ((PsiJavaToken)right).getTokenType() == JavaTokenType.OR) {
first = myTypeElement;
last = right;
}
else if (right == null) {
final PsiElement left = PsiTreeUtil.skipSiblingsBackward(myTypeElement, PsiWhiteSpace.class, PsiComment.class);
if (!(left instanceof PsiJavaToken)) return;
final IElementType leftType = ((PsiJavaToken)left).getTokenType();
if (leftType != JavaTokenType.OR) return;
first = left;
last = myTypeElement;
}
else {
return;
}
parentType.deleteChildRange(first, last);
final List<PsiTypeElement> typeElements = PsiTreeUtil.getChildrenOfTypeAsList(parentType, PsiTypeElement.class);
if (typeElements.size() == 1) {
final PsiElement parameter = parentType.getParent();
parameter.addRangeAfter(parentType.getFirstChild(), parentType.getLastChild(), parentType);
parentType.delete();
}
}
@Override
public boolean startInWriteAction() {
return true;
}
}

View File

@@ -493,7 +493,7 @@ public class DeclarationParser {
} }
} }
else { else {
final PsiBuilder.Marker param = parseParameter(builder, true); final PsiBuilder.Marker param = parseParameter(builder, true, false);
if (param != null) { if (param != null) {
commaExpected = true; commaExpected = true;
if (invalidElements != null) { if (invalidElements != null) {
@@ -533,23 +533,25 @@ public class DeclarationParser {
} }
@Nullable @Nullable
public static PsiBuilder.Marker parseParameter(final PsiBuilder builder, final boolean ellipsis) { public static PsiBuilder.Marker parseParameter(final PsiBuilder builder, final boolean ellipsis, final boolean disjunctiveType) {
final PsiBuilder.Marker param = builder.mark(); final PsiBuilder.Marker param = builder.mark();
final Pair<PsiBuilder.Marker, Boolean> modListInfo = parseModifierList(builder); final Pair<PsiBuilder.Marker, Boolean> modListInfo = parseModifierList(builder);
int flags = ReferenceParser.EAT_LAST_DOT | ReferenceParser.WILDCARD; int flags = ReferenceParser.EAT_LAST_DOT | ReferenceParser.WILDCARD;
if (ellipsis) flags |= ReferenceParser.ELLIPSIS; if (ellipsis) flags |= ReferenceParser.ELLIPSIS;
if (disjunctiveType) flags |= ReferenceParser.DISJUNCTIONS;
final ReferenceParser.TypeInfo typeInfo = ReferenceParser.parseTypeInfo(builder, flags); final ReferenceParser.TypeInfo typeInfo = ReferenceParser.parseTypeInfo(builder, flags);
if (typeInfo == null && modListInfo.second) {
param.rollbackTo();
return null;
}
if (typeInfo == null) { if (typeInfo == null) {
error(builder, JavaErrorMessages.message("expected.type")); if (modListInfo.second) {
emptyElement(builder, JavaElementType.TYPE); param.rollbackTo();
return null;
}
else {
error(builder, JavaErrorMessages.message("expected.type"));
emptyElement(builder, JavaElementType.TYPE);
}
} }
if (expect(builder, JavaTokenType.IDENTIFIER)) { if (expect(builder, JavaTokenType.IDENTIFIER)) {

View File

@@ -142,6 +142,11 @@ public class JavaParserUtil {
return getLanguageLevel(builder).isAtLeast(LanguageLevel.JDK_1_7); return getLanguageLevel(builder).isAtLeast(LanguageLevel.JDK_1_7);
} }
// todo[r.sh] join all JDK 7 check clauses into single method (IDEA 11)
public static boolean areMultiCatchSupported(final PsiBuilder builder) {
return getLanguageLevel(builder).isAtLeast(LanguageLevel.JDK_1_7);
}
public static boolean areTypeAnnotationsSupported(final PsiBuilder builder) { public static boolean areTypeAnnotationsSupported(final PsiBuilder builder) {
return getLanguageLevel(builder).isAtLeast(LanguageLevel.JDK_1_8); return getLanguageLevel(builder).isAtLeast(LanguageLevel.JDK_1_8);
} }
@@ -460,4 +465,4 @@ public class JavaParserUtil {
myDelegate.putUserDataUnprotected(key, value); myDelegate.putUserDataUnprotected(key, value);
} }
} }
} }

View File

@@ -36,6 +36,7 @@ public class ReferenceParser {
public static final int ELLIPSIS = 0x02; public static final int ELLIPSIS = 0x02;
public static final int WILDCARD = 0x04; public static final int WILDCARD = 0x04;
public static final int DIAMONDS = 0x08; public static final int DIAMONDS = 0x08;
public static final int DISJUNCTIONS = 0x10;
public static class TypeInfo { public static class TypeInfo {
public boolean isPrimitive = false; public boolean isPrimitive = false;
@@ -58,7 +59,24 @@ public class ReferenceParser {
@Nullable @Nullable
public static TypeInfo parseTypeInfo(final PsiBuilder builder, final int flags) { public static TypeInfo parseTypeInfo(final PsiBuilder builder, final int flags) {
return parseTypeInfo(builder, isSet(flags, EAT_LAST_DOT), isSet(flags, WILDCARD), isSet(flags, DIAMONDS), isSet(flags, ELLIPSIS)); final TypeInfo typeInfo =
parseTypeInfo(builder, isSet(flags, EAT_LAST_DOT), isSet(flags, WILDCARD), isSet(flags, DIAMONDS), isSet(flags, ELLIPSIS));
if (typeInfo != null && isSet(flags, DISJUNCTIONS) && builder.getTokenType() == JavaTokenType.OR) {
typeInfo.marker = typeInfo.marker.precede();
while (builder.getTokenType() == JavaTokenType.OR) {
builder.advanceLexer();
if (builder.getTokenType() != JavaTokenType.IDENTIFIER) {
error(builder, JavaErrorMessages.message("expected.identifier"));
}
parseTypeInfo(builder, isSet(flags, EAT_LAST_DOT), isSet(flags, WILDCARD), isSet(flags, DIAMONDS), isSet(flags, ELLIPSIS));
}
typeInfo.marker.done(JavaElementType.TYPE);
}
return typeInfo;
} }
@Nullable @Nullable

View File

@@ -375,7 +375,7 @@ public class StatementParser {
} }
final PsiBuilder.Marker afterParenth = builder.mark(); final PsiBuilder.Marker afterParenth = builder.mark();
final PsiBuilder.Marker param = DeclarationParser.parseParameter(builder, false); final PsiBuilder.Marker param = DeclarationParser.parseParameter(builder, false, false);
if (param == null || JavaParserUtil.exprType(param) != JavaElementType.PARAMETER || builder.getTokenType() != JavaTokenType.COLON) { if (param == null || JavaParserUtil.exprType(param) != JavaElementType.PARAMETER || builder.getTokenType() != JavaTokenType.COLON) {
afterParenth.rollbackTo(); afterParenth.rollbackTo();
return parseForLoopFromInitialization(builder, statement); return parseForLoopFromInitialization(builder, statement);
@@ -651,7 +651,7 @@ public class StatementParser {
return false; return false;
} }
final PsiBuilder.Marker param = DeclarationParser.parseParameter(builder, false); final PsiBuilder.Marker param = DeclarationParser.parseParameter(builder, false, areMultiCatchSupported(builder));
if (param == null) { if (param == null) {
error(builder, JavaErrorMessages.message("expected.parameter")); error(builder, JavaErrorMessages.message("expected.parameter"));
} }

View File

@@ -31,6 +31,7 @@ import com.intellij.util.containers.Stack;
import gnu.trove.THashMap; import gnu.trove.THashMap;
import gnu.trove.TIntArrayList; import gnu.trove.TIntArrayList;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*; import java.util.*;
@@ -63,11 +64,11 @@ class ControlFlowAnalyzer extends JavaJspElementVisitor {
private final boolean myEnabledShortCircuit; private final boolean myEnabledShortCircuit;
// true if evaluate constant expression inside 'if' statement condition and alter control flow accordingly // true if evaluate constant expression inside 'if' statement condition and alter control flow accordingly
// in case of unreachable statement analysis must be false // in case of unreachable statement analysis must be false
private final boolean myEvaluateConstantIfConfition; private final boolean myEvaluateConstantIfCondition;
private final boolean myAssignmentTargetsAreElements; private final boolean myAssignmentTargetsAreElements;
private final Stack<TIntArrayList> intArrayPool = new Stack<TIntArrayList>(); private final Stack<TIntArrayList> intArrayPool = new Stack<TIntArrayList>();
// map: PsiElement element -> TIntArrayList instructionOffsetsToPatch with getStartoffset(element) // map: PsiElement element -> TIntArrayList instructionOffsetsToPatch with getStartOffset(element)
private final Map<PsiElement,TIntArrayList> offsetsAddElementStart = new THashMap<PsiElement, TIntArrayList>(); private final Map<PsiElement,TIntArrayList> offsetsAddElementStart = new THashMap<PsiElement, TIntArrayList>();
// map: PsiElement element -> TIntArrayList instructionOffsetsToPatch with getEndOffset(element) // map: PsiElement element -> TIntArrayList instructionOffsetsToPatch with getEndOffset(element)
private final Map<PsiElement,TIntArrayList> offsetsAddElementEnd = new THashMap<PsiElement, TIntArrayList>(); private final Map<PsiElement,TIntArrayList> offsetsAddElementEnd = new THashMap<PsiElement, TIntArrayList>();
@@ -78,19 +79,19 @@ class ControlFlowAnalyzer extends JavaJspElementVisitor {
ControlFlowAnalyzer(@NotNull PsiElement codeFragment, ControlFlowAnalyzer(@NotNull PsiElement codeFragment,
@NotNull ControlFlowPolicy policy, @NotNull ControlFlowPolicy policy,
boolean enabledShortCircuit, boolean enabledShortCircuit,
boolean evaluateConstantIfConfition) { boolean evaluateConstantIfCondition) {
this(codeFragment, policy, enabledShortCircuit, evaluateConstantIfConfition, false); this(codeFragment, policy, enabledShortCircuit, evaluateConstantIfCondition, false);
} }
private ControlFlowAnalyzer(@NotNull PsiElement codeFragment, private ControlFlowAnalyzer(@NotNull PsiElement codeFragment,
@NotNull ControlFlowPolicy policy, @NotNull ControlFlowPolicy policy,
boolean enabledShortCircuit, boolean enabledShortCircuit,
boolean evaluateConstantIfConfition, boolean evaluateConstantIfCondition,
boolean assignmentTargetsAreElements) { boolean assignmentTargetsAreElements) {
myCodeFragment = codeFragment; myCodeFragment = codeFragment;
myPolicy = policy; myPolicy = policy;
myEnabledShortCircuit = enabledShortCircuit; myEnabledShortCircuit = enabledShortCircuit;
myEvaluateConstantIfConfition = evaluateConstantIfConfition; myEvaluateConstantIfCondition = evaluateConstantIfCondition;
myAssignmentTargetsAreElements = assignmentTargetsAreElements; myAssignmentTargetsAreElements = assignmentTargetsAreElements;
Project project = codeFragment.getProject(); Project project = codeFragment.getProject();
myControlFlowFactory = ControlFlowFactory.getInstance(project); myControlFlowFactory = ControlFlowFactory.getInstance(project);
@@ -205,7 +206,7 @@ class ControlFlowAnalyzer extends JavaJspElementVisitor {
ProgressManager.checkCanceled(); ProgressManager.checkCanceled();
ControlFlowSubRange subRange = entry.getValue(); ControlFlowSubRange subRange = entry.getValue();
PsiElement element = entry.getKey(); PsiElement element = entry.getKey();
myControlFlowFactory.registerSubRange(element, subRange, myEvaluateConstantIfConfition, myPolicy); myControlFlowFactory.registerSubRange(element, subRange, myEvaluateConstantIfCondition, myPolicy);
} }
} }
@@ -730,7 +731,7 @@ class ControlFlowAnalyzer extends JavaJspElementVisitor {
* [ generate (B) ] * [ generate (B) ]
* :end * :end
*/ */
if (myEvaluateConstantIfConfition) { if (myEvaluateConstantIfCondition) {
final Object value = myConstantEvaluationHelper.computeConstantExpression(conditionExpression); final Object value = myConstantEvaluationHelper.computeConstantExpression(conditionExpression);
if (value instanceof Boolean) { if (value instanceof Boolean) {
boolean condition = ((Boolean)value).booleanValue(); boolean condition = ((Boolean)value).booleanValue();
@@ -928,7 +929,7 @@ class ControlFlowAnalyzer extends JavaJspElementVisitor {
/** /**
* find offsets of catch(es) corresponding to this throw statement * find offsets of catch(es) corresponding to this throw statement
* mycatchParameters and mycatchpoints arrays should be sorted in ascending scope order (from outermost to innermost) * myCatchParameters and myCatchBlocks arrays should be sorted in ascending scope order (from outermost to innermost)
* *
* @return offset or -1 if not found * @return offset or -1 if not found
*/ */
@@ -946,12 +947,9 @@ class ControlFlowAnalyzer extends JavaJspElementVisitor {
ProgressManager.checkCanceled(); ProgressManager.checkCanceled();
PsiParameter parameter = myCatchParameters.get(i); PsiParameter parameter = myCatchParameters.get(i);
final PsiType type = parameter.getType(); final PsiType type = parameter.getType();
PsiClass catchedClass = PsiUtil.resolveClassInType(type); PsiClass caughtClass = PsiUtil.resolveClassInType(type);
if (catchedClass == null) continue; if (caughtClass == null) continue;
if (type.isAssignableFrom(throwType)) { if (type.isAssignableFrom(throwType) || throwType.isAssignableFrom(type)) {
blocks.add(myCatchBlocks.get(i));
}
else if (throwType.isAssignableFrom(type)) {
blocks.add(myCatchBlocks.get(i)); blocks.add(myCatchBlocks.get(i));
} }
} }
@@ -996,7 +994,8 @@ class ControlFlowAnalyzer extends JavaJspElementVisitor {
finishElement(statement); finishElement(statement);
} }
@Override public void visitTryStatement(PsiTryStatement statement) { @Override
public void visitTryStatement(PsiTryStatement statement) {
startElement(statement); startElement(statement);
PsiCodeBlock[] catchBlocks = statement.getCatchBlocks(); PsiCodeBlock[] catchBlocks = statement.getCatchBlocks();
@@ -1010,7 +1009,8 @@ class ControlFlowAnalyzer extends JavaJspElementVisitor {
final PsiType type = catchBlockParameters[i].getType(); final PsiType type = catchBlockParameters[i].getType();
// todo cast param // todo cast param
if (type instanceof PsiClassType && ExceptionUtil.isUncheckedExceptionOrSuperclass((PsiClassType)type)) { if (type instanceof PsiClassType && ExceptionUtil.isUncheckedExceptionOrSuperclass((PsiClassType)type) ||
type instanceof PsiDisjunctionType && ExceptionUtil.isUncheckedExceptionOrSuperclass(((PsiDisjunctionType)type).getLeastUpperBound())) {
myUnhandledExceptionCatchBlocks.push(catchBlocks[i]); myUnhandledExceptionCatchBlocks.push(catchBlocks[i]);
} }
} }
@@ -1028,6 +1028,7 @@ class ControlFlowAnalyzer extends JavaJspElementVisitor {
tryBlock.accept(this); tryBlock.accept(this);
} }
//noinspection StatementWithEmptyBody
while (myUnhandledExceptionCatchBlocks.pop() != null) ; while (myUnhandledExceptionCatchBlocks.pop() != null) ;
myCurrentFlow.addInstruction(new GoToInstruction(finallyBlock == null ? 0 : -6)); myCurrentFlow.addInstruction(new GoToInstruction(finallyBlock == null ? 0 : -6));
@@ -1361,7 +1362,7 @@ class ControlFlowAnalyzer extends JavaJspElementVisitor {
} }
private boolean shouldCalculateConstantExpression(PsiExpression expression) { private boolean shouldCalculateConstantExpression(PsiExpression expression) {
return myEvaluateConstantIfConfition || !isInsideIfCondition(expression); return myEvaluateConstantIfCondition || !isInsideIfCondition(expression);
} }
@Override public void visitClassObjectAccessExpression(PsiClassObjectAccessExpression expression) { @Override public void visitClassObjectAccessExpression(PsiClassObjectAccessExpression expression) {
@@ -1576,6 +1577,7 @@ class ControlFlowAnalyzer extends JavaJspElementVisitor {
myCurrentFlow.addInstruction(instruction); myCurrentFlow.addInstruction(instruction);
} }
@Nullable
private PsiVariable getUsedVariable(PsiReferenceExpression refExpr) { private PsiVariable getUsedVariable(PsiReferenceExpression refExpr) {
if (refExpr.getParent() instanceof PsiMethodCallExpression) return null; if (refExpr.getParent() instanceof PsiMethodCallExpression) return null;
return myPolicy.getUsedVariable(refExpr); return myPolicy.getUsedVariable(refExpr);

View File

@@ -35,6 +35,7 @@ import com.intellij.psi.impl.source.SourceTreeToPsiMap;
import com.intellij.psi.impl.source.tree.TreeElement; import com.intellij.psi.impl.source.tree.TreeElement;
import com.intellij.psi.javadoc.PsiDocComment; import com.intellij.psi.javadoc.PsiDocComment;
import com.intellij.psi.javadoc.PsiDocTag; import com.intellij.psi.javadoc.PsiDocTag;
import com.intellij.psi.util.PsiUtil;
import com.intellij.util.IncorrectOperationException; import com.intellij.util.IncorrectOperationException;
import com.intellij.util.containers.HashMap; import com.intellij.util.containers.HashMap;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@@ -60,7 +61,7 @@ public class PsiJavaParserFacadeImpl extends PsiParserFacadeImpl implements PsiJ
private static final JavaParserUtil.ParserWrapper PARAMETER = new JavaParserUtil.ParserWrapper() { private static final JavaParserUtil.ParserWrapper PARAMETER = new JavaParserUtil.ParserWrapper() {
@Override @Override
public void parse(final PsiBuilder builder) { public void parse(final PsiBuilder builder) {
DeclarationParser.parseParameter(builder, true); DeclarationParser.parseParameter(builder, true, false);
} }
}; };
@@ -71,6 +72,14 @@ public class PsiJavaParserFacadeImpl extends PsiParserFacadeImpl implements PsiJ
} }
}; };
private static final JavaParserUtil.ParserWrapper DISJUNCTIVE_TYPE = new JavaParserUtil.ParserWrapper() {
@Override
public void parse(final PsiBuilder builder) {
ReferenceParser.parseType(builder, ReferenceParser.EAT_LAST_DOT | ReferenceParser.ELLIPSIS |
ReferenceParser.WILDCARD | ReferenceParser.DISJUNCTIONS);
}
};
public static final JavaParserUtil.ParserWrapper REFERENCE = new JavaParserUtil.ParserWrapper() { public static final JavaParserUtil.ParserWrapper REFERENCE = new JavaParserUtil.ParserWrapper() {
@Override @Override
public void parse(final PsiBuilder builder) { public void parse(final PsiBuilder builder) {
@@ -240,7 +249,11 @@ public class PsiJavaParserFacadeImpl extends PsiParserFacadeImpl implements PsiJ
@NotNull @NotNull
public PsiTypeElement createTypeElementFromText(@NotNull final String text, final PsiElement context) throws IncorrectOperationException { public PsiTypeElement createTypeElementFromText(@NotNull final String text, final PsiElement context) throws IncorrectOperationException {
final DummyHolder holder = DummyHolderFactory.createHolder(myManager, new JavaDummyElement(text, TYPE, false), context); final boolean multiCatch = context instanceof PsiParameter &&
context.getParent() instanceof PsiCatchSection &&
PsiUtil.isLanguageLevel7OrHigher(context);
final JavaParserUtil.ParserWrapper wrapper = multiCatch ? DISJUNCTIVE_TYPE : TYPE;
final DummyHolder holder = DummyHolderFactory.createHolder(myManager, new JavaDummyElement(text, wrapper, false), context);
final PsiElement element = SourceTreeToPsiMap.treeElementToPsi(holder.getTreeElement().getFirstChildNode()); final PsiElement element = SourceTreeToPsiMap.treeElementToPsi(holder.getTreeElement().getFirstChildNode());
if (!(element instanceof PsiTypeElement)) { if (!(element instanceof PsiTypeElement)) {
throw new IncorrectOperationException("Incorrect type \"" + text + "\"."); throw new IncorrectOperationException("Incorrect type \"" + text + "\".");
@@ -261,7 +274,8 @@ public class PsiJavaParserFacadeImpl extends PsiParserFacadeImpl implements PsiJ
@NotNull @NotNull
public PsiJavaCodeReferenceElement createReferenceFromText(@NotNull final String text, final PsiElement context) throws IncorrectOperationException { public PsiJavaCodeReferenceElement createReferenceFromText(@NotNull final String text, final PsiElement context) throws IncorrectOperationException {
final boolean isStaticImport = context instanceof PsiImportStaticStatement && !((PsiImportStaticStatement)context).isOnDemand(); final boolean isStaticImport = context instanceof PsiImportStaticStatement &&
!((PsiImportStaticStatement)context).isOnDemand();
final JavaParserUtil.ParserWrapper wrapper = isStaticImport ? STATIC_IMPORT_REF : REFERENCE; final JavaParserUtil.ParserWrapper wrapper = isStaticImport ? STATIC_IMPORT_REF : REFERENCE;
final DummyHolder holder = DummyHolderFactory.createHolder(myManager, new JavaDummyElement(text, wrapper, false), context); final DummyHolder holder = DummyHolderFactory.createHolder(myManager, new JavaDummyElement(text, wrapper, false), context);
final PsiElement element = SourceTreeToPsiMap.treeElementToPsi(holder.getTreeElement().getFirstChildNode()); final PsiElement element = SourceTreeToPsiMap.treeElementToPsi(holder.getTreeElement().getFirstChildNode());

View File

@@ -174,6 +174,9 @@ public class PsiModifierListImpl extends JavaStubPsiElement<PsiModifierListStub>
} }
} }
} }
else if (parent instanceof PsiParameter) {
if (type == JavaTokenType.FINAL_KEYWORD && ((PsiParameter)parent).getType() instanceof PsiDisjunctionType) return true;
}
if (type == null){ // package local if (type == null){ // package local
return !hasModifierProperty(PsiModifier.PUBLIC) && !hasModifierProperty(PsiModifier.PRIVATE) && !hasModifierProperty(PsiModifier.PROTECTED); return !hasModifierProperty(PsiModifier.PUBLIC) && !hasModifierProperty(PsiModifier.PRIVATE) && !hasModifierProperty(PsiModifier.PROTECTED);
@@ -206,22 +209,22 @@ public class PsiModifierListImpl extends JavaStubPsiElement<PsiModifierListStub>
if (value){ if (value){
if (parentTreeElement.getElementType() == JavaElementType.FIELD && if (parentTreeElement.getElementType() == JavaElementType.FIELD &&
parentTreeElement.getTreeParent().getElementType() == JavaElementType.CLASS && parentTreeElement.getTreeParent().getElementType() == JavaElementType.CLASS &&
((PsiClass)SourceTreeToPsiMap.treeElementToPsi(parentTreeElement.getTreeParent())).isInterface()) { SourceTreeToPsiMap.<PsiClass>treeToPsiNotNull(parentTreeElement.getTreeParent()).isInterface()) {
if (type == JavaTokenType.PUBLIC_KEYWORD || type == JavaTokenType.STATIC_KEYWORD || type == JavaTokenType.FINAL_KEYWORD) return; if (type == JavaTokenType.PUBLIC_KEYWORD || type == JavaTokenType.STATIC_KEYWORD || type == JavaTokenType.FINAL_KEYWORD) return;
} }
else if (parentTreeElement.getElementType() == JavaElementType.METHOD && else if (parentTreeElement.getElementType() == JavaElementType.METHOD &&
parentTreeElement.getTreeParent().getElementType() == JavaElementType.CLASS && parentTreeElement.getTreeParent().getElementType() == JavaElementType.CLASS &&
((PsiClass)SourceTreeToPsiMap.treeElementToPsi(parentTreeElement.getTreeParent())).isInterface()) { SourceTreeToPsiMap.<PsiClass>treeToPsiNotNull(parentTreeElement.getTreeParent()).isInterface()) {
if (type == JavaTokenType.PUBLIC_KEYWORD || type == JavaTokenType.ABSTRACT_KEYWORD) return; if (type == JavaTokenType.PUBLIC_KEYWORD || type == JavaTokenType.ABSTRACT_KEYWORD) return;
} }
else if (parentTreeElement.getElementType() == JavaElementType.CLASS && else if (parentTreeElement.getElementType() == JavaElementType.CLASS &&
parentTreeElement.getTreeParent().getElementType() == JavaElementType.CLASS && parentTreeElement.getTreeParent().getElementType() == JavaElementType.CLASS &&
((PsiClass)SourceTreeToPsiMap.treeElementToPsi(parentTreeElement.getTreeParent())).isInterface()) { SourceTreeToPsiMap.<PsiClass>treeToPsiNotNull(parentTreeElement.getTreeParent()).isInterface()) {
if (type == JavaTokenType.PUBLIC_KEYWORD) return; if (type == JavaTokenType.PUBLIC_KEYWORD) return;
} }
else if (parentTreeElement.getElementType() == JavaElementType.ANNOTATION_METHOD && else if (parentTreeElement.getElementType() == JavaElementType.ANNOTATION_METHOD &&
parentTreeElement.getTreeParent().getElementType() == JavaElementType.CLASS && parentTreeElement.getTreeParent().getElementType() == JavaElementType.CLASS &&
((PsiClass)SourceTreeToPsiMap.treeElementToPsi(parentTreeElement.getTreeParent())).isAnnotationType()) { SourceTreeToPsiMap.<PsiClass>treeToPsiNotNull(parentTreeElement.getTreeParent()).isAnnotationType()) {
if (type == JavaTokenType.PUBLIC_KEYWORD || type == JavaTokenType.ABSTRACT_KEYWORD) return; if (type == JavaTokenType.PUBLIC_KEYWORD || type == JavaTokenType.ABSTRACT_KEYWORD) return;
} }
@@ -246,8 +249,8 @@ public class PsiModifierListImpl extends JavaStubPsiElement<PsiModifierListStub>
TreeElement keyword = Factory.createSingleLeafElement(type, name, null, getManager()); TreeElement keyword = Factory.createSingleLeafElement(type, name, null, getManager());
treeElement.addInternal(keyword, keyword, null, null); treeElement.addInternal(keyword, keyword, null, null);
} }
if ((type == JavaTokenType.ABSTRACT_KEYWORD || type == JavaTokenType.NATIVE_KEYWORD) && parentTreeElement.getElementType() == if ((type == JavaTokenType.ABSTRACT_KEYWORD || type == JavaTokenType.NATIVE_KEYWORD) &&
JavaElementType.METHOD){ parentTreeElement.getElementType() == JavaElementType.METHOD){
//Q: remove body? //Q: remove body?
} }
} }
@@ -257,7 +260,7 @@ public class PsiModifierListImpl extends JavaStubPsiElement<PsiModifierListStub>
} }
ASTNode child = treeElement.findChildByType(type); ASTNode child = treeElement.findChildByType(type);
if (child != null){ if (child != null){
SourceTreeToPsiMap.treeElementToPsi(child).delete(); SourceTreeToPsiMap.treeToPsiNotNull(child).delete();
} }
} }
} }

View File

@@ -34,6 +34,7 @@ import com.intellij.util.PatchedSoftReference;
import com.intellij.util.SmartList; import com.intellij.util.SmartList;
import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
@@ -41,6 +42,7 @@ import java.util.List;
public class PsiTypeElementImpl extends CompositePsiElement implements PsiTypeElement { public class PsiTypeElementImpl extends CompositePsiElement implements PsiTypeElement {
private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.source.PsiTypeElementImpl"); private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.source.PsiTypeElementImpl");
private volatile PsiType myCachedType = null; private volatile PsiType myCachedType = null;
private volatile PatchedSoftReference<PsiType> myCachedDetachedType = null; private volatile PatchedSoftReference<PsiType> myCachedDetachedType = null;
@@ -78,26 +80,36 @@ public class PsiTypeElementImpl extends CompositePsiElement implements PsiTypeEl
if (cachedType != null) { if (cachedType != null) {
return cachedType; return cachedType;
} }
final List<PsiAnnotation> typeAnnotations = new ArrayList<PsiAnnotation>();
TreeElement element = getFirstChildNode(); TreeElement element = getFirstChildNode();
List<PsiAnnotation> typeAnnos = new ArrayList<PsiAnnotation>();
while (element != null) { while (element != null) {
IElementType elementType = element.getElementType(); IElementType elementType = element.getElementType();
if (element.getTreeNext() == null && ElementType.PRIMITIVE_TYPE_BIT_SET.contains(elementType)) { if (element.getTreeNext() == null && ElementType.PRIMITIVE_TYPE_BIT_SET.contains(elementType)) {
addTypeUseAnnotationsFromModifierList(getParent(), typeAnnos); addTypeUseAnnotationsFromModifierList(getParent(), typeAnnotations);
PsiAnnotation[] array = toAnnotationsArray(typeAnnos); final PsiAnnotation[] array = toAnnotationsArray(typeAnnotations);
cachedType = JavaPsiFacade.getInstance(getProject()).getElementFactory().createPrimitiveType(element.getText(), array); cachedType = JavaPsiFacade.getInstance(getProject()).getElementFactory().createPrimitiveType(element.getText(), array);
assert cachedType != null; assert cachedType != null;
} }
else if (elementType == JavaElementType.TYPE) { else if (elementType == JavaElementType.TYPE) {
PsiType componentType = ((PsiTypeElement)SourceTreeToPsiMap.treeElementToPsi(element)).getType(); final IElementType tailType = getLastChildNode().getElementType();
cachedType = getLastChildNode().getElementType() == JavaTokenType.ELLIPSIS ? new PsiEllipsisType(componentType) if (tailType == JavaTokenType.ELLIPSIS) {
: componentType.createArrayType(); final PsiType componentType = ((PsiTypeElement)SourceTreeToPsiMap.treeToPsiNotNull(element)).getType();
cachedType = new PsiEllipsisType(componentType);
}
else if (tailType == JavaTokenType.RBRACKET) {
final PsiType componentType = ((PsiTypeElement)SourceTreeToPsiMap.treeToPsiNotNull(element)).getType();
cachedType = componentType.createArrayType();
}
else {
cachedType = new PsiDisjunctionType(this);
}
} }
else if (elementType == JavaElementType.JAVA_CODE_REFERENCE) { else if (elementType == JavaElementType.JAVA_CODE_REFERENCE) {
addTypeUseAnnotationsFromModifierList(getParent(), typeAnnos); addTypeUseAnnotationsFromModifierList(getParent(), typeAnnotations);
PsiAnnotation[] array = toAnnotationsArray(typeAnnos); final PsiAnnotation[] array = toAnnotationsArray(typeAnnotations);
cachedType = new PsiClassReferenceType((PsiJavaCodeReferenceElement)element.getPsi(), null,array); final PsiJavaCodeReferenceElement reference = SourceTreeToPsiMap.treeToPsiNotNull(element);
cachedType = new PsiClassReferenceType(reference, null, array);
} }
else if (elementType == JavaTokenType.QUEST) { else if (elementType == JavaTokenType.QUEST) {
cachedType = createWildcardType(); cachedType = createWildcardType();
@@ -107,8 +119,9 @@ public class PsiTypeElementImpl extends CompositePsiElement implements PsiTypeEl
continue; continue;
} }
else if (elementType == JavaElementType.ANNOTATION) { else if (elementType == JavaElementType.ANNOTATION) {
PsiAnnotation annotation = JavaPsiFacade.getInstance(getProject()).getElementFactory().createAnnotationFromText(element.getText(), this); final PsiElementFactory elementFactory = JavaPsiFacade.getInstance(getProject()).getElementFactory();
typeAnnos.add(annotation); final PsiAnnotation annotation = elementFactory.createAnnotationFromText(element.getText(), this);
typeAnnotations.add(annotation);
element = element.getTreeNext(); element = element.getTreeNext();
continue; continue;
} }
@@ -128,18 +141,18 @@ public class PsiTypeElementImpl extends CompositePsiElement implements PsiTypeEl
return cachedType; return cachedType;
} }
private static PsiAnnotation[] toAnnotationsArray(List<PsiAnnotation> typeAnnos) { private static PsiAnnotation[] toAnnotationsArray(List<PsiAnnotation> typeAnnotations) {
final int size = typeAnnos.size(); final int size = typeAnnotations.size();
return size == 0 ? PsiAnnotation.EMPTY_ARRAY : typeAnnos.toArray(new PsiAnnotation[size]); return size == 0 ? PsiAnnotation.EMPTY_ARRAY : typeAnnotations.toArray(new PsiAnnotation[size]);
} }
public static void addTypeUseAnnotationsFromModifierList(PsiElement member, List<PsiAnnotation> typeAnnos) { public static void addTypeUseAnnotationsFromModifierList(PsiElement member, List<PsiAnnotation> typeAnnotations) {
if (!(member instanceof PsiModifierListOwner)) return; if (!(member instanceof PsiModifierListOwner)) return;
PsiModifierList list = ((PsiModifierListOwner)member).getModifierList(); PsiModifierList list = ((PsiModifierListOwner)member).getModifierList();
PsiAnnotation[] gluedAnnos = list == null ? PsiAnnotation.EMPTY_ARRAY : list.getAnnotations(); PsiAnnotation[] gluedAnnotations = list == null ? PsiAnnotation.EMPTY_ARRAY : list.getAnnotations();
for (PsiAnnotation anno : gluedAnnos) { for (PsiAnnotation anno : gluedAnnotations) {
if (AnnotationsHighlightUtil.isAnnotationApplicableTo(anno, false, "TYPE_USE")) { if (AnnotationsHighlightUtil.isAnnotationApplicableTo(anno, false, "TYPE_USE")) {
typeAnnos.add(anno); typeAnnotations.add(anno);
} }
} }
} }
@@ -149,8 +162,8 @@ public class PsiTypeElementImpl extends CompositePsiElement implements PsiTypeEl
PsiType type = cached == null ? null : cached.get(); PsiType type = cached == null ? null : cached.get();
if (type != null) return type; if (type != null) return type;
try { try {
String combinedAnnos = getCombinedAnnosText(); String combinedAnnotations = getCombinedAnnotationsText();
String text = combinedAnnos.length() == 0 ? getText().trim() : combinedAnnos + " " + getText().trim(); String text = combinedAnnotations.length() == 0 ? getText().trim() : combinedAnnotations + " " + getText().trim();
type = JavaPsiFacade.getInstance(getProject()).getElementFactory().createTypeFromText(text, context); type = JavaPsiFacade.getInstance(getProject()).getElementFactory().createTypeFromText(text, context);
myCachedDetachedType = new PatchedSoftReference<PsiType>(type); myCachedDetachedType = new PatchedSoftReference<PsiType>(type);
} }
@@ -161,7 +174,7 @@ public class PsiTypeElementImpl extends CompositePsiElement implements PsiTypeEl
} }
@NotNull @NotNull
private String getCombinedAnnosText() { private String getCombinedAnnotationsText() {
final boolean typeAnnotationsSupported = PsiUtil.isLanguageLevel8OrHigher(this); final boolean typeAnnotationsSupported = PsiUtil.isLanguageLevel8OrHigher(this);
if (!typeAnnotationsSupported) return ""; if (!typeAnnotationsSupported) return "";
return StringUtil.join(getApplicableAnnotations(), ANNOTATION_TEXT, " "); return StringUtil.join(getApplicableAnnotations(), ANNOTATION_TEXT, " ");
@@ -177,8 +190,8 @@ public class PsiTypeElementImpl extends CompositePsiElement implements PsiTypeEl
PsiFile file = getContainingFile(); PsiFile file = getContainingFile();
String text; String text;
if (PsiUtil.isLanguageLevel8OrHigher(file)) { if (PsiUtil.isLanguageLevel8OrHigher(file)) {
String combinedAnnos = StringUtil.join(getAnnotations(), ANNOTATION_TEXT, " "); String combinedAnnotations = StringUtil.join(getAnnotations(), ANNOTATION_TEXT, " ");
text = combinedAnnos.length() == 0 ? getText().trim() : combinedAnnos + " " + getText().trim(); text = combinedAnnotations.length() == 0 ? getText().trim() : combinedAnnotations + " " + getText().trim();
} }
else { else {
text = getText().trim(); text = getText().trim();
@@ -201,7 +214,7 @@ public class PsiTypeElementImpl extends CompositePsiElement implements PsiTypeEl
temp = PsiWildcardType.createUnbounded(getManager()); temp = PsiWildcardType.createUnbounded(getManager());
} }
else if (getLastChildNode().getElementType() == JavaElementType.TYPE) { else if (getLastChildNode().getElementType() == JavaElementType.TYPE) {
PsiTypeElement bound = (PsiTypeElement)SourceTreeToPsiMap.treeElementToPsi(getLastChildNode()); PsiTypeElement bound = SourceTreeToPsiMap.treeToPsiNotNull(getLastChildNode());
ASTNode keyword = getFirstChildNode(); ASTNode keyword = getFirstChildNode();
while (keyword != null && while (keyword != null &&
keyword.getElementType() != JavaTokenType.EXTENDS_KEYWORD && keyword.getElementType() != JavaTokenType.EXTENDS_KEYWORD &&
@@ -235,7 +248,7 @@ public class PsiTypeElementImpl extends CompositePsiElement implements PsiTypeEl
TreeElement firstChildNode = getFirstChildNode(); TreeElement firstChildNode = getFirstChildNode();
if (firstChildNode == null) return null; if (firstChildNode == null) return null;
if (firstChildNode.getElementType() == JavaElementType.TYPE) { if (firstChildNode.getElementType() == JavaElementType.TYPE) {
return ((PsiTypeElement)SourceTreeToPsiMap.treeElementToPsi(firstChildNode)).getInnermostComponentReferenceElement(); return SourceTreeToPsiMap.<PsiTypeElement>treeToPsiNotNull(firstChildNode).getInnermostComponentReferenceElement();
} }
else { else {
return getReferenceElement(); return getReferenceElement();
@@ -245,12 +258,12 @@ public class PsiTypeElementImpl extends CompositePsiElement implements PsiTypeEl
public PsiAnnotationOwner getOwner(PsiAnnotation annotation) { public PsiAnnotationOwner getOwner(PsiAnnotation annotation) {
PsiElement next = PsiTreeUtil.skipSiblingsForward(annotation, PsiComment.class, PsiWhiteSpace.class); PsiElement next = PsiTreeUtil.skipSiblingsForward(annotation, PsiComment.class, PsiWhiteSpace.class);
if (next != null && next.getNode().getElementType() == JavaTokenType.LBRACKET) { if (next != null && next.getNode().getElementType() == JavaTokenType.LBRACKET) {
PsiType type = getType(); return getType(); // annotation belongs to array type dimension
return type; // annotation belongs to array type dimension
} }
return this; return this;
} }
@Nullable
private PsiJavaCodeReferenceElement getReferenceElement() { private PsiJavaCodeReferenceElement getReferenceElement() {
ASTNode ref = findChildByType(JavaElementType.JAVA_CODE_REFERENCE); ASTNode ref = findChildByType(JavaElementType.JAVA_CODE_REFERENCE);
if (ref == null) return null; if (ref == null) return null;
@@ -337,4 +350,3 @@ public class PsiTypeElementImpl extends CompositePsiElement implements PsiTypeEl
return result; return result;
} }
} }

View File

@@ -465,8 +465,13 @@ public class JavaCodeStyleManagerImpl extends JavaCodeStyleManager {
return getTypeName(((PsiCapturedWildcardType)type).getWildcard()); return getTypeName(((PsiCapturedWildcardType)type).getWildcard());
} }
else { else {
LOG.error("Unknown type:" + type); if (type instanceof PsiDisjunctionType) {
return null; return getTypeName(((PsiDisjunctionType)type).getLeastUpperBound());
}
else {
LOG.error("Unknown type:" + type);
return null;
}
} }
} }
} }
@@ -474,8 +479,8 @@ public class JavaCodeStyleManagerImpl extends JavaCodeStyleManager {
} }
} }
@Nullable private static @Nullable
String getLongTypeName(PsiType type) { private static String getLongTypeName(PsiType type) {
if (type instanceof PsiClassType) { if (type instanceof PsiClassType) {
PsiClass aClass = ((PsiClassType)type).resolve(); PsiClass aClass = ((PsiClassType)type).resolve();
if( aClass == null ) if( aClass == null )
@@ -525,8 +530,13 @@ public class JavaCodeStyleManagerImpl extends JavaCodeStyleManager {
return getLongTypeName(((PsiIntersectionType)type).getRepresentative()); return getLongTypeName(((PsiIntersectionType)type).getRepresentative());
} }
else { else {
LOG.error("Unknown type:" + type); if (type instanceof PsiDisjunctionType) {
return null; return getLongTypeName(((PsiDisjunctionType)type).getLeastUpperBound());
}
else {
LOG.error("Unknown type:" + type);
return null;
}
} }
} }
} }

View File

@@ -291,6 +291,9 @@ public class PsiScopesUtil {
if (!processQualifierType(conjunct, processor, manager, methodCall)) break; if (!processQualifierType(conjunct, processor, manager, methodCall)) break;
} }
} }
else if (type instanceof PsiDisjunctionType) {
processQualifierType(((PsiDisjunctionType)type).getLeastUpperBound(), processor, manager, methodCall);
}
else { else {
processQualifierType(type, processor, manager, methodCall); processQualifierType(type, processor, manager, methodCall);
} }

View File

@@ -0,0 +1,29 @@
abstract class C {
private static class NE { }
private static class E extends Exception { }
private static class E1 extends E { }
private static class E2 extends E { }
private static class E3 extends E { }
private static class RE extends RuntimeException { }
abstract void f() throws E1, E2;
void m() {
try { f(); } catch (E1 | E2 e) { }
try { f(); } catch (E2 | E e) { e.printStackTrace(); }
try { f(); } catch (E2 | E1 e) { } catch (E e) { } catch (RE e) { }
try { f(); } catch (E1 | E e) { E ee = e; }
try { f(); } catch (E1 | E2 | <error descr="Exception 'C.E3' is never thrown in the corresponding try block">E3</error> e) { }
try { f(); } catch (<error descr="Exception 'C.E3' is never thrown in the corresponding try block">E3</error> | E e) { }
try { f(); } catch (E | <error descr="Exception 'C.E1' has already been caught">E1</error> e) { }
try { f(); } catch (E | <error descr="Exception 'C.E3' has already been caught">E3</error> e) { }
try { f(); } catch (E e) { } catch (<error descr="Exception 'C.E1' has already been caught">E1</error> | <error descr="Exception 'C.E3' has already been caught">E3</error> e) { }
try { f(); } catch (E1 | E e) { } catch (<error descr="Exception 'C.E2' has already been caught">E2</error> e) { }
try { f(); } catch (E1 | E2 e) { } catch (E e) { <error descr="Incompatible types. Found: 'C.E', required: 'C.E1'">E1 ee = e;</error> }
try { } catch (<error descr="Incompatible types. Found: 'C.RE | C.NE', required: 'java.lang.Throwable'">RE | <error descr="Exception 'C.NE' is never thrown in the corresponding try block">NE</error> e</error>) { }
try { f(); } catch (E | RE e) { <error descr="Cannot assign a value to final variable 'e'">e = null</error>; }
}
}

View File

@@ -0,0 +1,12 @@
// "Delete catch for 'java.io.IOException'" "true"
import java.io.*;
class C {
void m() {
try {
int p = 0;
}
catch (/*somethihg*/ RuntimeException e) {
}
}
}

View File

@@ -0,0 +1,12 @@
// "Delete catch for 'java.io.FileNotFoundException'" "true"
import java.io.*;
class C {
void m() {
try {
int p = 0;
}
catch (IOException /*somethihg*/ e) {
}
}
}

View File

@@ -0,0 +1,12 @@
// "Delete catch for 'java.io.FileNotFoundException'" "true"
import java.io.*;
class C {
void m() {
try {
int p = 0;
}
catch (IOException | RuntimeException e) {
}
}
}

View File

@@ -0,0 +1,12 @@
// "Delete catch for 'java.io.IOException'" "true"
import java.io.*;
class C {
void m() {
try {
int p = 0;
}
catch (<caret>IOException | /*somethihg*/ RuntimeException e) {
}
}
}

View File

@@ -0,0 +1,12 @@
// "Delete catch for 'java.io.FileNotFoundException'" "true"
import java.io.*;
class C {
void m() {
try {
int p = 0;
}
catch (IOException | <caret>FileNotFoundException /*somethihg*/ e) {
}
}
}

View File

@@ -0,0 +1,12 @@
// "Delete catch for 'java.io.FileNotFoundException'" "true"
import java.io.*;
class C {
void m() {
try {
int p = 0;
}
catch (IOException | <caret>FileNotFoundException | RuntimeException e) {
}
}
}

View File

@@ -0,0 +1,5 @@
class A{
{
try{}catch(E| e){}
}
}

View File

@@ -0,0 +1,56 @@
PsiJavaFile:Incomplete9.java
PsiImportList
<empty list>
PsiClass:A
PsiModifierList:
<empty list>
PsiKeyword:class('class')
PsiWhiteSpace(' ')
PsiIdentifier:A('A')
PsiTypeParameterList
<empty list>
PsiReferenceList
<empty list>
PsiReferenceList
<empty list>
PsiJavaToken:LBRACE('{')
PsiWhiteSpace('\n ')
PsiClassInitializer
PsiModifierList:
<empty list>
PsiCodeBlock
PsiJavaToken:LBRACE('{')
PsiWhiteSpace('\n ')
PsiTryStatement
PsiKeyword:try('try')
PsiCodeBlock
PsiJavaToken:LBRACE('{')
PsiJavaToken:RBRACE('}')
PsiCatchSection
PsiKeyword:catch('catch')
PsiJavaToken:LPARENTH('(')
PsiModifierList:
<empty list>
PsiTypeElement:E| e
PsiTypeElement:E
PsiJavaCodeReferenceElement:E
PsiIdentifier:E('E')
PsiReferenceParameterList
<empty list>
PsiJavaToken:OR('|')
PsiWhiteSpace(' ')
PsiTypeElement:e
PsiJavaCodeReferenceElement:e
PsiIdentifier:e('e')
PsiReferenceParameterList
<empty list>
PsiErrorElement:Identifier expected
<empty list>
PsiJavaToken:RPARENTH(')')
PsiCodeBlock
PsiJavaToken:LBRACE('{')
PsiJavaToken:RBRACE('}')
PsiWhiteSpace('\n ')
PsiJavaToken:RBRACE('}')
PsiWhiteSpace('\n')
PsiJavaToken:RBRACE('}')

View File

@@ -0,0 +1,5 @@
class A{
{
try{}catch(E1|E2 e){}
}
}

View File

@@ -0,0 +1,56 @@
PsiJavaFile:Normal4.java
PsiImportList
<empty list>
PsiClass:A
PsiModifierList:
<empty list>
PsiKeyword:class('class')
PsiWhiteSpace(' ')
PsiIdentifier:A('A')
PsiTypeParameterList
<empty list>
PsiReferenceList
<empty list>
PsiReferenceList
<empty list>
PsiJavaToken:LBRACE('{')
PsiWhiteSpace('\n ')
PsiClassInitializer
PsiModifierList:
<empty list>
PsiCodeBlock
PsiJavaToken:LBRACE('{')
PsiWhiteSpace('\n ')
PsiTryStatement
PsiKeyword:try('try')
PsiCodeBlock
PsiJavaToken:LBRACE('{')
PsiJavaToken:RBRACE('}')
PsiCatchSection
PsiKeyword:catch('catch')
PsiJavaToken:LPARENTH('(')
PsiParameter:e
PsiModifierList:
<empty list>
PsiTypeElement:E1|E2
PsiTypeElement:E1
PsiJavaCodeReferenceElement:E1
PsiIdentifier:E1('E1')
PsiReferenceParameterList
<empty list>
PsiJavaToken:OR('|')
PsiTypeElement:E2
PsiJavaCodeReferenceElement:E2
PsiIdentifier:E2('E2')
PsiReferenceParameterList
<empty list>
PsiWhiteSpace(' ')
PsiIdentifier:e('e')
PsiJavaToken:RPARENTH(')')
PsiCodeBlock
PsiJavaToken:LBRACE('{')
PsiJavaToken:RBRACE('}')
PsiWhiteSpace('\n ')
PsiJavaToken:RBRACE('}')
PsiWhiteSpace('\n')
PsiJavaToken:RBRACE('}')

View File

@@ -0,0 +1,10 @@
PsiJavaFile:Type8.java
PsiTypeElement:A|
PsiTypeElement:A
PsiJavaCodeReferenceElement:A
PsiIdentifier:A('A')
PsiReferenceParameterList
<empty list>
PsiJavaToken:OR('|')
PsiErrorElement:Identifier expected
<empty list>

View File

@@ -0,0 +1,13 @@
PsiJavaFile:Type9.java
PsiTypeElement:A|B
PsiTypeElement:A
PsiJavaCodeReferenceElement:A
PsiIdentifier:A('A')
PsiReferenceParameterList
<empty list>
PsiJavaToken:OR('|')
PsiTypeElement:B
PsiJavaCodeReferenceElement:B
PsiIdentifier:B('B')
PsiReferenceParameterList
<empty list>

View File

@@ -148,4 +148,8 @@ public class LightAdvHighlightingJdk7Test extends LightDaemonAnalyzerTestCase {
public void testNumericLiterals() throws Exception { public void testNumericLiterals() throws Exception {
doTest(false, false); doTest(false, false);
} }
public void testMultiCatch() throws Exception {
doTest(false, false);
}
} }

View File

@@ -0,0 +1,25 @@
/*
* Copyright 2000-2011 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.codeInsight.daemon.quickFix;
public class DeleteMultiCatchTest extends LightQuickFixTestCase {
public void test() throws Exception { doAllTests(); }
@Override
protected String getBasePath() {
return "/codeInsight/daemonCodeAnalyzer/quickFix/deleteMultiCatch";
}
}

View File

@@ -42,6 +42,8 @@ public class ReferenceParserTest extends JavaParsingTestCase {
}}); }});
} }
public void testType7() { doTypeParserTest("Diamond<>"); } public void testType7() { doTypeParserTest("Diamond<>"); }
public void testType8() { doTypeParserTest("A|"); }
public void testType9() { doTypeParserTest("A|B"); }
public void testTypeParams0() { doTypeParamsParserTest("<T>"); } public void testTypeParams0() { doTypeParamsParserTest("<T>"); }
public void testTypeParams1() { doTypeParamsParserTest("<T, U>"); } public void testTypeParams1() { doTypeParamsParserTest("<T, U>"); }
@@ -65,7 +67,7 @@ public class ReferenceParserTest extends JavaParsingTestCase {
doParserTest(text, new TestParser() { doParserTest(text, new TestParser() {
@Override @Override
public void parse(final PsiBuilder builder) { public void parse(final PsiBuilder builder) {
ReferenceParser.parseType(builder, ReferenceParser.DIAMONDS | ReferenceParser.ELLIPSIS); ReferenceParser.parseType(builder, ReferenceParser.ELLIPSIS | ReferenceParser.DIAMONDS | ReferenceParser.DISJUNCTIONS);
} }
}); });
} }

View File

@@ -1,7 +1,7 @@
package com.intellij.lang.java.parser.statementParsing; package com.intellij.lang.java.parser.statementParsing;
import com.intellij.lang.java.parser.JavaParsingTestCase; import com.intellij.lang.java.parser.JavaParsingTestCase;
import com.intellij.pom.java.LanguageLevel;
public class TryParsingTest extends JavaParsingTestCase { public class TryParsingTest extends JavaParsingTestCase {
@@ -12,6 +12,11 @@ public class TryParsingTest extends JavaParsingTestCase {
public void testNormal1() { doTest(true); } public void testNormal1() { doTest(true); }
public void testNormal2() { doTest(true); } public void testNormal2() { doTest(true); }
public void testNormal3() { doTest(true); } public void testNormal3() { doTest(true); }
public void testNormal4() {
withLevel(LanguageLevel.JDK_1_7, new Runnable() { @Override public void run() {
doTest(true);
}});
}
public void testIncomplete1() { doTest(true); } public void testIncomplete1() { doTest(true); }
public void testIncomplete2() { doTest(true); } public void testIncomplete2() { doTest(true); }
@@ -21,4 +26,9 @@ public class TryParsingTest extends JavaParsingTestCase {
public void testIncomplete6() { doTest(true); } public void testIncomplete6() { doTest(true); }
public void testIncomplete7() { doTest(true); } public void testIncomplete7() { doTest(true); }
public void testIncomplete8() { doTest(true); } public void testIncomplete8() { doTest(true); }
public void testIncomplete9() {
withLevel(LanguageLevel.JDK_1_7, new Runnable() { @Override public void run() {
doTest(true);
}});
}
} }

View File

@@ -0,0 +1,118 @@
/*
* Copyright 2000-2011 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.psi;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.util.*;
import com.intellij.util.Function;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import java.util.Collections;
import java.util.List;
public class PsiDisjunctionType extends PsiType {
private final PsiTypeElement myTypeElement;
private final List<PsiType> myTypes;
private final CachedValue<PsiClassType> myLubCache;
public PsiDisjunctionType(final PsiTypeElement typeElement) {
super(PsiAnnotation.EMPTY_ARRAY);
myTypeElement = typeElement;
final List<PsiTypeElement> typeElements = PsiTreeUtil.getChildrenOfTypeAsList(myTypeElement, PsiTypeElement.class);
myTypes = Collections.unmodifiableList(ContainerUtil.map(typeElements, new Function<PsiTypeElement, PsiType>() {
@Override
public PsiType fun(final PsiTypeElement psiTypeElement) {
return psiTypeElement.getType();
}
}));
final CachedValuesManager cacheManager = CachedValuesManager.getManager(myTypeElement.getProject());
myLubCache = cacheManager.createCachedValue(new CachedValueProvider<PsiClassType>() {
public Result<PsiClassType> compute() {
PsiType lub = myTypes.get(0);
for (int i = 1; i < myTypes.size(); i++) {
lub = GenericsUtil.getLeastUpperBound(lub, myTypes.get(i), myTypeElement.getManager());
}
assert lub instanceof PsiClassType : getCanonicalText() + ", " + lub;
return Result.create((PsiClassType)lub, PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT);
}
}, false);
}
public PsiClassType getLeastUpperBound() {
return myLubCache.getValue();
}
public List<PsiType> getDisjunctions() {
return myTypes;
}
@Override
public String getPresentableText() {
return StringUtil.join(myTypes, new Function<PsiType, String>() {
@Override public String fun(PsiType psiType) { return psiType.getPresentableText(); }
}, " | ");
}
@Override
public String getCanonicalText() {
return StringUtil.join(myTypes, new Function<PsiType, String>() {
@Override public String fun(PsiType psiType) { return psiType.getCanonicalText(); }
}, " | ");
}
@Override
public String getInternalCanonicalText() {
return StringUtil.join(myTypes, new Function<PsiType, String>() {
@Override public String fun(PsiType psiType) { return psiType.getInternalCanonicalText(); }
}, " | ");
}
@Override
public boolean isValid() {
for (PsiType type : myTypes) {
if (!type.isValid()) return false;
}
return true;
}
@Override
public boolean equalsToText(@NonNls final String text) {
return Comparing.equal(text, getCanonicalText());
}
@Override
public <A> A accept(final PsiTypeVisitor<A> visitor) {
return visitor.visitClassType(getLeastUpperBound());
}
@Override
public GlobalSearchScope getResolveScope() {
return getLeastUpperBound().getResolveScope();
}
@NotNull
@Override
public PsiType[] getSuperTypes() {
return getLeastUpperBound().getSuperTypes();
}
}

View File

@@ -16,12 +16,15 @@
package com.intellij.psi.util; package com.intellij.psi.util;
import com.intellij.psi.*; import com.intellij.psi.*;
import com.intellij.util.containers.HashSet;
import gnu.trove.THashMap; import gnu.trove.THashMap;
import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.Map; import java.util.Map;
import java.util.Set;
public class PsiTypesUtil { public class PsiTypesUtil {
@NonNls private static final Map<String, String> ourUnboxedTypes = new THashMap<String, String>(); @NonNls private static final Map<String, String> ourUnboxedTypes = new THashMap<String, String>();
@@ -47,6 +50,7 @@ public class PsiTypesUtil {
ourBoxedTypes.put("char", CommonClassNames.JAVA_LANG_CHARACTER); ourBoxedTypes.put("char", CommonClassNames.JAVA_LANG_CHARACTER);
} }
private PsiTypesUtil() { }
public static String getDefaultValueOfType(PsiType type) { public static String getDefaultValueOfType(PsiType type) {
if (type instanceof PsiArrayType) { if (type instanceof PsiArrayType) {
@@ -115,4 +119,16 @@ public class PsiTypesUtil {
public static PsiClassType getClassType(@NotNull PsiClass psiClass) { public static PsiClassType getClassType(@NotNull PsiClass psiClass) {
return JavaPsiFacade.getElementFactory(psiClass.getProject()).createType(psiClass); return JavaPsiFacade.getElementFactory(psiClass.getProject()).createType(psiClass);
} }
@NotNull
public static Collection<PsiClass> getPsiClasses(@NotNull final Collection<PsiType> types) {
final Set<PsiClass> result = new HashSet<PsiClass>();
for (PsiType type : types) {
final PsiClass psiClass = getPsiClass(type);
if (psiClass != null) {
result.add(psiClass);
}
}
return result;
}
} }

View File

@@ -371,6 +371,9 @@ public final class PsiUtil extends PsiUtilBase {
if (type instanceof PsiArrayType) { if (type instanceof PsiArrayType) {
return resolveClassInType(((PsiArrayType) type).getComponentType()); return resolveClassInType(((PsiArrayType) type).getComponentType());
} }
if (type instanceof PsiDisjunctionType) {
return ((PsiDisjunctionType)type).getLeastUpperBound().resolve();
}
return null; return null;
} }

View File

@@ -77,7 +77,7 @@ public class TypeConversionUtil {
/** /**
* @return true iff fromType can be casted to toType * @return true if fromType can be casted to toType
*/ */
public static boolean areTypesConvertible(@NotNull PsiType fromType, @NotNull PsiType toType) { public static boolean areTypesConvertible(@NotNull PsiType fromType, @NotNull PsiType toType) {
if (fromType == toType) return true; if (fromType == toType) return true;
@@ -114,7 +114,7 @@ public class TypeConversionUtil {
} }
/** /**
* see JLS 5.1.5, JLS3 5.5 * see JLS 5.1.5, JLS3 5.1.6
*/ */
private static boolean isNarrowingReferenceConversionAllowed(PsiType fromType, PsiType toType) { private static boolean isNarrowingReferenceConversionAllowed(PsiType fromType, PsiType toType) {
if (toType instanceof PsiPrimitiveType || fromType instanceof PsiPrimitiveType) return fromType.equals(toType); if (toType instanceof PsiPrimitiveType || fromType instanceof PsiPrimitiveType) return fromType.equals(toType);
@@ -154,7 +154,15 @@ public class TypeConversionUtil {
if (isNarrowingReferenceConversionAllowed(conjunct, toType)) return true; if (isNarrowingReferenceConversionAllowed(conjunct, toType)) return true;
} }
return false; return false;
} else if (toType instanceof PsiIntersectionType) return false; }
else if (toType instanceof PsiIntersectionType) return false;
if (fromType instanceof PsiDisjunctionType) {
return isNarrowingReferenceConversionAllowed(((PsiDisjunctionType)fromType).getLeastUpperBound(), toType);
}
if (toType instanceof PsiDisjunctionType) {
return false;
}
if (fromType instanceof PsiWildcardType) { if (fromType instanceof PsiWildcardType) {
final PsiWildcardType fromWildcard = (PsiWildcardType)fromType; final PsiWildcardType fromWildcard = (PsiWildcardType)fromType;
@@ -665,6 +673,16 @@ public class TypeConversionUtil {
} }
} }
if (left instanceof PsiDisjunctionType) {
for (PsiType type : ((PsiDisjunctionType)left).getDisjunctions()) {
if (isAssignable(type, right, allowUncheckedConversion)) return true;
}
return false;
}
if (right instanceof PsiDisjunctionType) {
return isAssignable(left, ((PsiDisjunctionType)right).getLeastUpperBound(), allowUncheckedConversion);
}
if (left instanceof PsiArrayType) return false; if (left instanceof PsiArrayType) return false;
if (right instanceof PsiPrimitiveType) { if (right instanceof PsiPrimitiveType) {
if (isVoidType(right)) return false; if (isVoidType(right)) return false;