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    
017    package org.jetbrains.jet.lang.resolve.java;
018    
019    import com.intellij.psi.*;
020    import com.intellij.psi.util.PsiFormatUtil;
021    import org.jetbrains.annotations.NotNull;
022    import org.jetbrains.annotations.Nullable;
023    import org.jetbrains.jet.lang.descriptors.*;
024    import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
025    import org.jetbrains.jet.lang.resolve.constants.StringValue;
026    import org.jetbrains.jet.lang.resolve.java.kt.PsiAnnotationWithFlags;
027    import org.jetbrains.jet.lang.resolve.java.wrapper.PsiClassWrapper;
028    import org.jetbrains.jet.lang.resolve.java.wrapper.PsiMemberWrapper;
029    import org.jetbrains.jet.lang.resolve.java.wrapper.PsiMethodWrapper;
030    import org.jetbrains.jet.lang.resolve.name.FqName;
031    import org.jetbrains.jet.lang.resolve.name.FqNameUnsafe;
032    import org.jetbrains.jet.lang.resolve.name.Name;
033    import org.jetbrains.jet.lang.types.JetType;
034    
035    import java.util.Collection;
036    import java.util.Collections;
037    import java.util.List;
038    
039    import static com.intellij.psi.util.PsiFormatUtilBase.*;
040    import static org.jetbrains.jet.lang.resolve.DescriptorUtils.getClassObjectName;
041    import static org.jetbrains.jet.lang.resolve.DescriptorUtils.isEnumClassObject;
042    
043    public 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    }