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