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