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.Maps; 020import com.google.common.collect.Sets; 021import org.jetbrains.annotations.NotNull; 022import org.jetbrains.annotations.Nullable; 023import org.jetbrains.jet.lang.descriptors.*; 024import org.jetbrains.jet.lang.resolve.name.LabelName; 025import org.jetbrains.jet.lang.resolve.name.Name; 026import org.jetbrains.jet.lang.types.TypeSubstitutor; 027 028import java.util.Collection; 029import java.util.List; 030import java.util.Map; 031import java.util.Set; 032 033public class SubstitutingScope implements JetScope { 034 035 private final JetScope workerScope; 036 private final TypeSubstitutor substitutor; 037 038 private Map<DeclarationDescriptor, DeclarationDescriptor> substitutedDescriptors = null; 039 private Collection<DeclarationDescriptor> allDescriptors = null; 040 041 public SubstitutingScope(JetScope workerScope, @NotNull TypeSubstitutor substitutor) { 042 this.workerScope = workerScope; 043 this.substitutor = substitutor; 044 } 045 046 @Nullable 047 private <D extends DeclarationDescriptor> D substitute(@Nullable D descriptor) { 048 if (descriptor == null) return null; 049 if (substitutor.isEmpty()) return descriptor; 050 051 if (substitutedDescriptors == null) { 052 substitutedDescriptors = Maps.newHashMap(); 053 } 054 055 DeclarationDescriptor substituted = substitutedDescriptors.get(descriptor); 056 if (substituted == null && !substitutedDescriptors.containsKey(descriptor)) { 057 substituted = descriptor.substitute(substitutor); 058 059 //noinspection ConstantConditions 060 substitutedDescriptors.put(descriptor, substituted); 061 } 062 063 //noinspection unchecked 064 return (D) substituted; 065 } 066 067 @NotNull 068 private <D extends DeclarationDescriptor> Collection<D> substitute(@NotNull Collection<D> descriptors) { 069 if (substitutor.isEmpty()) return descriptors; 070 if (descriptors.isEmpty()) return descriptors; 071 072 Set<D> result = Sets.newHashSetWithExpectedSize(descriptors.size()); 073 for (D descriptor : descriptors) { 074 D substitute = substitute(descriptor); 075 if (substitute != null) { 076 result.add(substitute); 077 } 078 } 079 080 return result; 081 } 082 083 @NotNull 084 @Override 085 public Collection<VariableDescriptor> getProperties(@NotNull Name name) { 086 return substitute(workerScope.getProperties(name)); 087 } 088 089 @Override 090 public VariableDescriptor getLocalVariable(@NotNull Name name) { 091 return substitute(workerScope.getLocalVariable(name)); 092 } 093 094 @Override 095 public ClassifierDescriptor getClassifier(@NotNull Name name) { 096 return substitute(workerScope.getClassifier(name)); 097 } 098 099 @Override 100 public ClassDescriptor getObjectDescriptor(@NotNull Name name) { 101 return substitute(workerScope.getObjectDescriptor(name)); 102 } 103 104 @NotNull 105 @Override 106 public Collection<ClassDescriptor> getObjectDescriptors() { 107 return substitute(workerScope.getObjectDescriptors()); 108 } 109 110 @NotNull 111 @Override 112 public Collection<FunctionDescriptor> getFunctions(@NotNull Name name) { 113 return substitute(workerScope.getFunctions(name)); 114 } 115 116 @Override 117 public NamespaceDescriptor getNamespace(@NotNull Name name) { 118 return workerScope.getNamespace(name); // TODO 119 } 120 121 @NotNull 122 @Override 123 public List<ReceiverParameterDescriptor> getImplicitReceiversHierarchy() { 124 throw new UnsupportedOperationException(); // TODO 125 } 126 127 @NotNull 128 @Override 129 public DeclarationDescriptor getContainingDeclaration() { 130 return workerScope.getContainingDeclaration(); 131 } 132 133 @NotNull 134 @Override 135 public Collection<DeclarationDescriptor> getDeclarationsByLabel(@NotNull LabelName labelName) { 136 throw new UnsupportedOperationException(); // TODO 137 } 138 139 @Override 140 public PropertyDescriptor getPropertyByFieldReference(@NotNull Name fieldName) { 141 throw new UnsupportedOperationException(); // TODO 142 } 143 144 @NotNull 145 @Override 146 public Collection<DeclarationDescriptor> getAllDescriptors() { 147 if (allDescriptors == null) { 148 allDescriptors = substitute(workerScope.getAllDescriptors()); 149 } 150 return allDescriptors; 151 } 152 153 @NotNull 154 @Override 155 public Collection<DeclarationDescriptor> getOwnDeclaredDescriptors() { 156 return substitute(workerScope.getOwnDeclaredDescriptors()); 157 } 158}