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;
018
019 import com.google.common.collect.Sets;
020 import com.intellij.psi.PsiElement;
021 import org.jetbrains.annotations.NotNull;
022 import org.jetbrains.annotations.Nullable;
023 import org.jetbrains.jet.lang.descriptors.ModuleDescriptorImpl;
024 import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor;
025 import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
026 import org.jetbrains.jet.lang.descriptors.impl.NamespaceDescriptorImpl;
027 import org.jetbrains.jet.lang.descriptors.impl.NamespaceDescriptorParent;
028 import org.jetbrains.jet.lang.psi.JetFile;
029 import org.jetbrains.jet.lang.psi.JetNamespaceHeader;
030 import org.jetbrains.jet.lang.psi.JetReferenceExpression;
031 import org.jetbrains.jet.lang.psi.JetSimpleNameExpression;
032 import org.jetbrains.jet.lang.resolve.name.FqName;
033 import org.jetbrains.jet.lang.resolve.name.FqNameUnsafe;
034 import org.jetbrains.jet.lang.resolve.name.Name;
035 import org.jetbrains.jet.lang.resolve.scopes.JetScope;
036 import org.jetbrains.jet.lang.resolve.scopes.RedeclarationHandler;
037 import org.jetbrains.jet.lang.resolve.scopes.WritableScope;
038 import org.jetbrains.jet.lang.resolve.scopes.WritableScopeImpl;
039
040 import javax.inject.Inject;
041 import java.util.Collection;
042 import java.util.Collections;
043
044 import static org.jetbrains.jet.lang.resolve.BindingContext.*;
045
046 public class NamespaceFactoryImpl implements NamespaceFactory {
047
048 private ModuleDescriptorImpl moduleDescriptor;
049 private BindingTrace trace;
050
051 @Inject
052 public void setModuleDescriptor(ModuleDescriptorImpl moduleDescriptor) {
053 this.moduleDescriptor = moduleDescriptor;
054 }
055
056 @Inject
057 public void setTrace(BindingTrace trace) {
058 this.trace = trace;
059 }
060
061 @NotNull
062 public NamespaceDescriptorImpl createNamespaceDescriptorPathIfNeeded(@NotNull JetFile file,
063 @NotNull JetScope outerScope,
064 @NotNull RedeclarationHandler handler) {
065 JetNamespaceHeader namespaceHeader = file.getNamespaceHeader();
066
067 if (moduleDescriptor.getRootNamespaceDescriptorImpl() == null) {
068 createRootNamespaceDescriptorIfNeeded(null, moduleDescriptor, null, handler);
069 }
070
071 NamespaceDescriptorImpl currentOwner = moduleDescriptor.getRootNamespaceDescriptorImpl();
072 if (currentOwner == null) {
073 throw new IllegalStateException("must be initialized 5 lines above");
074 }
075
076 for (JetSimpleNameExpression nameExpression : namespaceHeader.getParentNamespaceNames()) {
077 Name namespaceName = Name.identifier(nameExpression.getReferencedName());
078
079 NamespaceDescriptorImpl namespaceDescriptor = createNamespaceDescriptorIfNeeded(
080 null, currentOwner, namespaceName, nameExpression, handler);
081
082 trace.record(BindingContext.NAMESPACE_IS_SRC, namespaceDescriptor, true);
083 trace.record(RESOLUTION_SCOPE, nameExpression, outerScope);
084
085 outerScope = namespaceDescriptor.getMemberScope();
086 currentOwner = namespaceDescriptor;
087 }
088
089 NamespaceDescriptorImpl namespaceDescriptor;
090 Name name;
091 if (namespaceHeader.isRoot()) {
092 // previous call to createRootNamespaceDescriptorIfNeeded couldn't store occurrence for current file.
093 namespaceDescriptor = moduleDescriptor.getRootNamespaceDescriptorImpl();
094 storeBindingForFileAndExpression(file, null, namespaceDescriptor);
095 }
096 else {
097 name = namespaceHeader.getNameAsName();
098 namespaceDescriptor = createNamespaceDescriptorIfNeeded(
099 file, currentOwner, name, namespaceHeader.getLastPartExpression(), handler);
100
101 trace.record(RESOLUTION_SCOPE, namespaceHeader, outerScope);
102 }
103 trace.record(BindingContext.NAMESPACE_IS_SRC, namespaceDescriptor, true);
104
105 return namespaceDescriptor;
106 }
107
108 @Override
109 @NotNull
110 public NamespaceDescriptorImpl createNamespaceDescriptorPathIfNeeded(@NotNull FqName fqName) {
111 NamespaceDescriptorImpl owner = null;
112 for (FqName pathElement : fqName.path()) {
113 if (pathElement.isRoot()) {
114 owner = createRootNamespaceDescriptorIfNeeded(null,
115 moduleDescriptor,
116 null,
117 RedeclarationHandler.DO_NOTHING);
118 }
119 else {
120 assert owner != null : "Should never be null as first element in the path must be root";
121 owner = createNamespaceDescriptorIfNeeded(null,
122 owner,
123 pathElement.shortName(),
124 null,
125 RedeclarationHandler.DO_NOTHING);
126 }
127
128 }
129
130 assert owner != null : "Should never be null as first element in the path must be root";
131 return owner;
132 }
133
134 private NamespaceDescriptorImpl createRootNamespaceDescriptorIfNeeded(@Nullable JetFile file,
135 @NotNull ModuleDescriptorImpl owner,
136 @Nullable JetReferenceExpression expression,
137 @NotNull RedeclarationHandler handler) {
138 FqName fqName = FqName.ROOT;
139 NamespaceDescriptorImpl namespaceDescriptor = owner.getRootNamespaceDescriptorImpl();
140
141 if (namespaceDescriptor == null) {
142 namespaceDescriptor = createNewNamespaceDescriptor(owner, FqNameUnsafe.ROOT_NAME, expression, handler, fqName);
143 }
144
145 storeBindingForFileAndExpression(file, expression, namespaceDescriptor);
146
147 return namespaceDescriptor;
148 }
149
150 @NotNull
151 private NamespaceDescriptorImpl createNamespaceDescriptorIfNeeded(@Nullable JetFile file,
152 @NotNull NamespaceDescriptorImpl owner,
153 @NotNull Name name,
154 @Nullable JetReferenceExpression expression,
155 @NotNull RedeclarationHandler handler) {
156 FqName ownerFqName = DescriptorUtils.getFQName(owner).toSafe();
157 FqName fqName = ownerFqName.child(name);
158 // !!!
159 NamespaceDescriptorImpl namespaceDescriptor = (NamespaceDescriptorImpl) owner.getMemberScope().getDeclaredNamespace(name);
160
161 if (namespaceDescriptor == null) {
162 namespaceDescriptor = createNewNamespaceDescriptor(owner, name, expression, handler, fqName);
163 }
164
165 storeBindingForFileAndExpression(file, expression, namespaceDescriptor);
166
167 return namespaceDescriptor;
168 }
169
170 private NamespaceDescriptorImpl createNewNamespaceDescriptor(NamespaceDescriptorParent owner,
171 Name name,
172 PsiElement expression,
173 RedeclarationHandler handler,
174 FqName fqName) {
175 NamespaceDescriptorImpl namespaceDescriptor;
176 namespaceDescriptor = new NamespaceDescriptorImpl(
177 owner,
178 Collections.<AnnotationDescriptor>emptyList(), // TODO: annotations
179 name
180 );
181 trace.record(FQNAME_TO_NAMESPACE_DESCRIPTOR, fqName, namespaceDescriptor);
182
183 WritableScopeImpl scope = new WritableScopeImpl(JetScope.EMPTY, namespaceDescriptor, handler, "Namespace member scope");
184 scope.changeLockLevel(WritableScope.LockLevel.BOTH);
185
186 namespaceDescriptor.initialize(scope);
187 scope.changeLockLevel(WritableScope.LockLevel.BOTH);
188 //
189 moduleDescriptor.getModuleConfiguration().extendNamespaceScope(trace, namespaceDescriptor, scope);
190 owner.addNamespace(namespaceDescriptor);
191 if (expression != null) {
192 trace.record(BindingContext.NAMESPACE, expression, namespaceDescriptor);
193 }
194 return namespaceDescriptor;
195 }
196
197 private void storeBindingForFileAndExpression(@Nullable JetFile file,
198 @Nullable JetReferenceExpression expression,
199 @NotNull NamespaceDescriptor namespaceDescriptor) {
200 if (expression != null) {
201 trace.record(REFERENCE_TARGET, expression, namespaceDescriptor);
202 }
203
204 if (file != null) {
205 trace.record(BindingContext.FILE_TO_NAMESPACE, file, namespaceDescriptor);
206
207 // Register files corresponding to this namespace
208 // The trace currently does not support bi-di multimaps that would handle this task nicer
209 Collection<JetFile> files = trace.get(NAMESPACE_TO_FILES, namespaceDescriptor);
210 if (files == null) {
211 files = Sets.newIdentityHashSet();
212 }
213 files.add(file);
214 trace.record(BindingContext.NAMESPACE_TO_FILES, namespaceDescriptor, files);
215 }
216 }
217 }