001    /*
002     * Copyright 2010-2015 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.kotlin.resolve;
018    
019    import com.google.common.collect.Lists;
020    import com.intellij.psi.PsiElement;
021    import com.intellij.psi.PsiFile;
022    import org.jetbrains.annotations.NotNull;
023    import org.jetbrains.annotations.Nullable;
024    import org.jetbrains.kotlin.descriptors.*;
025    import org.jetbrains.kotlin.psi.JetFile;
026    import org.jetbrains.kotlin.resolve.source.SourcePackage;
027    
028    import java.util.ArrayList;
029    import java.util.List;
030    import java.util.Set;
031    
032    import static org.jetbrains.kotlin.descriptors.CallableMemberDescriptor.Kind.DECLARATION;
033    import static org.jetbrains.kotlin.descriptors.CallableMemberDescriptor.Kind.SYNTHESIZED;
034    
035    public final class DescriptorToSourceUtils {
036    
037        @Nullable
038        private static PsiElement doGetDescriptorToDeclaration(@NotNull DeclarationDescriptor descriptor) {
039            DeclarationDescriptor original = descriptor.getOriginal();
040            if (!(original instanceof DeclarationDescriptorWithSource)) {
041                return null;
042            }
043            return SourcePackage.getPsi(((DeclarationDescriptorWithSource) original).getSource());
044        }
045    
046        // NOTE this is also used by KDoc
047        @Nullable
048        public static PsiElement descriptorToDeclaration(@NotNull DeclarationDescriptor descriptor) {
049            if (descriptor instanceof CallableMemberDescriptor) {
050                return callableDescriptorToDeclaration((CallableMemberDescriptor) descriptor);
051            }
052            else if (descriptor instanceof ClassDescriptor) {
053                return classDescriptorToDeclaration((ClassDescriptor) descriptor);
054            }
055            else {
056                return doGetDescriptorToDeclaration(descriptor);
057            }
058        }
059    
060        @NotNull
061        public static List<PsiElement> descriptorToDeclarations(@NotNull DeclarationDescriptor descriptor) {
062            if (descriptor instanceof CallableMemberDescriptor) {
063                return callableDescriptorToDeclarations((CallableMemberDescriptor) descriptor);
064            }
065            else {
066                PsiElement psiElement = descriptorToDeclaration(descriptor);
067                if (psiElement != null) {
068                    return Lists.newArrayList(psiElement);
069                } else {
070                    return Lists.newArrayList();
071                }
072            }
073        }
074    
075        @Nullable
076        public static PsiElement callableDescriptorToDeclaration(@NotNull CallableMemberDescriptor callable) {
077            if (callable.getKind() == DECLARATION || callable.getKind() == SYNTHESIZED) {
078                return doGetDescriptorToDeclaration(callable);
079            }
080            //TODO: should not use this method for fake_override and delegation
081            Set<? extends CallableMemberDescriptor> overriddenDescriptors = callable.getOverriddenDescriptors();
082            if (overriddenDescriptors.size() == 1) {
083                return callableDescriptorToDeclaration(overriddenDescriptors.iterator().next());
084            }
085            return null;
086        }
087    
088        @NotNull
089        public static List<PsiElement> callableDescriptorToDeclarations(@NotNull CallableMemberDescriptor callable) {
090            if (callable.getKind() == DECLARATION || callable.getKind() == SYNTHESIZED) {
091                PsiElement psiElement = doGetDescriptorToDeclaration(callable);
092                return psiElement != null ? Lists.newArrayList(psiElement) : Lists.<PsiElement>newArrayList();
093            }
094    
095            List<PsiElement> r = new ArrayList<PsiElement>();
096            Set<? extends CallableMemberDescriptor> overriddenDescriptors = callable.getOverriddenDescriptors();
097            for (CallableMemberDescriptor overridden : overriddenDescriptors) {
098                r.addAll(callableDescriptorToDeclarations(overridden));
099            }
100            return r;
101        }
102    
103        @Nullable
104        public static PsiElement classDescriptorToDeclaration(@NotNull ClassDescriptor clazz) {
105            return doGetDescriptorToDeclaration(clazz);
106        }
107    
108        private DescriptorToSourceUtils() {}
109    
110        @Nullable
111        public static JetFile getContainingFile(@NotNull DeclarationDescriptor declarationDescriptor) {
112            // declarationDescriptor may describe a synthesized element which doesn't have PSI
113            // To workaround that, we find a top-level parent (which is inside a PackageFragmentDescriptor), which is guaranteed to have PSI
114            DeclarationDescriptor descriptor = findTopLevelParent(declarationDescriptor);
115            if (descriptor == null) return null;
116    
117            PsiElement declaration = descriptorToDeclaration(descriptor);
118            if (declaration == null) return null;
119    
120            PsiFile containingFile = declaration.getContainingFile();
121            if (!(containingFile instanceof JetFile)) return null;
122            return (JetFile) containingFile;
123        }
124    
125        @Nullable
126        private static DeclarationDescriptor findTopLevelParent(@NotNull DeclarationDescriptor declarationDescriptor) {
127            DeclarationDescriptor descriptor = declarationDescriptor;
128            if (declarationDescriptor instanceof PropertyAccessorDescriptor) {
129                descriptor = ((PropertyAccessorDescriptor) descriptor).getCorrespondingProperty();
130            }
131            while (!(descriptor == null || DescriptorUtils.isTopLevelDeclaration(descriptor))) {
132                descriptor = descriptor.getContainingDeclaration();
133            }
134            return descriptor;
135        }
136    }
137    
138