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