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.lazy;
018    
019    import com.intellij.psi.PsiElement;
020    import com.intellij.psi.util.PsiTreeUtil;
021    import org.jetbrains.annotations.NotNull;
022    import org.jetbrains.kotlin.context.GlobalContext;
023    import org.jetbrains.kotlin.descriptors.*;
024    import org.jetbrains.kotlin.name.FqName;
025    import org.jetbrains.kotlin.name.Name;
026    import org.jetbrains.kotlin.psi.*;
027    import org.jetbrains.kotlin.psi.psiUtil.PsiUtilPackage;
028    import org.jetbrains.kotlin.renderer.DescriptorRenderer;
029    import org.jetbrains.kotlin.resolve.AnnotationResolver;
030    import org.jetbrains.kotlin.resolve.BindingContext;
031    import org.jetbrains.kotlin.resolve.BindingTrace;
032    import org.jetbrains.kotlin.resolve.lazy.descriptors.LazyPackageDescriptor;
033    import org.jetbrains.kotlin.resolve.scopes.JetScope;
034    import org.jetbrains.kotlin.storage.LockBasedLazyResolveStorageManager;
035    
036    import javax.inject.Inject;
037    import java.util.List;
038    
039    public class LazyDeclarationResolver {
040    
041        private final BindingTrace trace;
042    
043        protected DeclarationScopeProvider scopeProvider;
044        private TopLevelDescriptorProvider topLevelDescriptorProvider;
045    
046        @Inject
047        public void setDeclarationScopeProvider(@NotNull DeclarationScopeProviderImpl scopeProvider) {
048            this.scopeProvider = scopeProvider;
049        }
050    
051        @Inject
052        public void setTopLevelDescriptorProvider(@NotNull TopLevelDescriptorProvider topLevelDescriptorProvider) {
053            this.topLevelDescriptorProvider = topLevelDescriptorProvider;
054        }
055    
056        @Deprecated
057        public LazyDeclarationResolver(
058                @NotNull GlobalContext globalContext,
059                @NotNull BindingTrace delegationTrace
060        ) {
061            LockBasedLazyResolveStorageManager lockBasedLazyResolveStorageManager =
062                    new LockBasedLazyResolveStorageManager(globalContext.getStorageManager());
063    
064            this.trace = lockBasedLazyResolveStorageManager.createSafeTrace(delegationTrace);
065        }
066    
067        @NotNull
068        public ClassDescriptor getClassDescriptor(@NotNull JetClassOrObject classOrObject) {
069            JetScope resolutionScope = resolutionScopeToResolveDeclaration(classOrObject);
070    
071            // Why not use the result here. Because it may be that there is a redeclaration:
072            //     class A {} class A { fun foo(): A<completion here>}
073            // and if we find the class by name only, we may b-not get the right one.
074            // This call is only needed to make sure the classes are written to trace
075            ClassifierDescriptor scopeDescriptor = resolutionScope.getClassifier(classOrObject.getNameAsSafeName());
076            DeclarationDescriptor descriptor = getBindingContext().get(BindingContext.DECLARATION_TO_DESCRIPTOR, classOrObject);
077    
078            if (descriptor == null) {
079                throw new IllegalArgumentException(
080                       String.format("Could not find a classifier for %s.\n" +
081                                     "Found descriptor: %s (%s).\n",
082                                     PsiUtilPackage.getElementTextWithContext(classOrObject),
083                                     scopeDescriptor != null ? DescriptorRenderer.DEBUG_TEXT.render(scopeDescriptor) : "null",
084                                     scopeDescriptor != null ? (scopeDescriptor.getContainingDeclaration().getClass()) : null));
085            }
086    
087            return (ClassDescriptor) descriptor;
088        }
089    
090        @NotNull
091        private BindingContext getBindingContext() {
092            return trace.getBindingContext();
093        }
094    
095        @NotNull
096        public DeclarationDescriptor resolveToDescriptor(@NotNull JetDeclaration declaration) {
097            DeclarationDescriptor result = declaration.accept(new JetVisitor<DeclarationDescriptor, Void>() {
098                @Override
099                public DeclarationDescriptor visitClass(@NotNull JetClass klass, Void data) {
100                    return getClassDescriptor(klass);
101                }
102    
103                @Override
104                public DeclarationDescriptor visitObjectDeclaration(@NotNull JetObjectDeclaration declaration, Void data) {
105                    return getClassDescriptor(declaration);
106                }
107    
108                @Override
109                public DeclarationDescriptor visitTypeParameter(@NotNull JetTypeParameter parameter, Void data) {
110                    JetTypeParameterListOwner ownerElement = PsiTreeUtil.getParentOfType(parameter, JetTypeParameterListOwner.class);
111                    DeclarationDescriptor ownerDescriptor = resolveToDescriptor(ownerElement);
112    
113                    List<TypeParameterDescriptor> typeParameters;
114                    if (ownerDescriptor instanceof CallableDescriptor) {
115                        CallableDescriptor callableDescriptor = (CallableDescriptor) ownerDescriptor;
116                        typeParameters = callableDescriptor.getTypeParameters();
117                    }
118                    else if (ownerDescriptor instanceof ClassDescriptor) {
119                        ClassDescriptor classDescriptor = (ClassDescriptor) ownerDescriptor;
120                        typeParameters = classDescriptor.getTypeConstructor().getParameters();
121                    }
122                    else {
123                        throw new IllegalStateException("Unknown owner kind for a type parameter: " + ownerDescriptor);
124                    }
125    
126                    Name name = parameter.getNameAsSafeName();
127                    for (TypeParameterDescriptor typeParameterDescriptor : typeParameters) {
128                        if (typeParameterDescriptor.getName().equals(name)) {
129                            return typeParameterDescriptor;
130                        }
131                    }
132    
133                    throw new IllegalStateException("Type parameter " + name + " not found for " + ownerDescriptor);
134                }
135    
136                @Override
137                public DeclarationDescriptor visitNamedFunction(@NotNull JetNamedFunction function, Void data) {
138                    JetScope scopeForDeclaration = resolutionScopeToResolveDeclaration(function);
139                    scopeForDeclaration.getFunctions(function.getNameAsSafeName());
140                    return getBindingContext().get(BindingContext.DECLARATION_TO_DESCRIPTOR, function);
141                }
142    
143                @Override
144                public DeclarationDescriptor visitParameter(@NotNull JetParameter parameter, Void data) {
145                    PsiElement grandFather = parameter.getParent().getParent();
146                    if (grandFather instanceof JetPrimaryConstructor) {
147                        JetClassOrObject jetClass = ((JetPrimaryConstructor) grandFather).getContainingClassOrObject();
148                        // This is a primary constructor parameter
149                        ClassDescriptor classDescriptor = getClassDescriptor(jetClass);
150                        if (parameter.hasValOrVarNode()) {
151                            classDescriptor.getDefaultType().getMemberScope().getProperties(parameter.getNameAsSafeName());
152                            return getBindingContext().get(BindingContext.PRIMARY_CONSTRUCTOR_PARAMETER, parameter);
153                        }
154                        else {
155                            ConstructorDescriptor constructor = classDescriptor.getUnsubstitutedPrimaryConstructor();
156                            assert constructor != null: "There are constructor parameters found, so a constructor should also exist";
157                            constructor.getValueParameters();
158                            return getBindingContext().get(BindingContext.VALUE_PARAMETER, parameter);
159                        }
160                    }
161                    else if (grandFather instanceof JetNamedFunction) {
162                        FunctionDescriptor function = (FunctionDescriptor) visitNamedFunction((JetNamedFunction) grandFather, data);
163                        function.getValueParameters();
164                        return getBindingContext().get(BindingContext.VALUE_PARAMETER, parameter);
165                    }
166                    else if (grandFather instanceof JetSecondaryConstructor) {
167                        ConstructorDescriptor constructorDescriptor = (ConstructorDescriptor) visitSecondaryConstructor(
168                                (JetSecondaryConstructor) grandFather, data
169                        );
170                        constructorDescriptor.getValueParameters();
171                        return getBindingContext().get(BindingContext.VALUE_PARAMETER, parameter);
172                    }
173                    else {
174                        //TODO: support parameters in accessors and other places(?)
175                        return super.visitParameter(parameter, data);
176                    }
177                }
178    
179                @Override
180                public DeclarationDescriptor visitSecondaryConstructor(@NotNull JetSecondaryConstructor constructor, Void data) {
181                    getClassDescriptor((JetClassOrObject) constructor.getParent().getParent()).getConstructors();
182                    return getBindingContext().get(BindingContext.CONSTRUCTOR, constructor);
183                }
184    
185                @Override
186                public DeclarationDescriptor visitPrimaryConstructor(@NotNull JetPrimaryConstructor constructor, Void data) {
187                    JetClassOrObject klass = constructor.getContainingClassOrObject();
188                    getClassDescriptor(klass).getConstructors();
189                    return getBindingContext().get(BindingContext.CONSTRUCTOR, klass);
190                }
191    
192                @Override
193                public DeclarationDescriptor visitProperty(@NotNull JetProperty property, Void data) {
194                    JetScope scopeForDeclaration = resolutionScopeToResolveDeclaration(property);
195                    scopeForDeclaration.getProperties(property.getNameAsSafeName());
196                    return getBindingContext().get(BindingContext.DECLARATION_TO_DESCRIPTOR, property);
197                }
198    
199                @Override
200                public DeclarationDescriptor visitScript(@NotNull JetScript script, Void data) {
201                    return topLevelDescriptorProvider.getScriptDescriptor(script);
202                }
203    
204                @Override
205                public DeclarationDescriptor visitJetElement(@NotNull JetElement element, Void data) {
206                    throw new IllegalArgumentException("Unsupported declaration type: " + element + " " +
207                                                       PsiUtilPackage.getElementTextWithContext(element));
208                }
209            }, null);
210            if (result == null) {
211                throw new IllegalStateException("No descriptor resolved for " + declaration + ":\n" +
212                                                PsiUtilPackage.getElementTextWithContext(declaration));
213            }
214            AnnotationResolver.resolveAnnotationsArguments(result.getAnnotations());
215            return result;
216        }
217    
218        @NotNull
219        /*package*/ JetScope resolutionScopeToResolveDeclaration(@NotNull JetDeclaration declaration) {
220            boolean isTopLevel = JetStubbedPsiUtil.getContainingDeclaration(declaration) == null;
221            if (isTopLevel) { // for top level declarations we search directly in package because of possible conflicts with imports
222                FqName fqName = ((JetFile) declaration.getContainingFile()).getPackageFqName();
223                LazyPackageDescriptor packageDescriptor = topLevelDescriptorProvider.getPackageFragment(fqName);
224                assert packageDescriptor != null;
225                return packageDescriptor.getMemberScope();
226            }
227            else {
228                return scopeProvider.getResolutionScopeForDeclaration(declaration);
229            }
230        }
231    }