diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ClosureAnnotator.java b/compiler/backend/src/org/jetbrains/jet/codegen/ClosureAnnotator.java index 0c0886e651f..94e13393852 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ClosureAnnotator.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ClosureAnnotator.java @@ -16,6 +16,7 @@ package org.jetbrains.jet.codegen; +import com.intellij.openapi.util.Pair; import com.intellij.util.containers.MultiMap; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -47,6 +48,7 @@ public class ClosureAnnotator { private final Map classesForFunctions = new HashMap(); private final Map enclosing = new HashMap(); + private final MultiMap namespaceName2MultiNamespaceFiles = MultiMap.create(); private final MultiMap namespaceName2Files = MultiMap.create(); private BindingContext bindingContext; @@ -165,9 +167,33 @@ public class ClosureAnnotator { for (JetFile jetFile : entry.getValue()) { jetFile.accept(visitor); } + + ArrayList namespaceFiles = new ArrayList(); + for (JetFile jetFile : entry.getValue()) { + ArrayList fileFunctions = new ArrayList(); + for (JetDeclaration declaration : jetFile.getDeclarations()) { + if (declaration instanceof JetNamedFunction) { + fileFunctions.add(declaration); + } + } + + if (fileFunctions.size() > 0) { + namespaceFiles.add(jetFile); + } + } + + if(namespaceFiles.size() > 1) { + for (JetFile namespaceFile : namespaceFiles) { + namespaceName2MultiNamespaceFiles.putValue(entry.getKey(), namespaceFile); + } + } } } + public boolean isMultiFileNamespace(FqName fqName) { + return namespaceName2MultiNamespaceFiles.get(fqName).size() > 0; + } + public JvmClassName classNameForAnonymousClass(JetElement expression) { if (expression instanceof JetObjectLiteralExpression) { JetObjectLiteralExpression jetObjectLiteralExpression = (JetObjectLiteralExpression) expression; diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/NamespaceCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/NamespaceCodegen.java index 648fc0aad8a..2b411364da6 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/NamespaceCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/NamespaceCodegen.java @@ -81,20 +81,7 @@ public class NamespaceCodegen { } public void generate(CompilationErrorHandler errorHandler, final Progress progress) { - ArrayList>> byFile = new ArrayList>>(); - - for (JetFile file : files) { - ArrayList fileFunctions = new ArrayList(); - for (JetDeclaration declaration : file.getDeclarations()) { - if (declaration instanceof JetNamedFunction) { - fileFunctions.add(declaration); - } - } - if (fileFunctions.size() > 0) - byFile.add(new Pair>(file, fileFunctions)); - } - - boolean multiFile = byFile.size() > 1; + boolean multiFile = state.getInjector().getClosureAnnotator().isMultiFileNamespace(name); for (JetFile file : files) { VirtualFile vFile = file.getVirtualFile(); @@ -165,7 +152,9 @@ public class NamespaceCodegen { if (k > 0) { PsiFile containingFile = file.getContainingFile(); - String className = name.child(Name.identifier("namespace$src$" + (nextMultiFile++))).getFqName().replace('.','/'); + String fname = containingFile.getName(); + fname = fname.substring(0,fname.lastIndexOf('.')); + String className = name.child(Name.identifier("namespace$src$" + fname)).getFqName().replace('.','/'); ClassBuilder builder = state.forNamespacepart(className, file); builder.defineClass(containingFile, V1_6, diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JetFilesProvider.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JetFilesProvider.java index 55834d5ae0d..65b6ea471fe 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JetFilesProvider.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JetFilesProvider.java @@ -19,13 +19,20 @@ */ package org.jetbrains.jet.lang.resolve.java; +import com.google.common.base.Predicate; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.UserDataHolder; +import com.intellij.openapi.util.UserDataHolderBase; +import com.intellij.psi.PsiFile; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.util.Function; import org.jetbrains.jet.lang.psi.JetFile; +import org.jetbrains.jet.lang.psi.JetPsiUtil; +import org.jetbrains.jet.lang.resolve.name.FqName; import java.util.Collection; +import java.util.LinkedList; import java.util.List; public abstract class JetFilesProvider { @@ -33,6 +40,37 @@ public abstract class JetFilesProvider { return ServiceManager.getService(project, JetFilesProvider.class); } + public final Function> allNamespaceFiles() { + return new Function>() { + @Override + public List fun(JetFile file) { + return new SameJetFilePredicate(file).filter(sampleToAllFilesInModule().fun(file)); + } + }; + } + public abstract Function> sampleToAllFilesInModule(); public abstract List allInScope(GlobalSearchScope scope); + + public static class SameJetFilePredicate implements Predicate { + private final FqName name; + + public SameJetFilePredicate(JetFile file) { + this.name = JetPsiUtil.getFQName(file); + } + + @Override + public boolean apply(PsiFile psiFile) { + return JetPsiUtil.getFQName((JetFile) psiFile).equals(name); + } + + public List filter(Collection allFiles) { + LinkedList files = new LinkedList(); + for (JetFile aFile : allFiles) { + if(apply(aFile)) + files.add(aFile); + } + return files; + } + } } diff --git a/compiler/frontend/src/org/jetbrains/jet/analyzer/AnalyzerFacadeForEverything.java b/compiler/frontend/src/org/jetbrains/jet/analyzer/AnalyzerFacadeForEverything.java index 83bd59101b8..8e358e4e05d 100644 --- a/compiler/frontend/src/org/jetbrains/jet/analyzer/AnalyzerFacadeForEverything.java +++ b/compiler/frontend/src/org/jetbrains/jet/analyzer/AnalyzerFacadeForEverything.java @@ -34,6 +34,9 @@ import java.util.List; */ public class AnalyzerFacadeForEverything { + private AnalyzerFacadeForEverything() { + } + public static AnalyzeExhaust analyzeBodiesInFilesWithJavaIntegration( Project project, List scriptParameters, Predicate filesToAnalyzeCompletely, @NotNull BindingTrace traceContext, diff --git a/compiler/tests/org/jetbrains/jet/codegen/CodegenTestFiles.java b/compiler/tests/org/jetbrains/jet/codegen/CodegenTestFiles.java index 48dc5d3e094..a8cc049de95 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/CodegenTestFiles.java +++ b/compiler/tests/org/jetbrains/jet/codegen/CodegenTestFiles.java @@ -27,6 +27,7 @@ import org.jetbrains.jet.lang.resolve.name.Name; import org.jetbrains.jet.lang.types.ref.JetTypeName; import org.jetbrains.jet.parsing.JetParsingTest; +import java.io.File; import java.io.IOException; import java.util.*; import java.util.regex.Matcher; @@ -93,6 +94,8 @@ public class CodegenTestFiles { for (String name : names) { try { String content = JetTestUtils.doLoadFile(JetParsingTest.getTestDataDir() + "/codegen/", name); + int i = name.lastIndexOf(File.separatorChar); + name = name.substring(i+1); JetFile file = (JetFile) JetTestUtils.createFile(name, content, project); files.add(file); } catch (IOException e) { diff --git a/idea/src/org/jetbrains/jet/plugin/debugger/JetPositionManager.java b/idea/src/org/jetbrains/jet/plugin/debugger/JetPositionManager.java index e1ddfc0ec15..a8aeeda8079 100644 --- a/idea/src/org/jetbrains/jet/plugin/debugger/JetPositionManager.java +++ b/idea/src/org/jetbrains/jet/plugin/debugger/JetPositionManager.java @@ -28,11 +28,12 @@ import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.search.FilenameIndex; import com.intellij.psi.search.ProjectScope; -import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.psi.util.*; import com.sun.jdi.AbsentInformationException; import com.sun.jdi.Location; import com.sun.jdi.ReferenceType; import com.sun.jdi.request.ClassPrepareRequest; +import com.sun.jna.TypeMapper; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.analyzer.AnalyzeExhaust; @@ -42,17 +43,20 @@ import org.jetbrains.jet.di.InjectorForJetTypeMapper; import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.BindingContext; +import org.jetbrains.jet.lang.resolve.java.JetFilesProvider; import org.jetbrains.jet.lang.resolve.java.JvmClassName; +import org.jetbrains.jet.lang.resolve.name.FqName; import org.jetbrains.jet.plugin.project.WholeProjectAnalyzerFacade; import java.util.*; /** * @author yole + * @author alex.tkachman */ public class JetPositionManager implements PositionManager { private final DebugProcess myDebugProcess; - private WeakHashMap myTypeMappers = new WeakHashMap(); + private WeakHashMap> myTypeMappers = new WeakHashMap>(); public JetPositionManager(DebugProcess debugProcess) { myDebugProcess = debugProcess; @@ -132,7 +136,7 @@ public class JetPositionManager implements PositionManager { final JetFile file = (JetFile)sourcePosition.getFile(); JetTypeMapper typeMapper = prepareTypeMapper(file); - PsiElement psiElement = PsiTreeUtil.getParentOfType(sourcePosition.getElementAt(), JetClassOrObject.class, JetFunctionLiteralExpression.class); + PsiElement psiElement = PsiTreeUtil.getParentOfType(sourcePosition.getElementAt(), JetClassOrObject.class, JetFunctionLiteralExpression.class, JetNamedFunction.class); if (psiElement == null) { JetFile namespace = PsiTreeUtil.getParentOfType(sourcePosition.getElementAt(), JetFile.class); if (namespace != null) { @@ -143,8 +147,31 @@ public class JetPositionManager implements PositionManager { } } else { - if (psiElement instanceof JetClassOrObject) + if (psiElement instanceof JetClassOrObject) { names.addAll(typeMapper.allJvmNames((JetClassOrObject) psiElement)); + } + else if(psiElement instanceof JetNamedFunction) { + if(psiElement.getParent() instanceof JetFile) { + JetFile namespace = PsiTreeUtil.getParentOfType(sourcePosition.getElementAt(), JetFile.class); + boolean multiFileNamespace = typeMapper.getClosureAnnotator().isMultiFileNamespace(JetPsiUtil.getFQName(namespace)); + if(multiFileNamespace) { + String name = namespace.getName(); + names.add(NamespaceCodegen.getJVMClassNameForKotlinNs(JetPsiUtil.getFQName(namespace)).getInternalName() + "$src$" + name.substring(0,name.lastIndexOf('.'))); + } + else { + names.add(NamespaceCodegen.getJVMClassNameForKotlinNs(JetPsiUtil.getFQName(namespace)).getInternalName()); + } + } + else { + JetFile namespace = PsiTreeUtil.getParentOfType(sourcePosition.getElementAt(), JetFile.class); + if (namespace != null) { + names.add(NamespaceCodegen.getJVMClassNameForKotlinNs(JetPsiUtil.getFQName(namespace)).getInternalName()); + } + else { + names.add(NamespaceCodegen.getJVMClassNameForKotlinNs(JetPsiUtil.getFQName(file)).getInternalName()); + } + } + } else { names.add(typeMapper.getClosureAnnotator().classNameForAnonymousClass((JetElement) psiElement).getInternalName()); } @@ -155,17 +182,27 @@ public class JetPositionManager implements PositionManager { return names; } - private JetTypeMapper prepareTypeMapper(JetFile file) { - final JetTypeMapper mapper = myTypeMappers.get(file); - if (mapper != null) { - return mapper; + private JetTypeMapper prepareTypeMapper(final JetFile file) { + FqName fqName = JetPsiUtil.getFQName(file); + CachedValue value = myTypeMappers.get(fqName); + if(value == null) { + value = CachedValuesManager.getManager(file.getProject()).createCachedValue(new CachedValueProvider() { + @Override + public Result compute() { + final AnalyzeExhaust analyzeExhaust = WholeProjectAnalyzerFacade.analyzeProjectWithCacheOnAFile(file); + analyzeExhaust.throwIfError(); + + List namespaceFiles = JetFilesProvider.getInstance(file.getProject()).allNamespaceFiles().fun(file); + + JetTypeMapper typeMapper = new InjectorForJetTypeMapper(analyzeExhaust.getBindingContext(), namespaceFiles).getJetTypeMapper(); + typeMapper.getClosureAnnotator().init(); + return new Result(typeMapper, PsiModificationTracker.MODIFICATION_COUNT); + } + }, false); + myTypeMappers.put(fqName, value); } - final AnalyzeExhaust analyzeExhaust = WholeProjectAnalyzerFacade.analyzeProjectWithCacheOnAFile(file); - analyzeExhaust.throwIfError(); - JetTypeMapper typeMapper = new InjectorForJetTypeMapper( - analyzeExhaust.getBindingContext(), Collections.singletonList(file)).getJetTypeMapper(); - myTypeMappers.put(file, typeMapper); - return typeMapper; + + return value.getValue(); } @NotNull diff --git a/idea/src/org/jetbrains/jet/plugin/project/AnalyzerFacadeWithCache.java b/idea/src/org/jetbrains/jet/plugin/project/AnalyzerFacadeWithCache.java index 6ecdf1328f7..4bc6ffc70d7 100644 --- a/idea/src/org/jetbrains/jet/plugin/project/AnalyzerFacadeWithCache.java +++ b/idea/src/org/jetbrains/jet/plugin/project/AnalyzerFacadeWithCache.java @@ -16,6 +16,7 @@ package org.jetbrains.jet.plugin.project; +import com.google.common.base.Predicate; import com.google.common.base.Predicates; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.ProcessCanceledException; @@ -29,14 +30,18 @@ import com.intellij.psi.util.CachedValuesManager; import com.intellij.psi.util.PsiModificationTracker; import com.intellij.util.Function; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.analyzer.AnalyzeExhaust; import org.jetbrains.jet.lang.diagnostics.DiagnosticUtils; import org.jetbrains.jet.lang.diagnostics.Errors; import org.jetbrains.jet.lang.psi.JetFile; +import org.jetbrains.jet.lang.psi.JetPsiUtil; import org.jetbrains.jet.lang.resolve.AnalyzerScriptParameter; import org.jetbrains.jet.lang.resolve.BindingTraceContext; import org.jetbrains.jet.lang.resolve.BodiesResolveContext; import org.jetbrains.jet.lang.resolve.DelegatingBindingTrace; +import org.jetbrains.jet.lang.resolve.java.JetFilesProvider; +import org.jetbrains.jet.lang.resolve.name.FqName; import java.util.Collection; import java.util.Collections; @@ -91,11 +96,11 @@ public final class AnalyzerFacadeWithCache { BodiesResolveContext context = analyzeExhaustHeaders.getBodiesResolveContext(); assert context != null : "Headers resolver should prepare and stored information for bodies resolve"; - // Need to resolve bodies in given file + // Need to resolve bodies in given file and all in the same package AnalyzeExhaust exhaust = AnalyzerFacadeProvider.getAnalyzerFacadeForFile(file).analyzeBodiesInFiles( file.getProject(), Collections.emptyList(), - Predicates.equalTo(file), + new JetFilesProvider.SameJetFilePredicate(file), new DelegatingBindingTrace(analyzeExhaustHeaders.getBindingContext()), context);