generate line number info (initial); position manager (supports stopping at breakpoints, doesn't support stepping yet)

This commit is contained in:
Dmitry Jemerov
2011-07-13 17:37:11 +02:00
parent 42397c887a
commit cec1ce7c9a
13 changed files with 211 additions and 8 deletions
+1
View File
@@ -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);
}
}