From 5368e8cef38d518f772e32a851806526a78584fe Mon Sep 17 00:00:00 2001 From: Nikolay Krasko Date: Fri, 30 Nov 2012 15:29:38 +0400 Subject: [PATCH] Process imports for functioncs and properties in creating scope for file during lazy resolve Fix for "KT-3096 No completion in function literal" and "KT-3102 No completion/auto-import for an extension method" #KT-3102 Fixed #KT-3096 Fixed --- .../resolve/lazy/LazyPackageMemberScope.java | 2 +- .../resolve/lazy/ResolveSessionUtils.java | 2 +- .../jet/lang/resolve/lazy/ScopeProvider.java | 117 ++++++++++++------ .../CompletionOnImportedFunction-1.kt | 9 ++ .../CompletionOnImportedFunction-2.kt | 9 ++ .../ExtensionFunctionOnImportedFunction-1.kt | 9 ++ .../ExtensionFunctionOnImportedFunction-2.kt | 9 ++ .../InImportedFunctionLiteralParameter-1.kt | 11 ++ .../InImportedFunctionLiteralParameter-2.kt | 9 ++ .../JetMultifileBasicCompletionTest.java | 11 ++ 10 files changed, 150 insertions(+), 38 deletions(-) create mode 100644 idea/testData/completion/basic/multifile/CompletionOnImportedFunction-1.kt create mode 100644 idea/testData/completion/basic/multifile/CompletionOnImportedFunction-2.kt create mode 100644 idea/testData/completion/basic/multifile/ExtensionFunctionOnImportedFunction-1.kt create mode 100644 idea/testData/completion/basic/multifile/ExtensionFunctionOnImportedFunction-2.kt create mode 100644 idea/testData/completion/basic/multifile/InImportedFunctionLiteralParameter-1.kt create mode 100644 idea/testData/completion/basic/multifile/InImportedFunctionLiteralParameter-2.kt diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/lazy/LazyPackageMemberScope.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/lazy/LazyPackageMemberScope.java index 43453b8eb05..e8fa63328f9 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/lazy/LazyPackageMemberScope.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/lazy/LazyPackageMemberScope.java @@ -72,7 +72,7 @@ public class LazyPackageMemberScope extends AbstractLazyMemberScope fileScopeCache = new WeakHashMap(); + private final Map fileScopeWithImportedClassesCache = new WeakHashMap(); + private final Map fileScopeWithAllImportedCache = new WeakHashMap(); - // This scope does not contain imported functions @NotNull - public JetScope getFileScopeForDeclarationResolution(JetFile file) { - if (!fileScopeCache.containsKey(file)) { - // package - JetNamespaceHeader header = file.getNamespaceHeader(); - if (header == null) { - throw new IllegalArgumentException("Scripts are not supported: " + file.getName()); - } + public JetScope getFileScopeWithImportedClasses(JetFile file) { + JetScope scope = fileScopeWithImportedClassesCache.get(file); + if (scope == null) { + scope = createFileScopeWithImportedClasses(file); + fileScopeWithImportedClassesCache.put(file, scope); + } + return scope; + } - FqName fqName = new FqName(header.getQualifiedName()); - NamespaceDescriptor packageDescriptor = resolveSession.getPackageDescriptorByFqName(fqName); + @NotNull + public JetScope getFileScopeWithAllImported(JetFile file) { + JetScope scope = fileScopeWithAllImportedCache.get(file); + if (scope == null) { + scope = createFileScopeWithAllImported(file); + fileScopeWithAllImportedCache.put(file, scope); + } + return scope; + } - if (packageDescriptor == null) { - throw new IllegalStateException("Package not found: " + fqName + " maybe the file is not in scope of this resolve session: " + file.getName()); - } + private JetScope createFileScopeWithImportedClasses(JetFile file) { + NamespaceDescriptor packageDescriptor = getFilePackageDescriptor(file); - WritableScope fileScope = new WritableScopeImpl( - JetScope.EMPTY, packageDescriptor, RedeclarationHandler.DO_NOTHING, "File scope for declaration resolution"); + WritableScope fileScope = new WritableScopeImpl( + JetScope.EMPTY, packageDescriptor, RedeclarationHandler.DO_NOTHING, "File scope for declaration resolution with only classes imported"); - fileScope.changeLockLevel(WritableScope.LockLevel.BOTH); + fileScope.changeLockLevel(WritableScope.LockLevel.BOTH); - NamespaceDescriptor rootPackageDescriptor = resolveSession.getPackageDescriptorByFqName(FqName.ROOT); - if (rootPackageDescriptor == null) { - throw new IllegalStateException("Root package not found"); - } - - // Don't import twice - if (!packageDescriptor.getQualifiedName().equals(FqName.ROOT)) { - fileScope.importScope(rootPackageDescriptor.getMemberScope()); - } - - ImportsResolver.processImportsInFile(true, fileScope, Lists.newArrayList(file.getImportDirectives()), - rootPackageDescriptor.getMemberScope(), - resolveSession.getModuleConfiguration(), resolveSession.getTrace(), - resolveSession.getInjector().getQualifiedExpressionResolver()); - - fileScope.changeLockLevel(WritableScope.LockLevel.READING); - fileScopeCache.put(file, new ChainedScope(packageDescriptor, packageDescriptor.getMemberScope(), fileScope)); + NamespaceDescriptor rootPackageDescriptor = resolveSession.getPackageDescriptorByFqName(FqName.ROOT); + if (rootPackageDescriptor == null) { + throw new IllegalStateException("Root package not found"); } - return fileScopeCache.get(file); + // Don't import twice + if (!packageDescriptor.getQualifiedName().equals(FqName.ROOT)) { + fileScope.importScope(rootPackageDescriptor.getMemberScope()); + } + + ImportsResolver.processImportsInFile(true, fileScope, Lists.newArrayList(file.getImportDirectives()), + rootPackageDescriptor.getMemberScope(), + resolveSession.getModuleConfiguration(), resolveSession.getTrace(), + resolveSession.getInjector().getQualifiedExpressionResolver()); + + fileScope.changeLockLevel(WritableScope.LockLevel.READING); + + return new ChainedScope(packageDescriptor, packageDescriptor.getMemberScope(), fileScope); + } + + private NamespaceDescriptor getFilePackageDescriptor(JetFile file) { + // package + JetNamespaceHeader header = file.getNamespaceHeader(); + if (header == null) { + throw new IllegalArgumentException("Scripts are not supported: " + file.getName()); + } + + FqName fqName = new FqName(header.getQualifiedName()); + NamespaceDescriptor packageDescriptor = resolveSession.getPackageDescriptorByFqName(fqName); + + if (packageDescriptor == null) { + throw new IllegalStateException("Package not found: " + fqName + " maybe the file is not in scope of this resolve session: " + file.getName()); + } + return packageDescriptor; + } + + private JetScope createFileScopeWithAllImported(JetFile file) { + JetScope scopeWithImportedClasses = getFileScopeWithImportedClasses(file); + NamespaceDescriptor packageDescriptor = getFilePackageDescriptor(file); + + NamespaceDescriptor rootPackageDescriptor = resolveSession.getPackageDescriptorByFqName(FqName.ROOT); + if (rootPackageDescriptor == null) { + throw new IllegalStateException("Root package not found"); + } + + WritableScope fileMemberScope = new WritableScopeImpl( + JetScope.EMPTY, packageDescriptor, RedeclarationHandler.DO_NOTHING, "File scope for members declaration resolution with non-class imports"); + + fileMemberScope.changeLockLevel(WritableScope.LockLevel.BOTH); + + ImportsResolver.processImportsInFile(false, fileMemberScope, Lists.newArrayList(file.getImportDirectives()), + rootPackageDescriptor.getMemberScope(), + resolveSession.getModuleConfiguration(), resolveSession.getTrace(), + resolveSession.getInjector().getQualifiedExpressionResolver()); + + fileMemberScope.changeLockLevel(WritableScope.LockLevel.READING); + + return new ChainedScope(packageDescriptor, scopeWithImportedClasses, fileMemberScope); } @NotNull @@ -95,7 +140,7 @@ public class ScopeProvider { JetDeclaration parentDeclaration = PsiTreeUtil.getParentOfType(jetDeclaration, JetDeclaration.class); if (parentDeclaration == null) { - return getFileScopeForDeclarationResolution((JetFile) elementOfDeclaration.getContainingFile()); + return getFileScopeWithAllImported((JetFile) elementOfDeclaration.getContainingFile()); } assert jetDeclaration != null : "Can't happen because of getParentOfType(null, ?) == null"; diff --git a/idea/testData/completion/basic/multifile/CompletionOnImportedFunction-1.kt b/idea/testData/completion/basic/multifile/CompletionOnImportedFunction-1.kt new file mode 100644 index 00000000000..10e2e956cf6 --- /dev/null +++ b/idea/testData/completion/basic/multifile/CompletionOnImportedFunction-1.kt @@ -0,0 +1,9 @@ +package first + +import second.testFun + +fun test() { + testFun(). +} + +// EXIST: testMethod \ No newline at end of file diff --git a/idea/testData/completion/basic/multifile/CompletionOnImportedFunction-2.kt b/idea/testData/completion/basic/multifile/CompletionOnImportedFunction-2.kt new file mode 100644 index 00000000000..19fc60ebadb --- /dev/null +++ b/idea/testData/completion/basic/multifile/CompletionOnImportedFunction-2.kt @@ -0,0 +1,9 @@ +package second + +class TestSecond { + fun testMethod() { + + } +} + +fun testFun() : TestSecond = TestSecond() \ No newline at end of file diff --git a/idea/testData/completion/basic/multifile/ExtensionFunctionOnImportedFunction-1.kt b/idea/testData/completion/basic/multifile/ExtensionFunctionOnImportedFunction-1.kt new file mode 100644 index 00000000000..e2fea3e03f8 --- /dev/null +++ b/idea/testData/completion/basic/multifile/ExtensionFunctionOnImportedFunction-1.kt @@ -0,0 +1,9 @@ +package first + +// For KT-3102 + +import second.foo + +fun test() = foo().ext + +// EXIST: extensionFunction1, extensionFunction2 \ No newline at end of file diff --git a/idea/testData/completion/basic/multifile/ExtensionFunctionOnImportedFunction-2.kt b/idea/testData/completion/basic/multifile/ExtensionFunctionOnImportedFunction-2.kt new file mode 100644 index 00000000000..4d5180866da --- /dev/null +++ b/idea/testData/completion/basic/multifile/ExtensionFunctionOnImportedFunction-2.kt @@ -0,0 +1,9 @@ +package second + +class Some + +// Two function to prevent automatic insert +fun Some.extensionFunction1() = 12 +fun Some.extensionFunction2() = 12 + +fun foo() = Some() \ No newline at end of file diff --git a/idea/testData/completion/basic/multifile/InImportedFunctionLiteralParameter-1.kt b/idea/testData/completion/basic/multifile/InImportedFunctionLiteralParameter-1.kt new file mode 100644 index 00000000000..1e89da624a2 --- /dev/null +++ b/idea/testData/completion/basic/multifile/InImportedFunctionLiteralParameter-1.kt @@ -0,0 +1,11 @@ +package first + +// For KT-3096 No completion in function literal + +import second.someWithLiteral + +fun test() { + someWithLiteral({file -> file.testFu}) +} + +// EXIST: testFunction1, testFunction2 \ No newline at end of file diff --git a/idea/testData/completion/basic/multifile/InImportedFunctionLiteralParameter-2.kt b/idea/testData/completion/basic/multifile/InImportedFunctionLiteralParameter-2.kt new file mode 100644 index 00000000000..761296cd307 --- /dev/null +++ b/idea/testData/completion/basic/multifile/InImportedFunctionLiteralParameter-2.kt @@ -0,0 +1,9 @@ +package second + +class Some { + // Two function to prevent automatic insert + fun testFunction1() : Int = 12 + fun testFunction2() : Int = 12 +} + +fun someWithLiteral(body: (Some) -> Unit) = 12 \ No newline at end of file diff --git a/idea/tests/org/jetbrains/jet/completion/JetMultifileBasicCompletionTest.java b/idea/tests/org/jetbrains/jet/completion/JetMultifileBasicCompletionTest.java index e08dc606d33..0b7fe34fae7 100644 --- a/idea/tests/org/jetbrains/jet/completion/JetMultifileBasicCompletionTest.java +++ b/idea/tests/org/jetbrains/jet/completion/JetMultifileBasicCompletionTest.java @@ -22,6 +22,9 @@ import org.jetbrains.jet.plugin.PluginTestCaseBase; * @author Nikolay Krasko */ public class JetMultifileBasicCompletionTest extends JetCompletionMultiTestBase { + public void testCompletionOnImportedFunction() { + doFileTest(); + } public void testDoNotCompleteWithConstraints() { doFileTest(); @@ -31,6 +34,10 @@ public class JetMultifileBasicCompletionTest extends JetCompletionMultiTestBase doFileTest(); } + public void testExtensionFunctionOnImportedFunction() throws Exception { + doFileTest(2); + } + public void todotestExtensionFunctionOnUnresolved() throws Exception { doFileTest(); } @@ -43,6 +50,10 @@ public class JetMultifileBasicCompletionTest extends JetCompletionMultiTestBase doFileTest(); } + public void testInImportedFunctionLiteralParameter() throws Exception { + doFileTest(2); + } + public void testJavaInnerClasses() throws Exception { String fileName = getTestName(false); doFileTest(1, new String[] {fileName + ".kt", fileName + ".java"});