blob: 6834e39b2ff6e4c58cb7d6b1f3621af93ce8b1df [file] [log] [blame]
/*
* 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.
* 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.project.Project;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.util.TypeConversionUtil;
import com.intellij.util.ArrayFactory;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Representation of Java type (primitive type, array or class type).
*/
public abstract class PsiType implements PsiAnnotationOwner {
public static final PsiPrimitiveType BYTE = new PsiPrimitiveType("byte", "java.lang.Byte");
public static final PsiPrimitiveType CHAR = new PsiPrimitiveType("char", "java.lang.Character");
public static final PsiPrimitiveType DOUBLE = new PsiPrimitiveType("double", "java.lang.Double");
public static final PsiPrimitiveType FLOAT = new PsiPrimitiveType("float", "java.lang.Float");
public static final PsiPrimitiveType INT = new PsiPrimitiveType("int", "java.lang.Integer");
public static final PsiPrimitiveType LONG = new PsiPrimitiveType("long", "java.lang.Long");
public static final PsiPrimitiveType SHORT = new PsiPrimitiveType("short", "java.lang.Short");
public static final PsiPrimitiveType BOOLEAN = new PsiPrimitiveType("boolean", "java.lang.Boolean");
public static final PsiPrimitiveType VOID = new PsiPrimitiveType("void", "java.lang.Void");
public static final PsiPrimitiveType NULL = new PsiPrimitiveType("null", (String)null);
public static final PsiType[] EMPTY_ARRAY = new PsiType[0];
public static final ArrayFactory<PsiType> ARRAY_FACTORY = new ArrayFactory<PsiType>() {
@NotNull
@Override
public PsiType[] create(int count) {
return count == 0 ? EMPTY_ARRAY : new PsiType[count];
}
};
@NotNull
public static PsiType[] createArray(int count) {
return ARRAY_FACTORY.create(count);
}
private final PsiAnnotation[] myAnnotations;
protected PsiType(@NotNull PsiAnnotation[] annotations) {
myAnnotations = annotations;
}
/**
* Creates array type with this type as a component.
*/
@NotNull
public PsiArrayType createArrayType() {
return new PsiArrayType(this);
}
/**
* Creates array type with this type as a component.
*/
@NotNull
public PsiArrayType createArrayType(@NotNull PsiAnnotation... annotations) {
return new PsiArrayType(this, annotations);
}
/**
* Returns text of the type that can be presented to a user (references normally non-qualified).
*/
@NonNls
@NotNull
public abstract String getPresentableText();
/**
* Returns canonical representation of the type (all references fully-qualified).
*/
@NonNls
@NotNull
public String getCanonicalText(boolean annotated) {
return getCanonicalText();
}
/**
* Same as {@code getCanonicalText(false)}.
*/
@NonNls
@NotNull
public abstract String getCanonicalText();
/**
* Return canonical text of the type with some internal details added for presentational purposes. Use with care.
* todo[r.sh] merge with getPresentableText()
*/
@NonNls
@NotNull
public abstract String getInternalCanonicalText();
/**
* Checks if the type is currently valid.
*
* @return true if the type is valid, false otherwise.
* @see PsiElement#isValid()
*/
public abstract boolean isValid();
/**
* @return true if values of type <code>type</code> can be assigned to rvalues of this type.
*/
public boolean isAssignableFrom(@NotNull PsiType type) {
return TypeConversionUtil.isAssignable(this, type);
}
/**
* Checks whether values of type <code>type</code> can be casted to this type.
*/
public boolean isConvertibleFrom(@NotNull PsiType type) {
return TypeConversionUtil.areTypesConvertible(type, this);
}
/**
* Checks if the specified string is equivalent to the canonical text of the type.
*
* @param text the text to compare with.
* @return true if the string is equivalent to the type, false otherwise
*/
public abstract boolean equalsToText(@NotNull @NonNls String text);
/**
* Returns the class type for qualified class name.
*
* @param qName qualified class name.
* @param project
* @param resolveScope the scope in which the class is searched.
* @return the class instance.
*/
public static PsiClassType getTypeByName(String qName, Project project, GlobalSearchScope resolveScope) {
PsiElementFactory factory = JavaPsiFacade.getInstance(project).getElementFactory();
return factory.createTypeByFQClassName(qName, resolveScope);
}
/**
* Returns the class type for the java.lang.Object class.
*
* @param manager the PSI manager used to create the class type.
* @param resolveScope the scope in which the class is searched.
* @return the class instance.
*/
@NotNull
public static PsiClassType getJavaLangObject(@NotNull PsiManager manager, @NotNull GlobalSearchScope resolveScope) {
return getTypeByName(CommonClassNames.JAVA_LANG_OBJECT, manager.getProject(), resolveScope);
}
/**
* Returns the class type for the java.lang.Class class.
*
* @param manager the PSI manager used to create the class type.
* @param resolveScope the scope in which the class is searched.
* @return the class instance.
*/
@NotNull
public static PsiClassType getJavaLangClass(@NotNull PsiManager manager, @NotNull GlobalSearchScope resolveScope) {
return getTypeByName(CommonClassNames.JAVA_LANG_CLASS, manager.getProject(), resolveScope);
}
/**
* Returns the class type for the java.lang.Throwable class.
*
* @param manager the PSI manager used to create the class type.
* @param resolveScope the scope in which the class is searched.
* @return the class instance.
*/
@NotNull
public static PsiClassType getJavaLangThrowable(@NotNull PsiManager manager, @NotNull GlobalSearchScope resolveScope) {
return getTypeByName(CommonClassNames.JAVA_LANG_THROWABLE, manager.getProject(), resolveScope);
}
/**
* Returns the class type for the java.lang.String class.
*
* @param manager the PSI manager used to create the class type.
* @param resolveScope the scope in which the class is searched.
* @return the class instance.
*/
@NotNull
public static PsiClassType getJavaLangString(@NotNull PsiManager manager, @NotNull GlobalSearchScope resolveScope) {
return getTypeByName(CommonClassNames.JAVA_LANG_STRING, manager.getProject(), resolveScope);
}
/**
* Returns the class type for the java.lang.Error class.
*
* @param manager the PSI manager used to create the class type.
* @param resolveScope the scope in which the class is searched.
* @return the class instance.
*/
@NotNull
public static PsiClassType getJavaLangError(@NotNull PsiManager manager, @NotNull GlobalSearchScope resolveScope) {
return getTypeByName(CommonClassNames.JAVA_LANG_ERROR, manager.getProject(), resolveScope);
}
/**
* Returns the class type for the java.lang.RuntimeException class.
*
* @param manager the PSI manager used to create the class type.
* @param resolveScope the scope in which the class is searched.
* @return the class instance.
*/
@NotNull
public static PsiClassType getJavaLangRuntimeException(@NotNull PsiManager manager, @NotNull GlobalSearchScope resolveScope) {
return getTypeByName(CommonClassNames.JAVA_LANG_RUNTIME_EXCEPTION, manager.getProject(), resolveScope);
}
/**
* Passes the type to the specified visitor.
*
* @param visitor the visitor to accept the type.
* @return the value returned by the visitor.
*/
public abstract <A> A accept(@NotNull PsiTypeVisitor<A> visitor);
/**
* Returns the number of array dimensions for the type.
*
* @return the number of dimensions, or 0 if the type is not an array type.
*/
public final int getArrayDimensions() {
PsiType type = this;
int dims = 0;
while (type instanceof PsiArrayType) {
dims++;
type = ((PsiArrayType)type).getComponentType();
}
return dims;
}
/**
* Returns the innermost component type for an array type.
*
* @return the innermost (non-array) component of the type, or <code>this</code> if the type is not
* an array type.
*/
@NotNull
public final PsiType getDeepComponentType() {
PsiType type = this;
while (type instanceof PsiArrayType) {
type = ((PsiArrayType)type).getComponentType();
}
return type;
}
/**
* Returns the scope in which the reference to the underlying class of a class type is searched.
*
* @return the resolve scope instance, or null if the type is a primitive or an array of primitives.
*/
@Nullable
public abstract GlobalSearchScope getResolveScope();
/**
* Returns the list of superclass types for a class type.
*
* @return the array of superclass types, or an empty array if the type is not a class type.
*/
@NotNull
public abstract PsiType[] getSuperTypes();
@Override
@NotNull
public PsiAnnotation[] getAnnotations() {
return myAnnotations;
}
@Override
public PsiAnnotation findAnnotation(@NotNull @NonNls String qualifiedName) {
for (PsiAnnotation annotation : myAnnotations) {
if (qualifiedName.equals(annotation.getQualifiedName())) {
return annotation;
}
}
return null;
}
@Override
@NotNull
public PsiAnnotation addAnnotation(@NotNull @NonNls String qualifiedName) {
throw new UnsupportedOperationException();
}
@Override
@NotNull
public PsiAnnotation[] getApplicableAnnotations() {
return getAnnotations();
}
/** @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(' ');
if (PsiNameHelper.appendAnnotations(sb, annotations, qualified) &&!trailingSpace) sb.setLength(sb.length() - 1);
return sb.toString();
}
@Override
public String toString() {
//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);
}
}