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.Multimap;
021import com.google.common.collect.Sets;
022import org.jetbrains.annotations.NotNull;
023import org.jetbrains.annotations.Nullable;
024import org.jetbrains.jet.lang.descriptors.*;
025import org.jetbrains.jet.lang.resolve.name.LabelName;
026import org.jetbrains.jet.lang.resolve.name.Name;
027
028import java.util.Collection;
029import java.util.Set;
030
031public class WriteThroughScope extends WritableScopeWithImports {
032    private final WritableScope writableWorker;
033    private Collection<DeclarationDescriptor> allDescriptors;
034
035    public WriteThroughScope(@NotNull JetScope outerScope, @NotNull WritableScope scope,
036            @NotNull RedeclarationHandler redeclarationHandler, @NotNull String debugName) {
037        super(outerScope, redeclarationHandler, debugName);
038        this.writableWorker = scope;
039    }
040
041    @Override
042    @Nullable
043    public PropertyDescriptor getPropertyByFieldReference(@NotNull Name fieldName) {
044        checkMayRead();
045
046        return writableWorker.getPropertyByFieldReference(fieldName);
047    }
048
049    @Override
050    @NotNull
051    public Collection<DeclarationDescriptor> getDeclarationsByLabel(LabelName labelName) {
052        checkMayRead();
053
054        return writableWorker.getDeclarationsByLabel(labelName);
055    }
056
057    @Override
058    @NotNull
059    public DeclarationDescriptor getContainingDeclaration() {
060        checkMayRead();
061
062        return writableWorker.getContainingDeclaration();
063    }
064
065    @Override
066    @NotNull
067    public Collection<FunctionDescriptor> getFunctions(@NotNull Name name) {
068        checkMayRead();
069
070        Set<FunctionDescriptor> result = Sets.newLinkedHashSet();
071
072        result.addAll(writableWorker.getFunctions(name));
073
074        result.addAll(getWorkerScope().getFunctions(name));
075
076        result.addAll(super.getFunctions(name)); // Imports
077
078        return result;
079    }
080
081    @Override
082    @NotNull
083    public Set<VariableDescriptor> getProperties(@NotNull Name name) {
084        checkMayRead();
085
086        Set<VariableDescriptor> properties = Sets.newLinkedHashSet();
087        properties.addAll(writableWorker.getProperties(name));
088        properties.addAll(getWorkerScope().getProperties(name));
089        properties.addAll(super.getProperties(name)); //imports
090        return properties;
091    }
092
093    @Override
094    @Nullable
095    public VariableDescriptor getLocalVariable(@NotNull Name name) {
096        checkMayRead();
097
098        VariableDescriptor variable = writableWorker.getLocalVariable(name);
099        if (variable != null) return variable;
100
101        variable = getWorkerScope().getLocalVariable(name);
102        if (variable != null) return variable;
103
104        return super.getLocalVariable(name); // Imports
105    }
106
107    @Override
108    @Nullable
109    public NamespaceDescriptor getNamespace(@NotNull Name name) {
110        checkMayRead();
111
112        NamespaceDescriptor namespace = writableWorker.getNamespace(name);
113        if (namespace != null) return namespace;
114
115        namespace = getWorkerScope().getNamespace(name);
116        if (namespace != null) return namespace;
117
118        return super.getNamespace(name); // Imports
119    }
120
121    @Override
122    @Nullable
123    public ClassifierDescriptor getClassifier(@NotNull Name name) {
124        checkMayRead();
125
126        ClassifierDescriptor classifier = writableWorker.getClassifier(name);
127        if (classifier != null) return classifier;
128
129        classifier = getWorkerScope().getClassifier(name);
130        if (classifier != null) return classifier;
131
132        return super.getClassifier(name); // Imports
133    }
134
135    @Override
136    public ClassDescriptor getObjectDescriptor(@NotNull Name name) {
137        checkMayRead();
138
139        ClassDescriptor objectDescriptor = writableWorker.getObjectDescriptor(name);
140        if (objectDescriptor != null) return objectDescriptor;
141
142        objectDescriptor = getWorkerScope().getObjectDescriptor(name);
143        if (objectDescriptor != null) return objectDescriptor;
144
145        return super.getObjectDescriptor(name); // Imports
146    }
147
148    @NotNull
149    @Override
150    public Set<ClassDescriptor> getObjectDescriptors() {
151        checkMayRead();
152        Set<ClassDescriptor> objectDescriptors = Sets.newHashSet();
153
154        objectDescriptors.addAll(super.getObjectDescriptors());
155        objectDescriptors.addAll(getWorkerScope().getObjectDescriptors());
156        objectDescriptors.addAll(writableWorker.getObjectDescriptors());
157        return objectDescriptors;
158    }
159
160    @Override
161    public void addLabeledDeclaration(@NotNull DeclarationDescriptor descriptor) {
162        checkMayWrite();
163
164        writableWorker.addLabeledDeclaration(descriptor); // TODO : review
165    }
166
167    @Override
168    public void addVariableDescriptor(@NotNull VariableDescriptor variableDescriptor) {
169        checkMayWrite();
170
171        writableWorker.addVariableDescriptor(variableDescriptor);
172    }
173
174    @Override
175    public void addPropertyDescriptor(@NotNull VariableDescriptor propertyDescriptor) {
176        checkMayWrite();
177
178        writableWorker.addPropertyDescriptor(propertyDescriptor);
179    }
180
181    @Override
182    public void addFunctionDescriptor(@NotNull FunctionDescriptor functionDescriptor) {
183        checkMayWrite();
184
185        writableWorker.addFunctionDescriptor(functionDescriptor);
186    }
187
188    @Override
189    public void addTypeParameterDescriptor(@NotNull TypeParameterDescriptor typeParameterDescriptor) {
190        checkMayWrite();
191
192        writableWorker.addTypeParameterDescriptor(typeParameterDescriptor);
193    }
194
195    @Override
196    public void addClassifierDescriptor(@NotNull ClassifierDescriptor classDescriptor) {
197        checkMayWrite();
198
199        writableWorker.addClassifierDescriptor(classDescriptor);
200    }
201
202    @Override
203    public void addObjectDescriptor(@NotNull ClassDescriptor objectDescriptor) {
204        checkMayWrite();
205
206        writableWorker.addObjectDescriptor(objectDescriptor);
207    }
208
209    @Override
210    public void addClassifierAlias(@NotNull Name name, @NotNull ClassifierDescriptor classifierDescriptor) {
211        checkMayWrite();
212
213        writableWorker.addClassifierAlias(name, classifierDescriptor);
214    }
215
216    @Override
217    public void addNamespaceAlias(@NotNull Name name, @NotNull NamespaceDescriptor namespaceDescriptor) {
218        checkMayWrite();
219
220        writableWorker.addNamespaceAlias(name, namespaceDescriptor);
221    }
222
223    @Override
224    public void addVariableAlias(@NotNull Name name, @NotNull VariableDescriptor variableDescriptor) {
225        checkMayWrite();
226        
227        writableWorker.addVariableAlias(name, variableDescriptor);
228    }
229
230    @Override
231    public void addFunctionAlias(@NotNull Name name, @NotNull FunctionDescriptor functionDescriptor) {
232        checkMayWrite();
233
234        writableWorker.addFunctionAlias(name, functionDescriptor);
235    }
236
237    @Override
238    public void addNamespace(@NotNull NamespaceDescriptor namespaceDescriptor) {
239        checkMayWrite();
240
241        writableWorker.addNamespace(namespaceDescriptor);
242    }
243
244    @Override
245    @Nullable
246    public NamespaceDescriptor getDeclaredNamespace(@NotNull Name name) {
247        checkMayRead();
248
249        return writableWorker.getDeclaredNamespace(name);
250    }
251
252    @NotNull
253    @Override
254    public Multimap<Name, DeclarationDescriptor> getDeclaredDescriptorsAccessibleBySimpleName() {
255        return writableWorker.getDeclaredDescriptorsAccessibleBySimpleName();
256    }
257
258    @Override
259    public void importScope(@NotNull JetScope imported) {
260        checkMayWrite();
261
262        super.importScope(imported); //
263    }
264
265    @Override
266    public void setImplicitReceiver(@NotNull ReceiverParameterDescriptor implicitReceiver) {
267        checkMayWrite();
268
269        writableWorker.setImplicitReceiver(implicitReceiver);
270    }
271
272    @NotNull
273    @Override
274    public Collection<DeclarationDescriptor> getAllDescriptors() {
275        checkMayRead();
276
277        if (allDescriptors == null) {
278            allDescriptors = Lists.newArrayList();
279            allDescriptors.addAll(writableWorker.getAllDescriptors());
280            allDescriptors.addAll(getWorkerScope().getAllDescriptors());
281
282            for (JetScope imported : getImports()) {
283                allDescriptors.addAll(imported.getAllDescriptors());
284            }
285        }
286        return allDescriptors;
287    }
288
289    @NotNull
290    public JetScope getOuterScope() {
291        checkMayRead();
292
293        return getWorkerScope();
294    }
295}