001/*
002 * Copyright 2010-2013 JetBrains s.r.o.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.jetbrains.jet.lang.resolve.java;
018
019import com.intellij.psi.*;
020import com.intellij.psi.util.PsiFormatUtil;
021import org.jetbrains.annotations.NotNull;
022import org.jetbrains.annotations.Nullable;
023import org.jetbrains.jet.lang.descriptors.*;
024import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
025import org.jetbrains.jet.lang.resolve.constants.StringValue;
026import org.jetbrains.jet.lang.resolve.java.kt.PsiAnnotationWithFlags;
027import org.jetbrains.jet.lang.resolve.java.wrapper.PsiClassWrapper;
028import org.jetbrains.jet.lang.resolve.java.wrapper.PsiMemberWrapper;
029import org.jetbrains.jet.lang.resolve.java.wrapper.PsiMethodWrapper;
030import org.jetbrains.jet.lang.resolve.name.FqName;
031import org.jetbrains.jet.lang.resolve.name.FqNameUnsafe;
032import org.jetbrains.jet.lang.resolve.name.Name;
033import org.jetbrains.jet.lang.types.JetType;
034
035import java.util.Collection;
036import java.util.Collections;
037import java.util.List;
038
039import static com.intellij.psi.util.PsiFormatUtilBase.*;
040import static org.jetbrains.jet.lang.resolve.DescriptorUtils.getClassObjectName;
041import static org.jetbrains.jet.lang.resolve.DescriptorUtils.isEnumClassObject;
042
043public final class DescriptorResolverUtils {
044    public static final FqName OBJECT_FQ_NAME = new FqName("java.lang.Object");
045
046    private DescriptorResolverUtils() {
047    }
048
049    public static boolean isKotlinClass(@NotNull PsiClass psiClass) {
050        PsiClassWrapper wrapper = new PsiClassWrapper(psiClass);
051        return wrapper.getJetClass().isDefined() ||  wrapper.getJetPackageClass().isDefined();
052    }
053
054    @NotNull
055    public static Collection<JetType> getSupertypes(@NotNull ClassOrNamespaceDescriptor classOrNamespaceDescriptor) {
056        if (classOrNamespaceDescriptor instanceof ClassDescriptor) {
057            return ((ClassDescriptor) classOrNamespaceDescriptor).getTypeConstructor().getSupertypes();
058        }
059        return Collections.emptyList();
060    }
061
062    public static Modality resolveModality(PsiMemberWrapper memberWrapper, boolean isFinal) {
063        if (memberWrapper instanceof PsiMethodWrapper) {
064            PsiMethodWrapper method = (PsiMethodWrapper) memberWrapper;
065            if (method.getJetMethodAnnotation().hasForceOpenFlag()) {
066                return Modality.OPEN;
067            }
068            if (method.getJetMethodAnnotation().hasForceFinalFlag()) {
069                return Modality.FINAL;
070            }
071        }
072
073        return Modality.convertFromFlags(memberWrapper.isAbstract(), !isFinal);
074    }
075
076    public static Visibility resolveVisibility(
077            @NotNull PsiModifierListOwner modifierListOwner,
078            @Nullable PsiAnnotationWithFlags annotation
079    ) {
080        if (annotation != null) {
081            if (annotation.hasPrivateFlag()) {
082                return Visibilities.PRIVATE;
083            }
084            else if (annotation.hasInternalFlag()) {
085                return Visibilities.INTERNAL;
086            }
087            else if (annotation.hasProtectedFlag()) {
088                return Visibilities.PROTECTED;
089            }
090        }
091
092        if (modifierListOwner.hasModifierProperty(PsiModifier.PUBLIC)) {
093            return Visibilities.PUBLIC;
094        }
095        if (modifierListOwner.hasModifierProperty(PsiModifier.PRIVATE)) {
096            return Visibilities.PRIVATE;
097        }
098        if (modifierListOwner.hasModifierProperty(PsiModifier.PROTECTED)) {
099            if (modifierListOwner.hasModifierProperty(PsiModifier.STATIC)) {
100                return JavaDescriptorResolver.PROTECTED_STATIC_VISIBILITY;
101            }
102            return JavaDescriptorResolver.PROTECTED_AND_PACKAGE;
103        }
104        return JavaDescriptorResolver.PACKAGE_VISIBILITY;
105    }
106
107    @Nullable
108    public static ValueParameterDescriptor getValueParameterDescriptorForAnnotationParameter(
109            Name argumentName,
110            ClassDescriptor classDescriptor
111    ) {
112        Collection<ConstructorDescriptor> constructors = classDescriptor.getConstructors();
113        assert constructors.size() == 1 : "Annotation class descriptor must have only one constructor";
114        List<ValueParameterDescriptor> valueParameters = constructors.iterator().next().getValueParameters();
115
116        for (ValueParameterDescriptor parameter : valueParameters) {
117            Name parameterName = parameter.getName();
118            if (parameterName.equals(argumentName)) {
119                return parameter;
120            }
121        }
122        return null;
123    }
124
125    public static Visibility getConstructorVisibility(ClassDescriptor classDescriptor) {
126        Visibility containingClassVisibility = classDescriptor.getVisibility();
127        if (containingClassVisibility == JavaDescriptorResolver.PROTECTED_STATIC_VISIBILITY) {
128            return JavaDescriptorResolver.PROTECTED_AND_PACKAGE;
129        }
130        return containingClassVisibility;
131    }
132
133    public static void checkPsiClassIsNotJet(@Nullable PsiClass psiClass) {
134        if (psiClass instanceof JetJavaMirrorMarker) {
135            throw new IllegalStateException("trying to resolve fake jet PsiClass as regular PsiClass: " + psiClass.getQualifiedName());
136        }
137    }
138
139    @NotNull
140    public static FqNameUnsafe getFqNameForClassObject(@NotNull PsiClass psiClass) {
141        String psiClassQualifiedName = psiClass.getQualifiedName();
142        assert psiClassQualifiedName != null : "Reading java class with no qualified name";
143        return new FqNameUnsafe(psiClassQualifiedName + "." + getClassObjectName(psiClass.getName()).asString());
144    }
145
146    @NotNull
147    public static AnnotationDescriptor getAnnotationDescriptorForJavaLangDeprecated(ClassDescriptor classDescriptor) {
148        AnnotationDescriptor annotationDescriptor = new AnnotationDescriptor();
149        annotationDescriptor.setAnnotationType(classDescriptor.getDefaultType());
150        ValueParameterDescriptor value = getValueParameterDescriptorForAnnotationParameter(Name.identifier("value"), classDescriptor);
151        assert value != null : "jet.deprecated must have one parameter called value";
152        annotationDescriptor.setValueArgument(value, new StringValue("Deprecated in Java"));
153        return annotationDescriptor;
154    }
155
156    /**
157     * @return true if {@code member} is a static member of enum class, which is to be put into its class object (and not into the
158     * corresponding package). This applies to enum entries, values() and valueOf(String) methods
159     */
160    public static boolean shouldBeInEnumClassObject(@NotNull PsiMember member) {
161        PsiClass psiClass = member.getContainingClass();
162        if (psiClass == null || !psiClass.isEnum()) return false;
163
164        if (member instanceof PsiEnumConstant) return true;
165
166        if (!(member instanceof PsiMethod)) return false;
167        String signature = PsiFormatUtil.formatMethod((PsiMethod) member,
168                PsiSubstitutor.EMPTY, SHOW_NAME | SHOW_PARAMETERS, SHOW_TYPE | SHOW_FQ_CLASS_NAMES);
169
170        return "values()".equals(signature) ||
171               "valueOf(java.lang.String)".equals(signature);
172    }
173
174    public static boolean isCorrectOwnerForEnumMember(
175            @NotNull ClassOrNamespaceDescriptor ownerDescriptor,
176            @NotNull PsiMember member
177    ) {
178        return isEnumClassObject(ownerDescriptor) == shouldBeInEnumClassObject(member);
179    }
180}