Merge remote-tracking branch 'origin/master'

This commit is contained in:
svtk
2011-11-29 19:04:30 +04:00
41 changed files with 1000 additions and 55 deletions
+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>
@@ -6,11 +6,12 @@ import com.intellij.openapi.actionSystem.LangDataKeys;
import com.intellij.openapi.actionSystem.PlatformDataKeys;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiFile;
import org.jetbrains.jet.checkers.CheckerTestUtil;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.resolve.AnalyzingUtils;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.java.AnalyzerFacade;
import org.jetbrains.jet.plugin.compiler.WholeProjectAnalyzerFacade;
import java.awt.*;
@@ -18,6 +19,7 @@ import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.ClipboardOwner;
import java.awt.datatransfer.StringSelection;
import java.awt.datatransfer.Transferable;
import java.util.List;
/**
* @author abreslav
@@ -30,8 +32,9 @@ public class CopyAsDiagnosticTestAction extends AnAction {
assert editor != null && psiFile != null;
BindingContext bindingContext = WholeProjectAnalyzerFacade.analyzeProjectWithCacheOnAFile((JetFile) psiFile);
List<TextRange> syntaxError = AnalyzingUtils.getSyntaxErrorRanges(psiFile);
String result = CheckerTestUtil.addDiagnosticMarkersToText(psiFile, bindingContext).toString();
String result = CheckerTestUtil.addDiagnosticMarkersToText(psiFile, bindingContext, syntaxError).toString();
Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
clipboard.setContents(new StringSelection(result), new ClipboardOwner() {
@@ -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;
/*
* @author abreslav
*/
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);
PsiElement end = PsiUtilCore.getElementAtOffset(psiFile, endOffset - 1);
elementAtOffset = PsiTreeUtil.findCommonParent(start, end);
}
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();
}
}