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
017package org.jetbrains.jet.lang.resolve.scopes;
018
019import com.google.common.collect.Lists;
020import com.google.common.collect.Sets;
021import org.jetbrains.annotations.NotNull;
022import org.jetbrains.jet.lang.descriptors.*;
023import org.jetbrains.jet.lang.resolve.name.LabelName;
024import org.jetbrains.jet.lang.resolve.name.Name;
025
026import java.util.Collection;
027import java.util.Collections;
028import java.util.List;
029import java.util.Set;
030
031public 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}