001 /*
002 * Copyright 2010-2015 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.kotlin.resolve;
018
019 import com.google.common.base.Predicate;
020 import com.google.common.collect.Collections2;
021 import com.google.common.collect.Lists;
022 import com.google.common.collect.Sets;
023 import com.intellij.psi.util.PsiTreeUtil;
024 import org.jetbrains.annotations.Mutable;
025 import org.jetbrains.annotations.NotNull;
026 import org.jetbrains.annotations.Nullable;
027 import org.jetbrains.kotlin.descriptors.*;
028 import org.jetbrains.kotlin.diagnostics.Errors;
029 import org.jetbrains.kotlin.incremental.KotlinLookupLocation;
030 import org.jetbrains.kotlin.name.Name;
031 import org.jetbrains.kotlin.psi.*;
032 import org.jetbrains.kotlin.resolve.scopes.AbstractScopeAdapter;
033 import org.jetbrains.kotlin.resolve.scopes.JetScope;
034 import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue;
035 import org.jetbrains.kotlin.resolve.validation.SymbolUsageValidator;
036
037 import java.util.Collection;
038 import java.util.Collections;
039 import java.util.Set;
040
041 import static org.jetbrains.kotlin.diagnostics.Errors.*;
042
043 public class QualifiedExpressionResolver {
044 @NotNull private final SymbolUsageValidator symbolUsageValidator;
045 @NotNull private final ImportDirectiveProcessor importDirectiveProcessor = new ImportDirectiveProcessor(this);
046
047 public QualifiedExpressionResolver(@NotNull SymbolUsageValidator symbolUsageValidator) {
048 this.symbolUsageValidator = symbolUsageValidator;
049 }
050
051 private static final Predicate<DeclarationDescriptor> CLASSIFIERS_AND_PACKAGE_VIEWS = new Predicate<DeclarationDescriptor>() {
052 @Override
053 public boolean apply(@Nullable DeclarationDescriptor descriptor) {
054 return descriptor instanceof ClassifierDescriptor || descriptor instanceof PackageViewDescriptor;
055 }
056 };
057
058 public enum LookupMode {
059 // Only classifier and packages are resolved
060 ONLY_CLASSES_AND_PACKAGES,
061
062 // Resolve all descriptors
063 EVERYTHING
064 }
065
066 @NotNull
067 public JetScope processImportReference(
068 @NotNull JetImportDirective importDirective,
069 @NotNull ModuleDescriptor moduleDescriptor,
070 @NotNull BindingTrace trace,
071 @NotNull LookupMode lookupMode
072 ) {
073 return importDirectiveProcessor.processImportReference(importDirective, moduleDescriptor, trace, lookupMode);
074 }
075
076 @NotNull
077 public Collection<DeclarationDescriptor> lookupDescriptorsForUserType(
078 @NotNull JetUserType userType,
079 @NotNull JetScope outerScope,
080 @NotNull BindingTrace trace,
081 boolean onlyClassifiers
082 ) {
083
084 if (userType.isAbsoluteInRootPackage()) {
085 trace.report(Errors.UNSUPPORTED.on(userType, "package"));
086 return Collections.emptyList();
087 }
088
089 JetSimpleNameExpression referenceExpression = userType.getReferenceExpression();
090 /*
091 if (referenceExpression == null) {
092 return Collections.emptyList();
093 }
094 */
095 JetUserType qualifier = userType.getQualifier();
096
097 // We do not want to resolve the last segment of a user type to a package
098 JetScope filteredScope = filterOutPackagesIfNeeded(outerScope, onlyClassifiers);
099
100 DeclarationDescriptor shouldBeVisibleFrom = outerScope.getContainingDeclaration();
101 if (qualifier == null) {
102 if (referenceExpression == null) return Collections.emptyList();
103 return lookupDescriptorsForSimpleNameReference(referenceExpression, filteredScope, shouldBeVisibleFrom, trace,
104 LookupMode.ONLY_CLASSES_AND_PACKAGES,
105 false, true);
106 }
107 Collection<DeclarationDescriptor> declarationDescriptors = lookupDescriptorsForUserType(qualifier, outerScope, trace, false);
108 if (referenceExpression == null) return Collections.emptyList();
109 return lookupSelectorDescriptors(referenceExpression, declarationDescriptors, trace, shouldBeVisibleFrom,
110 LookupMode.ONLY_CLASSES_AND_PACKAGES, true);
111 }
112
113 private static JetScope filterOutPackagesIfNeeded(final JetScope outerScope, boolean noPackages) {
114 return !noPackages ? outerScope : new AbstractScopeAdapter() {
115
116 @NotNull
117 @Override
118 protected JetScope getWorkerScope() {
119 return outerScope;
120 }
121
122 @Nullable
123 @Override
124 public PackageViewDescriptor getPackage(@NotNull Name name) {
125 return null;
126 }
127 };
128 }
129
130 @NotNull
131 public Collection<DeclarationDescriptor> lookupSelectorDescriptors(
132 @NotNull JetSimpleNameExpression selector,
133 @NotNull Collection<DeclarationDescriptor> declarationDescriptors,
134 @NotNull BindingTrace trace,
135 @NotNull DeclarationDescriptor shouldBeVisibleFrom,
136 @NotNull LookupMode lookupMode,
137 boolean storeResult
138 ) {
139 Set<LookupResult> results = Sets.newLinkedHashSet();
140 for (DeclarationDescriptor declarationDescriptor : declarationDescriptors) {
141 if (declarationDescriptor instanceof PackageViewDescriptor) {
142 results.add(lookupSimpleNameReference(selector, ((PackageViewDescriptor) declarationDescriptor).getMemberScope(),
143 lookupMode, true));
144 }
145 if (declarationDescriptor instanceof ClassDescriptor) {
146 addResultsForClass(results, selector, lookupMode, (ClassDescriptor) declarationDescriptor);
147 }
148 }
149 return filterAndStoreResolutionResult(results, selector, trace, shouldBeVisibleFrom, lookupMode, storeResult);
150 }
151
152 private static void addResultsForClass(
153 @NotNull @Mutable Set<LookupResult> results,
154 @NotNull JetSimpleNameExpression selector,
155 @NotNull LookupMode lookupMode,
156 @NotNull ClassDescriptor descriptor
157 ) {
158 JetScope scope = lookupMode == LookupMode.ONLY_CLASSES_AND_PACKAGES
159 ? descriptor.getUnsubstitutedInnerClassesScope()
160 : descriptor.getDefaultType().getMemberScope();
161 results.add(lookupSimpleNameReference(selector, scope, lookupMode, false));
162
163 results.add(lookupSimpleNameReference(selector, descriptor.getStaticScope(), lookupMode, true));
164 }
165
166
167 @NotNull
168 @SuppressWarnings("MethodMayBeStatic")
169 public Collection<DeclarationDescriptor> lookupDescriptorsForSimpleNameReference(
170 @NotNull JetSimpleNameExpression referenceExpression,
171 @NotNull JetScope outerScope,
172 @NotNull DeclarationDescriptor shouldBeVisibleFrom,
173 @NotNull BindingTrace trace,
174 @NotNull LookupMode lookupMode,
175 boolean packageLevel,
176 boolean storeResult
177 ) {
178 LookupResult lookupResult = lookupSimpleNameReference(referenceExpression, outerScope, lookupMode, packageLevel);
179 return filterAndStoreResolutionResult(Collections.singletonList(lookupResult), referenceExpression, trace, shouldBeVisibleFrom,
180 lookupMode, storeResult);
181 }
182
183 @NotNull
184 private static LookupResult lookupSimpleNameReference(
185 @NotNull JetSimpleNameExpression referenceExpression,
186 @NotNull JetScope outerScope,
187 @NotNull LookupMode lookupMode,
188 boolean packageLevel
189 ) {
190 Name referencedName = referenceExpression.getReferencedNameAsName();
191
192 Collection<DeclarationDescriptor> descriptors = Sets.newLinkedHashSet();
193 PackageViewDescriptor packageDescriptor = outerScope.getPackage(referencedName);
194 if (packageDescriptor != null) {
195 descriptors.add(packageDescriptor);
196 }
197
198 KotlinLookupLocation location = new KotlinLookupLocation(referenceExpression);
199
200 ClassifierDescriptor classifierDescriptor = outerScope.getClassifier(referencedName, location);
201 if (classifierDescriptor != null) {
202 descriptors.add(classifierDescriptor);
203 }
204
205 if (lookupMode == LookupMode.EVERYTHING) {
206 descriptors.addAll(outerScope.getFunctions(referencedName, location));
207 descriptors.addAll(outerScope.getProperties(referencedName, location));
208
209 VariableDescriptor localVariable = outerScope.getLocalVariable(referencedName);
210 if (localVariable != null) {
211 descriptors.add(localVariable);
212 }
213 }
214
215 return new LookupResult(descriptors, outerScope, packageLevel);
216 }
217
218 @NotNull
219 private Collection<DeclarationDescriptor> filterAndStoreResolutionResult(
220 @NotNull Collection<LookupResult> lookupResults,
221 @NotNull JetSimpleNameExpression referenceExpression,
222 @NotNull BindingTrace trace,
223 @NotNull DeclarationDescriptor shouldBeVisibleFrom,
224 @NotNull LookupMode lookupMode,
225 boolean storeResult
226 ) {
227 if (lookupResults.isEmpty()) {
228 return Collections.emptyList();
229 }
230
231 Collection<DeclarationDescriptor> descriptors = Sets.newLinkedHashSet();
232 for (LookupResult lookupResult : lookupResults) {
233 descriptors.addAll(lookupResult.descriptors);
234 }
235
236 Collection<DeclarationDescriptor> filteredDescriptors;
237 if (lookupMode == LookupMode.ONLY_CLASSES_AND_PACKAGES) {
238 filteredDescriptors = Collections2.filter(descriptors, CLASSIFIERS_AND_PACKAGE_VIEWS);
239 }
240 else {
241 filteredDescriptors = Sets.newLinkedHashSet();
242 //functions and properties can be imported if lookupResult.packageLevel == true
243 for (LookupResult lookupResult : lookupResults) {
244 if (lookupResult.packageLevel) {
245 filteredDescriptors.addAll(lookupResult.descriptors);
246 }
247 else {
248 filteredDescriptors.addAll(Collections2.filter(lookupResult.descriptors, CLASSIFIERS_AND_PACKAGE_VIEWS));
249 }
250 }
251 }
252
253 if (storeResult) {
254 Collection<JetScope> possibleResolutionScopes = Lists.newArrayList();
255 for (LookupResult lookupResult : lookupResults) {
256 if (!lookupResult.descriptors.isEmpty()) {
257 possibleResolutionScopes.add(lookupResult.resolutionScope);
258 }
259 }
260 if (possibleResolutionScopes.isEmpty()) {
261 for (LookupResult lookupResult : lookupResults) {
262 possibleResolutionScopes.add(lookupResult.resolutionScope);
263 }
264 }
265
266 storeResolutionResult(descriptors, filteredDescriptors, referenceExpression, possibleResolutionScopes, trace,
267 shouldBeVisibleFrom);
268 }
269
270 return filteredDescriptors;
271 }
272
273 private void storeResolutionResult(
274 @NotNull Collection<DeclarationDescriptor> descriptors,
275 @NotNull Collection<DeclarationDescriptor> canBeImportedDescriptors,
276 @NotNull JetSimpleNameExpression referenceExpression,
277 @NotNull Collection<JetScope> possibleResolutionScopes,
278 @NotNull BindingTrace trace,
279 @NotNull DeclarationDescriptor shouldBeVisibleFrom
280 ) {
281 assert canBeImportedDescriptors.size() <= descriptors.size();
282 assert !possibleResolutionScopes.isEmpty();
283 //todo completion here needs all possible resolution scopes, if there are many
284 JetScope resolutionScope = possibleResolutionScopes.iterator().next();
285
286 // A special case - will fill all trace information
287 if (resolveClassPackageAmbiguity(canBeImportedDescriptors, referenceExpression, resolutionScope, trace, shouldBeVisibleFrom)) {
288 return;
289 }
290
291 // Simple case of no descriptors
292 if (descriptors.isEmpty()) {
293 trace.record(BindingContext.RESOLUTION_SCOPE, referenceExpression, resolutionScope);
294 trace.report(UNRESOLVED_REFERENCE.on(referenceExpression, referenceExpression));
295 return;
296 }
297
298 // Decide if expression has resolved reference
299 DeclarationDescriptor descriptor = null;
300 if (descriptors.size() == 1) {
301 descriptor = descriptors.iterator().next();
302 assert canBeImportedDescriptors.size() <= 1;
303 }
304 else if (canBeImportedDescriptors.size() == 1) {
305 descriptor = canBeImportedDescriptors.iterator().next();
306 }
307 if (descriptor != null) {
308 trace.record(BindingContext.REFERENCE_TARGET, referenceExpression, descriptors.iterator().next());
309 trace.record(BindingContext.RESOLUTION_SCOPE, referenceExpression, resolutionScope);
310
311 if (descriptor instanceof ClassifierDescriptor) {
312 symbolUsageValidator.validateTypeUsage((ClassifierDescriptor) descriptor, trace, referenceExpression);
313 }
314
315 if (descriptor instanceof DeclarationDescriptorWithVisibility) {
316 checkVisibility((DeclarationDescriptorWithVisibility) descriptor, trace, referenceExpression, shouldBeVisibleFrom);
317 }
318 }
319
320 // Check for more information and additional errors
321 if (canBeImportedDescriptors.isEmpty()) {
322 assert descriptors.size() >= 1;
323 trace.report(CANNOT_BE_IMPORTED.on(referenceExpression, descriptors.iterator().next()));
324 return;
325 }
326 if (canBeImportedDescriptors.size() > 1) {
327 trace.record(BindingContext.AMBIGUOUS_REFERENCE_TARGET, referenceExpression, descriptors);
328 }
329 }
330
331 /**
332 * This method tries to resolve descriptors ambiguity between class descriptor and package descriptor for the same class.
333 * It's ok choose class for expression reference resolution.
334 *
335 * @return <code>true</code> if method has successfully resolved ambiguity
336 */
337 private static boolean resolveClassPackageAmbiguity(
338 @NotNull Collection<DeclarationDescriptor> filteredDescriptors,
339 @NotNull JetSimpleNameExpression referenceExpression,
340 @NotNull JetScope resolutionScope,
341 @NotNull BindingTrace trace,
342 @NotNull DeclarationDescriptor shouldBeVisibleFrom
343 ) {
344 if (filteredDescriptors.size() == 2) {
345 PackageViewDescriptor packageView = null;
346 ClassDescriptor classDescriptor = null;
347
348 for (DeclarationDescriptor filteredDescriptor : filteredDescriptors) {
349 if (filteredDescriptor instanceof PackageViewDescriptor) {
350 packageView = (PackageViewDescriptor) filteredDescriptor;
351 }
352 else if (filteredDescriptor instanceof ClassDescriptor) {
353 classDescriptor = (ClassDescriptor) filteredDescriptor;
354 }
355 }
356
357 if (packageView != null && classDescriptor != null) {
358 if (packageView.getFqName().equalsTo(DescriptorUtils.getFqName(classDescriptor))) {
359 trace.record(BindingContext.REFERENCE_TARGET, referenceExpression, classDescriptor);
360 trace.record(BindingContext.RESOLUTION_SCOPE, referenceExpression, resolutionScope);
361 checkVisibility(classDescriptor, trace, referenceExpression, shouldBeVisibleFrom);
362 return true;
363 }
364 }
365 }
366
367 return false;
368 }
369
370 private static void checkVisibility(
371 @NotNull DeclarationDescriptorWithVisibility descriptor,
372 @NotNull BindingTrace trace,
373 @NotNull JetSimpleNameExpression referenceExpression,
374 @NotNull DeclarationDescriptor shouldBeVisibleFrom
375 ) {
376 if (!Visibilities.isVisible(ReceiverValue.IRRELEVANT_RECEIVER, descriptor, shouldBeVisibleFrom)) {
377 Visibility visibility = descriptor.getVisibility();
378 if (PsiTreeUtil.getParentOfType(referenceExpression, JetImportDirective.class) != null && !visibility.mustCheckInImports()) {
379 return;
380 }
381 //noinspection ConstantConditions
382 trace.report(INVISIBLE_REFERENCE.on(referenceExpression, descriptor, visibility, descriptor.getContainingDeclaration()));
383 }
384 }
385
386 private static class LookupResult {
387 private final Collection<DeclarationDescriptor> descriptors;
388 private final JetScope resolutionScope;
389 private final boolean packageLevel;
390
391 public LookupResult(
392 @NotNull Collection<DeclarationDescriptor> descriptors,
393 @NotNull JetScope resolutionScope,
394 boolean packageLevel
395 ) {
396 this.descriptors = descriptors;
397 this.resolutionScope = resolutionScope;
398 this.packageLevel = packageLevel;
399 }
400 }
401 }