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.base.Predicate;
020 import com.google.common.collect.Lists;
021 import com.intellij.openapi.util.Pair;
022 import org.jetbrains.annotations.NotNull;
023 import org.jetbrains.annotations.Nullable;
024 import org.jetbrains.jet.lang.PlatformToKotlinClassMap;
025 import org.jetbrains.jet.lang.descriptors.*;
026 import org.jetbrains.jet.lang.resolve.name.Name;
027 import org.jetbrains.jet.lang.resolve.scopes.FilteringScope;
028 import org.jetbrains.jet.lang.resolve.scopes.JetScope;
029 import org.jetbrains.jet.lang.resolve.scopes.WritableScope;
030
031 import java.util.Collection;
032 import java.util.List;
033
034 public 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 }