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