diff --git a/idea/src/META-INF/plugin.xml b/idea/src/META-INF/plugin.xml
index 857f5bb1d13..3e7739c9d4e 100644
--- a/idea/src/META-INF/plugin.xml
+++ b/idea/src/META-INF/plugin.xml
@@ -45,5 +45,6 @@
+
diff --git a/idea/src/org/jetbrains/jet/codegen/ClassCodegen.java b/idea/src/org/jetbrains/jet/codegen/ClassCodegen.java
index 07dee13f7da..4c3ca0a0eea 100644
--- a/idea/src/org/jetbrains/jet/codegen/ClassCodegen.java
+++ b/idea/src/org/jetbrains/jet/codegen/ClassCodegen.java
@@ -17,7 +17,7 @@ public class ClassCodegen {
}
public void generate(ClassContext parentContext, JetClassOrObject aClass) {
- state.prepareAnonymousClasses((JetElement) aClass);
+ GenerationState.prepareAnonymousClasses((JetElement) aClass, state.getTypeMapper());
if (aClass instanceof JetObjectDeclaration) {
generateImplementation(parentContext, aClass, OwnerKind.IMPLEMENTATION);
diff --git a/idea/src/org/jetbrains/jet/codegen/ClassFileFactory.java b/idea/src/org/jetbrains/jet/codegen/ClassFileFactory.java
index d485b7f7ce2..bc00c386c08 100644
--- a/idea/src/org/jetbrains/jet/codegen/ClassFileFactory.java
+++ b/idea/src/org/jetbrains/jet/codegen/ClassFileFactory.java
@@ -49,7 +49,8 @@ public class ClassFileFactory {
String fqName = namespace.getFQName();
NamespaceCodegen codegen = ns2codegen.get(fqName);
if (codegen == null) {
- codegen = new NamespaceCodegen(newVisitor(NamespaceCodegen.getJVMClassName(fqName) + ".class"), fqName, state);
+ final ClassVisitor classVisitor = newVisitor(NamespaceCodegen.getJVMClassName(fqName) + ".class");
+ codegen = new NamespaceCodegen(classVisitor, fqName, state, namespace.getContainingFile());
ns2codegen.put(fqName, codegen);
}
diff --git a/idea/src/org/jetbrains/jet/codegen/ClosureCodegen.java b/idea/src/org/jetbrains/jet/codegen/ClosureCodegen.java
index 9af17666bcc..f93ddd3b44f 100644
--- a/idea/src/org/jetbrains/jet/codegen/ClosureCodegen.java
+++ b/idea/src/org/jetbrains/jet/codegen/ClosureCodegen.java
@@ -107,6 +107,7 @@ public class ClosureCodegen {
funClass,
new String[0]
);
+ cv.visitSource(fun.getContainingFile().getName(), null);
generateBridge(name, funDescriptor, cv);
diff --git a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java
index 2f7d11653f7..2469b476c94 100644
--- a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java
+++ b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java
@@ -1,5 +1,6 @@
package org.jetbrains.jet.codegen;
+import com.intellij.openapi.editor.Document;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.psi.search.ProjectScope;
@@ -581,6 +582,7 @@ public class ExpressionCodegen extends JetVisitor {
for (int i = 0, statementsSize = statements.size(); i < statementsSize; i++) {
JetElement statement = statements.get(i);
+ markLineNumber(statement);
if (i == statements.size() - 1) {
gen(statement);
}
@@ -604,6 +606,16 @@ public class ExpressionCodegen extends JetVisitor {
}
}
+ private void markLineNumber(JetElement statement) {
+ final Document document = statement.getContainingFile().getViewProvider().getDocument();
+ if (document != null) {
+ int lineNumber = document.getLineNumber(statement.getTextRange().getStartOffset());
+ Label label = new Label();
+ v.visitLabel(label);
+ v.visitLineNumber(lineNumber, label);
+ }
+ }
+
@Override
public void visitReturnExpression(JetReturnExpression expression) {
final JetExpression returnedExpression = expression.getReturnedExpression();
diff --git a/idea/src/org/jetbrains/jet/codegen/GenerationState.java b/idea/src/org/jetbrains/jet/codegen/GenerationState.java
index a935133f248..631776165d0 100644
--- a/idea/src/org/jetbrains/jet/codegen/GenerationState.java
+++ b/idea/src/org/jetbrains/jet/codegen/GenerationState.java
@@ -77,7 +77,7 @@ public class GenerationState {
}
public void compile(JetFile psiFile) {
- final JetNamespace namespace = ((JetFile) psiFile).getRootNamespace();
+ final JetNamespace namespace = psiFile.getRootNamespace();
NamespaceCodegen codegen = forNamespace(namespace);
final BindingContext bindingContext = AnalyzingUtils.analyzeNamespace(namespace, JetControlFlowDataTraceFactory.EMPTY);
bindingContexts.push(bindingContext);
@@ -101,7 +101,7 @@ public class GenerationState {
return new GeneratedAnonymousClassDescriptor(nameAndVisitor.first, new Method("", "()V"), false);
}
- void prepareAnonymousClasses(JetElement aClass) {
+ public static void prepareAnonymousClasses(JetElement aClass, final JetTypeMapper typeMapper) {
aClass.acceptChildren(new JetVisitor() {
@Override
public void visitJetElement(JetElement element) {
@@ -111,7 +111,7 @@ public class GenerationState {
@Override
public void visitObjectLiteralExpression(JetObjectLiteralExpression expression) {
- getTypeMapper().classNameForAnonymousClass(expression.getObjectDeclaration());
+ typeMapper.classNameForAnonymousClass(expression.getObjectDeclaration());
}
});
}
diff --git a/idea/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java b/idea/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java
index 6cfa5fdf0d8..aefc174ed42 100644
--- a/idea/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java
+++ b/idea/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java
@@ -47,6 +47,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
superClass,
interfaces.toArray(new String[interfaces.size()])
);
+ v.visitSource(myClass.getContainingFile().getName(), null);
}
private String jvmName() {
diff --git a/idea/src/org/jetbrains/jet/codegen/InterfaceBodyCodegen.java b/idea/src/org/jetbrains/jet/codegen/InterfaceBodyCodegen.java
index 52f31470129..a40f28684b6 100644
--- a/idea/src/org/jetbrains/jet/codegen/InterfaceBodyCodegen.java
+++ b/idea/src/org/jetbrains/jet/codegen/InterfaceBodyCodegen.java
@@ -39,6 +39,7 @@ public class InterfaceBodyCodegen extends ClassBodyCodegen {
"java/lang/Object",
superInterfaces.toArray(new String[superInterfaces.size()])
);
+ v.visitSource(myClass.getContainingFile().getName(), null);
}
static Set getSuperInterfaces(JetClassOrObject aClass, final BindingContext bindingContext) {
diff --git a/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java b/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java
index 9cdf479a8c4..7cf9e82ff23 100644
--- a/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java
+++ b/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java
@@ -211,7 +211,7 @@ public class JetTypeMapper {
return Type.getType("L" + jvmNameForDelegatingImplementation(classDescriptor) + ";");
}
- static String jvmName(JetNamespace namespace) {
+ public static String jvmName(JetNamespace namespace) {
return NamespaceCodegen.getJVMClassName(namespace.getFQName());
}
@@ -572,4 +572,15 @@ public class JetTypeMapper {
classNamesForAnonymousClasses.put(expression, className);
return className;
}
+
+ public Collection allJvmNames(JetClassOrObject jetClass) {
+ Set result = new HashSet();
+ final ClassDescriptor classDescriptor = bindingContext.getClassDescriptor(jetClass);
+ if (classDescriptor != null) {
+ result.add(jvmName(classDescriptor, OwnerKind.INTERFACE));
+ result.add(jvmName(classDescriptor, OwnerKind.IMPLEMENTATION));
+ result.add(jvmName(classDescriptor, OwnerKind.DELEGATING_IMPLEMENTATION));
+ }
+ return result;
+ }
}
diff --git a/idea/src/org/jetbrains/jet/codegen/NamespaceCodegen.java b/idea/src/org/jetbrains/jet/codegen/NamespaceCodegen.java
index 01cf982bc57..32d81e65a4c 100644
--- a/idea/src/org/jetbrains/jet/codegen/NamespaceCodegen.java
+++ b/idea/src/org/jetbrains/jet/codegen/NamespaceCodegen.java
@@ -1,5 +1,6 @@
package org.jetbrains.jet.codegen;
+import com.intellij.psi.PsiFile;
import org.jetbrains.jet.lang.descriptors.PropertyDescriptor;
import org.jetbrains.jet.lang.psi.*;
import org.objectweb.asm.ClassVisitor;
@@ -15,7 +16,7 @@ public class NamespaceCodegen {
private final ClassVisitor v;
private final GenerationState state;
- public NamespaceCodegen(ClassVisitor v, String fqName, GenerationState state) {
+ public NamespaceCodegen(ClassVisitor v, String fqName, GenerationState state, PsiFile sourceFile) {
this.v = v;
this.state = state;
@@ -27,6 +28,8 @@ public class NamespaceCodegen {
"java/lang/Object",
new String[0]
);
+ // TODO figure something out for a namespace that spans multiple files
+ v.visitSource(sourceFile.getName(), null);
}
public void generate(JetNamespace namespace) {
@@ -36,7 +39,7 @@ public class NamespaceCodegen {
final PropertyCodegen propertyCodegen = new PropertyCodegen(context, v, functionCodegen, state);
final ClassCodegen classCodegen = state.forClass();
- state.prepareAnonymousClasses(namespace);
+ GenerationState.prepareAnonymousClasses(namespace, state.getTypeMapper());
if (hasNonConstantPropertyInitializers(namespace)) {
generateStaticInitializers(namespace);
diff --git a/idea/src/org/jetbrains/jet/plugin/JetFileType.java b/idea/src/org/jetbrains/jet/plugin/JetFileType.java
index 465804366ba..531a8e21314 100644
--- a/idea/src/org/jetbrains/jet/plugin/JetFileType.java
+++ b/idea/src/org/jetbrains/jet/plugin/JetFileType.java
@@ -34,4 +34,9 @@ public class JetFileType extends LanguageFileType {
public Icon getIcon() {
return Icons.PROJECT_ICON;
}
+
+ @Override
+ public boolean isJVMDebuggingSupported() {
+ return true;
+ }
}
diff --git a/idea/src/org/jetbrains/jet/plugin/debugger/JetPositionManager.java b/idea/src/org/jetbrains/jet/plugin/debugger/JetPositionManager.java
new file mode 100644
index 00000000000..3057038b8f6
--- /dev/null
+++ b/idea/src/org/jetbrains/jet/plugin/debugger/JetPositionManager.java
@@ -0,0 +1,152 @@
+package org.jetbrains.jet.plugin.debugger;
+
+import com.intellij.debugger.NoDataException;
+import com.intellij.debugger.PositionManager;
+import com.intellij.debugger.SourcePosition;
+import com.intellij.debugger.engine.DebugProcess;
+import com.intellij.debugger.requests.ClassPrepareRequestor;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.util.PsiTreeUtil;
+import com.sun.jdi.AbsentInformationException;
+import com.sun.jdi.Location;
+import com.sun.jdi.ReferenceType;
+import com.sun.jdi.request.ClassPrepareRequest;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.jet.codegen.GenerationState;
+import org.jetbrains.jet.codegen.JetTypeMapper;
+import org.jetbrains.jet.lang.psi.*;
+import org.jetbrains.jet.lang.resolve.AnalyzingUtils;
+import org.jetbrains.jet.lang.resolve.BindingContext;
+import org.jetbrains.jet.lang.types.JetStandardLibrary;
+
+import java.util.*;
+
+/**
+ * @author yole
+ */
+public class JetPositionManager implements PositionManager {
+ private final DebugProcess myDebugProcess;
+ private WeakHashMap myTypeMappers = new WeakHashMap();
+
+ public JetPositionManager(DebugProcess debugProcess) {
+ myDebugProcess = debugProcess;
+ }
+
+ @Override
+ @Nullable
+ public SourcePosition getSourcePosition(@Nullable Location location) throws NoDataException {
+ PsiFile psiFile = getPsiFileByLocation(location);
+ throw new NoDataException();
+ }
+
+ private PsiFile getPsiFileByLocation(Location location) {
+ final ReferenceType referenceType = location.declaringType();
+ if (referenceType == null) {
+ return null;
+ }
+
+ // TODO
+ return null;
+ }
+
+ @NotNull
+ @Override
+ public List getAllClasses(SourcePosition sourcePosition) throws NoDataException {
+ if (!(sourcePosition.getFile() instanceof JetFile)) {
+ throw new NoDataException();
+ }
+ final Collection names = classNamesForPosition(sourcePosition);
+ List result = new ArrayList();
+ for (String name : names) {
+ result.addAll(myDebugProcess.getVirtualMachineProxy().classesByName(name));
+ }
+ return result;
+ }
+
+ private Collection classNamesForPosition(SourcePosition sourcePosition) {
+ final JetFile file = (JetFile) sourcePosition.getFile();
+ JetTypeMapper typeMapper = prepareTypeMapper(file);
+ final Collection names = new ArrayList();
+ JetClassOrObject jetClass = PsiTreeUtil.getParentOfType(sourcePosition.getElementAt(), JetClassOrObject.class);
+ if (jetClass != null) {
+ names.addAll(typeMapper.allJvmNames(jetClass));
+ }
+ else {
+ JetNamespace namespace = PsiTreeUtil.getParentOfType(sourcePosition.getElementAt(), JetNamespace.class);
+ if (namespace != null) {
+ names.add(JetTypeMapper.jvmName(namespace));
+ }
+ else {
+ names.add(JetTypeMapper.jvmName(file.getRootNamespace()));
+ }
+ }
+ return names;
+ }
+
+ private JetTypeMapper prepareTypeMapper(JetFile file) {
+ final JetTypeMapper mapper = myTypeMappers.get(file);
+ if (mapper != null) {
+ return mapper;
+ }
+ final BindingContext bindingContext = AnalyzingUtils.analyzeFileWithCache(file);
+ final JetStandardLibrary standardLibrary = JetStandardLibrary.getJetStandardLibrary(myDebugProcess.getProject());
+ final JetTypeMapper typeMapper = new JetTypeMapper(standardLibrary, bindingContext);
+ file.acceptChildren(new JetVisitor() {
+ @Override
+ public void visitJetElement(JetElement element) {
+ element.acceptChildren(this);
+ }
+
+ @Override
+ public void visitClass(JetClass klass) {
+ GenerationState.prepareAnonymousClasses(klass, typeMapper);
+ }
+ });
+ myTypeMappers.put(file, typeMapper);
+ return typeMapper;
+ }
+
+ @NotNull
+ @Override
+ public List locationsOfLine(ReferenceType type, SourcePosition position) throws NoDataException {
+ if (!(position.getFile() instanceof JetFile)) {
+ throw new NoDataException();
+ }
+ try {
+ int line = position.getLine() + 1;
+ List locations = myDebugProcess.getVirtualMachineProxy().versionHigher("1.4")
+ ? type.locationsOfLine(DebugProcess.JAVA_STRATUM, null, line)
+ : type.locationsOfLine(line);
+ if (locations == null || locations.isEmpty()) throw new NoDataException();
+ return locations;
+ }
+ catch (AbsentInformationException e) {
+ throw new NoDataException();
+ }
+ }
+
+ @Override
+ public ClassPrepareRequest createPrepareRequest(ClassPrepareRequestor classPrepareRequestor,
+ SourcePosition sourcePosition) throws NoDataException {
+ if (!(sourcePosition.getFile() instanceof JetFile)) {
+ throw new NoDataException();
+ }
+ final Collection classNames = classNamesForPosition(sourcePosition);
+ if (classNames.isEmpty()) {
+ return null;
+ }
+ final Iterator iterator = classNames.iterator();
+ boolean wildcard = false;
+ String namePattern = iterator.next();
+ while (iterator.hasNext()) {
+ namePattern = StringUtil.commonPrefix(namePattern, iterator.next());
+ wildcard = true;
+ }
+ if (wildcard) {
+ namePattern += "*";
+ }
+ return myDebugProcess.getRequestsManager().createClassPrepareRequest(classPrepareRequestor, namePattern.replace('/', '.'));
+ }
+}
diff --git a/idea/src/org/jetbrains/jet/plugin/debugger/JetPositionManagerFactory.java b/idea/src/org/jetbrains/jet/plugin/debugger/JetPositionManagerFactory.java
new file mode 100644
index 00000000000..9cef8c7adc7
--- /dev/null
+++ b/idea/src/org/jetbrains/jet/plugin/debugger/JetPositionManagerFactory.java
@@ -0,0 +1,15 @@
+package org.jetbrains.jet.plugin.debugger;
+
+import com.intellij.debugger.PositionManager;
+import com.intellij.debugger.PositionManagerFactory;
+import com.intellij.debugger.engine.DebugProcess;
+
+/**
+ * @author yole
+ */
+public class JetPositionManagerFactory implements PositionManagerFactory {
+ @Override
+ public PositionManager create(DebugProcess debugProcess) {
+ return new JetPositionManager(debugProcess);
+ }
+}