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