From a28bf2afc5e7745723da422e3fd3f43d549628eb Mon Sep 17 00:00:00 2001 From: "Egor.Ushakov" Date: Tue, 15 Sep 2015 13:17:53 +0300 Subject: [PATCH 01/11] preparing to enable multithreaded test --- .../src/com/intellij/debugger/DebuggerTestCase.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/java/testFramework/src/com/intellij/debugger/DebuggerTestCase.java b/java/testFramework/src/com/intellij/debugger/DebuggerTestCase.java index 3aa8106ee282..f39ce8f84167 100644 --- a/java/testFramework/src/com/intellij/debugger/DebuggerTestCase.java +++ b/java/testFramework/src/com/intellij/debugger/DebuggerTestCase.java @@ -61,6 +61,7 @@ import com.intellij.xdebugger.XDebugProcess; import com.intellij.xdebugger.XDebugProcessStarter; import com.intellij.xdebugger.XDebugSession; import com.intellij.xdebugger.XDebuggerManager; +import com.sun.jdi.Location; import org.jdom.Element; import org.jetbrains.annotations.NotNull; @@ -421,6 +422,17 @@ public abstract class DebuggerTestCase extends ExecutionWithDebuggerToolsTestCas return createDebuggerContext(suspendContext, suspendContext.getFrameProxy()); } + protected void printLocation(SuspendContextImpl suspendContext) { + try { + Location location = suspendContext.getFrameProxy().location(); + String message = "paused at " + location.sourcePath() + ":" + location.lineNumber(); + println(message, ProcessOutputTypes.SYSTEM); + } + catch (Throwable e) { + addException(e); + } + } + protected void createBreakpointInHelloWorld() { DebuggerInvocationUtil.invokeAndWait(myProject, new Runnable() { @Override From 6e209f5cdac1ed1a85b7377cd3bf6d5b32b94169 Mon Sep 17 00:00:00 2001 From: "Egor.Ushakov" Date: Tue, 15 Sep 2015 14:35:46 +0300 Subject: [PATCH 02/11] preparing to delete FrameVariableTree --- .../ExecutionWithDebuggerToolsTestCase.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/java/testFramework/src/com/intellij/debugger/ExecutionWithDebuggerToolsTestCase.java b/java/testFramework/src/com/intellij/debugger/ExecutionWithDebuggerToolsTestCase.java index 5362879c9eca..ade8358e30dd 100644 --- a/java/testFramework/src/com/intellij/debugger/ExecutionWithDebuggerToolsTestCase.java +++ b/java/testFramework/src/com/intellij/debugger/ExecutionWithDebuggerToolsTestCase.java @@ -127,6 +127,20 @@ public abstract class ExecutionWithDebuggerToolsTestCase extends ExecutionTestCa myScriptRunnables.add(runnable); } + protected void doWhenPausedThenResume(final SuspendContextRunnable runnable) { + onBreakpoint(new SuspendContextRunnable() { + @Override + public void run(SuspendContextImpl suspendContext) throws Exception { + try { + runnable.run(suspendContext); + } + finally { + resume(suspendContext); + } + } + }); + } + protected void addDefaultBreakpointListener() { if (myPauseScriptListener == null) { final DebugProcessImpl debugProcess = getDebugProcess(); From 358b39ebaea6f4bceeec4f99bea18608172a48df Mon Sep 17 00:00:00 2001 From: "Egor.Ushakov" Date: Tue, 15 Sep 2015 15:21:34 +0300 Subject: [PATCH 03/11] deleted FrameVariableTree --- .../debugger/engine/JavaStackFrame.java | 288 +++++++- .../debugger/ui/impl/FrameVariablesTree.java | 614 ------------------ .../debugger/ui/impl/VariablesPanel.java | 155 ----- .../debugger/ui/impl/WatchDebuggerTree.java | 119 ---- 4 files changed, 277 insertions(+), 899 deletions(-) delete mode 100644 java/debugger/impl/src/com/intellij/debugger/ui/impl/FrameVariablesTree.java delete mode 100644 java/debugger/impl/src/com/intellij/debugger/ui/impl/VariablesPanel.java delete mode 100644 java/debugger/impl/src/com/intellij/debugger/ui/impl/WatchDebuggerTree.java diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/JavaStackFrame.java b/java/debugger/impl/src/com/intellij/debugger/engine/JavaStackFrame.java index 2830f3a28848..62e317826a86 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/JavaStackFrame.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/JavaStackFrame.java @@ -20,6 +20,7 @@ import com.intellij.debugger.SourcePosition; import com.intellij.debugger.engine.evaluation.EvaluateException; import com.intellij.debugger.engine.evaluation.EvaluationContextImpl; import com.intellij.debugger.engine.evaluation.TextWithImports; +import com.intellij.debugger.engine.evaluation.TextWithImportsImpl; import com.intellij.debugger.engine.events.DebuggerContextCommandImpl; import com.intellij.debugger.impl.DebuggerContextImpl; import com.intellij.debugger.impl.DebuggerSession; @@ -31,16 +32,21 @@ import com.intellij.debugger.jdi.StackFrameProxyImpl; import com.intellij.debugger.settings.DebuggerSettings; import com.intellij.debugger.settings.NodeRendererSettings; import com.intellij.debugger.ui.breakpoints.Breakpoint; -import com.intellij.debugger.ui.impl.FrameVariablesTree; import com.intellij.debugger.ui.impl.watch.*; import com.intellij.debugger.ui.tree.render.DescriptorLabelListener; +import com.intellij.lang.java.JavaLanguage; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.util.Computable; -import com.intellij.openapi.util.Pair; +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.fileEditor.FileDocumentManager; +import com.intellij.openapi.util.*; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.*; +import com.intellij.psi.util.PsiTreeUtil; import com.intellij.ui.ColoredTextContainer; import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.text.CharArrayUtil; import com.intellij.xdebugger.XDebugSession; import com.intellij.xdebugger.XSourcePosition; import com.intellij.xdebugger.evaluation.XDebuggerEvaluator; @@ -55,9 +61,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; +import java.util.*; /** * @author egor @@ -246,7 +250,7 @@ public class JavaStackFrame extends XStackFrame { // copied from FrameVariablesTree private void buildVariables(DebuggerContextImpl debuggerContext, - EvaluationContextImpl evaluationContext, + final EvaluationContextImpl evaluationContext, @NotNull DebugProcessImpl debugProcess, XValueChildrenList children, ObjectReference thisObjectReference, @@ -283,13 +287,12 @@ public class JavaStackFrame extends XStackFrame { superBuildVariables(evaluationContext, children); } else { - final Map visibleVariables = FrameVariablesTree.getVisibleVariables(getStackFrameProxy()); - final EvaluationContextImpl evalContext = evaluationContext; + final Map visibleVariables = getVisibleVariables(getStackFrameProxy()); final Pair, Set> usedVars = ApplicationManager.getApplication().runReadAction(new Computable, Set>>() { @Override public Pair, Set> compute() { - return FrameVariablesTree.findReferencedVars(ContainerUtil.union(visibleVariables.keySet(), visibleLocals), sourcePosition, evalContext); + return findReferencedVars(ContainerUtil.union(visibleVariables.keySet(), visibleLocals), sourcePosition, evaluationContext); } }); // add locals @@ -307,7 +310,7 @@ public class JavaStackFrame extends XStackFrame { final EvaluationContextImpl evalContextCopy = evaluationContext.createEvaluationContext(evaluationContext.getThisObject()); evalContextCopy.setAutoLoadClasses(false); - final Set extraVars = computeExtraVars(usedVars, sourcePosition, evalContext); + final Set extraVars = computeExtraVars(usedVars, sourcePosition, evaluationContext); // add extra vars addToChildrenFrom(extraVars, children, evaluationContext); @@ -420,4 +423,267 @@ public class JavaStackFrame extends XStackFrame { return "JavaFrame position unknown"; } } + + private static class VariablesCollector extends JavaRecursiveElementVisitor { + private final Set myVisibleLocals; + private final TextRange myLineRange; + private final Set myExpressions; + private final Set myVars; + private final SourcePosition myPosition; + private final EvaluationContextImpl myEvalContext; + private final boolean myCollectExpressions; + + public VariablesCollector(final Set visibleLocals, + final TextRange lineRange, + final Set expressions, + final Set vars, + SourcePosition position, EvaluationContextImpl evalContext) { + myVisibleLocals = visibleLocals; + myLineRange = lineRange; + myExpressions = expressions; + myVars = vars; + myPosition = position; + myEvalContext = evalContext; + myCollectExpressions = XDebuggerSettingsManager.getInstance().getDataViewSettings().isAutoExpressions(); + } + + @Override + public void visitElement(final PsiElement element) { + if (myLineRange.intersects(element.getTextRange())) { + super.visitElement(element); + } + } + + @Override + public void visitMethodCallExpression(final PsiMethodCallExpression expression) { + if (myCollectExpressions) { + final PsiMethod psiMethod = expression.resolveMethod(); + if (psiMethod != null && !DebuggerUtils.hasSideEffectsOrReferencesMissingVars(expression, myVisibleLocals)) { + myExpressions.add(new TextWithImportsImpl(expression)); + } + } + super.visitMethodCallExpression(expression); + } + + @Override + public void visitReferenceExpression(final PsiReferenceExpression reference) { + if (myLineRange.intersects(reference.getTextRange())) { + final PsiElement psiElement = reference.resolve(); + if (psiElement instanceof PsiVariable) { + final PsiVariable var = (PsiVariable)psiElement; + if (var instanceof PsiField) { + if (myCollectExpressions && !DebuggerUtils.hasSideEffectsOrReferencesMissingVars(reference, myVisibleLocals)) { + /* + if (var instanceof PsiEnumConstant && reference.getQualifier() == null) { + final PsiClass enumClass = ((PsiEnumConstant)var).getContainingClass(); + if (enumClass != null) { + final PsiExpression expression = JavaPsiFacade.getInstance(var.getProject()).getParserFacade().createExpressionFromText(enumClass.getName() + "." + var.getName(), var); + final PsiReference ref = expression.getReference(); + if (ref != null) { + ref.bindToElement(var); + myExpressions.add(new TextWithImportsImpl(expression)); + } + } + } + else { + myExpressions.add(new TextWithImportsImpl(reference)); + } + */ + final PsiModifierList modifierList = var.getModifierList(); + boolean isConstant = (var instanceof PsiEnumConstant) || + (modifierList != null && modifierList.hasModifierProperty(PsiModifier.STATIC) && modifierList.hasModifierProperty(PsiModifier.FINAL)); + if (!isConstant) { + myExpressions.add(new TextWithImportsImpl(reference)); + } + } + } + else { + if (myVisibleLocals.contains(var.getName())) { + myVars.add(var.getName()); + } + else { + // fix for variables used in inner classes + if (!Comparing.equal(PsiTreeUtil.getParentOfType(reference, PsiClass.class), + PsiTreeUtil.getParentOfType(var, PsiClass.class))) { + myExpressions.add(new TextWithImportsImpl(reference)); + } + } + } + } + } + super.visitReferenceExpression(reference); + } + + @Override + public void visitArrayAccessExpression(final PsiArrayAccessExpression expression) { + if (myCollectExpressions && !DebuggerUtils.hasSideEffectsOrReferencesMissingVars(expression, myVisibleLocals)) { + myExpressions.add(new TextWithImportsImpl(expression)); + } + super.visitArrayAccessExpression(expression); + } + + @Override + public void visitParameter(final PsiParameter parameter) { + processVariable(parameter); + super.visitParameter(parameter); + } + + @Override + public void visitLocalVariable(final PsiLocalVariable variable) { + processVariable(variable); + super.visitLocalVariable(variable); + } + + private void processVariable(final PsiVariable variable) { + if (myLineRange.intersects(variable.getTextRange()) && myVisibleLocals.contains(variable.getName())) { + myVars.add(variable.getName()); + } + } + + @Override + public void visitClass(final PsiClass aClass) { + // Do not step in to local and anonymous classes... + } + } + + public static Map getVisibleVariables(final StackFrameProxyImpl frame) throws EvaluateException { + final Map vars = new HashMap(); + for (LocalVariableProxyImpl localVariableProxy : frame.visibleVariables()) { + vars.put(localVariableProxy.name(), localVariableProxy); + } + return vars; + } + + private static boolean shouldSkipLine(final PsiFile file, Document doc, int line) { + final int start = doc.getLineStartOffset(line); + final int end = doc.getLineEndOffset(line); + final int _start = CharArrayUtil.shiftForward(doc.getCharsSequence(), start, " \n\t"); + if (_start >= end) { + return true; + } + + TextRange alreadyChecked = null; + for (PsiElement elem = file.findElementAt(_start); elem != null && elem.getTextOffset() <= end && (alreadyChecked == null || !alreadyChecked .contains(elem.getTextRange())); elem = elem.getNextSibling()) { + for (PsiElement _elem = elem; _elem.getTextOffset() >= _start; _elem = _elem.getParent()) { + alreadyChecked = _elem.getTextRange(); + + if (_elem instanceof PsiDeclarationStatement) { + final PsiElement[] declared = ((PsiDeclarationStatement)_elem).getDeclaredElements(); + for (PsiElement declaredElement : declared) { + if (declaredElement instanceof PsiVariable) { + return false; + } + } + } + + if (_elem instanceof PsiJavaCodeReferenceElement) { + final PsiElement resolved = ((PsiJavaCodeReferenceElement)_elem).resolve(); + if (resolved instanceof PsiVariable) { + return false; + } + } + } + } + return true; + } + + public static Pair, Set> findReferencedVars(final Set visibleVars, + final SourcePosition position, + EvaluationContextImpl evalContext) { + final int line = position.getLine(); + if (line < 0) { + return Pair.create(Collections.emptySet(), Collections.emptySet()); + } + final PsiFile positionFile = position.getFile(); + if (!positionFile.getLanguage().isKindOf(JavaLanguage.INSTANCE)) { + return Pair.create(visibleVars, Collections.emptySet()); + } + + final VirtualFile vFile = positionFile.getVirtualFile(); + final Document doc = vFile != null ? FileDocumentManager.getInstance().getDocument(vFile) : null; + if (doc == null || doc.getLineCount() == 0 || line > (doc.getLineCount() - 1)) { + return Pair.create(Collections.emptySet(), Collections.emptySet()); + } + + final TextRange limit = calculateLimitRange(positionFile, doc, line); + + int startLine = Math.max(limit.getStartOffset(), line - 1); + startLine = Math.min(startLine, limit.getEndOffset()); + while (startLine > limit.getStartOffset() && shouldSkipLine(positionFile, doc, startLine)) { + startLine--; + } + final int startOffset = doc.getLineStartOffset(startLine); + + int endLine = Math.min(line + 2, limit.getEndOffset()); + while (endLine < limit.getEndOffset() && shouldSkipLine(positionFile, doc, endLine)) { + endLine++; + } + final int endOffset = doc.getLineEndOffset(endLine); + + final TextRange lineRange = new TextRange(startOffset, endOffset); + if (!lineRange.isEmpty()) { + final int offset = CharArrayUtil.shiftForward(doc.getCharsSequence(), doc.getLineStartOffset(line), " \t"); + PsiElement element = positionFile.findElementAt(offset); + if (element != null) { + PsiMethod method = PsiTreeUtil.getNonStrictParentOfType(element, PsiMethod.class); + if (method != null) { + element = method; + } + else { + PsiField field = PsiTreeUtil.getNonStrictParentOfType(element, PsiField.class); + if (field != null) { + element = field; + } + else { + final PsiClassInitializer initializer = PsiTreeUtil.getNonStrictParentOfType(element, PsiClassInitializer.class); + if (initializer != null) { + element = initializer; + } + } + } + + //noinspection unchecked + if (element instanceof PsiCompiledElement) { + return Pair.create(visibleVars, Collections.emptySet()); + } + else { + final Set vars = new HashSet(); + final Set expressions = new HashSet(); + final PsiElementVisitor variablesCollector = new VariablesCollector(visibleVars, adjustRange(element, lineRange), expressions, vars, position, evalContext); + element.accept(variablesCollector); + + return Pair.create(vars, expressions); + } + } + } + return Pair.create(Collections.emptySet(), Collections.emptySet()); + } + + private static TextRange calculateLimitRange(final PsiFile file, final Document doc, final int line) { + final int offset = doc.getLineStartOffset(line); + if (offset > 0) { + PsiMethod method = PsiTreeUtil.getParentOfType(file.findElementAt(offset), PsiMethod.class, false); + if (method != null) { + final TextRange elemRange = method.getTextRange(); + return new TextRange(doc.getLineNumber(elemRange.getStartOffset()), doc.getLineNumber(elemRange.getEndOffset())); + } + } + return new TextRange(0, doc.getLineCount() - 1); + } + + private static TextRange adjustRange(final PsiElement element, final TextRange originalRange) { + final Ref rangeRef = new Ref(originalRange); + element.accept(new JavaRecursiveElementVisitor() { + @Override public void visitExpressionStatement(final PsiExpressionStatement statement) { + final TextRange stRange = statement.getTextRange(); + if (originalRange.intersects(stRange)) { + final TextRange currentRange = rangeRef.get(); + final int start = Math.min(currentRange.getStartOffset(), stRange.getStartOffset()); + final int end = Math.max(currentRange.getEndOffset(), stRange.getEndOffset()); + rangeRef.set(new TextRange(start, end)); + } + } + }); + return rangeRef.get(); + } } diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/FrameVariablesTree.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/FrameVariablesTree.java deleted file mode 100644 index 3bdbe4d2b851..000000000000 --- a/java/debugger/impl/src/com/intellij/debugger/ui/impl/FrameVariablesTree.java +++ /dev/null @@ -1,614 +0,0 @@ -/* - * Copyright 2000-2015 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * Class FrameDebuggerTree - * @author Jeka - */ -package com.intellij.debugger.ui.impl; - -import com.intellij.debugger.DebuggerBundle; -import com.intellij.debugger.DebuggerInvocationUtil; -import com.intellij.debugger.SourcePosition; -import com.intellij.debugger.engine.DebuggerUtils; -import com.intellij.debugger.engine.SuspendManager; -import com.intellij.debugger.engine.evaluation.EvaluateException; -import com.intellij.debugger.engine.evaluation.EvaluationContextImpl; -import com.intellij.debugger.engine.evaluation.TextWithImports; -import com.intellij.debugger.engine.evaluation.TextWithImportsImpl; -import com.intellij.debugger.engine.events.DebuggerCommandImpl; -import com.intellij.debugger.impl.DebuggerContextImpl; -import com.intellij.debugger.impl.DebuggerSession; -import com.intellij.debugger.jdi.*; -import com.intellij.debugger.settings.ViewsGeneralSettings; -import com.intellij.debugger.ui.impl.watch.*; -import com.intellij.lang.java.JavaLanguage; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.editor.Document; -import com.intellij.openapi.fileEditor.FileDocumentManager; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.*; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.psi.*; -import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.util.text.CharArrayUtil; -import com.intellij.util.ui.tree.TreeModelAdapter; -import com.intellij.xdebugger.XDebuggerBundle; -import com.intellij.xdebugger.frame.XStackFrame; -import com.intellij.xdebugger.settings.XDebuggerSettingsManager; -import com.sun.jdi.AbsentInformationException; -import com.sun.jdi.ObjectCollectedException; -import com.sun.jdi.Value; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import javax.swing.event.TreeModelEvent; -import javax.swing.tree.TreeModel; -import javax.swing.tree.TreePath; -import java.util.*; - -public class FrameVariablesTree extends DebuggerTree { - private static final Logger LOG = Logger.getInstance(FrameVariablesTree.class); - - private boolean myAnyNewLocals; - private boolean myAutoWatchMode = false; - - private final VariablesPanel myVariablesPanel; - - public FrameVariablesTree(@NotNull Project project) { - this(project, null); - } - - public FrameVariablesTree(@NotNull Project project, @Nullable VariablesPanel variablesPanel) { - super(project); - - getEmptyText().setText(XDebuggerBundle.message("debugger.variables.not.available")); - myVariablesPanel = variablesPanel; - } - - public boolean isAutoWatchMode() { - return myAutoWatchMode; - } - - public void setAutoVariablesMode(final boolean autoWatchMode) { - final boolean valueChanged = myAutoWatchMode != autoWatchMode; - myAutoWatchMode = autoWatchMode; - if (valueChanged) { - rebuild(getDebuggerContext()); - } - } - - @Override - protected void build(DebuggerContextImpl context) { - myAnyNewLocals = false; - buildWhenPaused(context, new RefreshFrameTreeCommand(context)); - } - - @Override - public void restoreNodeState(DebuggerTreeNodeImpl node) { - if (myAnyNewLocals) { - final NodeDescriptorImpl descriptor = node.getDescriptor(); - final boolean isLocalVar = descriptor instanceof LocalVariableDescriptorImpl; - descriptor.myIsSelected &= isLocalVar; - // override this setting so that tree will scroll to new locals - descriptor.myIsVisible = isLocalVar && descriptor.myIsSelected; - if (!descriptor.myIsVisible) { - descriptor.putUserData(VISIBLE_RECT, null); - } - } - super.restoreNodeState(node); - if (myAnyNewLocals && node.getDescriptor().myIsExpanded) { - DebuggerTreeNodeImpl root = (DebuggerTreeNodeImpl)getMutableModel().getRoot(); - scrollToVisible(root); - } - } - - - @Override - protected DebuggerCommandImpl getBuildNodeCommand(@NotNull DebuggerTreeNodeImpl node) { - if (node.getDescriptor() instanceof StackFrameDescriptorImpl) { - return new BuildFrameTreeVariablesCommand(node); - } - return super.getBuildNodeCommand(node); - } - - private class BuildFrameTreeVariablesCommand extends BuildStackFrameCommand { - public BuildFrameTreeVariablesCommand(DebuggerTreeNodeImpl stackNode) { - super(stackNode); - } - - @Override - public void threadAction() { - if (myVariablesPanel != null) { - StackFrameDescriptorImpl stackDescriptor = (StackFrameDescriptorImpl)getNode().getDescriptor(); - XStackFrame xStackFrame = stackDescriptor.getXStackFrame(); - myVariablesPanel.stackChanged(xStackFrame); - if (xStackFrame != null) { - return; - } - } - - super.threadAction(); - } - - @Override - protected void buildVariables(final StackFrameDescriptorImpl stackDescriptor, final EvaluationContextImpl evaluationContext) throws EvaluateException { - final DebuggerContextImpl debuggerContext = getDebuggerContext(); - final SourcePosition sourcePosition = debuggerContext.getSourcePosition(); - if (sourcePosition == null) { - return; - } - - try { - if (!XDebuggerSettingsManager.getInstance().getDataViewSettings().isAutoExpressions() && !myAutoWatchMode) { - // optimization - super.buildVariables(stackDescriptor, evaluationContext); - } - else { - final Map visibleVariables = getVisibleVariables(stackDescriptor.getFrameProxy()); - final EvaluationContextImpl evalContext = debuggerContext.createEvaluationContext(); - final Pair, Set> usedVars = - ApplicationManager.getApplication().runReadAction(new Computable, Set>>() { - @Override - public Pair, Set> compute() { - return findReferencedVars(visibleVariables.keySet(), sourcePosition, evalContext); - } - }); - // add locals - if (myAutoWatchMode) { - for (String var : usedVars.first) { - final LocalVariableDescriptorImpl descriptor = myNodeManager.getLocalVariableDescriptor(stackDescriptor, visibleVariables.get(var)); - myChildren.add(myNodeManager.createNode(descriptor, evaluationContext)); - } - } - else { - super.buildVariables(stackDescriptor, evaluationContext); - } - // add expressions - final EvaluationContextImpl evalContextCopy = evaluationContext.createEvaluationContext(evaluationContext.getThisObject()); - evalContextCopy.setAutoLoadClasses(false); - for (TextWithImports text : usedVars.second) { - myChildren.add(myNodeManager.createNode(myNodeManager.getWatchItemDescriptor(stackDescriptor, text, null), evalContextCopy)); - } - } - } - catch (EvaluateException e) { - if (e.getCause() instanceof AbsentInformationException) { - final StackFrameProxyImpl frame = stackDescriptor.getFrameProxy(); - - final Collection argValues = frame.getArgumentValues(); - int index = 0; - for (Value argValue : argValues) { - final ArgumentValueDescriptorImpl descriptor = - myNodeManager.getArgumentValueDescriptor(stackDescriptor, index++, argValue, false); - final DebuggerTreeNodeImpl variableNode = myNodeManager.createNode(descriptor, evaluationContext); - myChildren.add(variableNode); - } - myChildren.add(myNodeManager.createMessageNode(MessageDescriptor.LOCAL_VARIABLES_INFO_UNAVAILABLE)); - // trying to collect values from variable slots - try { - Map values = LocalVariablesUtil.fetchValues(frame); - for (Map.Entry entry : values.entrySet()) { - DecompiledLocalVariable var = entry.getKey(); - final ArgumentValueDescriptorImpl descriptor = - myNodeManager.getArgumentValueDescriptor(stackDescriptor, var.getSlot(), entry.getValue(), var.isParam()); - final DebuggerTreeNodeImpl variableNode = myNodeManager.createNode(descriptor, evaluationContext); - myChildren.add(variableNode); - } - } - catch (Exception ex) { - LOG.info(ex); - } - } - else { - throw e; - } - } - } - } - - public static Map getVisibleVariables(final StackFrameProxyImpl frame) throws EvaluateException { - final Map vars = new HashMap(); - for (LocalVariableProxyImpl localVariableProxy : frame.visibleVariables()) { - vars.put(localVariableProxy.name(), localVariableProxy); - } - return vars; - } - - private static boolean shouldSkipLine(final PsiFile file, Document doc, int line) { - final int start = doc.getLineStartOffset(line); - final int end = doc.getLineEndOffset(line); - final int _start = CharArrayUtil.shiftForward(doc.getCharsSequence(), start, " \n\t"); - if (_start >= end) { - return true; - } - - TextRange alreadyChecked = null; - for (PsiElement elem = file.findElementAt(_start); elem != null && elem.getTextOffset() <= end && (alreadyChecked == null || !alreadyChecked .contains(elem.getTextRange())); elem = elem.getNextSibling()) { - for (PsiElement _elem = elem; _elem.getTextOffset() >= _start; _elem = _elem.getParent()) { - alreadyChecked = _elem.getTextRange(); - - if (_elem instanceof PsiDeclarationStatement) { - final PsiElement[] declared = ((PsiDeclarationStatement)_elem).getDeclaredElements(); - for (PsiElement declaredElement : declared) { - if (declaredElement instanceof PsiVariable) { - return false; - } - } - } - - if (_elem instanceof PsiJavaCodeReferenceElement) { - final PsiElement resolved = ((PsiJavaCodeReferenceElement)_elem).resolve(); - if (resolved instanceof PsiVariable) { - return false; - } - } - } - } - return true; - } - - public static Pair, Set> findReferencedVars(final Set visibleVars, - final SourcePosition position, - EvaluationContextImpl evalContext) { - final int line = position.getLine(); - if (line < 0) { - return Pair.create(Collections.emptySet(), Collections.emptySet()); - } - final PsiFile positionFile = position.getFile(); - if (!positionFile.getLanguage().isKindOf(JavaLanguage.INSTANCE)) { - return Pair.create(visibleVars, Collections.emptySet()); - } - - final VirtualFile vFile = positionFile.getVirtualFile(); - final Document doc = vFile != null? FileDocumentManager.getInstance().getDocument(vFile) : null; - if (doc == null || doc.getLineCount() == 0 || line > (doc.getLineCount() - 1)) { - return Pair.create(Collections.emptySet(), Collections.emptySet()); - } - - final TextRange limit = calculateLimitRange(positionFile, doc, line); - - int startLine = Math.max(limit.getStartOffset(), line - 1); - startLine = Math.min(startLine, limit.getEndOffset()); - while (startLine > limit.getStartOffset() && shouldSkipLine(positionFile, doc, startLine)) { - startLine--; - } - final int startOffset = doc.getLineStartOffset(startLine); - - int endLine = Math.min(line + 2, limit.getEndOffset()); - while (endLine < limit.getEndOffset() && shouldSkipLine(positionFile, doc, endLine)) { - endLine++; - } - final int endOffset = doc.getLineEndOffset(endLine); - - final TextRange lineRange = new TextRange(startOffset, endOffset); - if (!lineRange.isEmpty()) { - final int offset = CharArrayUtil.shiftForward(doc.getCharsSequence(), doc.getLineStartOffset(line), " \t"); - PsiElement element = positionFile.findElementAt(offset); - if (element != null) { - PsiMethod method = PsiTreeUtil.getNonStrictParentOfType(element, PsiMethod.class); - if (method != null) { - element = method; - } - else { - PsiField field = PsiTreeUtil.getNonStrictParentOfType(element, PsiField.class); - if (field != null) { - element = field; - } - else { - final PsiClassInitializer initializer = PsiTreeUtil.getNonStrictParentOfType(element, PsiClassInitializer.class); - if (initializer != null) { - element = initializer; - } - } - } - - //noinspection unchecked - if (element instanceof PsiCompiledElement) { - return Pair.create(visibleVars, Collections.emptySet()); - } - else { - final Set vars = new HashSet(); - final Set expressions = new HashSet(); - final PsiElementVisitor variablesCollector = new VariablesCollector(visibleVars, adjustRange(element, lineRange), expressions, vars, position, evalContext); - element.accept(variablesCollector); - - return Pair.create(vars, expressions); - } - } - } - return Pair.create(Collections.emptySet(), Collections.emptySet()); - } - - private static TextRange calculateLimitRange(final PsiFile file, final Document doc, final int line) { - final int offset = doc.getLineStartOffset(line); - if (offset > 0) { - PsiMethod method = PsiTreeUtil.getParentOfType(file.findElementAt(offset), PsiMethod.class, false); - if (method != null) { - final TextRange elemRange = method.getTextRange(); - return new TextRange(doc.getLineNumber(elemRange.getStartOffset()), doc.getLineNumber(elemRange.getEndOffset())); - } - } - return new TextRange(0, doc.getLineCount() - 1); - } - - private static TextRange adjustRange(final PsiElement element, final TextRange originalRange) { - final Ref rangeRef = new Ref(originalRange); - element.accept(new JavaRecursiveElementVisitor() { - @Override public void visitExpressionStatement(final PsiExpressionStatement statement) { - final TextRange stRange = statement.getTextRange(); - if (originalRange.intersects(stRange)) { - final TextRange currentRange = rangeRef.get(); - final int start = Math.min(currentRange.getStartOffset(), stRange.getStartOffset()); - final int end = Math.max(currentRange.getEndOffset(), stRange.getEndOffset()); - rangeRef.set(new TextRange(start, end)); - } - } - }); - return rangeRef.get(); - } - - private class RefreshFrameTreeCommand extends RefreshDebuggerTreeCommand { - public RefreshFrameTreeCommand(DebuggerContextImpl context) { - super(context); - } - - @Override - public void contextAction() throws Exception { - DebuggerTreeNodeImpl rootNode; - - final DebuggerContextImpl debuggerContext = getDebuggerContext(); - final ThreadReferenceProxyImpl currentThread = debuggerContext.getThreadProxy(); - if (currentThread == null) { - return; - } - - try { - StackFrameProxyImpl frame = debuggerContext.getFrameProxy(); - if (frame != null) { - NodeManagerImpl nodeManager = getNodeFactory(); - rootNode = nodeManager.createNode(nodeManager.getStackFrameDescriptor(null, frame), debuggerContext.createEvaluationContext()); - } - else { - rootNode = getNodeFactory().getDefaultNode(); - SuspendManager suspendManager = getSuspendContext().getDebugProcess().getSuspendManager(); - try { - if (suspendManager.isSuspended(currentThread)) { - try { - if (currentThread.frameCount() == 0) { - rootNode.add(MessageDescriptor.THREAD_IS_EMPTY); - } - else { - rootNode.add(MessageDescriptor.DEBUG_INFO_UNAVAILABLE); - } - } - catch (EvaluateException e) { - rootNode.add(new MessageDescriptor(e.getMessage())); - } - } - else { - rootNode.add(MessageDescriptor.THREAD_IS_RUNNING); - } - } - catch (ObjectCollectedException ignored) { - rootNode.add(new MessageDescriptor(DebuggerBundle.message("label.thread.node.thread.collected", currentThread.name()))); - } - } - } - catch (Exception ex) { - if (LOG.isDebugEnabled()) { - LOG.debug(ex); - } - rootNode = getNodeFactory().getDefaultNode(); - rootNode.add(MessageDescriptor.DEBUG_INFO_UNAVAILABLE); - } - - final DebuggerTreeNodeImpl rootNode1 = rootNode; - DebuggerInvocationUtil.swingInvokeLater(getProject(), new Runnable() { - @Override - public void run() { - getMutableModel().setRoot(rootNode1); - treeChanged(); - - final TreeModel model = getModel(); - model.addTreeModelListener(new TreeModelAdapter() { - @Override - public void treeStructureChanged(TreeModelEvent e) { - final Object[] path = e.getPath(); - if (path.length > 0 && path[path.length - 1] == rootNode1) { - // wait until rootNode1 (the root just set) becomes the root - model.removeTreeModelListener(this); - if (ViewsGeneralSettings.getInstance().AUTOSCROLL_TO_NEW_LOCALS) { - autoscrollToNewLocals(rootNode1); - } - else { - // should clear this flag, otherwise, if AUTOSCROLL_TO_NEW_LOCALS option turned - // to true during the debug process, all these variables will be considered 'new' - for (Enumeration children = rootNode1.rawChildren(); children.hasMoreElements();) { - final DebuggerTreeNodeImpl child = (DebuggerTreeNodeImpl)children.nextElement(); - final NodeDescriptorImpl descriptor = child.getDescriptor(); - if (descriptor instanceof LocalVariableDescriptorImpl) { - ((LocalVariableDescriptorImpl)descriptor).setNewLocal(false); - } - } - } - } - } - }); - } - - private void autoscrollToNewLocals(DebuggerTreeNodeImpl frameNode) { - final DebuggerSession debuggerSession = debuggerContext.getDebuggerSession(); - final boolean isSteppingThrough = debuggerSession != null && debuggerSession.isSteppingThrough(debuggerContext.getThreadProxy()); - final List toClear = new ArrayList(); - final List newLocalsToSelect = new ArrayList(); - - for (Enumeration e = frameNode.rawChildren(); e.hasMoreElements();) { - final DebuggerTreeNodeImpl child = (DebuggerTreeNodeImpl)e.nextElement(); - final NodeDescriptorImpl descriptor = child.getDescriptor(); - if (!(descriptor instanceof LocalVariableDescriptorImpl)) { - continue; - } - final LocalVariableDescriptorImpl localVariableDescriptor = (LocalVariableDescriptorImpl)descriptor; - if (isSteppingThrough && localVariableDescriptor.isNewLocal()) { - myAnyNewLocals = true; - newLocalsToSelect.add(child); - } - else { - toClear.add(child); - } - localVariableDescriptor.setNewLocal(false); - } - - if (!newLocalsToSelect.isEmpty()) { - for (DebuggerTreeNodeImpl child : toClear) { - removeSelectionPath(new TreePath(child.getPath())); - child.getDescriptor().myIsSelected = false; - } - for (DebuggerTreeNodeImpl child : newLocalsToSelect) { - addSelectionPath(new TreePath(child.getPath())); - child.getDescriptor().myIsSelected = true; - } - } - } - }); - } - - } - - private static class VariablesCollector extends JavaRecursiveElementVisitor { - private final Set myVisibleLocals; - private final TextRange myLineRange; - private final Set myExpressions; - private final Set myVars; - private final SourcePosition myPosition; - private final EvaluationContextImpl myEvalContext; - private final boolean myCollectExpressions; - - public VariablesCollector(final Set visibleLocals, - final TextRange lineRange, - final Set expressions, - final Set vars, - SourcePosition position, EvaluationContextImpl evalContext) { - myVisibleLocals = visibleLocals; - myLineRange = lineRange; - myExpressions = expressions; - myVars = vars; - myPosition = position; - myEvalContext = evalContext; - myCollectExpressions = XDebuggerSettingsManager.getInstance().getDataViewSettings().isAutoExpressions(); - } - - @Override - public void visitElement(final PsiElement element) { - if (myLineRange.intersects(element.getTextRange())) { - super.visitElement(element); - } - } - - @Override - public void visitMethodCallExpression(final PsiMethodCallExpression expression) { - if (myCollectExpressions) { - final PsiMethod psiMethod = expression.resolveMethod(); - if (psiMethod != null && !DebuggerUtils.hasSideEffectsOrReferencesMissingVars(expression, myVisibleLocals)) { - myExpressions.add(new TextWithImportsImpl(expression)); - } - } - super.visitMethodCallExpression(expression); - } - - @Override - public void visitReferenceExpression(final PsiReferenceExpression reference) { - if (myLineRange.intersects(reference.getTextRange())) { - final PsiElement psiElement = reference.resolve(); - if (psiElement instanceof PsiVariable) { - final PsiVariable var = (PsiVariable)psiElement; - if (var instanceof PsiField) { - if (myCollectExpressions && !DebuggerUtils.hasSideEffectsOrReferencesMissingVars(reference, myVisibleLocals)) { - /* - if (var instanceof PsiEnumConstant && reference.getQualifier() == null) { - final PsiClass enumClass = ((PsiEnumConstant)var).getContainingClass(); - if (enumClass != null) { - final PsiExpression expression = JavaPsiFacade.getInstance(var.getProject()).getParserFacade().createExpressionFromText(enumClass.getName() + "." + var.getName(), var); - final PsiReference ref = expression.getReference(); - if (ref != null) { - ref.bindToElement(var); - myExpressions.add(new TextWithImportsImpl(expression)); - } - } - } - else { - myExpressions.add(new TextWithImportsImpl(reference)); - } - */ - final PsiModifierList modifierList = var.getModifierList(); - boolean isConstant = (var instanceof PsiEnumConstant) || - (modifierList != null && modifierList.hasModifierProperty(PsiModifier.STATIC) && modifierList.hasModifierProperty(PsiModifier.FINAL)); - if (!isConstant) { - myExpressions.add(new TextWithImportsImpl(reference)); - } - } - } - else { - if (myVisibleLocals.contains(var.getName())) { - myVars.add(var.getName()); - } - else { - // fix for variables used in inner classes - if (!Comparing.equal(PsiTreeUtil.getParentOfType(reference, PsiClass.class), - PsiTreeUtil.getParentOfType(var, PsiClass.class))) { - myExpressions.add(new TextWithImportsImpl(reference)); - } - } - } - } - } - super.visitReferenceExpression(reference); - } - - @Override - public void visitArrayAccessExpression(final PsiArrayAccessExpression expression) { - if (myCollectExpressions && !DebuggerUtils.hasSideEffectsOrReferencesMissingVars(expression, myVisibleLocals)) { - myExpressions.add(new TextWithImportsImpl(expression)); - } - super.visitArrayAccessExpression(expression); - } - - @Override - public void visitParameter(final PsiParameter parameter) { - processVariable(parameter); - super.visitParameter(parameter); - } - - @Override - public void visitLocalVariable(final PsiLocalVariable variable) { - processVariable(variable); - super.visitLocalVariable(variable); - } - - private void processVariable(final PsiVariable variable) { - if (myLineRange.intersects(variable.getTextRange()) && myVisibleLocals.contains(variable.getName())) { - myVars.add(variable.getName()); - } - } - - @Override - public void visitClass(final PsiClass aClass) { - // Do not step in to local and anonymous classes... - } - } -} diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/VariablesPanel.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/VariablesPanel.java deleted file mode 100644 index 96e837559c38..000000000000 --- a/java/debugger/impl/src/com/intellij/debugger/ui/impl/VariablesPanel.java +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright 2000-2015 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.intellij.debugger.ui.impl; - -import com.intellij.debugger.actions.DebuggerAction; -import com.intellij.debugger.actions.DebuggerActions; -import com.intellij.debugger.impl.DebuggerContextImpl; -import com.intellij.debugger.impl.DebuggerSession; -import com.intellij.debugger.impl.DebuggerStateManager; -import com.intellij.debugger.ui.impl.watch.DebuggerTree; -import com.intellij.openapi.Disposable; -import com.intellij.openapi.actionSystem.*; -import com.intellij.openapi.editor.Document; -import com.intellij.openapi.fileTypes.FileType; -import com.intellij.openapi.project.Project; -import com.intellij.ui.AppUIUtil; -import com.intellij.ui.ScrollPaneFactory; -import com.intellij.util.SystemProperties; -import com.intellij.xdebugger.XSourcePosition; -import com.intellij.xdebugger.evaluation.EvaluationMode; -import com.intellij.xdebugger.evaluation.XDebuggerEditorsProvider; -import com.intellij.xdebugger.frame.XStackFrame; -import com.intellij.xdebugger.impl.frame.XVariablesViewBase; -import org.jetbrains.annotations.NonNls; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import javax.swing.*; -import java.awt.*; -import java.awt.event.KeyEvent; - -public class VariablesPanel extends DebuggerTreePanel implements DataProvider { - @NonNls private static final String HELP_ID = "debugging.debugFrame"; - - private static final String TREE = "tree"; - private static final String X_TREE = "xTree"; - private final JPanel myCards; - private final MyXVariablesView myXTree; - - public VariablesPanel(Project project, DebuggerStateManager stateManager, Disposable parent) { - super(project, stateManager); - - setBorder(null); - - final FrameVariablesTree frameTree = getFrameTree(); - - myCards = new JPanel(new CardLayout()); - myCards.add(frameTree, TREE); - - myXTree = new MyXVariablesView(project); - registerDisposable(myXTree); - myCards.add(myXTree.getTree(), X_TREE); - - JScrollPane pane = ScrollPaneFactory.createScrollPane(myCards); - pane.getVerticalScrollBar().setUnitIncrement(10); - add(pane, BorderLayout.CENTER); - registerDisposable(DebuggerAction.installEditAction(frameTree, DebuggerActions.EDIT_NODE_SOURCE)); - - overrideShortcut(frameTree, DebuggerActions.COPY_VALUE, CommonShortcuts.getCopy()); - overrideShortcut(frameTree, DebuggerActions.SET_VALUE, new CustomShortcutSet(KeyStroke.getKeyStroke(KeyEvent.VK_F2, 0))); - - new ValueNodeDnD(myTree, parent); - } - - @Override - protected DebuggerTree createTreeView() { - return new FrameVariablesTree(getProject(), SystemProperties.getBooleanProperty("java.debugger.xTree", true) ? this : null); - } - - @Override - protected void changeEvent(DebuggerContextImpl newContext, DebuggerSession.Event event) { - if (event != DebuggerSession.Event.THREADS_REFRESH) { - super.changeEvent(newContext, event); - } - } - - @Override - protected ActionPopupMenu createPopupMenu() { - ActionGroup group = (ActionGroup)ActionManager.getInstance().getAction(DebuggerActions.FRAME_PANEL_POPUP); - return ActionManager.getInstance().createActionPopupMenu(DebuggerActions.FRAME_PANEL_POPUP, group); - } - - @Override - public Object getData(String dataId) { - if (PlatformDataKeys.HELP_ID.is(dataId)) { - return HELP_ID; - } - return super.getData(dataId); - } - - public FrameVariablesTree getFrameTree() { - return (FrameVariablesTree)getTree(); - } - - public void stackChanged(@Nullable final XStackFrame xStackFrame) { - AppUIUtil.invokeOnEdt(new Runnable() { - @Override - public void run() { - myXTree.stackChanged(xStackFrame); - ((CardLayout)(myCards.getLayout())).show(myCards, xStackFrame == null ? TREE : X_TREE); - } - }); - } - - private static final class MyXVariablesView extends XVariablesViewBase { - private XStackFrame myCurrentXStackFrame; - - public MyXVariablesView(@NotNull Project project) { - super(project, new XDebuggerEditorsProvider() { - @NotNull - @Override - public FileType getFileType() { - throw new UnsupportedOperationException(); - } - - @NotNull - @Override - public Document createDocument(@NotNull Project project, @NotNull String text, @Nullable XSourcePosition sourcePosition, @NotNull EvaluationMode mode) { - throw new UnsupportedOperationException(); - } - }, null); - } - - public void stackChanged(@Nullable XStackFrame stackFrame) { - if (myCurrentXStackFrame != null) { - saveCurrentTreeState(stackFrame); - } - - myCurrentXStackFrame = stackFrame; - if (stackFrame == null) { - getTree().setSourcePosition(null); - } - else { - buildTreeAndRestoreState(stackFrame); - } - } - - @Override - public void processSessionEvent(@NotNull SessionEvent event) { - } - } -} diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/WatchDebuggerTree.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/WatchDebuggerTree.java deleted file mode 100644 index 12e5b1c7fa9b..000000000000 --- a/java/debugger/impl/src/com/intellij/debugger/ui/impl/WatchDebuggerTree.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright 2000-2009 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.intellij.debugger.ui.impl; - -import com.intellij.debugger.engine.evaluation.TextWithImports; -import com.intellij.debugger.impl.DebuggerContextImpl; -import com.intellij.debugger.ui.impl.watch.DebuggerTree; -import com.intellij.debugger.ui.impl.watch.DebuggerTreeNodeImpl; -import com.intellij.debugger.ui.impl.watch.WatchItemDescriptor; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.project.Project; -import com.intellij.xdebugger.XDebuggerBundle; -import org.jetbrains.annotations.Nullable; - -import javax.swing.tree.TreePath; -import java.util.Enumeration; - -public class WatchDebuggerTree extends DebuggerTree { - private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.ui.impl.WatchDebuggerTree"); - - public WatchDebuggerTree(Project project) { - super(project); - getEmptyText().setText(XDebuggerBundle.message("debugger.no.watches")); - } - - public DebuggerTreeNodeImpl[] getWatches() { - DebuggerTreeNodeImpl root = (DebuggerTreeNodeImpl)getModel().getRoot(); - DebuggerTreeNodeImpl[] watches = new DebuggerTreeNodeImpl[root.getChildCount()]; - - final Enumeration e = root.children(); - int i = 0; - while(e.hasMoreElements()) { - watches[i++] = (DebuggerTreeNodeImpl)e.nextElement(); - } - - return watches; - } - - public int getWatchCount() { - DebuggerTreeNodeImpl root = (DebuggerTreeNodeImpl) getModel().getRoot(); - return root != null ? root.getChildCount() : 0; - } - - public DebuggerTreeNodeImpl addWatch(WatchItemDescriptor descriptor) { - ApplicationManager.getApplication().assertIsDispatchThread(); - final DebuggerTreeNodeImpl root = (DebuggerTreeNodeImpl) getModel().getRoot(); - WatchItemDescriptor watchDescriptor = new WatchItemDescriptor(getProject(), descriptor.getEvaluationText()); - watchDescriptor.displayAs(descriptor); - - final DebuggerTreeNodeImpl node = DebuggerTreeNodeImpl.createNodeNoUpdate(this, watchDescriptor); - root.add(node); - - treeChanged(); - getSelectionModel().setSelectionPath(new TreePath(node.getPath())); - - //node.calcValue(); - - return node; - } - - public DebuggerTreeNodeImpl addWatch(TextWithImports text, @Nullable String customName) { - ApplicationManager.getApplication().assertIsDispatchThread(); - final DebuggerTreeNodeImpl root = (DebuggerTreeNodeImpl) getModel().getRoot(); - final WatchItemDescriptor descriptor = new WatchItemDescriptor(getProject(), text, customName); - DebuggerTreeNodeImpl node = DebuggerTreeNodeImpl.createNodeNoUpdate(this, descriptor); - root.add(node); - - treeChanged(); - final TreePath path = new TreePath(node.getPath()); - getSelectionModel().setSelectionPath(path); - scrollPathToVisible(path); - return node; - } - - public void removeWatch(DebuggerTreeNodeImpl node) { - ApplicationManager.getApplication().assertIsDispatchThread(); - LOG.assertTrue(node.getDescriptor() instanceof WatchItemDescriptor); - - DebuggerTreeNodeImpl root = (DebuggerTreeNodeImpl) getModel().getRoot(); - DebuggerTreeNodeImpl nodeToSelect = (DebuggerTreeNodeImpl) node.getNextSibling(); - - getMutableModel().removeNodeFromParent(node); - treeChanged(); - - if(nodeToSelect == null && root.getChildCount() > 0) { - nodeToSelect = (DebuggerTreeNodeImpl) root.getChildAt(root.getChildCount() - 1); - } - - if(nodeToSelect != null) { - setSelectionPath(new TreePath(nodeToSelect.getPath())); - } - } - - protected void build(DebuggerContextImpl context) { - for (DebuggerTreeNodeImpl node : getWatches()) { - node.calcValue(); - } - } - - public static void setWatchNodeText(final DebuggerTreeNodeImpl node, TextWithImports text) { - ((WatchItemDescriptor)node.getDescriptor()).setEvaluationText(text); - node.calcValue(); - } - -} From 8673d7ee500d51aba1a8fbe58c2177eed57d04a6 Mon Sep 17 00:00:00 2001 From: Nadya Zabrodina Date: Tue, 15 Sep 2015 14:24:35 +0300 Subject: [PATCH 04/11] [Shelf]: (IDEA-144946, EA-72761) Exceptions from shelf after project move to another folder * store all paths in system independent way and force convert if needed --- .../vcs/changes/shelf/ShelvedBinaryFile.java | 14 +++++++++++--- .../vcs/changes/shelf/ShelvedChangeList.java | 1 + 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/shelf/ShelvedBinaryFile.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/shelf/ShelvedBinaryFile.java index 16e9ee46c76c..67637e68c471 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/shelf/ShelvedBinaryFile.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/shelf/ShelvedBinaryFile.java @@ -50,9 +50,10 @@ public class ShelvedBinaryFile implements JDOMExternalizable { public ShelvedBinaryFile(final String beforePath, final String afterPath, @Nullable final String shelvedPath) { assert beforePath != null || afterPath != null; - BEFORE_PATH = convertToSystemIndependent(beforePath); - AFTER_PATH = convertToSystemIndependent(afterPath); - SHELVED_PATH = convertToSystemIndependent(shelvedPath); + BEFORE_PATH = beforePath; + AFTER_PATH = afterPath; + SHELVED_PATH = shelvedPath; + convertPathsToSystemIndependent(); } @Nullable @@ -60,8 +61,15 @@ public class ShelvedBinaryFile implements JDOMExternalizable { return beforePath != null ? FileUtil.toSystemIndependentName(beforePath) : null; } + private void convertPathsToSystemIndependent() { + BEFORE_PATH = convertToSystemIndependent(BEFORE_PATH); + AFTER_PATH = convertToSystemIndependent(AFTER_PATH); + SHELVED_PATH = convertToSystemIndependent(SHELVED_PATH); + } + public void readExternal(Element element) throws InvalidDataException { DefaultJDOMExternalizer.readExternal(this, element); + convertPathsToSystemIndependent(); } public void writeExternal(Element element) throws WriteExternalException { diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/shelf/ShelvedChangeList.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/shelf/ShelvedChangeList.java index 834f37e74455..738fc3d16aec 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/shelf/ShelvedChangeList.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/shelf/ShelvedChangeList.java @@ -84,6 +84,7 @@ public class ShelvedChangeList implements JDOMExternalizable, ExternalizableSche @Override public void readExternal(Element element) throws InvalidDataException { DefaultJDOMExternalizer.readExternal(this, element); + PATH = FileUtil.toSystemIndependentName(PATH); mySchemeName = element.getAttributeValue(NAME_ATTRIBUTE); DATE = new Date(Long.parseLong(element.getAttributeValue(ATTRIBUTE_DATE))); myRecycled = Boolean.parseBoolean(element.getAttributeValue(ATTRIBUTE_RECYCLED_CHANGELIST)); From c7958be5a56c600d3755b83f84e98db3dbd56685 Mon Sep 17 00:00:00 2001 From: Eugene Zhuravlev Date: Tue, 15 Sep 2015 14:24:44 +0200 Subject: [PATCH 05/11] compile scratches with debug info (IDEA-145117) --- .../intellij/execution/impl/JavaScratchCompilationSupport.java | 1 + 1 file changed, 1 insertion(+) diff --git a/java/execution/impl/src/com/intellij/execution/impl/JavaScratchCompilationSupport.java b/java/execution/impl/src/com/intellij/execution/impl/JavaScratchCompilationSupport.java index 5bfb4ba6f4a3..00327b870eca 100644 --- a/java/execution/impl/src/com/intellij/execution/impl/JavaScratchCompilationSupport.java +++ b/java/execution/impl/src/com/intellij/execution/impl/JavaScratchCompilationSupport.java @@ -140,6 +140,7 @@ public class JavaScratchCompilationSupport implements ProjectComponent, CompileT } final List options = new ArrayList(); + options.add("-g"); // always compile with debug info final JavaSdkVersion sdkVersion = JavaSdk.getInstance().getVersion(targetSdk); if (sdkVersion != null) { final String langLevel = "1." + Integer.valueOf(3 + sdkVersion.getMaxLanguageLevel().ordinal()); From b593d17b5282d317222a20f6938fa989b35a6d1a Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Tue, 15 Sep 2015 15:33:26 +0300 Subject: [PATCH 06/11] Sync with GitHub --- python/helpers/python-skeletons/alembic.py | 6 + .../python-skeletons/pytest/__init__.py | 276 ++++++++++++++++++ 2 files changed, 282 insertions(+) create mode 100644 python/helpers/python-skeletons/alembic.py create mode 100644 python/helpers/python-skeletons/pytest/__init__.py diff --git a/python/helpers/python-skeletons/alembic.py b/python/helpers/python-skeletons/alembic.py new file mode 100644 index 000000000000..8c5bcaf58c73 --- /dev/null +++ b/python/helpers/python-skeletons/alembic.py @@ -0,0 +1,6 @@ +from alembic.operations import Operations +from alembic.environment import EnvironmentContext + +op = Operations() +context = EnvironmentContext() + diff --git a/python/helpers/python-skeletons/pytest/__init__.py b/python/helpers/python-skeletons/pytest/__init__.py new file mode 100644 index 000000000000..dec4ffc01121 --- /dev/null +++ b/python/helpers/python-skeletons/pytest/__init__.py @@ -0,0 +1,276 @@ +"""Skeleton for 'pytest'. + +Project: pytest 2.6.4 +Skeleton by: Bruno Oliveira + +Exposing everything that can be extracted from `pytest_namespace` hook +in standard pytest modules, using original docstrings. +""" + + +# _pytest.genscript +def freeze_includes(): + """ + Returns a list of module names used by py.test that should be + included by cx_freeze. + """ + + +# _pytest.main +class collect: + + class Item: + """ a basic test invocation item. Note that for a single function + there might be multiple test invocation items. + """ + + class Collector: + """ Collector instances create children through collect() + and thus iteratively build a tree. + """ + + class File: + """ base class for collecting tests from a file. """ + + class Session: + """ + """ + + # _pytest.python + class Module: + """ Collector for test classes and functions. """ + + class Class: + """ Collector for test methods. """ + + class Instance: + """ + """ + + class Function: + """ a Function Item is responsible for setting up and executing a + Python test function. + """ + + class Generator: + """ + """ + + @staticmethod + def _fillfuncargs(function): + """ fill missing funcargs for a test function. """ + + +# _pytest.mark +class mark: + + @staticmethod + def skipif(condition, reason=None): + """skip the given test function if eval(condition) results in a True + value. + + Optionally specify a reason for better reporting. + + Evaluation happens within the module global context. + Example: ``skipif('sys.platform == "win32"')`` skips the test if + we are on the win32 platform. + + see http://pytest.org/latest/skipping.html + """ + + @staticmethod + def xfail(condition=None, reason=None, run=True): + """mark the the test function as an expected failure if eval(condition) + has a True value. + + Optionally specify a reason for better reporting and run=False if + you don't even want to execute the test function. + + See http://pytest.org/latest/skipping.html + """ + + @staticmethod + def parametrize(argnames, argvalues): + """call a test function multiple times passing in different arguments + in turn. + + :type argnames: str | list[str] + :param argvalues: generally needs to be a list of values if argnames + specifies only one name or a list of tuples of values if + argnames specifies multiple names. + + Example: @parametrize('arg1', [1,2]) would lead to two calls of the + decorated test function, one with arg1=1 and another with arg1=2. + + see http://pytest.org/latest/parametrize.html for more info + and examples. + """ + + @staticmethod + def usefixtures(*fixturenames): + """mark tests as needing all of the specified fixtures. + + see http://pytest.org/latest/fixture.html#usefixtures + """ + + @staticmethod + def tryfirst(f): + """mark a hook implementation function such that the plugin machinery + will try to call it first/as early as possible. + """ + + @staticmethod + def trylast(f): + """mark a hook implementation function such that the plugin machinery + will try to call it last/as late as possible. + """ + + @staticmethod + def hookwrapper(f): + """A hook wrapper is a generator function which yields exactly once. + When pytest invokes hooks it first executes hook wrappers and passes + the same arguments as to the regular hooks. + """ + + +# _pytest.pdb +def set_trace(): + """ invoke PDB set_trace debugging, dropping any IO capturing. """ + + +# _pytest.python +def raises(ExpectedException, *args, **kwargs): + """ assert that a code block/function call raises @ExpectedException and + raise a failure exception otherwise. + + :type ExpectedException: T + + This helper produces a ``py.code.ExceptionInfo()`` object. + + If using Python 2.5 or above, you may use this function as a + context manager:: + + >>> with raises(ZeroDivisionError): + ... 1/0 + + Or you can specify a callable by passing a to-be-called lambda:: + + >>> raises(ZeroDivisionError, lambda: 1/0) + + + or you can specify an arbitrary callable with arguments:: + + >>> def f(x): return 1/x + ... + >>> raises(ZeroDivisionError, f, 0) + + >>> raises(ZeroDivisionError, f, x=0) + + + A third possibility is to use a string to be executed:: + + >>> raises(ZeroDivisionError, "f(0)") + + + Performance note: + ----------------- + + Similar to caught exception objects in Python, explicitly clearing + local references to returned ``py.code.ExceptionInfo`` objects can + help the Python interpreter speed up its garbage collection. + + Clearing those references breaks a reference cycle + (``ExceptionInfo`` --> caught exception --> frame stack raising + the exception --> current frame stack --> local variables --> + ``ExceptionInfo``) which makes Python keep all objects referenced + from that cycle (including all local variables in the current + frame) alive until the next cyclic garbage collection run. See the + official Python ``try`` statement documentation for more detailed + information. + + """ + +def fixture(scope="function", params=None, autouse=False, ids=None): + """ (return a) decorator to mark a fixture factory function. + + This decorator can be used (with or or without parameters) to define + a fixture function. The name of the fixture function can later be + referenced to cause its invocation ahead of running tests: test + modules or classes can use the pytest.mark.usefixtures(fixturename) + marker. Test functions can directly use fixture names as input + arguments in which case the fixture instance returned from the fixture + function will be injected. + + :arg scope: the scope for which this fixture is shared, one of + "function" (default), "class", "module", "session". + + :arg params: an optional list of parameters which will cause multiple + invocations of the fixture function and all of the tests + using it. + + :arg autouse: if True, the fixture func is activated for all tests that + can see it. If False (the default) then an explicit + reference is needed to activate the fixture. + + :arg ids: list of string ids each corresponding to the params + so that they are part of the test id. If no ids are provided + they will be generated automatically from the params. + + """ + + +def yield_fixture(scope="function", params=None, autouse=False, ids=None): + """ (return a) decorator to mark a yield-fixture factory function + (EXPERIMENTAL). + + This takes the same arguments as :py:func:`pytest.fixture` but + expects a fixture function to use a ``yield`` instead of a ``return`` + statement to provide a fixture. See + http://pytest.org/en/latest/yieldfixture.html for more info. + """ + + +# _pytest.recwarn +def deprecated_call(func, *args, **kwargs): + """ assert that calling ``func(*args, **kwargs)`` + triggers a DeprecationWarning. + """ + + +# _pytest.runner +def exit(msg): + """ exit testing process as if KeyboardInterrupt was triggered. """ + +exit.Exception = Exception + + +def skip(msg=""): + """ skip an executing test with the given message. Note: it's usually + better to use the pytest.mark.skipif marker to declare a test to be + skipped under certain conditions like mismatching platforms or + dependencies. See the pytest_skipping plugin for details. + """ +skip.Exception = Exception + + +def fail(msg="", pytrace=True): + """ explicitely fail an currently-executing test with the given Message. + + :arg pytrace: if false the msg represents the full failure information + and no python traceback will be reported. + """ +fail.Exception = Exception + + +def importorskip(modname, minversion=None): + """ return imported module if it has at least "minversion" as its + __version__ attribute. If no minversion is specified the a skip + is only triggered if the module can not be imported. + Note that version comparison only works with simple version strings + like "1.2.3" but not "1.2.3.dev1" or others. + """ + +# _pytest.skipping +def xfail(reason=""): + """ xfail an executing test or setup functions with the given reason. + """ From 382702d15cd640c674d60d390a347c886acba3b3 Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Tue, 15 Sep 2015 15:38:09 +0300 Subject: [PATCH 07/11] Updated test data after removing __author__ from the new Python file template --- .../move/moduleToNonPackage/after/src/nonp3/__init__.py | 1 - python/testData/refactoring/move/newModule/after/src/b.py | 3 --- 2 files changed, 4 deletions(-) diff --git a/python/testData/refactoring/move/moduleToNonPackage/after/src/nonp3/__init__.py b/python/testData/refactoring/move/moduleToNonPackage/after/src/nonp3/__init__.py index 09ee69e66c3c..e69de29bb2d1 100644 --- a/python/testData/refactoring/move/moduleToNonPackage/after/src/nonp3/__init__.py +++ b/python/testData/refactoring/move/moduleToNonPackage/after/src/nonp3/__init__.py @@ -1 +0,0 @@ -__author__ = 'user1' diff --git a/python/testData/refactoring/move/newModule/after/src/b.py b/python/testData/refactoring/move/newModule/after/src/b.py index aaf94453e78c..70ea8554e628 100644 --- a/python/testData/refactoring/move/newModule/after/src/b.py +++ b/python/testData/refactoring/move/newModule/after/src/b.py @@ -1,6 +1,3 @@ -__author__ = 'user1' - - def f(url): '''Return the representation available at the URL. From dbc133b4b99137f1ad70dca85ca204f2f4ac0911 Mon Sep 17 00:00:00 2001 From: "Maxim.Mossienko" Date: Tue, 15 Sep 2015 14:31:32 +0200 Subject: [PATCH 08/11] - pluggability of test iteration - use results of FileNameCache.getVFileName to avoid DCE - test iterations for emulating getPath / linear scan --- .../impl/FileNameCacheMicroBenchmark.java | 98 +++++++++++++++++-- 1 file changed, 88 insertions(+), 10 deletions(-) diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/vfs/newvfs/impl/FileNameCacheMicroBenchmark.java b/platform/platform-tests/testSrc/com/intellij/openapi/vfs/newvfs/impl/FileNameCacheMicroBenchmark.java index 1d450ebddbb6..7dcf4fd22bf9 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/vfs/newvfs/impl/FileNameCacheMicroBenchmark.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/vfs/newvfs/impl/FileNameCacheMicroBenchmark.java @@ -60,6 +60,58 @@ public class FileNameCacheMicroBenchmark { System.exit(0); } + private static final TestIteration LONG_RANDOM_ACCESS = new TestIteration() { + @Override + public void doTest(int threadNumber, int[] ids, Random threadRandom, int queryCount) { + final int blackHole = threadRandom.nextInt(); + + for (int j = 0; j < queryCount; j++) { + final CharSequence name = FileNameCache.getVFileName(ids[threadRandom.nextInt(ids.length)]); + + if (blackHole == System.identityHashCode(name.hashCode())) { + failure(); + } + } + } + }; + + private static final TestIteration LONG_RANDOM_ACCESS_WITH_GET_PATH = new TestIteration() { + @Override + public void doTest(int threadNumber, int[] ids, Random threadRandom, int queryCount) { + final int blackHole = threadRandom.nextInt(); + + for (int j = 0; j < queryCount; j++) { + final int hash = getPath(threadRandom.nextInt(ids.length), ids); + + if (blackHole == hash) { + failure(); + } + } + } + }; + + private static final TestIteration LINEAR_SCAN_AND_RANDOM_ACCESS_WITH_GET_PATH = new TestIteration() { + @Override + public void doTest(int threadNumber, int[] ids, Random threadRandom, int queryCount) { + if (threadNumber % 2 == 1) { // linear scan for every second_case + final int blackHole = threadRandom.nextInt(); + int currentId = 0; + + for(int j = 0; j < queryCount; ++j) { + final int hash = getPath(currentId++, ids); + if (currentId == ids.length) currentId = 0; + if (blackHole == hash) { + failure(); + } + } + + return; + } + + LONG_RANDOM_ACCESS_WITH_GET_PATH.doTest(threadNumber, ids, threadRandom, queryCount); + } + }; + private static void runTest(int nameCount, String name) throws InterruptedException, ExecutionException { System.out.println("----- " + name + " ------ name count: "+nameCount); @@ -68,15 +120,23 @@ public class FileNameCacheMicroBenchmark { checkNames(map, ids); warmUp(ids); - measureAverageTime(ids, 1); - measureAverageTime(ids, 4); + measureAverageTime(ids, 1, LONG_RANDOM_ACCESS); + measureAverageTime(ids, 4, LONG_RANDOM_ACCESS); + + //measureAverageTime(ids, 1, LONG_RANDOM_ACCESS_WITH_GET_PATH); + //measureAverageTime(ids, 4, LONG_RANDOM_ACCESS_WITH_GET_PATH); + // + //measureAverageTime(ids, 1, LINEAR_SCAN_AND_RANDOM_ACCESS_WITH_GET_PATH); + //measureAverageTime(ids, 4, LINEAR_SCAN_AND_RANDOM_ACCESS_WITH_GET_PATH); } private static boolean warmedUp; private static void warmUp(int[] ids) throws InterruptedException, ExecutionException { if (warmedUp) return; for (int i = 0; i < 200000; i++) { - runThreads(ids, 2, 1000); + runThreads(ids, 2, 1000, LONG_RANDOM_ACCESS); + //runThreads(ids, 2, 1000, LONG_RANDOM_ACCESS_WITH_GET_PATH); + //runThreads(ids, 2, 1000, LINEAR_SCAN_AND_RANDOM_ACCESS_WITH_GET_PATH); } Thread.sleep(10000); @@ -84,11 +144,22 @@ public class FileNameCacheMicroBenchmark { warmedUp = true; } - private static void measureAverageTime(int[] ids, int threadCount) throws InterruptedException, ExecutionException { + private static int getPath(int id, int[] ids) { + int result = 0; + result += System.identityHashCode(FileNameCache.getVFileName(ids[id])); + + while (id > 10) { + result += System.identityHashCode(FileNameCache.getVFileName(ids[id / 10])); + id /= 10; + } + return result; + } + + private static void measureAverageTime(int[] ids, int threadCount, TestIteration iteration) throws InterruptedException, ExecutionException { System.out.println("Running "+threadCount+" threads"); TLongArrayList times = new TLongArrayList(); - for (int i = 0; i < 11; i++) { - long time = runThreads(ids, threadCount, 20000000); + for (int i = 0; i < 10; i++) { + long time = runThreads(ids, threadCount, 20000000, iteration); System.out.println(time); times.add(time); } @@ -98,18 +169,25 @@ public class FileNameCacheMicroBenchmark { System.out.println(); } - private static long runThreads(final int[] ids, int threadCount, final int queryCount) throws InterruptedException, ExecutionException { + abstract static class TestIteration { + abstract void doTest(int threadNumber, int[] ids, Random threadRandom, int queryCount); + protected final void failure() { + System.out.println("Failure"); + assert false; + } + } + + private static long runThreads(final int[] ids, int threadCount, final int queryCount, final TestIteration testIteration) throws InterruptedException, ExecutionException { long start = System.currentTimeMillis(); List> futures = ContainerUtil.newArrayList(); Random seedRandom = new Random(); for (int i = 0; i < threadCount; i++) { final Random threadRandom = new Random(seedRandom.nextInt()); + final int finalI = i; futures.add(ApplicationManager.getApplication().executeOnPooledThread(new Runnable() { @Override public void run() { - for (int j = 0; j < queryCount; j++) { - FileNameCache.getVFileName(ids[threadRandom.nextInt(ids.length)]); - } + testIteration.doTest(finalI, ids, threadRandom, queryCount); } })); } From 67c1f51419d440c32deff078b9a38c15f9bcc60b Mon Sep 17 00:00:00 2001 From: Oleg Sukhodolsky Date: Tue, 15 Sep 2015 15:53:37 +0300 Subject: [PATCH 09/11] EA-56820: Let's use PairConsumer instead of Function> --- .../com/intellij/execution/ExecutionMode.java | 12 ++++++++---- .../com/intellij/execution/ExecutionModes.java | 16 +++++++--------- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/execution/ExecutionMode.java b/platform/lang-impl/src/com/intellij/execution/ExecutionMode.java index 064210560e9d..f58168aab2ad 100644 --- a/platform/lang-impl/src/com/intellij/execution/ExecutionMode.java +++ b/platform/lang-impl/src/com/intellij/execution/ExecutionMode.java @@ -16,9 +16,8 @@ package com.intellij.execution; import com.intellij.execution.process.ProcessListener; -import com.intellij.openapi.util.Pair; import com.intellij.util.Function; -import com.intellij.util.Functions; +import com.intellij.util.PairConsumer; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -30,6 +29,11 @@ import java.util.List; * @author Roman.Chernyatchik */ public class ExecutionMode { + private static final PairConsumer NOOP_CONSUMER = new PairConsumer() { + @Override + public void consume(ExecutionMode mode, String s) { + } + }; private final boolean myCancelable; private final String myTitle; private final String myTitle2; @@ -60,8 +64,8 @@ public class ExecutionMode { } @NotNull - public Function, Void> getTimeoutCallback() { - return Functions.identity(); + public PairConsumer getTimeoutCallback() { + return NOOP_CONSUMER; } @Nullable diff --git a/platform/lang-impl/src/com/intellij/execution/ExecutionModes.java b/platform/lang-impl/src/com/intellij/execution/ExecutionModes.java index acf68504b237..331cdf6eb084 100644 --- a/platform/lang-impl/src/com/intellij/execution/ExecutionModes.java +++ b/platform/lang-impl/src/com/intellij/execution/ExecutionModes.java @@ -16,8 +16,7 @@ package com.intellij.execution; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.util.Pair; -import com.intellij.util.Function; +import com.intellij.util.PairConsumer; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -28,12 +27,11 @@ import javax.swing.*; */ public class ExecutionModes { private static final Logger LOG = Logger.getInstance(ExecutionMode.class); - private static final Function, Void> DEFAULT_TIMEOUT_CALLBACK = new Function, Void>() { + private static final PairConsumer DEFAULT_TIMEOUT_CALLBACK = new PairConsumer() { @Override - public Void fun(Pair pair) { - final String msg = "Timeout (" + pair.getFirst().getTimeout() + " sec) on executing: " + pair.getSecond(); + public void consume(ExecutionMode mode, String presentableCmdLine) { + final String msg = "Timeout (" + mode.getTimeout() + " sec) on executing: " + presentableCmdLine; LOG.error(msg); - return null; } }; @@ -75,7 +73,7 @@ public class ExecutionModes { public static class SameThreadMode extends ExecutionMode { private final int myTimeout; @NotNull - private final Function, Void> myTimeoutCallback; + private final PairConsumer myTimeoutCallback; public SameThreadMode(final boolean cancelable, @Nullable final String title2, @@ -86,7 +84,7 @@ public class ExecutionModes { public SameThreadMode(final boolean cancelable, @Nullable final String title2, final int timeout, - @NotNull final Function, Void> timeoutCallback + @NotNull final PairConsumer timeoutCallback ) { super(cancelable, null, title2, false, false, null); myTimeout = timeout; @@ -122,7 +120,7 @@ public class ExecutionModes { @NotNull @Override - public Function, Void> getTimeoutCallback() { + public PairConsumer getTimeoutCallback() { return myTimeoutCallback; } } From 26c77e7f1e02578670ac0259b668d0f4a4f08c24 Mon Sep 17 00:00:00 2001 From: Oleg Sukhodolsky Date: Tue, 15 Sep 2015 16:13:06 +0300 Subject: [PATCH 10/11] EA-56820: Let's use PairConsumer instead of Function> --- .../lang-impl/src/com/intellij/execution/ExecutionHelper.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/lang-impl/src/com/intellij/execution/ExecutionHelper.java b/platform/lang-impl/src/com/intellij/execution/ExecutionHelper.java index 2bf8c1eb39d5..0b780726de42 100644 --- a/platform/lang-impl/src/com/intellij/execution/ExecutionHelper.java +++ b/platform/lang-impl/src/com/intellij/execution/ExecutionHelper.java @@ -494,7 +494,7 @@ public class ExecutionHelper { try { final boolean finished = processHandler.waitFor(1000 * mode.getTimeout()); if (!finished) { - mode.getTimeoutCallback().fun(Pair.create(mode, presentableCmdline)); + mode.getTimeoutCallback().consume(mode, presentableCmdline); processHandler.destroyProcess(); } } From 90787aa4623fa881c996dfa54d05be70406a570c Mon Sep 17 00:00:00 2001 From: Oleg Sukhodolsky Date: Tue, 15 Sep 2015 16:13:51 +0300 Subject: [PATCH 11/11] EA-56820: code cleanup --- .../lang-impl/src/com/intellij/execution/ExecutionHelper.java | 1 - 1 file changed, 1 deletion(-) diff --git a/platform/lang-impl/src/com/intellij/execution/ExecutionHelper.java b/platform/lang-impl/src/com/intellij/execution/ExecutionHelper.java index 0b780726de42..e27d72707d75 100644 --- a/platform/lang-impl/src/com/intellij/execution/ExecutionHelper.java +++ b/platform/lang-impl/src/com/intellij/execution/ExecutionHelper.java @@ -35,7 +35,6 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.ui.popup.PopupChooserBuilder; import com.intellij.openapi.util.Disposer; -import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.wm.ToolWindow;