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.scopes;
018    
019    import com.google.common.collect.Lists;
020    import com.google.common.collect.Sets;
021    import org.jetbrains.annotations.NotNull;
022    import org.jetbrains.jet.lang.descriptors.*;
023    import org.jetbrains.jet.lang.resolve.name.LabelName;
024    import org.jetbrains.jet.lang.resolve.name.Name;
025    
026    import java.util.Collection;
027    import java.util.Collections;
028    import java.util.List;
029    import java.util.Set;
030    
031    public class ChainedScope implements JetScope {
032        private final DeclarationDescriptor containingDeclaration;
033        private final String debugName;
034        private final JetScope[] scopeChain;
035        private Collection<DeclarationDescriptor> allDescriptors;
036        private List<ReceiverParameterDescriptor> implicitReceiverHierarchy;
037    
038        public ChainedScope(DeclarationDescriptor containingDeclaration, JetScope... scopes) {
039            this(containingDeclaration, "Untitled chained scope", scopes);
040        }
041    
042        public ChainedScope(DeclarationDescriptor containingDeclaration, String debugName, JetScope... scopes) {
043            this.containingDeclaration = containingDeclaration;
044            scopeChain = scopes.clone();
045    
046            this.debugName = debugName;
047        }
048    
049        @Override
050        public ClassifierDescriptor getClassifier(@NotNull Name name) {
051            for (JetScope scope : scopeChain) {
052                ClassifierDescriptor classifier = scope.getClassifier(name);
053                if (classifier != null) return classifier;
054            }
055            return null;
056        }
057    
058        @Override
059        public ClassDescriptor getObjectDescriptor(@NotNull Name name) {
060            for (JetScope scope : scopeChain) {
061                ClassDescriptor objectDescriptor = scope.getObjectDescriptor(name);
062                if (objectDescriptor != null) return objectDescriptor;
063            }
064            return null;
065        }
066    
067        @NotNull
068        @Override
069        public Set<ClassDescriptor> getObjectDescriptors() {
070            Set<ClassDescriptor> objectDescriptors = Sets.newHashSet();
071            for (JetScope scope : scopeChain) {
072                objectDescriptors.addAll(scope.getObjectDescriptors());
073            }
074            return objectDescriptors;
075        }
076    
077        @Override
078        public NamespaceDescriptor getNamespace(@NotNull Name name) {
079            for (JetScope jetScope : scopeChain) {
080                NamespaceDescriptor namespace = jetScope.getNamespace(name);
081                if (namespace != null) {
082                    return namespace;
083                }
084            }
085            return null;
086        }
087    
088        @NotNull
089        @Override
090        public Set<VariableDescriptor> getProperties(@NotNull Name name) {
091            Set<VariableDescriptor> properties = Sets.newLinkedHashSet();
092            for (JetScope jetScope : scopeChain) {
093                properties.addAll(jetScope.getProperties(name));
094            }
095            return properties;
096        }
097    
098        @Override
099        public VariableDescriptor getLocalVariable(@NotNull Name name) {
100            for (JetScope jetScope : scopeChain) {
101                VariableDescriptor variable = jetScope.getLocalVariable(name);
102                if (variable != null) {
103                    return variable;
104                }
105            }
106            return null;
107        }
108    
109        @NotNull
110        @Override
111        public Set<FunctionDescriptor> getFunctions(@NotNull Name name) {
112            if (scopeChain.length == 0) {
113                return Collections.emptySet();
114            }
115    
116            Set<FunctionDescriptor> result = Sets.newLinkedHashSet();
117            for (JetScope jetScope : scopeChain) {
118                result.addAll(jetScope.getFunctions(name));
119            }
120            return result;
121        }
122    
123        @NotNull
124        @Override
125        public List<ReceiverParameterDescriptor> getImplicitReceiversHierarchy() {
126            if (implicitReceiverHierarchy == null) {
127                implicitReceiverHierarchy = Lists.newArrayList();
128                for (JetScope jetScope : scopeChain) {
129                    implicitReceiverHierarchy.addAll(jetScope.getImplicitReceiversHierarchy());
130                }
131            }
132            return implicitReceiverHierarchy;
133        }
134    
135        @NotNull
136        @Override
137        public DeclarationDescriptor getContainingDeclaration() {
138            return containingDeclaration;
139        }
140    
141        @NotNull
142        @Override
143        public Collection<DeclarationDescriptor> getDeclarationsByLabel(@NotNull LabelName labelName) {
144            for (JetScope jetScope : scopeChain) {
145                Collection<DeclarationDescriptor> declarationsByLabel = jetScope.getDeclarationsByLabel(labelName);
146                if (!declarationsByLabel.isEmpty()) return declarationsByLabel; // TODO : merge?
147            }
148            return Collections.emptyList();
149        }
150    
151        @Override
152        public PropertyDescriptor getPropertyByFieldReference(@NotNull Name fieldName) {
153            for (JetScope jetScope : scopeChain) {
154                PropertyDescriptor propertyByFieldReference = jetScope.getPropertyByFieldReference(fieldName);
155                if (propertyByFieldReference != null) {
156                    return propertyByFieldReference;
157                }
158            }
159            return null;
160        }
161    
162        @NotNull
163        @Override
164        public Collection<DeclarationDescriptor> getAllDescriptors() {
165            if (allDescriptors == null) {
166                allDescriptors = Sets.newHashSet();
167                for (JetScope scope : scopeChain) {
168                    allDescriptors.addAll(scope.getAllDescriptors());
169                }
170            }
171            return allDescriptors;
172        }
173    
174        @NotNull
175        @Override
176        public Collection<DeclarationDescriptor> getOwnDeclaredDescriptors() {
177            throw new UnsupportedOperationException();
178        }
179    
180        @Override
181        public String toString() {
182            return debugName;
183        }
184    }