Correctly resolving all references in library source.

Added test with stdlib.

Ignoring top-level members from library source to avoid ambiguity. Resolving classes from source when deserializing descriptors (for unification).
This commit is contained in:
Evgeny Gerashchenko
2013-09-11 16:53:35 +04:00
parent e4d8e4d61b
commit 53c832d88c
11 changed files with 241 additions and 31 deletions
@@ -0,0 +1,10 @@
<root>
<item
name='com.intellij.testFramework.LightProjectDescriptor void configureModule(com.intellij.openapi.module.Module, com.intellij.openapi.roots.ModifiableRootModel, com.intellij.openapi.roots.ContentEntry) 0'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
<item
name='com.intellij.testFramework.LightProjectDescriptor void configureModule(com.intellij.openapi.module.Module, com.intellij.openapi.roots.ModifiableRootModel, com.intellij.openapi.roots.ContentEntry) 1'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
</root>
@@ -0,0 +1,5 @@
<root>
<item name='com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase com.intellij.psi.PsiManager getPsiManager()'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
</root>
@@ -0,0 +1,66 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.lang.resolve;
import com.google.common.collect.Lists;
import com.intellij.openapi.util.Key;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
import org.jetbrains.jet.lang.descriptors.CallableMemberDescriptor;
import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor;
import java.util.Collection;
import java.util.List;
import static org.jetbrains.jet.lang.resolve.BindingContextUtils.callableDescriptorToDeclaration;
public class LibrarySourceHacks {
private LibrarySourceHacks() {
}
public static final Key<Boolean> SKIP_TOP_LEVEL_MEMBERS = Key.create("SKIP_TOP_LEVEL_MEMBERS"); // used when analyzing library source
public static <D extends CallableDescriptor> List<D> filterOutMembersFromLibrarySource(Collection<D> members, BindingTrace trace) {
List<D> filteredMembers = Lists.newArrayList();
for (D member : members) {
if (!shouldSkip(member, trace)) {
filteredMembers.add(member);
}
}
return filteredMembers;
}
private static boolean shouldSkip(CallableDescriptor member, BindingTrace trace) {
CallableDescriptor original = member.getOriginal();
if (!(original instanceof CallableMemberDescriptor)) {
return false;
}
if (!(original.getContainingDeclaration() instanceof NamespaceDescriptor)) {
return false;
}
PsiElement declaration = callableDescriptorToDeclaration(trace.getBindingContext(),
(CallableMemberDescriptor) original);
if (declaration == null) {
return false;
}
PsiFile file = declaration.getContainingFile();
return file != null && Boolean.TRUE.equals(file.getUserData(SKIP_TOP_LEVEL_MEMBERS));
}
}
@@ -18,6 +18,7 @@ package org.jetbrains.jet.lang.resolve.calls.tasks;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
import org.jetbrains.jet.lang.resolve.BindingTrace;
import org.jetbrains.jet.lang.resolve.name.Name;
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
import org.jetbrains.jet.lang.types.JetType;
@@ -26,11 +27,11 @@ import java.util.Collection;
public interface CallableDescriptorCollector<D extends CallableDescriptor> {
@NotNull
Collection<D> getNonExtensionsByName(JetScope scope, Name name);
Collection<D> getNonExtensionsByName(JetScope scope, Name name, @NotNull BindingTrace bindingTrace);
@NotNull
Collection<D> getMembersByName(@NotNull JetType receiver, Name name);
Collection<D> getMembersByName(@NotNull JetType receiver, Name name, @NotNull BindingTrace bindingTrace);
@NotNull
Collection<D> getNonMembersByName(JetScope scope, Name name);
Collection<D> getNonMembersByName(JetScope scope, Name name, @NotNull BindingTrace bindingTrace);
}
@@ -20,6 +20,7 @@ import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.resolve.BindingTrace;
import org.jetbrains.jet.lang.resolve.name.Name;
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
import org.jetbrains.jet.lang.types.ErrorUtils;
@@ -27,10 +28,15 @@ import org.jetbrains.jet.lang.types.JetType;
import java.util.*;
import static org.jetbrains.jet.lang.resolve.LibrarySourceHacks.filterOutMembersFromLibrarySource;
public class CallableDescriptorCollectors {
public static CallableDescriptorCollector<FunctionDescriptor> FUNCTIONS = new FunctionCollector();
public static CallableDescriptorCollector<VariableDescriptor> VARIABLES = new VariableCollector();
public static CallableDescriptorCollector<VariableDescriptor> PROPERTIES = new PropertyCollector();
public static CallableDescriptorCollector<FunctionDescriptor> FUNCTIONS =
new FilteredCollector<FunctionDescriptor>(new FunctionCollector());
public static CallableDescriptorCollector<VariableDescriptor> VARIABLES =
new FilteredCollector<VariableDescriptor>(new VariableCollector());
public static CallableDescriptorCollector<VariableDescriptor> PROPERTIES =
new FilteredCollector<VariableDescriptor>(new PropertyCollector());
public static List<CallableDescriptorCollector<? extends CallableDescriptor>> FUNCTIONS_AND_VARIABLES =
Lists.newArrayList(FUNCTIONS, VARIABLES);
@@ -38,7 +44,7 @@ public class CallableDescriptorCollectors {
@NotNull
@Override
public Collection<FunctionDescriptor> getNonExtensionsByName(JetScope scope, Name name) {
public Collection<FunctionDescriptor> getNonExtensionsByName(JetScope scope, Name name, @NotNull BindingTrace bindingTrace) {
Set<FunctionDescriptor> functions = Sets.newLinkedHashSet();
for (FunctionDescriptor function : scope.getFunctions(name)) {
if (function.getReceiverParameter() == null) {
@@ -51,7 +57,7 @@ public class CallableDescriptorCollectors {
@NotNull
@Override
public Collection<FunctionDescriptor> getMembersByName(@NotNull JetType receiverType, Name name) {
public Collection<FunctionDescriptor> getMembersByName(@NotNull JetType receiverType, Name name, @NotNull BindingTrace bindingTrace) {
JetScope receiverScope = receiverType.getMemberScope();
Set<FunctionDescriptor> members = Sets.newHashSet(receiverScope.getFunctions(name));
addConstructors(receiverScope, name, members);
@@ -60,7 +66,7 @@ public class CallableDescriptorCollectors {
@NotNull
@Override
public Collection<FunctionDescriptor> getNonMembersByName(JetScope scope, Name name) {
public Collection<FunctionDescriptor> getNonMembersByName(JetScope scope, Name name, @NotNull BindingTrace bindingTrace) {
return scope.getFunctions(name);
}
@@ -82,7 +88,7 @@ public class CallableDescriptorCollectors {
@NotNull
@Override
public Collection<VariableDescriptor> getNonExtensionsByName(JetScope scope, Name name) {
public Collection<VariableDescriptor> getNonExtensionsByName(JetScope scope, Name name, @NotNull BindingTrace bindingTrace) {
VariableDescriptor localVariable = scope.getLocalVariable(name);
if (localVariable != null) {
return Collections.singleton(localVariable);
@@ -99,13 +105,13 @@ public class CallableDescriptorCollectors {
@NotNull
@Override
public Collection<VariableDescriptor> getMembersByName(@NotNull JetType receiverType, Name name) {
public Collection<VariableDescriptor> getMembersByName(@NotNull JetType receiverType, Name name, @NotNull BindingTrace bindingTrace) {
return receiverType.getMemberScope().getProperties(name);
}
@NotNull
@Override
public Collection<VariableDescriptor> getNonMembersByName(JetScope scope, Name name) {
public Collection<VariableDescriptor> getNonMembersByName(JetScope scope, Name name, @NotNull BindingTrace bindingTrace) {
Collection<VariableDescriptor> result = Sets.newLinkedHashSet();
VariableDescriptor localVariable = scope.getLocalVariable(name);
@@ -135,20 +141,20 @@ public class CallableDescriptorCollectors {
@NotNull
@Override
public Collection<VariableDescriptor> getNonExtensionsByName(JetScope scope, Name name) {
return filterProperties(VARIABLES.getNonExtensionsByName(scope, name));
public Collection<VariableDescriptor> getNonExtensionsByName(JetScope scope, Name name, @NotNull BindingTrace bindingTrace) {
return filterProperties(VARIABLES.getNonExtensionsByName(scope, name, bindingTrace));
}
@NotNull
@Override
public Collection<VariableDescriptor> getMembersByName(@NotNull JetType receiver, Name name) {
return filterProperties(VARIABLES.getMembersByName(receiver, name));
public Collection<VariableDescriptor> getMembersByName(@NotNull JetType receiver, Name name, @NotNull BindingTrace bindingTrace) {
return filterProperties(VARIABLES.getMembersByName(receiver, name, bindingTrace));
}
@NotNull
@Override
public Collection<VariableDescriptor> getNonMembersByName(JetScope scope, Name name) {
return filterProperties(VARIABLES.getNonMembersByName(scope, name));
public Collection<VariableDescriptor> getNonMembersByName(JetScope scope, Name name, @NotNull BindingTrace bindingTrace) {
return filterProperties(VARIABLES.getNonMembersByName(scope, name, bindingTrace));
}
@Override
@@ -156,6 +162,37 @@ public class CallableDescriptorCollectors {
return "PROPERTIES";
}
}
private static class FilteredCollector<D extends CallableDescriptor> implements CallableDescriptorCollector<D> {
private final CallableDescriptorCollector<D> delegate;
private FilteredCollector(CallableDescriptorCollector<D> delegate) {
this.delegate = delegate;
}
@NotNull
@Override
public Collection<D> getNonExtensionsByName(JetScope scope, Name name, @NotNull BindingTrace bindingTrace) {
return filterOutMembersFromLibrarySource(delegate.getNonExtensionsByName(scope, name, bindingTrace), bindingTrace);
}
@NotNull
@Override
public Collection<D> getMembersByName(@NotNull JetType receiver, Name name, @NotNull BindingTrace bindingTrace) {
return filterOutMembersFromLibrarySource(delegate.getMembersByName(receiver, name, bindingTrace), bindingTrace);
}
@NotNull
@Override
public Collection<D> getNonMembersByName(JetScope scope, Name name, @NotNull BindingTrace bindingTrace) {
return filterOutMembersFromLibrarySource(delegate.getNonMembersByName(scope, name, bindingTrace), bindingTrace);
}
@Override
public String toString() {
return delegate.toString();
}
}
private CallableDescriptorCollectors() {
}
@@ -25,6 +25,7 @@ import org.jetbrains.jet.lang.psi.JetExpression;
import org.jetbrains.jet.lang.psi.JetReferenceExpression;
import org.jetbrains.jet.lang.psi.JetSuperExpression;
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
import org.jetbrains.jet.lang.resolve.LibrarySourceHacks;
import org.jetbrains.jet.lang.resolve.calls.autocasts.AutoCastServiceImpl;
import org.jetbrains.jet.lang.resolve.calls.context.BasicCallResolutionContext;
import org.jetbrains.jet.lang.resolve.name.Name;
@@ -41,7 +42,7 @@ import java.util.Collections;
import java.util.List;
import static org.jetbrains.jet.lang.resolve.DescriptorUtils.isClassObject;
import static org.jetbrains.jet.lang.resolve.calls.CallResolverUtil.*;
import static org.jetbrains.jet.lang.resolve.calls.CallResolverUtil.isOrOverridesSynthesized;
import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue.NO_RECEIVER;
public class TaskPrioritizer {
@@ -130,7 +131,8 @@ public class TaskPrioritizer {
for (CallableDescriptorCollector<? extends D> callableDescriptorCollector : c.callableDescriptorCollectors) {
Collection<ResolutionCandidate<D>> members = Lists.newArrayList();
for (ReceiverValue variant : variantsForExplicitReceiver) {
Collection<? extends D> membersForThisVariant = callableDescriptorCollector.getMembersByName(variant.getType(), c.name);
Collection<? extends D> membersForThisVariant =
callableDescriptorCollector.getMembersByName(variant.getType(), c.name, c.context.trace);
convertWithReceivers(membersForThisVariant, Collections.singletonList(variant),
Collections.singletonList(NO_RECEIVER), members, resolveInvoke);
}
@@ -144,9 +146,9 @@ public class TaskPrioritizer {
callableDescriptorCollector, c, resolveInvoke);
}
//extensions
Collection<ResolutionCandidate<D>> extensionFunctions = convertWithImpliedThis(
c.scope, variantsForExplicitReceiver, callableDescriptorCollector.getNonMembersByName(c.scope, c.name));
c.result.addCandidates(extensionFunctions);
Collection<ResolutionCandidate<D>> extensions = convertWithImpliedThis(
c.scope, variantsForExplicitReceiver, callableDescriptorCollector.getNonMembersByName(c.scope, c.name, c.context.trace));
c.result.addCandidates(extensions);
}
}
@@ -157,7 +159,7 @@ public class TaskPrioritizer {
boolean resolveInvoke
) {
Collection<? extends D> memberExtensions = callableDescriptorCollector.getNonMembersByName(
implicitReceiver.getType().getMemberScope(), c.name);
implicitReceiver.getType().getMemberScope(), c.name, c.context.trace);
List<ReceiverValue> variantsForImplicitReceiver = c.autoCastService.getVariantsForReceiver(implicitReceiver);
c.result.addCandidates(convertWithReceivers(memberExtensions, variantsForImplicitReceiver,
variantsForExplicitReceiver, resolveInvoke));
@@ -173,7 +175,7 @@ public class TaskPrioritizer {
Collection<ResolutionCandidate<D>> members =
convertWithImpliedThis(c.scope, Collections.singletonList(NO_RECEIVER), callableDescriptorCollector
.getNonExtensionsByName(c.scope, c.name));
.getNonExtensionsByName(c.scope, c.name, c.context.trace));
List<ResolutionCandidate<D>> nonlocals = Lists.newArrayList();
List<ResolutionCandidate<D>> locals = Lists.newArrayList();
@@ -54,7 +54,7 @@ public final class DeserializedDescriptorResolver {
@Nullable
@Override
public ClassDescriptor findClass(@NotNull ClassId classId) {
return javaClassResolver.resolveClass(kotlinFqNameToJavaFqName(classId.asSingleFqName()), IGNORE_KOTLIN_SOURCES);
return javaClassResolver.resolveClass(kotlinFqNameToJavaFqName(classId.asSingleFqName()), INCLUDE_KOTLIN_SOURCES);
}
@Nullable
@@ -91,7 +91,7 @@ public class JetPsiChecker implements Annotator {
@Override
public void annotate(@NotNull PsiElement element, @NotNull AnnotationHolder holder) {
if (!JetPluginUtil.isInSourceContent(element) ||
if (!JetPluginUtil.isInSource(element) ||
JetPluginUtil.isKtFileInGradleProjectInWrongFolder(element)) {
return;
}
@@ -106,7 +106,7 @@ public class JetPsiChecker implements Annotator {
try {
BindingContext bindingContext = AnalyzerFacadeWithCache.analyzeFileWithCache(file).getBindingContext();
if (JetPluginUtil.isInSourceContent(element, false)) {
if (JetPluginUtil.isInSourceContent(element, /* includeLibrarySources = */ false)) {
Collection<Diagnostic> diagnostics = Sets.newLinkedHashSet(bindingContext.getDiagnostics());
Set<PsiElement> redeclarations = Sets.newHashSet();
for (Diagnostic diagnostic : diagnostics) {
@@ -185,7 +185,10 @@ public final class AnalyzerFacadeWithCache {
VirtualFile virtualFile = fileToCache.getVirtualFile();
if (LightClassUtil.belongsToKotlinBuiltIns(fileToCache) ||
virtualFile != null && LibraryUtil.findLibraryEntry(virtualFile, fileToCache.getProject()) != null) {
/* For library sources we should resolve it, not only project files (as KotlinCacheManager do) */
// Library sources:
// Mark file to skip
fileToCache.putUserData(LibrarySourceHacks.SKIP_TOP_LEVEL_MEMBERS, true);
// Resolve this file, not only project files (as KotlinCacheManager do)
return AnalyzerFacadeForJVM.INSTANCE.analyzeFiles(
fileToCache.getProject(),
Collections.singleton(fileToCache),
@@ -26,6 +26,8 @@ import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.jet.JetTestCaseBuilder;
import org.jetbrains.jet.codegen.forTestCompile.ForTestPackJdkAnnotations;
import java.io.File;
public class PluginTestCaseBase {
public static final String TEST_DATA_PROJECT_RELATIVE = "/idea/testData";
@@ -37,8 +39,8 @@ public class PluginTestCaseBase {
return JetTestCaseBuilder.getHomeDirectory() + TEST_DATA_PROJECT_RELATIVE;
}
public static Sdk jdkFromIdeaHome() {
Sdk sdk = new JavaSdkImpl().createJdk("JDK", "compiler/testData/mockJDK/jre", true);
private static Sdk getSdk(String sdkHome) {
Sdk sdk = new JavaSdkImpl().createJdk("JDK", sdkHome, true);
SdkModificator modificator = sdk.getSdkModificator();
VirtualFile file = LocalFileSystem.getInstance().findFileByIoFile(ForTestPackJdkAnnotations.jdkAnnotationsForTests());
assert file != null;
@@ -46,4 +48,15 @@ public class PluginTestCaseBase {
modificator.commitChanges();
return sdk;
}
public static Sdk jdkFromIdeaHome() {
return getSdk("compiler/testData/mockJDK/jre");
}
public static Sdk fullJdk() {
String javaHome = System.getProperty("java.home");
assert new File(javaHome).isDirectory();
return getSdk(javaHome);
}
}
@@ -0,0 +1,73 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.highlighter
import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase
import com.intellij.testFramework.LightProjectDescriptor
import org.jetbrains.jet.plugin.ProjectDescriptorWithStdlibSources
import com.intellij.openapi.roots.ModuleRootManager
import org.jetbrains.jet.plugin.JetJdkAndLibraryProjectDescriptor
import com.intellij.openapi.roots.OrderRootType
import com.intellij.openapi.vfs.VfsUtil
import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache
import org.jetbrains.jet.lang.psi.JetFile
import org.jetbrains.jet.lang.diagnostics.Severity
import org.jetbrains.jet.cli.common.messages.AnalyzerWithCompilerReport
import org.jetbrains.jet.cli.common.messages.MessageCollectorPlainTextToStream
import com.intellij.openapi.projectRoots.Sdk
import org.jetbrains.jet.plugin.PluginTestCaseBase
import kotlin.test.assertEquals
public class NoErrorsInStdlibTest: LightCodeInsightFixtureTestCase() {
public fun testNoErrors() {
val orderEntries = ModuleRootManager.getInstance(myModule!!)!!.getOrderEntries()
val orderEntry = orderEntries.find { it.getPresentableName() == JetJdkAndLibraryProjectDescriptor.LIBRARY_NAME }!!
val root = orderEntry.getFiles(OrderRootType.SOURCES)[0]
val psiManager = getPsiManager() // workaround for KT-3974 IllegalAccessError when accessing protected method inherited by outer class
var totalErrors = 0
VfsUtil.processFileRecursivelyWithoutIgnored(root) { file ->
if (!file!!.isDirectory()) {
val psiFile = psiManager.findFile(file)
if (psiFile is JetFile) {
var bindingContext = AnalyzerFacadeWithCache.analyzeFileWithCache(psiFile).getBindingContext()
val errors = bindingContext.getDiagnostics().filter { it.getSeverity() == Severity.ERROR }
if (!errors.isEmpty()) {
System.err.println("${psiFile.getName()}: ${errors.size()} errors")
AnalyzerWithCompilerReport.reportDiagnostics(
bindingContext, MessageCollectorPlainTextToStream.PLAIN_TEXT_TO_SYSTEM_ERR)
totalErrors += errors.size()
}
}
}
true
}
assertEquals(0, totalErrors)
}
override fun getProjectDescriptor(): LightProjectDescriptor {
return object : ProjectDescriptorWithStdlibSources() {
override fun getSdk(): Sdk? = PluginTestCaseBase.fullJdk()
}
}
}