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.base.Predicate; 020import com.google.common.collect.Lists; 021import com.intellij.openapi.util.Pair; 022import org.jetbrains.annotations.NotNull; 023import org.jetbrains.annotations.Nullable; 024import org.jetbrains.jet.lang.PlatformToKotlinClassMap; 025import org.jetbrains.jet.lang.descriptors.*; 026import org.jetbrains.jet.lang.resolve.name.Name; 027import org.jetbrains.jet.lang.resolve.scopes.FilteringScope; 028import org.jetbrains.jet.lang.resolve.scopes.JetScope; 029import org.jetbrains.jet.lang.resolve.scopes.WritableScope; 030 031import java.util.Collection; 032import java.util.List; 033 034public interface Importer { 035 void addAllUnderImport(@NotNull DeclarationDescriptor descriptor, @NotNull PlatformToKotlinClassMap platformToKotlinClassMap); 036 037 void addAliasImport(@NotNull DeclarationDescriptor descriptor, @NotNull Name aliasName); 038 039 Importer DO_NOTHING = new Importer() { 040 @Override 041 public void addAllUnderImport(@NotNull DeclarationDescriptor descriptor, @NotNull PlatformToKotlinClassMap platformToKotlinClassMap) { 042 } 043 044 @Override 045 public void addAliasImport(@NotNull DeclarationDescriptor descriptor, @NotNull Name aliasName) { 046 } 047 }; 048 049 class StandardImporter implements Importer { 050 private final WritableScope namespaceScope; 051 052 public StandardImporter(WritableScope namespaceScope) { 053 this.namespaceScope = namespaceScope; 054 } 055 056 @Override 057 public void addAllUnderImport(@NotNull DeclarationDescriptor descriptor, @NotNull PlatformToKotlinClassMap platformToKotlinClassMap) { 058 importAllUnderDeclaration(descriptor, platformToKotlinClassMap); 059 } 060 061 @Override 062 public void addAliasImport(@NotNull DeclarationDescriptor descriptor, @NotNull Name aliasName) { 063 importDeclarationAlias(descriptor, aliasName); 064 } 065 066 @NotNull 067 private static JetScope createFilteringScope( 068 @NotNull JetScope scope, 069 @NotNull DeclarationDescriptor descriptor, 070 @NotNull PlatformToKotlinClassMap platformToKotlinClassMap 071 ) { 072 final Collection<ClassDescriptor> kotlinAnalogsForClassesInside = platformToKotlinClassMap.mapPlatformClassesInside( 073 descriptor); 074 if (kotlinAnalogsForClassesInside.isEmpty()) return scope; 075 return new FilteringScope(scope, new Predicate<DeclarationDescriptor>() { 076 @Override 077 public boolean apply(DeclarationDescriptor descriptor) { 078 for (ClassDescriptor kotlinAnalog : kotlinAnalogsForClassesInside) { 079 if (kotlinAnalog.getName().equals(descriptor.getName())) { 080 return false; 081 } 082 } 083 return true; 084 } 085 }); 086 } 087 088 protected void importAllUnderDeclaration(@NotNull DeclarationDescriptor descriptor, @NotNull PlatformToKotlinClassMap platformToKotlinClassMap) { 089 JetScope scopeToImport = null; 090 if (descriptor instanceof NamespaceDescriptor) { 091 scopeToImport = ((NamespaceDescriptor) descriptor).getMemberScope(); 092 } 093 if (descriptor instanceof ClassDescriptor && ((ClassDescriptor) descriptor).getKind() != ClassKind.OBJECT) { 094 ClassDescriptor classDescriptor = (ClassDescriptor) descriptor; 095 scopeToImport = classDescriptor.getUnsubstitutedInnerClassesScope(); 096 ClassDescriptor classObjectDescriptor = classDescriptor.getClassObjectDescriptor(); 097 if (classObjectDescriptor != null) { 098 scopeToImport = classObjectDescriptor.getUnsubstitutedInnerClassesScope(); 099 } 100 } 101 if (scopeToImport != null) { 102 namespaceScope.importScope(createFilteringScope(scopeToImport, descriptor, platformToKotlinClassMap)); 103 } 104 } 105 106 protected void importDeclarationAlias(@NotNull DeclarationDescriptor descriptor, @NotNull Name aliasName) { 107 if (descriptor instanceof ClassifierDescriptor) { 108 namespaceScope.importClassifierAlias(aliasName, (ClassifierDescriptor) descriptor); 109 } 110 else if (descriptor instanceof NamespaceDescriptor) { 111 namespaceScope.importNamespaceAlias(aliasName, (NamespaceDescriptor) descriptor); 112 } 113 else if (descriptor instanceof FunctionDescriptor) { 114 namespaceScope.importFunctionAlias(aliasName, (FunctionDescriptor) descriptor); 115 } 116 else if (descriptor instanceof VariableDescriptor) { 117 namespaceScope.importVariableAlias(aliasName, (VariableDescriptor) descriptor); 118 } 119 } 120 121 } 122 123 class DelayedImporter extends StandardImporter { 124 private interface DelayedImportEntry {} 125 private static class AllUnderImportEntry extends Pair<DeclarationDescriptor, PlatformToKotlinClassMap> implements DelayedImportEntry { 126 public AllUnderImportEntry(@NotNull DeclarationDescriptor first, @Nullable PlatformToKotlinClassMap second) { 127 super(first, second); 128 } 129 } 130 private static class AliasImportEntry extends Pair<DeclarationDescriptor, Name> implements DelayedImportEntry { 131 public AliasImportEntry(DeclarationDescriptor first, Name second) { 132 super(first, second); 133 } 134 } 135 136 private final List<DelayedImportEntry> imports = Lists.newArrayList(); 137 138 public DelayedImporter(@NotNull WritableScope namespaceScope) { 139 super(namespaceScope); 140 } 141 142 @Override 143 public void addAllUnderImport(@NotNull DeclarationDescriptor descriptor, @NotNull PlatformToKotlinClassMap platformToKotlinClassMap) { 144 imports.add(new AllUnderImportEntry(descriptor, platformToKotlinClassMap)); 145 } 146 147 @Override 148 public void addAliasImport(@NotNull DeclarationDescriptor descriptor, @NotNull Name aliasName) { 149 imports.add(new AliasImportEntry(descriptor, aliasName)); 150 } 151 152 public void processImports() { 153 for (DelayedImportEntry anImport : imports) { 154 if (anImport instanceof AllUnderImportEntry) { 155 AllUnderImportEntry allUnderImportEntry = (AllUnderImportEntry) anImport; 156 importAllUnderDeclaration(allUnderImportEntry.getFirst(), allUnderImportEntry.getSecond()); 157 } 158 else { 159 AliasImportEntry aliasImportEntry = (AliasImportEntry) anImport; 160 importDeclarationAlias(aliasImportEntry.getFirst(), aliasImportEntry.getSecond()); 161 } 162 } 163 } 164 } 165}