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
This commit is contained in:
+1
-1
@@ -72,7 +72,7 @@ public class LazyPackageMemberScope extends AbstractLazyMemberScope<NamespaceDes
|
|||||||
@Override
|
@Override
|
||||||
protected JetScope getScopeForMemberDeclarationResolution(JetDeclaration declaration) {
|
protected JetScope getScopeForMemberDeclarationResolution(JetDeclaration declaration) {
|
||||||
return resolveSession.getInjector().getScopeProvider()
|
return resolveSession.getInjector().getScopeProvider()
|
||||||
.getFileScopeForDeclarationResolution((JetFile) declaration.getContainingFile());
|
.getFileScopeWithImportedClasses((JetFile) declaration.getContainingFile());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -238,7 +238,7 @@ public class ResolveSessionUtils {
|
|||||||
ScopeProvider provider = resolveSession.getInjector().getScopeProvider();
|
ScopeProvider provider = resolveSession.getInjector().getScopeProvider();
|
||||||
JetDeclaration parentDeclaration = PsiTreeUtil.getParentOfType(expression, JetDeclaration.class);
|
JetDeclaration parentDeclaration = PsiTreeUtil.getParentOfType(expression, JetDeclaration.class);
|
||||||
if (parentDeclaration == null) {
|
if (parentDeclaration == null) {
|
||||||
return provider.getFileScopeForDeclarationResolution((JetFile) expression.getContainingFile());
|
return provider.getFileScopeWithAllImported((JetFile) expression.getContainingFile());
|
||||||
}
|
}
|
||||||
return provider.getResolutionScopeForDeclaration(parentDeclaration);
|
return provider.getResolutionScopeForDeclaration(parentDeclaration);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,50 +40,95 @@ public class ScopeProvider {
|
|||||||
this.resolveSession = resolveSession;
|
this.resolveSession = resolveSession;
|
||||||
}
|
}
|
||||||
|
|
||||||
private final Map<JetFile, JetScope> fileScopeCache = new WeakHashMap<JetFile, JetScope>();
|
private final Map<JetFile, JetScope> fileScopeWithImportedClassesCache = new WeakHashMap<JetFile, JetScope>();
|
||||||
|
private final Map<JetFile, JetScope> fileScopeWithAllImportedCache = new WeakHashMap<JetFile, JetScope>();
|
||||||
|
|
||||||
// This scope does not contain imported functions
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public JetScope getFileScopeForDeclarationResolution(JetFile file) {
|
public JetScope getFileScopeWithImportedClasses(JetFile file) {
|
||||||
if (!fileScopeCache.containsKey(file)) {
|
JetScope scope = fileScopeWithImportedClassesCache.get(file);
|
||||||
// package
|
if (scope == null) {
|
||||||
JetNamespaceHeader header = file.getNamespaceHeader();
|
scope = createFileScopeWithImportedClasses(file);
|
||||||
if (header == null) {
|
fileScopeWithImportedClassesCache.put(file, scope);
|
||||||
throw new IllegalArgumentException("Scripts are not supported: " + file.getName());
|
}
|
||||||
}
|
return scope;
|
||||||
|
}
|
||||||
|
|
||||||
FqName fqName = new FqName(header.getQualifiedName());
|
@NotNull
|
||||||
NamespaceDescriptor packageDescriptor = resolveSession.getPackageDescriptorByFqName(fqName);
|
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) {
|
private JetScope createFileScopeWithImportedClasses(JetFile file) {
|
||||||
throw new IllegalStateException("Package not found: " + fqName + " maybe the file is not in scope of this resolve session: " + file.getName());
|
NamespaceDescriptor packageDescriptor = getFilePackageDescriptor(file);
|
||||||
}
|
|
||||||
|
|
||||||
WritableScope fileScope = new WritableScopeImpl(
|
WritableScope fileScope = new WritableScopeImpl(
|
||||||
JetScope.EMPTY, packageDescriptor, RedeclarationHandler.DO_NOTHING, "File scope for declaration resolution");
|
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);
|
NamespaceDescriptor rootPackageDescriptor = resolveSession.getPackageDescriptorByFqName(FqName.ROOT);
|
||||||
if (rootPackageDescriptor == null) {
|
if (rootPackageDescriptor == null) {
|
||||||
throw new IllegalStateException("Root package not found");
|
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));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
@NotNull
|
||||||
@@ -95,7 +140,7 @@ public class ScopeProvider {
|
|||||||
|
|
||||||
JetDeclaration parentDeclaration = PsiTreeUtil.getParentOfType(jetDeclaration, JetDeclaration.class);
|
JetDeclaration parentDeclaration = PsiTreeUtil.getParentOfType(jetDeclaration, JetDeclaration.class);
|
||||||
if (parentDeclaration == null) {
|
if (parentDeclaration == null) {
|
||||||
return getFileScopeForDeclarationResolution((JetFile) elementOfDeclaration.getContainingFile());
|
return getFileScopeWithAllImported((JetFile) elementOfDeclaration.getContainingFile());
|
||||||
}
|
}
|
||||||
|
|
||||||
assert jetDeclaration != null : "Can't happen because of getParentOfType(null, ?) == null";
|
assert jetDeclaration != null : "Can't happen because of getParentOfType(null, ?) == null";
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package first
|
||||||
|
|
||||||
|
import second.testFun
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
testFun().<caret>
|
||||||
|
}
|
||||||
|
|
||||||
|
// EXIST: testMethod
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package second
|
||||||
|
|
||||||
|
class TestSecond {
|
||||||
|
fun testMethod() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testFun() : TestSecond = TestSecond()
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package first
|
||||||
|
|
||||||
|
// For KT-3102
|
||||||
|
|
||||||
|
import second.foo
|
||||||
|
|
||||||
|
fun test() = foo().ext<caret>
|
||||||
|
|
||||||
|
// EXIST: extensionFunction1, extensionFunction2
|
||||||
@@ -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()
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package first
|
||||||
|
|
||||||
|
// For KT-3096 No completion in function literal
|
||||||
|
|
||||||
|
import second.someWithLiteral
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
someWithLiteral({file -> file.testFu<caret>})
|
||||||
|
}
|
||||||
|
|
||||||
|
// EXIST: testFunction1, testFunction2
|
||||||
@@ -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
|
||||||
@@ -22,6 +22,9 @@ import org.jetbrains.jet.plugin.PluginTestCaseBase;
|
|||||||
* @author Nikolay Krasko
|
* @author Nikolay Krasko
|
||||||
*/
|
*/
|
||||||
public class JetMultifileBasicCompletionTest extends JetCompletionMultiTestBase {
|
public class JetMultifileBasicCompletionTest extends JetCompletionMultiTestBase {
|
||||||
|
public void testCompletionOnImportedFunction() {
|
||||||
|
doFileTest();
|
||||||
|
}
|
||||||
|
|
||||||
public void testDoNotCompleteWithConstraints() {
|
public void testDoNotCompleteWithConstraints() {
|
||||||
doFileTest();
|
doFileTest();
|
||||||
@@ -31,6 +34,10 @@ public class JetMultifileBasicCompletionTest extends JetCompletionMultiTestBase
|
|||||||
doFileTest();
|
doFileTest();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testExtensionFunctionOnImportedFunction() throws Exception {
|
||||||
|
doFileTest(2);
|
||||||
|
}
|
||||||
|
|
||||||
public void todotestExtensionFunctionOnUnresolved() throws Exception {
|
public void todotestExtensionFunctionOnUnresolved() throws Exception {
|
||||||
doFileTest();
|
doFileTest();
|
||||||
}
|
}
|
||||||
@@ -43,6 +50,10 @@ public class JetMultifileBasicCompletionTest extends JetCompletionMultiTestBase
|
|||||||
doFileTest();
|
doFileTest();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testInImportedFunctionLiteralParameter() throws Exception {
|
||||||
|
doFileTest(2);
|
||||||
|
}
|
||||||
|
|
||||||
public void testJavaInnerClasses() throws Exception {
|
public void testJavaInnerClasses() throws Exception {
|
||||||
String fileName = getTestName(false);
|
String fileName = getTestName(false);
|
||||||
doFileTest(1, new String[] {fileName + ".kt", fileName + ".java"});
|
doFileTest(1, new String[] {fileName + ".kt", fileName + ".java"});
|
||||||
|
|||||||
Reference in New Issue
Block a user