java: type annotations

This commit is contained in:
Roman Shevchenko
2014-03-04 10:53:04 +01:00
parent b428981188
commit b9b76dca15
27 changed files with 472 additions and 274 deletions
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
* Copyright 2000-2014 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.
@@ -33,10 +33,11 @@ import com.intellij.psi.*;
import com.intellij.psi.codeStyle.CodeStyleManager;
import com.intellij.psi.util.PsiUtil;
import com.intellij.psi.util.TypeConversionUtil;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import static com.intellij.util.ObjectUtils.assertNotNull;
public class AddTypeCastFix extends LocalQuickFixAndIntentionActionOnPsiElement {
private final PsiType myType;
@@ -75,28 +76,26 @@ public class AddTypeCastFix extends LocalQuickFixAndIntentionActionOnPsiElement
addTypeCast(project, (PsiExpression)startElement, myType);
}
private static void addTypeCast(Project project, PsiExpression originalExpression, PsiType type) throws IncorrectOperationException {
private static void addTypeCast(Project project, PsiExpression originalExpression, PsiType type) {
PsiExpression typeCast = createCastExpression(originalExpression, project, type);
originalExpression.replace(typeCast);
}
static PsiExpression createCastExpression(PsiExpression originalExpression, Project project, PsiType type) throws IncorrectOperationException {
static PsiExpression createCastExpression(PsiExpression originalExpression, Project project, PsiType type) {
// remove nested casts
PsiElement element = PsiUtil.deparenthesizeExpression(originalExpression);
if (element == null){
return null;
}
PsiElement expression = PsiUtil.deparenthesizeExpression(originalExpression);
if (expression == null) return null;
PsiElementFactory factory = JavaPsiFacade.getInstance(originalExpression.getProject()).getElementFactory();
PsiTypeCastExpression typeCast = (PsiTypeCastExpression)factory.createExpressionFromText("(Type)value", null);
assertNotNull(typeCast.getCastType()).replace(factory.createTypeElement(type));
typeCast = (PsiTypeCastExpression)CodeStyleManager.getInstance(project).reformat(typeCast);
typeCast.getCastType().replace(factory.createTypeElement(type));
if (element instanceof PsiConditionalExpression) {
// we'd better cast one branch of ternary expression if we could
PsiConditionalExpression expression = (PsiConditionalExpression)element.copy();
PsiExpression thenE = expression.getThenExpression();
PsiExpression elseE = expression.getElseExpression();
if (expression instanceof PsiConditionalExpression) {
// we'd better cast one branch of ternary expression if we can
PsiConditionalExpression conditional = (PsiConditionalExpression)expression.copy();
PsiExpression thenE = conditional.getThenExpression();
PsiExpression elseE = conditional.getElseExpression();
PsiType thenType = thenE == null ? null : thenE.getType();
PsiType elseType = elseE == null ? null : elseE.getType();
if (elseType != null && thenType != null) {
@@ -104,18 +103,20 @@ public class AddTypeCastFix extends LocalQuickFixAndIntentionActionOnPsiElement
boolean replaceElse = !TypeConversionUtil.isAssignable(type, elseType);
if (replaceThen != replaceElse) {
if (replaceThen) {
typeCast.getOperand().replace(thenE);
assertNotNull(typeCast.getOperand()).replace(thenE);
thenE.replace(typeCast);
}
else {
typeCast.getOperand().replace(elseE);
assertNotNull(typeCast.getOperand()).replace(elseE);
elseE.replace(typeCast);
}
return expression;
return conditional;
}
}
}
typeCast.getOperand().replace(element);
assertNotNull(typeCast.getOperand()).replace(expression);
return typeCast;
}
@@ -60,6 +60,12 @@ public class JavaReferenceAdjuster implements ReferenceAdjuster {
}
if (rightKind) {
// annotations may jump out of reference (see PsiJavaCodeReferenceImpl#setAnnotations()) so they should be processed first
List<PsiAnnotation> annotations = PsiTreeUtil.getChildrenOfTypeAsList(ref, PsiAnnotation.class);
for (PsiAnnotation annotation : annotations) {
process(annotation.getNode(), addImports, incompleteCode, useFqInJavadoc, useFqInCode);
}
boolean isInsideDocComment = TreeUtil.findParent(element, JavaDocElementType.DOC_COMMENT) != null;
boolean isShort = !ref.isQualified();
if (isInsideDocComment ? !useFqInJavadoc : !useFqInCode) {
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2013 JetBrains s.r.o.
* Copyright 2000-2014 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.
@@ -16,7 +16,6 @@
package com.intellij.psi;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.openapi.util.text.StringUtil;
import org.jetbrains.annotations.NotNull;
/**
@@ -24,7 +23,7 @@ import org.jetbrains.annotations.NotNull;
*
* @author max
*/
public class PsiArrayType extends PsiType {
public class PsiArrayType extends PsiType.Stub {
private final PsiType myComponentType;
/**
@@ -44,19 +43,33 @@ public class PsiArrayType extends PsiType {
@NotNull
@Override
public String getPresentableText() {
return StringUtil.join(myComponentType.getPresentableText(), getAnnotationsTextPrefix(false, true, true), "[]");
return getText(myComponentType.getPresentableText(), "[]", false, true);
}
@NotNull
@Override
public String getCanonicalText() {
return StringUtil.join(myComponentType.getCanonicalText(), "[]");
public String getCanonicalText(boolean annotated) {
return getText(myComponentType.getCanonicalText(annotated), "[]", true, annotated);
}
@NotNull
@Override
public String getInternalCanonicalText() {
return StringUtil.join(myComponentType.getInternalCanonicalText(), getAnnotationsTextPrefix(true, true, true), "[]");
return getText(myComponentType.getInternalCanonicalText(), "[]", true, true);
}
protected String getText(@NotNull String prefix, @NotNull String suffix, boolean qualified, boolean annotated) {
StringBuilder sb = new StringBuilder(prefix.length() + suffix.length());
sb.append(prefix);
if (annotated) {
PsiAnnotation[] annotations = getAnnotations();
if (annotations.length != 0) {
sb.append(' ');
PsiNameHelper.appendAnnotations(sb, annotations, qualified);
}
}
sb.append(suffix);
return sb.toString();
}
@Override
@@ -23,7 +23,7 @@ import org.jetbrains.annotations.Nullable;
/**
* @author ven
*/
public class PsiCapturedWildcardType extends PsiType {
public class PsiCapturedWildcardType extends PsiType.Stub {
@NotNull private final PsiWildcardType myExistential;
@NotNull private final PsiElement myContext;
@Nullable private final PsiTypeParameter myParameter;
@@ -78,8 +78,8 @@ public class PsiCapturedWildcardType extends PsiType {
@NotNull
@Override
public String getCanonicalText() {
return myExistential.getCanonicalText();
public String getCanonicalText(boolean annotated) {
return myExistential.getCanonicalText(annotated);
}
@NotNull
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2013 JetBrains s.r.o.
* Copyright 2000-2014 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.
@@ -280,4 +280,23 @@ public abstract class PsiClassType extends PsiType {
}
};
}
/**
* Temporary class to facilitate transition to {@link #getCanonicalText(boolean)}.
*/
public static abstract class Stub extends PsiClassType {
protected Stub(LanguageLevel languageLevel, @NotNull PsiAnnotation[] annotations) {
super(languageLevel, annotations);
}
@NotNull
@Override
public final String getCanonicalText() {
return getCanonicalText(false);
}
@NotNull
@Override
public abstract String getCanonicalText(boolean annotated);
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2013 JetBrains s.r.o.
* Copyright 2000-2014 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.
@@ -33,7 +33,7 @@ import java.util.List;
* Composite type resulting from Project Coin's multi-catch statements, i.e. <code>FileNotFoundException | EOFException</code>.
* In most cases should be threatened via its least upper bound (<code>IOException</code> in the example above).
*/
public class PsiDisjunctionType extends PsiType {
public class PsiDisjunctionType extends PsiType.Stub {
private final PsiManager myManager;
private final List<PsiType> myTypes;
private final CachedValue<PsiType> myLubCache;
@@ -85,15 +85,21 @@ public class PsiDisjunctionType extends PsiType {
@Override
public String getPresentableText() {
return StringUtil.join(myTypes, new Function<PsiType, String>() {
@Override public String fun(PsiType psiType) { return psiType.getPresentableText(); }
@Override
public String fun(PsiType psiType) {
return psiType.getPresentableText();
}
}, " | ");
}
@NotNull
@Override
public String getCanonicalText() {
public String getCanonicalText(final boolean annotated) {
return StringUtil.join(myTypes, new Function<PsiType, String>() {
@Override public String fun(PsiType psiType) { return psiType.getCanonicalText(); }
@Override
public String fun(PsiType psiType) {
return psiType.getCanonicalText(annotated);
}
}, " | ");
}
@@ -101,7 +107,10 @@ public class PsiDisjunctionType extends PsiType {
@Override
public String getInternalCanonicalText() {
return StringUtil.join(myTypes, new Function<PsiType, String>() {
@Override public String fun(PsiType psiType) { return psiType.getInternalCanonicalText(); }
@Override
public String fun(PsiType psiType) {
return psiType.getInternalCanonicalText();
}
}, " | ");
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2013 JetBrains s.r.o.
* Copyright 2000-2014 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.
@@ -15,7 +15,6 @@
*/
package com.intellij.psi;
import com.intellij.openapi.util.text.StringUtil;
import org.jetbrains.annotations.NotNull;
/**
@@ -45,19 +44,19 @@ public class PsiEllipsisType extends PsiArrayType {
@NotNull
@Override
public String getPresentableText() {
return StringUtil.join(getComponentType().getPresentableText(), getAnnotationsTextPrefix(false, true, true), "...");
return getText(getComponentType().getPresentableText(), "...", false, true);
}
@NotNull
@Override
public String getCanonicalText() {
return StringUtil.join(getComponentType().getCanonicalText(), "...");
public String getCanonicalText(boolean annotated) {
return getText(getComponentType().getCanonicalText(annotated), "...", true, annotated);
}
@NotNull
@Override
public String getInternalCanonicalText() {
return StringUtil.join(getComponentType().getInternalCanonicalText(), getAnnotationsTextPrefix(true, true, true), "...");
return getText(getComponentType().getInternalCanonicalText(), "...", true, true);
}
@Override
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2013 JetBrains s.r.o.
* Copyright 2000-2014 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.
@@ -29,7 +29,7 @@ import java.util.*;
*
* @author ven
*/
public class PsiIntersectionType extends PsiType {
public class PsiIntersectionType extends PsiType.Stub {
private final PsiType[] myConjuncts;
private PsiIntersectionType(@NotNull PsiType[] conjuncts) {
@@ -111,19 +111,19 @@ public class PsiIntersectionType extends PsiType {
@NotNull
@Override
public String getCanonicalText() {
return myConjuncts[0].getCanonicalText();
public String getCanonicalText(boolean annotated) {
return myConjuncts[0].getCanonicalText(annotated);
}
@NotNull
@Override
public String getInternalCanonicalText() {
StringBuilder buffer = new StringBuilder();
for (int i = 0; i < myConjuncts.length; i++) {
buffer.append(myConjuncts[i].getInternalCanonicalText());
if (i < myConjuncts.length - 1) buffer.append(" & ");
}
return buffer.toString();
return StringUtil.join(myConjuncts, new Function<PsiType, String>() {
@Override
public String fun(PsiType psiType) {
return psiType.getInternalCanonicalText();
}
}, " & ");
}
@Override
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2013 JetBrains s.r.o.
* Copyright 2000-2014 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.
@@ -23,8 +23,11 @@ import com.intellij.util.ArrayUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Pattern;
import static com.intellij.util.ObjectUtils.assertNotNull;
import static com.intellij.util.ObjectUtils.notNull;
/**
@@ -37,7 +40,7 @@ public abstract class PsiNameHelper {
public static PsiNameHelper getInstance(Project project) {
return ServiceManager.getService(project, PsiNameHelper.class);
}
/**
* Checks if the specified text is a Java identifier, using the language level of the project
* with which the name helper is associated to filter out keywords.
@@ -121,30 +124,15 @@ public abstract class PsiNameHelper {
}
@NotNull
public static String getPresentableText(@Nullable String refName, @NotNull PsiAnnotation[] annotations, @NotNull PsiType[] typeParameters) {
if (typeParameters.length == 0 && annotations.length == 0) {
public static String getPresentableText(@Nullable String refName, @NotNull PsiAnnotation[] annotations, @NotNull PsiType[] types) {
if (types.length == 0 && annotations.length == 0) {
return refName != null ? refName : "";
}
StringBuilder buffer = new StringBuilder();
if (annotations.length > 0) {
for (PsiAnnotation annotation : annotations) {
buffer.append(annotation.getText()).append(' ');
}
}
appendAnnotations(buffer, annotations, false);
buffer.append(refName);
if (typeParameters.length > 0) {
buffer.append("<");
for (int i = 0; i < typeParameters.length; i++) {
buffer.append(typeParameters[i].getPresentableText());
if (i < typeParameters.length - 1) buffer.append(", ");
}
buffer.append(">");
}
appendTypeArgs(buffer, types, false, true);
return buffer.toString();
}
@@ -262,4 +250,43 @@ public abstract class PsiNameHelper {
return subpackageName.equals(packageName) ||
subpackageName.startsWith(packageName) && subpackageName.charAt(packageName.length()) == '.';
}
public static void appendTypeArgs(@NotNull StringBuilder sb, @NotNull PsiType[] types, boolean canonical, boolean annotated) {
if (types.length == 0) return;
sb.append('<');
for (int i = 0; i < types.length; i++) {
if (i > 0) {
sb.append(canonical ? "," : ", ");
}
PsiType type = types[i];
if (canonical) {
sb.append(type.getCanonicalText(annotated));
}
else {
sb.append(type.getPresentableText());
}
}
sb.append('>');
}
public static boolean appendAnnotations(@NotNull StringBuilder sb, @NotNull PsiAnnotation[] annotations, boolean canonical) {
return appendAnnotations(sb, Arrays.asList(annotations), canonical);
}
public static boolean appendAnnotations(@NotNull StringBuilder sb, @NotNull List<PsiAnnotation> annotations, boolean canonical) {
for (PsiAnnotation annotation : annotations) {
sb.append('@');
if (canonical) {
sb.append(annotation.getQualifiedName());
sb.append(annotation.getParameterList().getText());
}
else {
sb.append(assertNotNull(annotation.getNameReferenceElement()).getText());
}
sb.append(' ');
}
return annotations.size() > 0;
}
}
@@ -30,7 +30,7 @@ import java.util.Map;
/**
* Represents primitive types of Java language.
*/
public class PsiPrimitiveType extends PsiType {
public class PsiPrimitiveType extends PsiType.Stub {
private static final Map<String, PsiPrimitiveType> ourQNameToUnboxed = new THashMap<String, PsiPrimitiveType>();
private static final Map<PsiPrimitiveType, String> ourUnboxedToQName = new THashMap<PsiPrimitiveType, String>();
@@ -52,19 +52,29 @@ public class PsiPrimitiveType extends PsiType {
@NotNull
@Override
public String getPresentableText() {
return getAnnotationsTextPrefix(false, false, true) + myName;
return getText(false, true);
}
@NotNull
@Override
public String getCanonicalText() {
return myName;
public String getCanonicalText(boolean annotated) {
return getText(true, annotated);
}
@NotNull
@Override
public String getInternalCanonicalText() {
return getAnnotationsTextPrefix(true, false, true) + myName;
return getText(true, true);
}
private String getText(boolean qualified, boolean annotated) {
PsiAnnotation[] annotations = getAnnotations();
if (!annotated || annotations.length == 0) return myName;
StringBuilder sb = new StringBuilder();
PsiNameHelper.appendAnnotations(sb, annotations, qualified);
sb.append(myName);
return sb.toString();
}
/**
@@ -84,6 +84,15 @@ public abstract class PsiType implements PsiAnnotationOwner {
*/
@NonNls
@NotNull
public String getCanonicalText(boolean annotated) {
return getCanonicalText();
}
/**
* Same as {@code getCanonicalText(false)}.
*/
@NonNls
@NotNull
public abstract String getCanonicalText();
/**
@@ -284,24 +293,15 @@ public abstract class PsiType implements PsiAnnotationOwner {
return getAnnotations();
}
@NotNull
/** @deprecated use {@link PsiNameHelper#appendAnnotations(StringBuilder, PsiAnnotation[], boolean)} (to remove in IDEA 14) */
@SuppressWarnings("UnusedDeclaration")
protected String getAnnotationsTextPrefix(boolean qualified, boolean leadingSpace, boolean trailingSpace) {
PsiAnnotation[] annotations = getAnnotations();
if (annotations.length == 0) return "";
StringBuilder sb = new StringBuilder();
if (leadingSpace) sb.append(' ');
for (int i = 0; i < annotations.length; i++) {
if (i > 0) sb.append(' ');
PsiAnnotation annotation = annotations[i];
if (qualified) {
sb.append('@').append(annotation.getQualifiedName()).append(annotation.getParameterList().getText());
}
else {
sb.append(annotation.getText());
}
}
if (trailingSpace) sb.append(' ');
if (PsiNameHelper.appendAnnotations(sb, annotations, qualified) &&!trailingSpace) sb.setLength(sb.length() - 1);
return sb.toString();
}
@@ -310,4 +310,23 @@ public abstract class PsiType implements PsiAnnotationOwner {
//noinspection HardCodedStringLiteral
return "PsiType:" + getPresentableText();
}
/**
* Temporary class to facilitate transition to {@link #getCanonicalText(boolean)}.
*/
protected static abstract class Stub extends PsiType {
protected Stub(@NotNull PsiAnnotation[] annotations) {
super(annotations);
}
@NotNull
@Override
public final String getCanonicalText() {
return getCanonicalText(false);
}
@NotNull
@Override
public abstract String getCanonicalText(boolean annotated);
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2013 JetBrains s.r.o.
* Copyright 2000-2014 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.
@@ -28,7 +28,7 @@ import org.jetbrains.annotations.Nullable;
*
* @author dsl
*/
public class PsiWildcardType extends PsiType {
public class PsiWildcardType extends PsiType.Stub {
private static final Logger LOG = Logger.getInstance("#com.intellij.psi.PsiWildcardType");
private static final Key<PsiWildcardType> UNBOUNDED_WILDCARD = new Key<PsiWildcardType>("UNBOUNDED_WILDCARD");
@@ -83,21 +83,37 @@ public class PsiWildcardType extends PsiType {
@NotNull
@Override
public String getPresentableText() {
return getAnnotationsTextPrefix(false, false, true) +
(myBound == null ? "?" : (myIsExtending ? EXTENDS_PREFIX : SUPER_PREFIX) + myBound.getPresentableText());
return getText(false, true, myBound == null ? null : myBound.getPresentableText());
}
@Override
@NotNull
public String getCanonicalText() {
return myBound == null ? "?" : (myIsExtending ? EXTENDS_PREFIX : SUPER_PREFIX) + myBound.getCanonicalText();
public String getCanonicalText(boolean annotated) {
return getText(true, annotated, myBound == null ? null : myBound.getCanonicalText(annotated));
}
@NotNull
@Override
public String getInternalCanonicalText() {
return getAnnotationsTextPrefix(true, false, true) +
(myBound == null ? "?" : (myIsExtending ? EXTENDS_PREFIX : SUPER_PREFIX) + myBound.getInternalCanonicalText());
return getText(true, true, myBound == null ? null : myBound.getInternalCanonicalText());
}
private String getText(boolean qualified, boolean annotated, @Nullable String suffix) {
PsiAnnotation[] annotations = getAnnotations();
if ((!annotated || annotations.length == 0) && suffix == null) return "?";
StringBuilder sb = new StringBuilder();
if (annotated) {
PsiNameHelper.appendAnnotations(sb, annotations, qualified);
}
if (suffix == null) {
sb.append('?');
}
else {
sb.append(myIsExtending ? EXTENDS_PREFIX : SUPER_PREFIX);
sb.append(suffix);
}
return sb.toString();
}
@Override
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2013 JetBrains s.r.o.
* Copyright 2000-2014 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.
@@ -30,16 +30,16 @@ import java.util.List;
/**
* @author max
*/
public class PsiClassReferenceType extends PsiClassType {
public class PsiClassReferenceType extends PsiClassType.Stub {
@NotNull
private final PsiJavaCodeReferenceElement myReference;
public PsiClassReferenceType(@NotNull PsiJavaCodeReferenceElement reference, LanguageLevel langLevel) {
this(reference, langLevel, collectAnnotations(reference));
public PsiClassReferenceType(@NotNull PsiJavaCodeReferenceElement reference, LanguageLevel level) {
this(reference, level, collectAnnotations(reference));
}
public PsiClassReferenceType(@NotNull PsiJavaCodeReferenceElement reference, LanguageLevel langLevel, @NotNull PsiAnnotation[] annotations) {
super(langLevel, annotations);
public PsiClassReferenceType(@NotNull PsiJavaCodeReferenceElement reference, LanguageLevel level, @NotNull PsiAnnotation[] annotations) {
super(level, annotations);
myReference = reference;
}
@@ -89,7 +89,7 @@ public class PsiClassReferenceType extends PsiClassType {
return resolveGenerics().getElement();
}
private static class DelegatingClassResolveResult implements ClassResolveResult {
private static class DelegatingClassResolveResult implements PsiClassType.ClassResolveResult {
private final JavaResolveResult myDelegate;
private DelegatingClassResolveResult(@NotNull JavaResolveResult delegate) {
@@ -182,19 +182,37 @@ public class PsiClassReferenceType extends PsiClassType {
@NotNull
@Override
public String getPresentableText() {
return getAnnotationsTextPrefix(false, false, true) + PsiNameHelper.getPresentableText(myReference);
String presentableText = PsiNameHelper.getPresentableText(myReference);
PsiAnnotation[] annotations = getAnnotations();
if (annotations.length == 0) return presentableText;
StringBuilder sb = new StringBuilder();
PsiNameHelper.appendAnnotations(sb, annotations, false);
sb.append(presentableText);
return sb.toString();
}
@NotNull
@Override
public String getCanonicalText() {
return myReference.getCanonicalText();
public String getCanonicalText(boolean annotated) {
return getText(annotated);
}
@NotNull
@Override
public String getInternalCanonicalText() {
return getAnnotationsTextPrefix(true, false, true) + getCanonicalText();
return getText(true);
}
private String getText(boolean annotated) {
if (myReference instanceof PsiJavaCodeReferenceElementImpl) {
PsiAnnotation[] annotations = getAnnotations();
if (!annotated || annotations.length == 0) annotations = null;
return ((PsiJavaCodeReferenceElementImpl)myReference).getCanonicalText(annotated, annotations);
}
else {
return myReference.getCanonicalText();
}
}
@NotNull
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2013 JetBrains s.r.o.
* Copyright 2000-2014 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.
@@ -15,6 +15,7 @@
*/
package com.intellij.psi.impl.source;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.*;
import com.intellij.psi.search.GlobalSearchScope;
@@ -30,11 +31,12 @@ import java.util.List;
/**
* @author dsl
*/
public class PsiImmediateClassType extends PsiClassType {
public class PsiImmediateClassType extends PsiClassType.Stub {
private final PsiClass myClass;
private final PsiSubstitutor mySubstitutor;
private final PsiManager myManager;
private String myCanonicalText;
private String myCanonicalTextAnnotated;
private String myPresentableText;
private String myInternalCanonicalText;
@@ -80,15 +82,15 @@ public class PsiImmediateClassType extends PsiClassType {
this(aClass, substitutor, null, PsiAnnotation.EMPTY_ARRAY);
}
public PsiImmediateClassType(@NotNull PsiClass aClass, @NotNull PsiSubstitutor substitutor, @Nullable LanguageLevel languageLevel) {
this(aClass, substitutor, languageLevel, PsiAnnotation.EMPTY_ARRAY);
public PsiImmediateClassType(@NotNull PsiClass aClass, @NotNull PsiSubstitutor substitutor, @Nullable LanguageLevel level) {
this(aClass, substitutor, level, PsiAnnotation.EMPTY_ARRAY);
}
public PsiImmediateClassType(@NotNull PsiClass aClass,
@NotNull PsiSubstitutor substitutor,
@Nullable LanguageLevel languageLevel,
@NotNull PsiAnnotation[] annotations) {
super(languageLevel, annotations);
@Nullable LanguageLevel level,
@NotNull PsiAnnotation... annotations) {
super(level, annotations);
myClass = aClass;
myManager = aClass.getManager();
mySubstitutor = substitutor;
@@ -138,112 +140,119 @@ public class PsiImmediateClassType extends PsiClassType {
@Override
public String getPresentableText() {
if (myPresentableText == null) {
StringBuilder buffer = new StringBuilder();
buildText(myClass, mySubstitutor, buffer, false, false);
myPresentableText = buffer.toString();
myPresentableText = getText(TextType.PRESENTABLE, true);
}
return myPresentableText;
}
@NotNull
@Override
public String getCanonicalText() {
if (myCanonicalText == null) {
assert mySubstitutor.isValid();
StringBuilder buffer = new StringBuilder();
buildText(myClass, mySubstitutor, buffer, true, false);
myCanonicalText = buffer.toString();
public String getCanonicalText(boolean annotated) {
String cached = annotated ? myCanonicalTextAnnotated : myCanonicalText;
if (cached == null) {
cached = getText(TextType.CANONICAL, annotated);
if (annotated) myCanonicalTextAnnotated = cached;
else myCanonicalText = cached;
}
return myCanonicalText;
return cached;
}
@NotNull
@Override
public String getInternalCanonicalText() {
if (myInternalCanonicalText == null) {
StringBuilder buffer = new StringBuilder();
buildText(myClass, mySubstitutor, buffer, true, true);
myInternalCanonicalText = buffer.toString();
myInternalCanonicalText = getText(TextType.INT_CANONICAL, true);
}
return myInternalCanonicalText;
}
private enum TextType { PRESENTABLE, CANONICAL, INT_CANONICAL }
private String getText(@NotNull TextType textType, boolean annotated) {
assert mySubstitutor.isValid();
StringBuilder buffer = new StringBuilder();
buildText(myClass, mySubstitutor, buffer, textType, annotated);
return buffer.toString();
}
private void buildText(@NotNull PsiClass aClass,
@NotNull PsiSubstitutor substitutor,
@NotNull StringBuilder buffer,
boolean canonical,
boolean internal) {
@NotNull TextType textType,
boolean annotated) {
if (aClass instanceof PsiAnonymousClass) {
ClassResolveResult baseResolveResult = ((PsiAnonymousClass) aClass).getBaseClassType().resolveGenerics();
ClassResolveResult baseResolveResult = ((PsiAnonymousClass)aClass).getBaseClassType().resolveGenerics();
PsiClass baseClass = baseResolveResult.getElement();
PsiSubstitutor baseSub = baseResolveResult.getSubstitutor();
if (baseClass != null) {
buildText(baseClass, baseSub, buffer, canonical, internal);
buildText(baseClass, baseResolveResult.getSubstitutor(), buffer, textType, false);
}
return;
}
if (canonical == internal) {
buffer.append(getAnnotationsTextPrefix(internal, false, true));
}
boolean qualified = textType != TextType.PRESENTABLE;
PsiClass enclosingClass = null;
if (!aClass.hasModifierProperty(PsiModifier.STATIC)) {
final PsiElement parent = aClass.getParent();
PsiElement parent = aClass.getParent();
if (parent instanceof PsiClass && !(parent instanceof PsiAnonymousClass)) {
enclosingClass = (PsiClass)parent;
}
}
if (enclosingClass != null) {
buildText(enclosingClass, substitutor, buffer, canonical, false);
buildText(enclosingClass, substitutor, buffer, textType, false);
buffer.append('.');
buffer.append(aClass.getName());
}
else {
final String name;
if (!canonical) {
name = aClass.getName();
}
else {
final String qualifiedName = aClass.getQualifiedName();
if (qualifiedName == null) {
name = aClass.getName();
}
else {
name = qualifiedName;
else if (qualified) {
String fqn = aClass.getQualifiedName();
if (fqn != null) {
String prefix = StringUtil.getPackageName(fqn);
if (!StringUtil.isEmpty(prefix)) {
buffer.append(prefix);
buffer.append('.');
}
}
buffer.append(name);
}
if (annotated) {
PsiNameHelper.appendAnnotations(buffer, getAnnotations(), qualified);
}
buffer.append(aClass.getName());
PsiTypeParameter[] typeParameters = aClass.getTypeParameters();
if (typeParameters.length > 0) {
StringBuilder pineBuffer = new StringBuilder();
pineBuffer.append('<');
int pos = buffer.length();
buffer.append('<');
for (int i = 0; i < typeParameters.length; i++) {
PsiTypeParameter typeParameter = typeParameters[i];
PsiUtilCore.ensureValid(typeParameter);
if (i > 0) pineBuffer.append(',');
final PsiType substitutionResult = substitutor.substitute(typeParameter);
if (i > 0) {
buffer.append(',');
if (textType == TextType.PRESENTABLE) buffer.append(' ');
}
PsiType substitutionResult = substitutor.substitute(typeParameter);
if (substitutionResult == null) {
pineBuffer = null;
buffer.setLength(pos);
pos = -1;
break;
}
PsiUtil.ensureValidType(substitutionResult);
if (canonical) {
if (internal) {
pineBuffer.append(substitutionResult.getInternalCanonicalText());
}
else {
pineBuffer.append(substitutionResult.getCanonicalText());
}
if (textType == TextType.PRESENTABLE) {
buffer.append(substitutionResult.getPresentableText());
}
else if (textType == TextType.CANONICAL) {
buffer.append(substitutionResult.getCanonicalText(annotated));
}
else {
pineBuffer.append(substitutionResult.getPresentableText());
buffer.append(substitutionResult.getInternalCanonicalText());
}
}
if (pineBuffer != null) {
buffer.append(pineBuffer);
if (pos >= 0) {
buffer.append('>');
}
}
@@ -265,7 +274,6 @@ public class PsiImmediateClassType extends PsiClassType {
return false;
}
return equals(patternType);
}
@Override
@@ -277,14 +285,12 @@ public class PsiImmediateClassType extends PsiClassType {
@Override
@NotNull
public LanguageLevel getLanguageLevel() {
if (myLanguageLevel != null) return myLanguageLevel;
return PsiUtil.getLanguageLevel(myClass);
return myLanguageLevel != null ? myLanguageLevel : PsiUtil.getLanguageLevel(myClass);
}
@NotNull
@Override
public PsiClassType setLanguageLevel(@NotNull final LanguageLevel languageLevel) {
if (languageLevel.equals(myLanguageLevel)) return this;
return new PsiImmediateClassType(myClass, mySubstitutor, languageLevel,getAnnotations());
public PsiClassType setLanguageLevel(@NotNull LanguageLevel level) {
return level.equals(myLanguageLevel) ? this : new PsiImmediateClassType(myClass, mySubstitutor, level, getAnnotations());
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2013 JetBrains s.r.o.
* Copyright 2000-2014 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.
@@ -49,6 +49,7 @@ import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import java.util.List;
public class PsiJavaCodeReferenceElementImpl extends CompositePsiElement implements PsiJavaCodeReferenceElement, SourceJavaCodeReference {
@@ -255,36 +256,47 @@ public class PsiJavaCodeReferenceElementImpl extends CompositePsiElement impleme
@Override
@NotNull
public String getCanonicalText() {
return getCanonicalText(false, null);
}
@NotNull
public String getCanonicalText(boolean annotated, @Nullable PsiAnnotation[] annotations) {
switch (getKind()) {
case CLASS_NAME_KIND:
case CLASS_OR_PACKAGE_NAME_KIND:
case CLASS_IN_QUALIFIED_NEW_KIND:
final PsiElement target = resolve();
if (target instanceof PsiClass) {
final PsiClass aClass = (PsiClass)target;
String name = aClass.getQualifiedName();
if (name == null) {
name = aClass.getName(); //?
PsiClass aClass = (PsiClass)target;
StringBuilder buffer = new StringBuilder();
PsiElement qualifier = getQualifier();
String prefix = null;
if (qualifier instanceof PsiJavaCodeReferenceElementImpl) {
prefix = ((PsiJavaCodeReferenceElementImpl)qualifier).getCanonicalText(annotated, null);
}
final PsiType[] types = getTypeParameters();
if (types.length == 0) {
final PsiElement qualifier = getQualifier();
if (qualifier instanceof PsiJavaCodeReferenceElement) {
return StringUtil.getQualifiedName(((PsiJavaCodeReferenceElement)qualifier).getCanonicalText(), aClass.getName());
else {
String fqn = aClass.getQualifiedName();
if (fqn != null) {
prefix = StringUtil.getPackageName(fqn);
}
return name;
}
final StringBuilder buf = new StringBuilder();
buf.append(name);
buf.append('<');
for (int i = 0; i < types.length; i++) {
if (i > 0) buf.append(',');
buf.append(types[i].getCanonicalText());
if (!StringUtil.isEmpty(prefix)) {
buffer.append(prefix);
buffer.append('.');
}
buf.append('>');
return buf.toString();
if (annotated) {
List<PsiAnnotation> list = annotations != null ? Arrays.asList(annotations) : getAnnotations();
PsiNameHelper.appendAnnotations(buffer, list, true);
}
buffer.append(aClass.getName());
PsiNameHelper.appendTypeArgs(buffer, getTypeParameters(), true, annotated);
return buffer.toString();
}
else if (target instanceof PsiPackage) {
return ((PsiPackage)target).getQualifiedName();
@@ -293,6 +305,7 @@ public class PsiJavaCodeReferenceElementImpl extends CompositePsiElement impleme
LOG.assertTrue(target == null, target);
return getNormalizedText();
}
case PACKAGE_NAME_KIND:
case CLASS_FQ_NAME_KIND:
case CLASS_FQ_OR_PACKAGE_NAME_KIND:
@@ -327,7 +340,7 @@ public class PsiJavaCodeReferenceElementImpl extends CompositePsiElement impleme
if (incompleteCode && result.length == 0 && kind != CLASS_FQ_NAME_KIND && kind != CLASS_FQ_OR_PACKAGE_NAME_KIND) {
VariableResolverProcessor processor = new VariableResolverProcessor(referenceElement, containingFile);
PsiScopesUtil.resolveAndWalk(processor, referenceElement, null, incompleteCode);
PsiScopesUtil.resolveAndWalk(processor, referenceElement, null, true);
result = processor.getResult();
if (result.length == 0 && kind == CLASS_NAME_KIND) {
result = referenceElement.resolve(PACKAGE_NAME_KIND, containingFile);
@@ -457,16 +470,16 @@ public class PsiJavaCodeReferenceElementImpl extends CompositePsiElement impleme
case CLASS_FQ_OR_PACKAGE_NAME_KIND:
case CLASS_OR_PACKAGE_NAME_KIND: {
int classKind = kind == CLASS_OR_PACKAGE_NAME_KIND ? CLASS_NAME_KIND : CLASS_FQ_NAME_KIND;
JavaResolveResult[] result = resolve(classKind,containingFile);
JavaResolveResult[] result = resolve(classKind, containingFile);
if (result.length == 1 && !result[0].isAccessible()) {
JavaResolveResult[] packageResult = resolve(PACKAGE_NAME_KIND,containingFile);
JavaResolveResult[] packageResult = resolve(PACKAGE_NAME_KIND, containingFile);
if (packageResult.length != 0) {
result = packageResult;
}
}
else if (result.length == 0) {
result = resolve(PACKAGE_NAME_KIND,containingFile);
result = resolve(PACKAGE_NAME_KIND, containingFile);
}
return result;
@@ -607,7 +620,12 @@ public class PsiJavaCodeReferenceElementImpl extends CompositePsiElement impleme
for (PsiAnnotation annotation : annotations) {
if (annotation.getParent() != newParent) {
newParent.addAfter(annotation, anchor);
if (anchor != null) {
newParent.addAfter(annotation, anchor);
}
else {
newParent.add(annotation);
}
annotation.delete();
}
}
@@ -935,7 +953,6 @@ public class PsiJavaCodeReferenceElementImpl extends CompositePsiElement impleme
final PsiReferenceParameterList parameterList = getParameterList();
if (parameterList == null) return PsiType.EMPTY_ARRAY;
return parameterList.getTypeArguments();
}
@Override
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2013 JetBrains s.r.o.
* Copyright 2000-2014 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.
@@ -131,7 +131,7 @@ public class JavaTreeGenerator implements TreeGenerator {
type = PsiType.getJavaLangObject(manager, GlobalSearchScope.projectScope(manager.getProject()));
}
String text = type.getPresentableText();
String text = type.getCanonicalText(true);
PsiJavaParserFacade parserFacade = JavaPsiFacade.getInstance(original.getProject()).getParserFacade();
PsiTypeElement element = parserFacade.createTypeElementFromText(text, original);
@@ -157,14 +157,14 @@ class ParenthTest<T extends TZ> {
class TestWildcardInference {
interface A<T> {
}
class B<V> implements A<V> {
B(C<V> v) {
}
}
class C<E> {}
class U {
void foo() {
C<? extends Number> x = null;
@@ -202,13 +202,13 @@ class Another {
System.out.println(i);
<error descr="Incompatible types. Found: 'Outer2.Inner2<java.lang.String>', required: 'Outer2.Inner2<java.lang.String>'">Outer2<Integer>.Inner2<String> i5 = new Outer2<>().new Inner2<>();</error>
<error descr="Incompatible types. Found: 'Outer2.Inner2<java.lang.String>', required: 'Outer2<java.lang.Integer>.Inner2<java.lang.String>'">Outer2<Integer>.Inner2<String> i5 = new Outer2<>().new Inner2<>();</error>
}
static Outer m() {return null;}
static <T extends Outer> T m1() {return null;}
static <T> T m2() {return null;}
}
class TypeParamsExtendsList {
@@ -40,6 +40,6 @@ class AAmbiguous {
}
public static void main(Promise<String> helloWorld) {
helloWorld.then<error descr="Ambiguous method call: both 'Promise.then(Function<? super String,Promise<Integer>>)' and 'Promise.then(AsyncFunction<? super String,Promise<Integer>>)' match">(AAmbiguous::calculateLength)</error>;
helloWorld.then<error descr="Ambiguous method call: both 'Promise.then(Function<? super String, Promise<Integer>>)' and 'Promise.then(AsyncFunction<? super String, Promise<Integer>>)' match">(AAmbiguous::calculateLength)</error>;
}
}
@@ -21,9 +21,9 @@ class Test {
}
void foo(Foo<String> as, final Foo<Character> ac) {
boolean b1 = as.forAll(s -> ac.forAll<error descr="Ambiguous method call: both 'Foo.forAll(I<Character,Boolean>)' and 'Foo.forAll(II<Character,String>)' match">(c -> false)</error>);
String s1 = as.forAll(s -> ac.forAll<error descr="Ambiguous method call: both 'Foo.forAll(I<Character,Boolean>)' and 'Foo.forAll(II<Character,String>)' match">(c -> "")</error>);
boolean b2 = as.forAll(s -> ac.forAll<error descr="Ambiguous method call: both 'Foo.forAll(I<Character,Boolean>)' and 'Foo.forAll(II<Character,String>)' match">(c -> "")</error>);
boolean b1 = as.forAll(s -> ac.forAll<error descr="Ambiguous method call: both 'Foo.forAll(I<Character, Boolean>)' and 'Foo.forAll(II<Character, String>)' match">(c -> false)</error>);
String s1 = as.forAll(s -> ac.forAll<error descr="Ambiguous method call: both 'Foo.forAll(I<Character, Boolean>)' and 'Foo.forAll(II<Character, String>)' match">(c -> "")</error>);
boolean b2 = as.forAll(s -> ac.forAll<error descr="Ambiguous method call: both 'Foo.forAll(I<Character, Boolean>)' and 'Foo.forAll(II<Character, String>)' match">(c -> "")</error>);
String s2 = as.forAll2(s -> ac.forAll2(<error descr="Incompatible return type boolean in lambda expression">c -> false</error>));
boolean b3 = as.forAll((I<String, Boolean>)s -> ac.forAll((I<Character, Boolean>)<error descr="Incompatible return type String in lambda expression">c -> ""</error>));
String s3 = as.forAll((II<String, String>)s -> ac.forAll((II<Character, String>)<error descr="Incompatible return type boolean in lambda expression">c -> false</error>));
@@ -53,7 +53,7 @@ class Test {
Test s1 = staticCall(Test::n0);
Test s2 = staticCall(Test::n1);
Test s3 = staticCall<error descr="Cannot resolve method 'staticCall(<method reference>)'">(Test::n2)</error>;
Test s4 = staticCall<error descr="Ambiguous method call: both 'Test.staticCall(I1<Test>)' and 'Test.staticCall(I2<Test,String>)' match">(Test::n01)</error>;
Test s5 = staticCall<error descr="Ambiguous method call: both 'Test.staticCall(I1<Test>)' and 'Test.staticCall(I2<Test,String>)' match">(Test::n012)</error>;
Test s4 = staticCall<error descr="Ambiguous method call: both 'Test.staticCall(I1<Test>)' and 'Test.staticCall(I2<Test, String>)' match">(Test::n01)</error>;
Test s5 = staticCall<error descr="Ambiguous method call: both 'Test.staticCall(I1<Test>)' and 'Test.staticCall(I2<Test, String>)' match">(Test::n012)</error>;
}
}
@@ -1,15 +1,12 @@
import java.lang.annotation.*;
import static java.lang.annotation.ElementType.*;
@Target({TYPE_USE}) @interface TA { }
import pkg.TA;
class Outer {
class Middle {
class Inner {
void m1(Outer.Middle.Inner p) { }
void m2(@TA Outer.Middle.Inner p) { }
void m3(Outer.@TA Middle.Inner p) { }
void m4(Outer.Middle.@TA @TA Inner p) { }
void m2(@pkg.TA Outer.Middle.Inner p) { }
void m3(Outer.@pkg.TA Middle.Inner p) { }
void m4(Outer.Middle.@pkg.TA @pkg.TA Inner p) { }
}
}
}
@@ -1,7 +1,4 @@
import java.lang.annotation.*;
import static java.lang.annotation.ElementType.*;
@Target({TYPE_USE}) @interface TA { }
import pkg.TA;
class Outer {
class Middle {
@@ -0,0 +1,6 @@
package pkg;
import java.lang.annotation.*;
@Target({ElementType.TYPE_USE})
@interface TA { }
@@ -2,6 +2,6 @@ import util.Pair;
class Client {
void method() {
Pair<String, Pair<Integer,Boolean>> p = PairProvider.getPair();
Pair<String, Pair<Integer, Boolean>> p = PairProvider.getPair();
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2013 JetBrains s.r.o.
* Copyright 2000-2014 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.
@@ -15,15 +15,22 @@
*/
package com.intellij.codeInsight.psi
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
import com.intellij.pom.java.LanguageLevel
import com.intellij.psi.*
import com.intellij.psi.impl.source.PsiImmediateClassType
import com.intellij.testFramework.LightIdeaTestCase
@SuppressWarnings(["GrUnresolvedAccess", "GroovyAssignabilityCheck"])
@SuppressWarnings("GroovyAssignabilityCheck")
class AnnotatedTypeTest extends LightIdeaTestCase {
private PsiFile context
private PsiElementFactory factory
public void setUp() throws Exception {
super.setUp()
factory = javaFacade.elementFactory
context = createFile("typeCompositionTest.java", """
package pkg;
public void testTypeComposition() {
PsiFile context = createFile("typeCompositionTest.java", """
import java.lang.annotation.*;
import static java.lang.annotation.ElementType.*;
@@ -33,31 +40,55 @@ import static java.lang.annotation.ElementType.*;
class E1 extends Exception { }
class E2 extends Exception { }
""")
PsiElement psi
psi = javaFacade.elementFactory.createStatementFromText("@A @TA(1) int @TA(2) [] a", context)
assertEquals("@TA(1) int @TA(2) []", psi.declaredElements[0].type.presentableText)
psi = javaFacade.elementFactory.createStatementFromText("try { } catch (@A @TA(1) E1 | @TA(2) E2 e) { }", context)
assertEquals("@TA(1) E1 | @TA(2) E2", psi.catchBlockParameters[0].type.presentableText)
psi = javaFacade.elementFactory.createStatementFromText("@A @TA(1) String @TA(2) [] f @TA(3) []", context)
assertEquals("@TA(1) String @TA(2) [] @TA(3) []", psi.declaredElements[0].type.presentableText)
psi = javaFacade.elementFactory.createStatementFromText("Class<@TA(1) ?> c", context)
assertEquals("Class<@TA(1) ?>", psi.declaredElements[0].type.presentableText)
psi = javaFacade.elementFactory.createStatementFromText("Class<@TA String> cs = new Class<>()", context)
assertEquals("Class<@TA String>", psi.declaredElements[0].initializer.type.presentableText)
psi = javaFacade.elementFactory.createStatementFromText("@A @TA(1) String s", context)
assertEquals("@TA(1) String", psi.declaredElements[0].type.presentableText)
psi = javaFacade.elementFactory.createStatementFromText("@A java.lang.@TA(1) String s", context)
assertEquals("@TA(1) String", psi.declaredElements[0].type.presentableText)
psi = javaFacade.elementFactory.createStatementFromText("Collection<? extends> s", context)
assertEquals("Collection<?>", psi.declaredElements[0].type.presentableText)
}
public void testPrimitiveArrayType() {
doTest("@A @TA(1) int @TA(2) [] a", "@pkg.TA(1) int @pkg.TA(2) []", "int[]")
}
public void testEllipsisType() {
def psi = factory.createParameterFromText("@TA int @TA ... p", context)
assertTypeText(psi.type, "@pkg.TA int @pkg.TA ...", "int...")
}
public void testClassReferenceType() {
doTest("@A @TA(1) String s", "java.lang.@pkg.TA(1) String", "java.lang.String")
doTest("@A java.lang.@TA(1) String s", "java.lang.@pkg.TA(1) String", "java.lang.String")
}
public void testCStyleArrayType() {
doTest("@A @TA(1) String @TA(2) [] f @TA(3) []", "java.lang.@pkg.TA(1) String @pkg.TA(2) [] @pkg.TA(3) []", "java.lang.String[][]")
}
public void testWildcardType() {
doTest("Class<@TA(1) ?> c", "java.lang.Class<@pkg.TA(1) ?>", "java.lang.Class<?>")
}
public void testDisjunctionType() {
def psi = factory.createStatementFromText("try { } catch (@A @TA(1) E1 | @TA(2) E2 e) { }", context)
assertTypeText(psi.catchBlockParameters[0].type, "pkg.@pkg.TA(1) E1 | pkg.@pkg.TA(2) E2", "pkg.E1 | pkg.E2")
}
public void testDiamondType() {
def psi = factory.createStatementFromText("Class<@TA String> cs = new Class<>()", context)
assertTypeText(psi.declaredElements[0].initializer.type, "java.lang.Class<java.lang.@pkg.TA String>", "java.lang.Class<java.lang.String>")
}
public void testImmediateClassType() {
def aClass = javaFacade.findClass(CommonClassNames.JAVA_LANG_OBJECT)
def statement = factory.createStatementFromText("@TA int x", context)
def annotations = statement.declaredElements[0].modifierList.annotations
def type = new PsiImmediateClassType(aClass, PsiSubstitutor.EMPTY, LanguageLevel.JDK_1_8, annotations)
assertTypeText(type, "java.lang.@pkg.TA Object", CommonClassNames.JAVA_LANG_OBJECT)
}
private void doTest(String text, String annotated, String canonical) {
def psi = factory.createStatementFromText(text, context)
assertTypeText(psi.declaredElements[0].type, annotated, canonical)
}
private static void assertTypeText(PsiType type, String annotated, String canonical) {
assert type.getCanonicalText(true) == annotated
assert type.getCanonicalText(false) == canonical
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2013 JetBrains s.r.o.
* Copyright 2000-2014 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.
@@ -61,6 +61,7 @@ public class ShortenClassReferencesTest extends LightCodeInsightFixtureTestCase
public void testSCR37254() { doTest(); }
public void testTypeAnnotatedRef() {
myFixture.configureByFile("pkg/TA.java");
doTest();
for (PsiParameter parameter : PsiTreeUtil.findChildrenOfType(myFixture.getFile(), PsiParameter.class)) {
PsiTypeElement typeElement = parameter.getTypeElement();
@@ -17,12 +17,15 @@ package com.siyeh.ipp.exceptions;
import com.intellij.psi.*;
import com.intellij.psi.impl.PsiImplUtil;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.IncorrectOperationException;
import com.siyeh.ipp.base.Intention;
import com.siyeh.ipp.base.PsiElementPredicate;
import org.jetbrains.annotations.NotNull;
import static com.intellij.psi.PsiAnnotation.TargetType;
import java.util.List;
import static com.intellij.util.ObjectUtils.assertNotNull;
public class SplitMultiCatchIntention extends Intention {
@@ -52,27 +55,30 @@ public class SplitMultiCatchIntention extends Intention {
return;
}
final PsiModifierList modifierList = parameter.getModifierList();
if (modifierList != null) {
for (PsiAnnotation annotation : modifierList.getAnnotations()) {
if (PsiImplUtil.findApplicableTarget(annotation, TargetType.TYPE_USE) == TargetType.TYPE_USE) {
annotation.delete();
final PsiElementFactory factory = JavaPsiFacade.getElementFactory(element.getProject());
final List<PsiTypeElement> disjunctions = PsiTreeUtil.getChildrenOfTypeAsList(parameter.getTypeElement(), PsiTypeElement.class);
for (int i = 0; i < disjunctions.size(); i++) {
final PsiCatchSection copy = (PsiCatchSection)catchSection.copy();
final PsiTypeElement typeElement = assertNotNull(assertNotNull(copy.getParameter()).getTypeElement());
final PsiTypeElement newTypeElement = factory.createTypeElementFromText(disjunctions.get(i).getText(), catchSection);
typeElement.replace(newTypeElement);
grandParent.addBefore(copy, catchSection);
if (i == 0) {
// clear the original from type annotations: they belong to the first disjunction and should not appear in others
final PsiModifierList modifierList = parameter.getModifierList();
if (modifierList != null) {
for (PsiAnnotation annotation : modifierList.getAnnotations()) {
if (PsiImplUtil.findApplicableTarget(annotation, PsiAnnotation.TargetType.TYPE_USE) == PsiAnnotation.TargetType.TYPE_USE) {
annotation.delete();
}
}
}
}
}
final PsiElementFactory factory = JavaPsiFacade.getElementFactory(element.getProject());
for (PsiType disjunction : ((PsiDisjunctionType)type).getDisjunctions()) {
final PsiCatchSection copy = (PsiCatchSection)catchSection.copy();
final PsiParameter copyParameter = copy.getParameter();
assert copyParameter != null : copy.getText();
final PsiTypeElement typeElement = copyParameter.getTypeElement();
assert typeElement != null : copyParameter.getText();
final PsiTypeElement newTypeElement = factory.createTypeElement(disjunction);
typeElement.replace(newTypeElement);
grandParent.addBefore(copy, catchSection);
}
catchSection.delete();
}
}