generate line number info (initial); position manager (supports stopping at breakpoints, doesn't support stepping yet)
This commit is contained in:
@@ -45,5 +45,6 @@
|
||||
<iconProvider implementation="org.jetbrains.jet.plugin.JetIconProvider"/>
|
||||
<fileTypeIndentOptionsProvider implementation="org.jetbrains.jet.plugin.formatter.JetIndentOptionsProvider"/>
|
||||
<elementDescriptionProvider implementation="org.jetbrains.jet.plugin.findUsages.JetElementDescriptionProvider"/>
|
||||
<debugger.positionManagerFactory implementation="org.jetbrains.jet.plugin.debugger.JetPositionManagerFactory"/>
|
||||
</extensions>
|
||||
</idea-plugin>
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -107,6 +107,7 @@ public class ClosureCodegen {
|
||||
funClass,
|
||||
new String[0]
|
||||
);
|
||||
cv.visitSource(fun.getContainingFile().getName(), null);
|
||||
|
||||
|
||||
generateBridge(name, funDescriptor, cv);
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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("<init>", "()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());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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<String> getSuperInterfaces(JetClassOrObject aClass, final BindingContext bindingContext) {
|
||||
|
||||
@@ -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<String> allJvmNames(JetClassOrObject jetClass) {
|
||||
Set<String> result = new HashSet<String>();
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -34,4 +34,9 @@ public class JetFileType extends LanguageFileType {
|
||||
public Icon getIcon() {
|
||||
return Icons.PROJECT_ICON;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isJVMDebuggingSupported() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<PsiFile, JetTypeMapper> myTypeMappers = new WeakHashMap<PsiFile, JetTypeMapper>();
|
||||
|
||||
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<ReferenceType> getAllClasses(SourcePosition sourcePosition) throws NoDataException {
|
||||
if (!(sourcePosition.getFile() instanceof JetFile)) {
|
||||
throw new NoDataException();
|
||||
}
|
||||
final Collection<String> names = classNamesForPosition(sourcePosition);
|
||||
List<ReferenceType> result = new ArrayList<ReferenceType>();
|
||||
for (String name : names) {
|
||||
result.addAll(myDebugProcess.getVirtualMachineProxy().classesByName(name));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private Collection<String> classNamesForPosition(SourcePosition sourcePosition) {
|
||||
final JetFile file = (JetFile) sourcePosition.getFile();
|
||||
JetTypeMapper typeMapper = prepareTypeMapper(file);
|
||||
final Collection<String> names = new ArrayList<String>();
|
||||
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<Location> locationsOfLine(ReferenceType type, SourcePosition position) throws NoDataException {
|
||||
if (!(position.getFile() instanceof JetFile)) {
|
||||
throw new NoDataException();
|
||||
}
|
||||
try {
|
||||
int line = position.getLine() + 1;
|
||||
List<Location> 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<String> classNames = classNamesForPosition(sourcePosition);
|
||||
if (classNames.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
final Iterator<String> 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('/', '.'));
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user