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.Lists;
020 import com.google.common.collect.Maps;
021 import org.jetbrains.annotations.NotNull;
022 import org.jetbrains.annotations.Nullable;
023 import org.jetbrains.jet.lang.PlatformToKotlinClassMap;
024 import org.jetbrains.jet.lang.descriptors.*;
025 import org.jetbrains.jet.lang.descriptors.impl.ScriptDescriptorImpl;
026 import org.jetbrains.jet.lang.psi.*;
027 import org.jetbrains.jet.lang.resolve.name.Name;
028 import org.jetbrains.jet.lang.resolve.scopes.JetScope;
029 import org.jetbrains.jet.lang.resolve.scopes.WritableScope;
030
031 import javax.inject.Inject;
032 import java.util.Collection;
033 import java.util.List;
034 import java.util.Map;
035
036 import static org.jetbrains.jet.lang.diagnostics.Errors.*;
037 import static org.jetbrains.jet.lang.resolve.QualifiedExpressionResolver.LookupMode;
038
039 public class ImportsResolver {
040 @NotNull
041 private ModuleDescriptor moduleDescriptor;
042 @NotNull
043 private QualifiedExpressionResolver qualifiedExpressionResolver;
044 @NotNull
045 private BindingTrace trace;
046 @NotNull
047 private JetImportsFactory importsFactory;
048
049 @Inject
050 public void setModuleDescriptor(@NotNull ModuleDescriptor moduleDescriptor) {
051 this.moduleDescriptor = moduleDescriptor;
052 }
053
054 @Inject
055 public void setTrace(@NotNull BindingTrace trace) {
056 this.trace = trace;
057 }
058
059 @Inject
060 public void setQualifiedExpressionResolver(@NotNull QualifiedExpressionResolver qualifiedExpressionResolver) {
061 this.qualifiedExpressionResolver = qualifiedExpressionResolver;
062 }
063
064 @Inject
065 public void setImportsFactory(@NotNull JetImportsFactory importsFactory) {
066 this.importsFactory = importsFactory;
067 }
068
069 public void processTypeImports(@NotNull TopDownAnalysisContext c) {
070 processImports(c, LookupMode.ONLY_CLASSES);
071 }
072
073 public void processMembersImports(@NotNull TopDownAnalysisContext c) {
074 processImports(c, LookupMode.EVERYTHING);
075 }
076
077 private void processImports(@NotNull TopDownAnalysisContext c, @NotNull LookupMode lookupMode) {
078 for (JetFile file : c.getFiles()) {
079 if (file.isScript()) continue;
080 WritableScope fileScope = c.getFileScopes().get(file);
081 processImportsInFile(lookupMode, fileScope, Lists.newArrayList(file.getImportDirectives()), file.getPackageFqName().isRoot());
082 }
083 // SCRIPT: process script import directives
084 for (JetScript script : c.getScripts().keySet()) {
085 WritableScope scriptScope = ((ScriptDescriptorImpl) c.getScripts().get(script)).getScopeForBodyResolution();
086 processImportsInFile(lookupMode, scriptScope, script.getContainingJetFile().getImportDirectives(), true);
087 }
088 }
089
090 private void processImportsInFile(@NotNull LookupMode lookupMode, WritableScope scope, List<JetImportDirective> directives, boolean inRootPackage) {
091 processImportsInFile(lookupMode, scope, directives, moduleDescriptor, trace, qualifiedExpressionResolver, importsFactory, inRootPackage);
092 }
093
094 private static void processImportsInFile(
095 LookupMode lookupMode,
096 @NotNull WritableScope fileScope,
097 @NotNull List<JetImportDirective> importDirectives,
098 @NotNull ModuleDescriptor module,
099 @NotNull BindingTrace trace,
100 @NotNull QualifiedExpressionResolver qualifiedExpressionResolver,
101 @NotNull JetImportsFactory importsFactory,
102 boolean inRootPackage
103 ) {
104 @NotNull JetScope rootScope = JetModuleUtil.getSubpackagesOfRootScope(module);
105
106 Importer.DelayedImporter delayedImporter = new Importer.DelayedImporter(fileScope);
107 if (lookupMode == LookupMode.EVERYTHING) {
108 fileScope.clearImports();
109 }
110
111 for (ImportPath defaultImportPath : module.getDefaultImports()) {
112 TemporaryBindingTrace temporaryTrace = TemporaryBindingTrace.create(
113 trace, "transient trace to resolve default imports"); //not to trace errors of default imports
114
115 JetImportDirective defaultImportDirective = importsFactory.createImportDirective(defaultImportPath);
116 qualifiedExpressionResolver.processImportReference(defaultImportDirective, rootScope, fileScope, delayedImporter,
117 temporaryTrace, module, lookupMode);
118 }
119
120 Map<JetImportDirective, Collection<? extends DeclarationDescriptor>> resolvedDirectives = Maps.newHashMap();
121
122 JetScope rootScopeForFile = JetModuleUtil.getImportsResolutionScope(module, inRootPackage);
123
124 for (JetImportDirective importDirective : importDirectives) {
125 Collection<? extends DeclarationDescriptor> descriptors =
126 qualifiedExpressionResolver.processImportReference(importDirective, rootScopeForFile, fileScope, delayedImporter,
127 trace, module, lookupMode);
128 if (!descriptors.isEmpty()) {
129 resolvedDirectives.put(importDirective, descriptors);
130 }
131
132 if (lookupMode != LookupMode.ONLY_CLASSES) {
133 checkPlatformTypesMappedToKotlin(module, trace, importDirective, descriptors);
134 }
135 }
136 delayedImporter.processImports();
137
138 if (lookupMode == LookupMode.EVERYTHING) {
139 for (JetImportDirective importDirective : importDirectives) {
140 reportUselessImport(importDirective, fileScope, resolvedDirectives.get(importDirective), trace);
141 }
142 }
143 }
144
145 public static void checkPlatformTypesMappedToKotlin(
146 @NotNull ModuleDescriptor module,
147 @NotNull BindingTrace trace,
148 @NotNull JetImportDirective importDirective,
149 @NotNull Collection<? extends DeclarationDescriptor> descriptors
150 ) {
151 JetExpression importedReference = importDirective.getImportedReference();
152 if (importedReference != null) {
153 for (DeclarationDescriptor descriptor : descriptors) {
154 reportPlatformClassMappedToKotlin(module, trace, importedReference, descriptor);
155 }
156 }
157 }
158
159 public static void reportPlatformClassMappedToKotlin(
160 @NotNull ModuleDescriptor module,
161 @NotNull BindingTrace trace,
162 @NotNull JetElement element,
163 @NotNull DeclarationDescriptor descriptor
164 ) {
165 if (!(descriptor instanceof ClassDescriptor)) return;
166
167 PlatformToKotlinClassMap platformToKotlinMap = module.getPlatformToKotlinClassMap();
168 Collection<ClassDescriptor> kotlinAnalogsForClass = platformToKotlinMap.mapPlatformClass((ClassDescriptor) descriptor);
169 if (!kotlinAnalogsForClass.isEmpty()) {
170 trace.report(PLATFORM_CLASS_MAPPED_TO_KOTLIN.on(element, kotlinAnalogsForClass));
171 }
172 }
173
174 public static void reportUselessImport(
175 @NotNull JetImportDirective importDirective,
176 @NotNull JetScope fileScope,
177 @Nullable Collection<? extends DeclarationDescriptor> resolvedDirectives,
178 @NotNull BindingTrace trace
179 ) {
180
181 JetExpression importedReference = importDirective.getImportedReference();
182 if (importedReference == null || resolvedDirectives == null) {
183 return;
184 }
185 Name aliasName = JetPsiUtil.getAliasName(importDirective);
186 if (aliasName == null) {
187 return;
188 }
189
190 boolean uselessHiddenImport = true;
191 for (DeclarationDescriptor wasResolved : resolvedDirectives) {
192 DeclarationDescriptor isResolved = null;
193 if (wasResolved instanceof ClassDescriptor) {
194 isResolved = fileScope.getClassifier(aliasName);
195 }
196 else if (wasResolved instanceof VariableDescriptor) {
197 isResolved = fileScope.getLocalVariable(aliasName);
198 }
199 else if (wasResolved instanceof PackageViewDescriptor) {
200 isResolved = fileScope.getPackage(aliasName);
201 }
202 if (isResolved == null || isResolved.equals(wasResolved)) {
203 uselessHiddenImport = false;
204 }
205 }
206 if (uselessHiddenImport) {
207 trace.report(USELESS_HIDDEN_IMPORT.on(importedReference));
208 }
209
210 if (!importDirective.isAllUnder() &&
211 importedReference instanceof JetSimpleNameExpression &&
212 importDirective.getAliasName() == null) {
213 trace.report(USELESS_SIMPLE_IMPORT.on(importedReference));
214 }
215 }
216 }