"Resolve window" for debugging purposes

This commit is contained in:
Andrey Breslav
2011-11-28 21:44:10 +03:00
parent a9a07857de
commit 11e957a87d
13 changed files with 330 additions and 4 deletions
@@ -32,4 +32,9 @@ public class AutoCastReceiver extends AbstractReceiverDescriptor {
public <R, D> R accept(@NotNull ReceiverDescriptorVisitor<R, D> visitor, D data) {
return original.accept(visitor, data);
}
@Override
public String toString() {
return "(" + original + " as " + getType() + ")";
}
}
@@ -19,4 +19,9 @@ public class DefaultValueArgument implements ResolvedValueArgument {
public List<JetExpression> getArgumentExpressions() {
return Collections.emptyList(); //throw new UnsupportedOperationException("Look into the default value of the parameter");
}
@Override
public String toString() {
return "|DEFAULT|";
}
}
@@ -29,4 +29,9 @@ public class ExpressionValueArgument implements ResolvedValueArgument {
if (expression == null) return Collections.emptyList();
return Collections.singletonList(expression);
}
@Override
public String toString() {
return expression.getText();
}
}
@@ -4,6 +4,7 @@ import com.google.common.collect.Lists;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.psi.JetExpression;
import java.util.Iterator;
import java.util.List;
/**
@@ -17,4 +18,17 @@ public class VarargValueArgument implements ResolvedValueArgument {
public List<JetExpression> getArgumentExpressions() {
return values;
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder("vararg:{");
for (Iterator<JetExpression> iterator = values.iterator(); iterator.hasNext(); ) {
JetExpression expression = iterator.next();
builder.append(expression.getText());
if (iterator.hasNext()) {
builder.append(", ");
}
}
return builder.append("}").toString();
}
}
@@ -11,6 +11,7 @@ import java.util.List;
*/
public interface AutoCastService {
AutoCastService NO_AUTO_CASTS = new AutoCastService() {
@NotNull
@Override
public DataFlowInfo getDataFlowInfo() {
return DataFlowInfo.EMPTY;
@@ -21,13 +22,17 @@ public interface AutoCastService {
return !receiver.getType().isNullable();
}
@NotNull
@Override
public List<ReceiverDescriptor> getVariantsForReceiver(ReceiverDescriptor receiverDescriptor) {
public List<ReceiverDescriptor> getVariantsForReceiver(@NotNull ReceiverDescriptor receiverDescriptor) {
return Collections.singletonList(receiverDescriptor);
}
};
List<ReceiverDescriptor> getVariantsForReceiver(ReceiverDescriptor receiverDescriptor);
@NotNull
List<ReceiverDescriptor> getVariantsForReceiver(@NotNull ReceiverDescriptor receiverDescriptor);
@NotNull
DataFlowInfo getDataFlowInfo();
boolean isNotNull(@NotNull ReceiverDescriptor receiver);
@@ -18,11 +18,13 @@ public class AutoCastServiceImpl implements AutoCastService {
this.bindingContext = bindingContext;
}
@NotNull
@Override
public List<ReceiverDescriptor> getVariantsForReceiver(ReceiverDescriptor receiverDescriptor) {
public List<ReceiverDescriptor> getVariantsForReceiver(@NotNull ReceiverDescriptor receiverDescriptor) {
return AutoCastUtils.getAutoCastVariants(bindingContext, dataFlowInfo, receiverDescriptor);
}
@NotNull
@Override
public DataFlowInfo getDataFlowInfo() {
return dataFlowInfo;
@@ -37,4 +37,9 @@ public class ClassReceiver implements ThisReceiverDescriptor {
public <R, D> R accept(@NotNull ReceiverDescriptorVisitor<R, D> visitor, D data) {
return visitor.visitClassReceiver(this, data);
}
@Override
public String toString() {
return "Class{" + getType() + "}";
}
}
@@ -25,4 +25,9 @@ public class ExpressionReceiver extends AbstractReceiverDescriptor implements Re
public <R, D> R accept(@NotNull ReceiverDescriptorVisitor<R, D> visitor, D data) {
return visitor.visitExpressionReceiver(this, data);
}
@Override
public String toString() {
return getType() + " {" + expression + ": " + expression.getText() + "}";
}
}
@@ -27,4 +27,9 @@ public class ExtensionReceiver extends AbstractReceiverDescriptor implements Thi
public <R, D> R accept(@NotNull ReceiverDescriptorVisitor<R, D> visitor, D data) {
return visitor.visitExtensionReceiver(this, data);
}
@Override
public String toString() {
return getType() + "Ext{" + descriptor + "}";
}
}
@@ -18,4 +18,9 @@ public class TransientReceiver extends AbstractReceiverDescriptor {
public <R, D> R accept(@NotNull ReceiverDescriptorVisitor<R, D> visitor, D data) {
return visitor.visitTransientReceiver(this, data);
}
@Override
public String toString() {
return "{Transient} : " + getType();
}
}
+3
View File
@@ -61,5 +61,8 @@
<toolWindow id="CodeWindow"
factoryClass="org.jetbrains.jet.plugin.internal.codewindow.BytecodeToolwindow$Factory"
anchor="right"/>
<toolWindow id="ResolveWindow"
factoryClass="org.jetbrains.jet.plugin.internal.resolvewindow.ResolveToolwindow$Factory"
anchor="right"/>
</extensions>
</idea-plugin>
@@ -208,7 +208,7 @@ public class BytecodeToolwindow extends JPanel {
}
}
private static class Location {
public static class Location {
final Editor editor;
final long modificationStamp;
final int startOffset;
@@ -225,6 +225,22 @@ public class BytecodeToolwindow extends JPanel {
return new Location(editor);
}
public Editor getEditor() {
return editor;
}
public long getModificationStamp() {
return modificationStamp;
}
public int getStartOffset() {
return startOffset;
}
public int getEndOffset() {
return endOffset;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
@@ -0,0 +1,251 @@
/*
* @author max
*/
package org.jetbrains.jet.plugin.internal.resolvewindow;
import com.intellij.openapi.application.Result;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.EditorFactory;
import com.intellij.openapi.editor.ex.EditorEx;
import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.wm.ToolWindow;
import com.intellij.openapi.wm.ToolWindowFactory;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtilCore;
import com.intellij.ui.content.ContentFactory;
import com.intellij.util.Alarm;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.psi.JetElement;
import org.jetbrains.jet.lang.psi.JetExpression;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.psi.JetReferenceExpression;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.calls.ResolvedCall;
import org.jetbrains.jet.lang.resolve.calls.ResolvedValueArgument;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.plugin.JetFileType;
import org.jetbrains.jet.plugin.compiler.WholeProjectAnalyzerFacade;
import org.jetbrains.jet.plugin.internal.codewindow.BytecodeToolwindow;
import javax.swing.*;
import java.awt.*;
import java.util.Map;
import static org.jetbrains.jet.lang.resolve.BindingContext.EXPRESSION_TYPE;
import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET;
import static org.jetbrains.jet.lang.resolve.BindingContext.RESOLVED_CALL;
public class ResolveToolwindow extends JPanel {
public static class Factory implements ToolWindowFactory {
@Override
public void createToolWindowContent(Project project, ToolWindow toolWindow) {
toolWindow.getContentManager().addContent(ContentFactory.SERVICE.getInstance().createContent(new ResolveToolwindow(project), "", false));
}
}
private static final int UPDATE_DELAY = 500;
private final Editor myEditor;
private final Alarm myUpdateAlarm;
private BytecodeToolwindow.Location myCurrentLocation;
private final Project myProject;
public ResolveToolwindow(Project project) {
super(new BorderLayout());
myProject = project;
myEditor = EditorFactory.getInstance().createEditor(EditorFactory.getInstance().createDocument(""), project, JetFileType.INSTANCE, true);
add(myEditor.getComponent());
myUpdateAlarm = new Alarm(Alarm.ThreadToUse.SWING_THREAD);
myUpdateAlarm.addRequest(new Runnable() {
@Override
public void run() {
myUpdateAlarm.addRequest(this, UPDATE_DELAY);
BytecodeToolwindow.Location location = BytecodeToolwindow.Location.fromEditor(FileEditorManager.getInstance(myProject).getSelectedTextEditor());
if (!Comparing.equal(location, myCurrentLocation)) {
render(location, myCurrentLocation);
myCurrentLocation = location;
}
}
}, UPDATE_DELAY);
}
private void render(BytecodeToolwindow.Location location, BytecodeToolwindow.Location oldLocation) {
Editor editor = location.getEditor();
if (editor == null) {
setText("No editor");
}
else {
VirtualFile vFile = ((EditorEx) editor).getVirtualFile();
if (vFile == null) {
setText("");
return;
}
PsiFile psiFile = PsiManager.getInstance(myProject).findFile(vFile);
if (!(psiFile instanceof JetFile)) {
setText("");
return;
}
int startOffset = location.getStartOffset();
int endOffset = location.getEndOffset();
if (oldLocation == null || !Comparing.equal(oldLocation.getEditor(), location.getEditor())
|| oldLocation.getStartOffset() != startOffset
|| oldLocation.getEndOffset() != endOffset) {
BindingContext bindingContext = WholeProjectAnalyzerFacade.analyzeProjectWithCacheOnAFile((JetFile) psiFile);
PsiElement elementAtOffset;
if (startOffset == endOffset) {
elementAtOffset = PsiUtilCore.getElementAtOffset(psiFile, startOffset);
}
else {
PsiElement start = PsiUtilCore.getElementAtOffset(psiFile, startOffset);
System.out.println("start = " + start.getText());
PsiElement end = PsiUtilCore.getElementAtOffset(psiFile, endOffset - 1);
System.out.println("end = " + end.getText());
elementAtOffset = PsiTreeUtil.findCommonParent(start, end);
System.out.println("elementAtOffset = " + elementAtOffset.getText());
}
PsiElement currentElement = elementAtOffset;
boolean callFound = false;
while (currentElement != null && !(currentElement instanceof PsiFile)) {
if (currentElement instanceof JetElement) {
JetElement atOffset = (JetElement) currentElement;
ResolvedCall<? extends CallableDescriptor> resolvedCall = bindingContext.get(RESOLVED_CALL, (JetElement) atOffset);
if (resolvedCall != null) {
setText(renderCall(resolvedCall) + "\n===\n" + currentElement + ": " + currentElement.getText());
callFound = true;
break;
}
}
currentElement = currentElement.getParent();
}
if (!callFound) {
JetExpression parentExpression = (elementAtOffset instanceof JetExpression) ? (JetExpression) elementAtOffset
: PsiTreeUtil.getParentOfType(elementAtOffset, JetExpression.class);
if (parentExpression != null) {
JetType type = bindingContext.get(EXPRESSION_TYPE, parentExpression);
String text = parentExpression + "|" + parentExpression.getText() + "| : " + type;
if (parentExpression instanceof JetReferenceExpression) {
JetReferenceExpression referenceExpression = (JetReferenceExpression) parentExpression;
DeclarationDescriptor target = bindingContext.get(REFERENCE_TARGET, referenceExpression);
text += "\nReference target: \n" + target;
}
setText(text);
}
}
}
}
}
private String renderCall(ResolvedCall<? extends CallableDescriptor> resolvedCall) {
StringBuilder builder = new StringBuilder();
CallableDescriptor resultingDescriptor = resolvedCall.getResultingDescriptor();
ReceiverDescriptor receiverArgument = resolvedCall.getReceiverArgument();
ReceiverDescriptor thisObject = resolvedCall.getThisObject();
Map<TypeParameterDescriptor, JetType> typeArguments = resolvedCall.getTypeArguments();
Map<ValueParameterDescriptor, ResolvedValueArgument> valueArguments = resolvedCall.getValueArguments();
renderReceiver(receiverArgument, thisObject, builder);
builder.append(resultingDescriptor.getName());
renderTypeArguments(typeArguments, builder);
if (resultingDescriptor instanceof FunctionDescriptor) {
renderValueArguments(valueArguments, builder);
}
builder.append(" : ").append(resultingDescriptor.getReturnType());
builder.append("\n");
builder.append("\n");
CallableDescriptor candidateDescriptor = resolvedCall.getCandidateDescriptor();
builder.append("Candidate: \n").append(candidateDescriptor).append("\n");
if (resultingDescriptor != candidateDescriptor) {
builder.append("Result: \n").append(resultingDescriptor).append("\n");
}
builder.append("Receiver: \n").append(receiverArgument).append("\n");
builder.append("This object: \n").append(thisObject).append("\n");
builder.append("Type args: \n").append(typeArguments).append("\n");
builder.append("Value args: \n").append(valueArguments).append("\n");
return builder.toString();
}
private void renderValueArguments(Map<ValueParameterDescriptor, ResolvedValueArgument> valueArguments, StringBuilder builder) {
ResolvedValueArgument[] args = new ResolvedValueArgument[valueArguments.size()];
for (Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> entry : valueArguments.entrySet()) {
ValueParameterDescriptor key = entry.getKey();
ResolvedValueArgument value = entry.getValue();
args[key.getIndex()] = value;
}
builder.append("(");
for (int i = 0, argsLength = args.length; i < argsLength; i++) {
ResolvedValueArgument arg = args[i];
builder.append(arg);
if (i != argsLength - 1) {
builder.append(", ");
}
}
builder.append(")");
}
private void renderTypeArguments(Map<TypeParameterDescriptor, JetType> typeArguments, StringBuilder builder) {
JetType[] args = new JetType[typeArguments.size()];
for (Map.Entry<TypeParameterDescriptor, JetType> entry : typeArguments.entrySet()) {
TypeParameterDescriptor key = entry.getKey();
JetType value = entry.getValue();
args[key.getIndex()] = value;
}
builder.append("<");
for (int i = 0, argsLength = args.length; i < argsLength; i++) {
JetType type = args[i];
builder.append(type);
if (i != argsLength - 1) {
builder.append(", ");
}
}
builder.append(">");
}
private void renderReceiver(ReceiverDescriptor receiverArgument, ReceiverDescriptor thisObject, StringBuilder builder) {
if (receiverArgument.exists()) {
builder.append("/").append(receiverArgument);
}
if (thisObject.exists()) {
builder.append("/this=").append(thisObject);
}
if (thisObject.exists() || receiverArgument.exists()) {
builder.append("/.");
}
}
private void setText(final String text) {
new WriteCommandAction(myProject) {
@Override
protected void run(Result result) throws Throwable {
myEditor.getDocument().setText(text);
}
}.execute();
}
}