diff --git a/.idea/modules.xml b/.idea/modules.xml index 5a29a2a547ff..7d37961600ad 100644 --- a/.idea/modules.xml +++ b/.idea/modules.xml @@ -64,6 +64,7 @@ + diff --git a/java/compiler/impl/testSrc/com/intellij/compiler/BaseCompilerTestCase.java b/java/compiler/impl/testSrc/com/intellij/compiler/BaseCompilerTestCase.java index 0351ca66c6ab..bc63355134a6 100644 --- a/java/compiler/impl/testSrc/com/intellij/compiler/BaseCompilerTestCase.java +++ b/java/compiler/impl/testSrc/com/intellij/compiler/BaseCompilerTestCase.java @@ -90,15 +90,18 @@ public abstract class BaseCompilerTestCase extends ModuleTestCase { @Override protected void tearDown() throws Exception { - for (Artifact artifact : getArtifactManager().getArtifacts()) { - final String outputPath = artifact.getOutputPath(); - if (!StringUtil.isEmpty(outputPath)) { - FileUtil.delete(new File(FileUtil.toSystemDependentName(outputPath))); + try { + for (Artifact artifact : getArtifactManager().getArtifacts()) { + final String outputPath = artifact.getOutputPath(); + if (!StringUtil.isEmpty(outputPath)) { + FileUtil.delete(new File(FileUtil.toSystemDependentName(outputPath))); + } } + CompilerTestUtil.disableExternalCompiler(getProject()); + } + finally { + super.tearDown(); } - CompilerTestUtil.disableExternalCompiler(getProject()); - - super.tearDown(); } protected ArtifactManager getArtifactManager() { diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/ForceEarlyReturnAction.java b/java/debugger/impl/src/com/intellij/debugger/actions/ForceEarlyReturnAction.java new file mode 100644 index 000000000000..8c37fda39f52 --- /dev/null +++ b/java/debugger/impl/src/com/intellij/debugger/actions/ForceEarlyReturnAction.java @@ -0,0 +1,252 @@ +/* + * 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.actions; + +import com.intellij.debugger.DebuggerBundle; +import com.intellij.debugger.engine.DebugProcessImpl; +import com.intellij.debugger.engine.JavaStackFrame; +import com.intellij.debugger.engine.JavaValue; +import com.intellij.debugger.engine.evaluation.EvaluateException; +import com.intellij.debugger.engine.events.DebuggerCommandImpl; +import com.intellij.debugger.engine.events.DebuggerContextCommandImpl; +import com.intellij.debugger.impl.DebuggerContextImpl; +import com.intellij.debugger.jdi.StackFrameProxyImpl; +import com.intellij.debugger.jdi.ThreadReferenceProxyImpl; +import com.intellij.idea.ActionsBundle; +import com.intellij.openapi.actionSystem.ActionPlaces; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ModalityState; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.DialogWrapper; +import com.intellij.openapi.ui.Messages; +import com.intellij.util.ui.UIUtil; +import com.intellij.xdebugger.XDebuggerBundle; +import com.intellij.xdebugger.XExpression; +import com.intellij.xdebugger.evaluation.XDebuggerEditorsProvider; +import com.intellij.xdebugger.evaluation.XDebuggerEvaluator; +import com.intellij.xdebugger.frame.XValue; +import com.intellij.xdebugger.impl.breakpoints.XExpressionImpl; +import com.intellij.xdebugger.impl.ui.XDebuggerExpressionEditor; +import com.sun.jdi.Method; +import com.sun.jdi.Value; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; + +public class ForceEarlyReturnAction extends DebuggerAction { + public void actionPerformed(@NotNull AnActionEvent e) { + final Project project = e.getProject(); + final JavaStackFrame stackFrame = PopFrameAction.getStackFrame(e); + if (stackFrame == null || project == null) { + return; + } + final DebuggerContextImpl debuggerContext = DebuggerAction.getDebuggerContext(e.getDataContext()); + final DebugProcessImpl debugProcess = debuggerContext.getDebugProcess(); + if (debugProcess == null) { + return; + } + + final StackFrameProxyImpl proxy = stackFrame.getStackFrameProxy(); + final ThreadReferenceProxyImpl thread = proxy.threadProxy(); + + debugProcess.getManagerThread().schedule(new DebuggerContextCommandImpl(debuggerContext, thread) { + @Override + public void threadAction() { + Method method; + try { + method = proxy.location().method(); + } + catch (EvaluateException e) { + showError(project, DebuggerBundle.message("error.early.return", e.getLocalizedMessage())); + return; + } + + if ("void".equals(method.returnTypeName())) { + forceEarlyReturnWithFinally(thread.getVirtualMachine().mirrorOfVoid(), stackFrame, debugProcess, null); + } + else { + //noinspection SSBasedInspection + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + new ReturnExpressionDialog(project, debugProcess.getXdebugProcess().getEditorsProvider(), debugProcess, stackFrame).show(); + } + }); + } + } + }); + } + + private static void forceEarlyReturnWithFinally(final Value value, + final JavaStackFrame frame, + final DebugProcessImpl debugProcess, + @Nullable final DialogWrapper dialog) { + //noinspection SSBasedInspection + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + if (PopFrameAction.evaluateFinallyBlocks(debugProcess.getProject(), + UIUtil.removeMnemonic(ActionsBundle.actionText("Debugger.ForceEarlyReturn")), + frame, + new XDebuggerEvaluator.XEvaluationCallback() { + @Override + public void evaluated(@NotNull XValue result) { + forceEarlyReturn(value, frame.getDescriptor().getFrameProxy().threadProxy(), debugProcess, dialog); + } + + @Override + public void errorOccurred(@NotNull String errorMessage) { + showError(debugProcess.getProject(), + DebuggerBundle.message("error.executing.finally", errorMessage)); + } + })) { + return; + } + forceEarlyReturn(value, frame.getDescriptor().getFrameProxy().threadProxy(), debugProcess, dialog); + } + }); + } + + private static void forceEarlyReturn(final Value value, + final ThreadReferenceProxyImpl thread, + final DebugProcessImpl debugProcess, + @Nullable final DialogWrapper dialog) { + debugProcess.getManagerThread().schedule(new DebuggerCommandImpl() { + @Override + protected void action() throws Exception { + try { + thread.forceEarlyReturn(value); + } + catch (Exception e) { + showError(debugProcess.getProject(), DebuggerBundle.message("error.early.return", e.getLocalizedMessage())); + return; + } + //noinspection SSBasedInspection + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + if (dialog != null) { + dialog.close(DialogWrapper.OK_EXIT_CODE); + } + debugProcess.getSession().stepInto(true, null); + } + }); + } + }); + } + + private static void evaluateAndReturn(final Project project, + final JavaStackFrame stackFrame, + final DebugProcessImpl debugProcess, + XExpression expression, + final DialogWrapper dialog) { + XDebuggerEvaluator evaluator = stackFrame.getEvaluator(); + if (evaluator != null) { + evaluator.evaluate(expression, + new XDebuggerEvaluator.XEvaluationCallback() { + @Override + public void evaluated(@NotNull XValue result) { + if (result instanceof JavaValue) { + forceEarlyReturnWithFinally(((JavaValue)result).getDescriptor().getValue(), + stackFrame, + debugProcess, + dialog); + } + } + + @Override + public void errorOccurred(@NotNull final String errorMessage) { + showError(project, DebuggerBundle.message("error.unable.to.evaluate.expression") + ": " + errorMessage); + } + }, stackFrame.getSourcePosition()); + } + else { + showError(project, XDebuggerBundle.message("xdebugger.evaluate.stack.frame.has.not.evaluator")); + } + } + + private static void showError(final Project project, final String message) { + ApplicationManager.getApplication().invokeLater(new Runnable() { + @Override + public void run() { + Messages.showMessageDialog(project, + message, + UIUtil.removeMnemonic(ActionsBundle.actionText("Debugger.ForceEarlyReturn")), + Messages.getErrorIcon()); + } + }, ModalityState.any()); + } + + public void update(@NotNull AnActionEvent e) { + boolean enable = false; + + JavaStackFrame stackFrame = PopFrameAction.getStackFrame(e); + if (stackFrame != null && stackFrame.getDescriptor().getUiIndex() == 0) { + enable = stackFrame.getStackFrameProxy().getVirtualMachine().canForceEarlyReturn(); + } + + if (ActionPlaces.isMainMenuOrActionSearch(e.getPlace()) || ActionPlaces.DEBUGGER_TOOLBAR.equals(e.getPlace())) { + e.getPresentation().setEnabled(enable); + } + else { + e.getPresentation().setVisible(enable); + } + } + + private static class ReturnExpressionDialog extends DialogWrapper { + private final Project myProject; + private final XDebuggerEditorsProvider myEditorsProvider; + private final DebugProcessImpl myProcess; + private final JavaStackFrame myFrame; + private final XDebuggerExpressionEditor myEditor; + + public ReturnExpressionDialog(@NotNull Project project, + XDebuggerEditorsProvider provider, + DebugProcessImpl process, + JavaStackFrame frame) { + super(project); + myProject = project; + myEditorsProvider = provider; + myProcess = process; + myFrame = frame; + myEditor = new XDebuggerExpressionEditor(myProject, myEditorsProvider, "forceReturnValue", myFrame.getSourcePosition(), + XExpressionImpl.EMPTY_EXPRESSION, false); + + setTitle("Return Value"); + init(); + } + + @Nullable + @Override + protected JComponent createCenterPanel() { + return myEditor.getComponent(); + } + + @Nullable + @Override + public JComponent getPreferredFocusedComponent() { + return myEditor.getPreferredFocusedComponent(); + } + + @Override + protected void doOKAction() { + evaluateAndReturn(myProject, myFrame, myProcess, myEditor.getExpression(), this); + } + } +} diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/PopFrameAction.java b/java/debugger/impl/src/com/intellij/debugger/actions/PopFrameAction.java index 5b4048129cba..8e1dc5075727 100644 --- a/java/debugger/impl/src/com/intellij/debugger/actions/PopFrameAction.java +++ b/java/debugger/impl/src/com/intellij/debugger/actions/PopFrameAction.java @@ -70,7 +70,7 @@ public class PopFrameAction extends DebuggerAction { public void actionPerformed(@NotNull AnActionEvent e) { final Project project = e.getData(CommonDataKeys.PROJECT); final JavaStackFrame stackFrame = getStackFrame(e); - if(stackFrame == null) { + if (stackFrame == null || stackFrame.getStackFrameProxy().isBottom()) { return; } try { @@ -81,76 +81,29 @@ public class PopFrameAction extends DebuggerAction { } debugProcess.getSession().setSteppingThrough(stackFrame.getStackFrameProxy().threadProxy()); - if (!DebuggerSettings.EVALUATE_FINALLY_NEVER.equals(DebuggerSettings.getInstance().EVALUATE_FINALLY_ON_POP_FRAME)) { - List statements = getFinallyStatements(debuggerContext.getSourcePosition()); - if (!statements.isEmpty()) { - StringBuilder sb = new StringBuilder(); - for (PsiStatement statement : statements) { - sb.append("\n").append(statement.getText()); - } - if (DebuggerSettings.EVALUATE_FINALLY_ALWAYS.equals(DebuggerSettings.getInstance().EVALUATE_FINALLY_ON_POP_FRAME)) { - evaluateAndPop(project, stackFrame, debuggerContext, debugProcess, sb); - return; - } - else { - int res = MessageDialogBuilder - .yesNoCancel(UIUtil.removeMnemonic(ActionsBundle.actionText(DebuggerActions.POP_FRAME)), - DebuggerBundle.message("warning.finally.block.detected") + sb) - .project(project) - .icon(Messages.getWarningIcon()) - .yesText(DebuggerBundle.message("button.execute.finally")) - .noText(DebuggerBundle.message("button.drop.anyway")) - .cancelText(CommonBundle.message("button.cancel")) - .doNotAsk( - new DialogWrapper.DoNotAskOption() { - @Override - public boolean isToBeShown() { - return !DebuggerSettings.EVALUATE_FINALLY_ALWAYS.equals(DebuggerSettings.getInstance().EVALUATE_FINALLY_ON_POP_FRAME) && - !DebuggerSettings.EVALUATE_FINALLY_NEVER.equals(DebuggerSettings.getInstance().EVALUATE_FINALLY_ON_POP_FRAME); - } + if (evaluateFinallyBlocks(project, + UIUtil.removeMnemonic(ActionsBundle.actionText(DebuggerActions.POP_FRAME)), + stackFrame, + new XDebuggerEvaluator.XEvaluationCallback() { + @Override + public void evaluated(@NotNull XValue result) { + popFrame(debugProcess, debuggerContext, stackFrame); + } - @Override - public void setToBeShown(boolean value, int exitCode) { - if (!value) { - DebuggerSettings.getInstance().EVALUATE_FINALLY_ON_POP_FRAME = - exitCode == Messages.YES ? DebuggerSettings.EVALUATE_FINALLY_ALWAYS : DebuggerSettings.EVALUATE_FINALLY_NEVER; - } - else { - DebuggerSettings.getInstance().EVALUATE_FINALLY_ON_POP_FRAME = DebuggerSettings.EVALUATE_FINALLY_ASK; - } - } - - @Override - public boolean canBeHidden() { - return true; - } - - @Override - public boolean shouldSaveOptionsOnCancel() { - return false; - } - - @NotNull - @Override - public String getDoNotShowMessage() { - return CommonBundle.message("dialog.options.do.not.show"); - } - }) - .show(); - - switch (res) { - case Messages.CANCEL: - return; - case Messages.NO: - break; - case Messages.YES: // evaluate finally - evaluateAndPop(project, stackFrame, debuggerContext, debugProcess, sb); - return; - } - } - } - } - debugProcess.getManagerThread().schedule(debugProcess.createPopFrameCommand(debuggerContext, stackFrame.getStackFrameProxy())); + @Override + public void errorOccurred(@NotNull final String errorMessage) { + ApplicationManager.getApplication().invokeLater(new Runnable() { + @Override + public void run() { + Messages + .showMessageDialog(project, DebuggerBundle.message("error.executing.finally", errorMessage), + UIUtil.removeMnemonic(ActionsBundle.actionText(DebuggerActions.POP_FRAME)), + Messages.getErrorIcon()); + } + }); + } + })) return; + popFrame(debugProcess, debuggerContext, stackFrame); } catch (NativeMethodException e2){ Messages.showMessageDialog(project, DebuggerBundle.message("error.native.method.exception"), @@ -162,33 +115,96 @@ public class PopFrameAction extends DebuggerAction { } } - private static void evaluateAndPop(final Project project, - final JavaStackFrame stackFrame, - final DebuggerContextImpl debuggerContext, - final DebugProcessImpl debugProcess, StringBuilder sb) { + static boolean evaluateFinallyBlocks(Project project, + String title, + JavaStackFrame stackFrame, + XDebuggerEvaluator.XEvaluationCallback callback) { + if (!DebuggerSettings.EVALUATE_FINALLY_NEVER.equals(DebuggerSettings.getInstance().EVALUATE_FINALLY_ON_POP_FRAME)) { + List statements = getFinallyStatements(stackFrame.getDescriptor().getSourcePosition()); + if (!statements.isEmpty()) { + StringBuilder sb = new StringBuilder(); + for (PsiStatement statement : statements) { + sb.append("\n").append(statement.getText()); + } + if (DebuggerSettings.EVALUATE_FINALLY_ALWAYS.equals(DebuggerSettings.getInstance().EVALUATE_FINALLY_ON_POP_FRAME)) { + evaluateAndAct(project, stackFrame, sb, callback); + return true; + } + else { + int res = MessageDialogBuilder + .yesNoCancel(title, + DebuggerBundle.message("warning.finally.block.detected") + sb) + .project(project) + .icon(Messages.getWarningIcon()) + .yesText(DebuggerBundle.message("button.execute.finally")) + .noText(DebuggerBundle.message("button.drop.anyway")) + .cancelText(CommonBundle.message("button.cancel")) + .doNotAsk( + new DialogWrapper.DoNotAskOption() { + @Override + public boolean isToBeShown() { + return !DebuggerSettings.EVALUATE_FINALLY_ALWAYS.equals(DebuggerSettings.getInstance().EVALUATE_FINALLY_ON_POP_FRAME) && + !DebuggerSettings.EVALUATE_FINALLY_NEVER.equals(DebuggerSettings.getInstance().EVALUATE_FINALLY_ON_POP_FRAME); + } + + @Override + public void setToBeShown(boolean value, int exitCode) { + if (!value) { + DebuggerSettings.getInstance().EVALUATE_FINALLY_ON_POP_FRAME = + exitCode == Messages.YES ? DebuggerSettings.EVALUATE_FINALLY_ALWAYS : DebuggerSettings.EVALUATE_FINALLY_NEVER; + } + else { + DebuggerSettings.getInstance().EVALUATE_FINALLY_ON_POP_FRAME = DebuggerSettings.EVALUATE_FINALLY_ASK; + } + } + + @Override + public boolean canBeHidden() { + return true; + } + + @Override + public boolean shouldSaveOptionsOnCancel() { + return false; + } + + @NotNull + @Override + public String getDoNotShowMessage() { + return CommonBundle.message("dialog.options.do.not.show"); + } + }) + .show(); + + switch (res) { + case Messages.CANCEL: + return true; + case Messages.NO: + break; + case Messages.YES: // evaluate finally + evaluateAndAct(project, stackFrame, sb, callback); + return true; + } + } + } + } + return false; + } + + private static void popFrame(DebugProcessImpl debugProcess, DebuggerContextImpl debuggerContext, JavaStackFrame stackFrame) { + debugProcess.getManagerThread() + .schedule(debugProcess.createPopFrameCommand(debuggerContext, stackFrame.getStackFrameProxy())); + } + + private static void evaluateAndAct(Project project, + JavaStackFrame stackFrame, + StringBuilder sb, + XDebuggerEvaluator.XEvaluationCallback callback) { XDebuggerEvaluator evaluator = stackFrame.getEvaluator(); if (evaluator != null) { evaluator.evaluate(XExpressionImpl.fromText(sb.toString(), EvaluationMode.CODE_FRAGMENT), - new XDebuggerEvaluator.XEvaluationCallback() { - @Override - public void evaluated(@NotNull XValue result) { - debugProcess.getManagerThread() - .schedule(debugProcess.createPopFrameCommand(debuggerContext, stackFrame.getStackFrameProxy())); - } - - @Override - public void errorOccurred(@NotNull final String errorMessage) { - ApplicationManager.getApplication().invokeLater(new Runnable() { - @Override - public void run() { - Messages - .showMessageDialog(project, DebuggerBundle.message("error.executing.finally", errorMessage), - UIUtil.removeMnemonic(ActionsBundle.actionText(DebuggerActions.POP_FRAME)), - Messages.getErrorIcon()); - } - }); - } - }, stackFrame.getSourcePosition()); + callback, + stackFrame.getSourcePosition()); } else { Messages.showMessageDialog(project, XDebuggerBundle.message("xdebugger.evaluate.stack.frame.has.not.evaluator"), @@ -214,21 +230,12 @@ public class PopFrameAction extends DebuggerAction { return res; } - private static JavaStackFrame getStackFrame(AnActionEvent e) { + static JavaStackFrame getStackFrame(AnActionEvent e) { StackFrameDescriptorImpl descriptor = getSelectedStackFrameDescriptor(e); if (descriptor != null) { - if (descriptor.getFrameProxy().isBottom()) { - return null; - } return new JavaStackFrame(descriptor, false); } - JavaStackFrame frame = getSelectedStackFrame(e); - if (frame != null) { - StackFrameProxyImpl proxy = frame.getStackFrameProxy(); - if (proxy == null || proxy.isBottom()) return null; - return frame; - } - return null; + return getSelectedStackFrame(e); } static StackFrameProxyImpl getStackFrameProxy(AnActionEvent e) { 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 b4cfc1680d26..3a8c2b6bac48 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/JavaStackFrame.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/JavaStackFrame.java @@ -397,6 +397,7 @@ public class JavaStackFrame extends XStackFrame { } } + @NotNull public StackFrameProxyImpl getStackFrameProxy() { return myDescriptor.getFrameProxy(); } diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/BlockStatementEvaluator.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/BlockStatementEvaluator.java index 57b1a44bb3c5..8956138882d9 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/BlockStatementEvaluator.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/BlockStatementEvaluator.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * 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. @@ -30,7 +30,7 @@ public class BlockStatementEvaluator implements Evaluator { @Override public Object evaluate(EvaluationContextImpl context) throws EvaluateException { - Object result = context.getSuspendContext().getDebugProcess().getVirtualMachineProxy().mirrorOf(); + Object result = context.getSuspendContext().getDebugProcess().getVirtualMachineProxy().mirrorOfVoid(); for (Evaluator statement : myStatements) { result = statement.evaluate(context); } diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/DoWhileStatementEvaluator.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/DoWhileStatementEvaluator.java index 1e48568a8dd8..c7de16e59362 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/DoWhileStatementEvaluator.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/DoWhileStatementEvaluator.java @@ -37,7 +37,7 @@ public class DoWhileStatementEvaluator extends LoopEvaluator { } public Object evaluate(EvaluationContextImpl context) throws EvaluateException { - Object value = context.getDebugProcess().getVirtualMachineProxy().mirrorOf(); + Object value = context.getDebugProcess().getVirtualMachineProxy().mirrorOfVoid(); while (true) { if (body(context)) break; diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/ForStatementEvaluatorBase.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/ForStatementEvaluatorBase.java index 1064d0747b2b..4a7eee833d38 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/ForStatementEvaluatorBase.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/ForStatementEvaluatorBase.java @@ -29,7 +29,7 @@ public abstract class ForStatementEvaluatorBase extends LoopEvaluator { } public Object evaluate(EvaluationContextImpl context) throws EvaluateException { - Object value = context.getDebugProcess().getVirtualMachineProxy().mirrorOf(); + Object value = context.getDebugProcess().getVirtualMachineProxy().mirrorOfVoid(); value = evaluateInitialization(context, value); while (true) { diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/IfStatementEvaluator.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/IfStatementEvaluator.java index a48e960008ee..31c3aab00d42 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/IfStatementEvaluator.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/IfStatementEvaluator.java @@ -54,7 +54,7 @@ public class IfStatementEvaluator implements Evaluator { value = myElseEvaluator.evaluate(context); myModifier = myElseEvaluator.getModifier(); } else { - value = context.getDebugProcess().getVirtualMachineProxy().mirrorOf(); + value = context.getDebugProcess().getVirtualMachineProxy().mirrorOfVoid(); myModifier = null; } } diff --git a/java/debugger/impl/src/com/intellij/debugger/jdi/JdiProxy.java b/java/debugger/impl/src/com/intellij/debugger/jdi/JdiProxy.java index ab8a3ce5ec26..1552cdeae648 100644 --- a/java/debugger/impl/src/com/intellij/debugger/jdi/JdiProxy.java +++ b/java/debugger/impl/src/com/intellij/debugger/jdi/JdiProxy.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * 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. @@ -15,6 +15,8 @@ */ package com.intellij.debugger.jdi; +import org.jetbrains.annotations.NotNull; + /** * Created by IntelliJ IDEA. * User: lex @@ -23,10 +25,10 @@ package com.intellij.debugger.jdi; * To change this template use Options | File Templates. */ public abstract class JdiProxy { - protected JdiTimer myTimer; + @NotNull protected JdiTimer myTimer; private int myTimeStamp = 0; - public JdiProxy(JdiTimer timer) { + public JdiProxy(@NotNull JdiTimer timer) { myTimer = timer; myTimeStamp = myTimer.getCurrentTime(); } diff --git a/java/debugger/impl/src/com/intellij/debugger/jdi/StackFrameProxyImpl.java b/java/debugger/impl/src/com/intellij/debugger/jdi/StackFrameProxyImpl.java index e24067f711d3..957ada3482a2 100644 --- a/java/debugger/impl/src/com/intellij/debugger/jdi/StackFrameProxyImpl.java +++ b/java/debugger/impl/src/com/intellij/debugger/jdi/StackFrameProxyImpl.java @@ -25,6 +25,7 @@ import com.intellij.debugger.engine.evaluation.EvaluateException; import com.intellij.debugger.engine.evaluation.EvaluateExceptionUtil; import com.intellij.debugger.engine.jdi.StackFrameProxy; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.util.ThreeState; import com.sun.jdi.*; import gnu.trove.THashMap; import org.jetbrains.annotations.NonNls; @@ -46,10 +47,10 @@ public class StackFrameProxyImpl extends JdiProxy implements StackFrameProxy { private StackFrame myStackFrame; private ObjectReference myThisReference; private ClassLoaderReference myClassLoader; - private Boolean myIsObsolete = null; + private ThreeState myIsObsolete = ThreeState.UNSURE; private Map myAllValues; - public StackFrameProxyImpl(ThreadReferenceProxyImpl threadProxy, @NotNull StackFrame frame, int fromBottomIndex /* 1-based */) { + public StackFrameProxyImpl(@NotNull ThreadReferenceProxyImpl threadProxy, @NotNull StackFrame frame, int fromBottomIndex /* 1-based */) { super(threadProxy.getVirtualMachine()); myThreadProxy = threadProxy; myFrameFromBottomIndex = fromBottomIndex; @@ -59,14 +60,14 @@ public class StackFrameProxyImpl extends JdiProxy implements StackFrameProxy { public boolean isObsolete() throws EvaluateException { DebuggerManagerThreadImpl.assertIsManagerThread(); checkValid(); - if (myIsObsolete != null) { - return myIsObsolete.booleanValue(); + if (myIsObsolete != ThreeState.UNSURE) { + return myIsObsolete.toBoolean(); } InvalidStackFrameException error = null; for (int attempt = 0; attempt < 2; attempt++) { try { boolean isObsolete = (getVirtualMachine().canRedefineClasses() && location().method().isObsolete()); - myIsObsolete = isObsolete? Boolean.TRUE : Boolean.FALSE; + myIsObsolete = ThreeState.fromBoolean(isObsolete); return isObsolete; } catch (InvalidStackFrameException e) { @@ -75,7 +76,7 @@ public class StackFrameProxyImpl extends JdiProxy implements StackFrameProxy { } catch (InternalException e) { if (e.errorCode() == 23 /*INVALID_METHODID according to JDI sources*/) { - myIsObsolete = Boolean.TRUE; + myIsObsolete = ThreeState.YES; return true; } throw e; @@ -108,7 +109,7 @@ public class StackFrameProxyImpl extends JdiProxy implements StackFrameProxy { } myFrameIndex = -1; myStackFrame = null; - myIsObsolete = null; + myIsObsolete = ThreeState.UNSURE; myThisReference = null; myClassLoader = null; myAllValues = null; @@ -171,6 +172,7 @@ public class StackFrameProxyImpl extends JdiProxy implements StackFrameProxy { // return false; // } + @NotNull @Override public VirtualMachineProxyImpl getVirtualMachine() { return (VirtualMachineProxyImpl) myTimer; diff --git a/java/debugger/impl/src/com/intellij/debugger/jdi/ThreadReferenceProxyImpl.java b/java/debugger/impl/src/com/intellij/debugger/jdi/ThreadReferenceProxyImpl.java index 7b8b1d1f9df0..1f53846f3ce3 100644 --- a/java/debugger/impl/src/com/intellij/debugger/jdi/ThreadReferenceProxyImpl.java +++ b/java/debugger/impl/src/com/intellij/debugger/jdi/ThreadReferenceProxyImpl.java @@ -65,6 +65,7 @@ public final class ThreadReferenceProxyImpl extends ObjectReferenceProxyImpl imp return (ThreadReference)getObjectReference(); } + @NotNull @Override public VirtualMachineProxyImpl getVirtualMachine() { DebuggerManagerThreadImpl.assertIsManagerThread(); @@ -309,6 +310,17 @@ public final class ThreadReferenceProxyImpl extends ObjectReferenceProxyImpl imp } } + public void forceEarlyReturn(Value value) throws ClassNotLoadedException, IncompatibleThreadStateException, InvalidTypeException { + DebuggerManagerThreadImpl.assertIsManagerThread(); + try { + getThreadReference().forceEarlyReturn(value); + } + finally { + clearCaches(); + getVirtualMachineProxy().clearCaches(); + } + } + public boolean isSuspended() throws ObjectCollectedException { try { DebuggerManagerThreadImpl.assertIsManagerThread(); diff --git a/java/debugger/impl/src/com/intellij/debugger/jdi/VirtualMachineProxyImpl.java b/java/debugger/impl/src/com/intellij/debugger/jdi/VirtualMachineProxyImpl.java index c2211fe1c648..57fadf168a81 100644 --- a/java/debugger/impl/src/com/intellij/debugger/jdi/VirtualMachineProxyImpl.java +++ b/java/debugger/impl/src/com/intellij/debugger/jdi/VirtualMachineProxyImpl.java @@ -88,6 +88,7 @@ public class VirtualMachineProxyImpl implements JdiTimer, VirtualMachineProxy { } } + @NotNull public VirtualMachine getVirtualMachine() { return myVirtualMachine; } @@ -278,7 +279,15 @@ public class VirtualMachineProxyImpl implements JdiTimer, VirtualMachineProxy { return myVirtualMachine.eventRequestManager(); } + /** + * @deprecated use {@link #mirrorOfVoid()} instead + */ + @Deprecated public VoidValue mirrorOf() throws EvaluateException { + return mirrorOfVoid(); + } + + public VoidValue mirrorOfVoid() { return myVirtualMachine.mirrorOfVoid(); } @@ -461,6 +470,15 @@ public class VirtualMachineProxyImpl implements JdiTimer, VirtualMachineProxy { return myPopFrames.isAvailable(); } + private final Capability myForceEarlyReturn = new Capability() { + protected boolean calcValue() { + return myVirtualMachine.canForceEarlyReturn(); + } + }; + public boolean canForceEarlyReturn() { + return myForceEarlyReturn.isAvailable(); + } + private final Capability myCanGetInstanceInfo = new Capability() { protected boolean calcValue() { if (!myVersionHigher_15) { diff --git a/java/execution/impl/src/com/intellij/execution/impl/JavaScratchRunConfigurationExtension.java b/java/execution/impl/src/com/intellij/execution/impl/JavaScratchRunConfigurationExtension.java index d8c1a40a14bb..f0a17365a9b5 100644 --- a/java/execution/impl/src/com/intellij/execution/impl/JavaScratchRunConfigurationExtension.java +++ b/java/execution/impl/src/com/intellij/execution/impl/JavaScratchRunConfigurationExtension.java @@ -43,13 +43,6 @@ import org.jetbrains.annotations.Nullable; import java.io.File; - -/* -execution-impl -> lang-impl(scratches are here) -compiler-impl -> lang-impl - -java-impl ->execution-impl, compiler-impl - */ public class JavaScratchRunConfigurationExtension extends RunConfigurationExtension{ private static final Key SCRATCH_FILE_ID = Key.create("_scratch_file_id_"); diff --git a/java/idea-ui/src/com/intellij/util/descriptors/impl/ConfigFileContainerImpl.java b/java/idea-ui/src/com/intellij/util/descriptors/impl/ConfigFileContainerImpl.java index a236694c6c4f..fa799ed3dbf8 100644 --- a/java/idea-ui/src/com/intellij/util/descriptors/impl/ConfigFileContainerImpl.java +++ b/java/idea-ui/src/com/intellij/util/descriptors/impl/ConfigFileContainerImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * 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. @@ -23,14 +23,13 @@ import com.intellij.openapi.util.MultiValuesMap; import com.intellij.openapi.util.SimpleModificationTracker; import com.intellij.openapi.vfs.*; import com.intellij.util.EventDispatcher; +import com.intellij.util.containers.ContainerUtil; import com.intellij.util.descriptors.*; +import gnu.trove.THashSet; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.Collection; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; +import java.util.*; /** * @author nik @@ -77,11 +76,7 @@ public class ConfigFileContainerImpl extends SimpleModificationTracker implement @Override @Nullable public ConfigFile getConfigFile(ConfigFileMetaData metaData) { - final Collection descriptors = myConfigFiles.get(metaData); - if (descriptors == null || descriptors.isEmpty()) { - return null; - } - return descriptors.iterator().next(); + return ContainerUtil.getFirstItem(myConfigFiles.get(metaData)); } @Override @@ -132,9 +127,9 @@ public class ConfigFileContainerImpl extends SimpleModificationTracker implement return myMetaDataProvider; } - public void updateDescriptors(final MultiValuesMap descriptorsMap) { - Set toDelete = new HashSet(myConfigFiles.values()); - Set added = new HashSet(); + public void updateDescriptors(@NotNull MultiValuesMap descriptorsMap) { + Set toDelete = myConfigFiles.isEmpty() ? Collections.emptySet() : new HashSet(myConfigFiles.values()); + Set added = null; for (Map.Entry> entry : descriptorsMap.entrySet()) { ConfigFileMetaData metaData = entry.getKey(); @@ -142,8 +137,7 @@ public class ConfigFileContainerImpl extends SimpleModificationTracker implement final Collection oldDescriptors = myConfigFiles.get(metaData); if (oldDescriptors != null) { for (ConfigFile descriptor : oldDescriptors) { - if (newDescriptors.contains(descriptor.getInfo())) { - newDescriptors.remove(descriptor.getInfo()); + if (newDescriptors.remove(descriptor.getInfo())) { toDelete.remove(descriptor); } } @@ -152,6 +146,9 @@ public class ConfigFileContainerImpl extends SimpleModificationTracker implement final ConfigFileImpl configFile = new ConfigFileImpl(this, configuration); Disposer.register(this, configFile); myConfigFiles.put(metaData, configFile); + if (added == null) { + added = new THashSet(); + } added.add(configFile); } } @@ -162,9 +159,11 @@ public class ConfigFileContainerImpl extends SimpleModificationTracker implement } myCachedConfigFiles = null; - for (ConfigFile configFile : added) { - incModificationCount(); - myDispatcher.getMulticaster().configFileAdded(configFile); + if (added != null) { + for (ConfigFile configFile : added) { + incModificationCount(); + myDispatcher.getMulticaster().configFileAdded(configFile); + } } for (ConfigFile configFile : toDelete) { incModificationCount(); diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java index 738e467c520a..2559f4e9f3a5 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java @@ -19,11 +19,11 @@ import com.intellij.codeInsight.AnnotationUtil; import com.intellij.codeInspection.dataFlow.instructions.*; import com.intellij.codeInspection.dataFlow.value.*; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.registry.Registry; import com.intellij.psi.*; import com.intellij.psi.search.GlobalSearchScope; -import com.intellij.psi.templateLanguages.OuterLanguageElement; import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.*; import com.intellij.util.IncorrectOperationException; @@ -42,18 +42,20 @@ import static com.intellij.psi.CommonClassNames.*; public class ControlFlowAnalyzer extends JavaElementVisitor { private static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.dataFlow.ControlFlowAnalyzer"); public static final String ORG_JETBRAINS_ANNOTATIONS_CONTRACT = Contract.class.getName(); + private final PsiElement myCodeFragment; private boolean myIgnoreAssertions; + private final Project myProject; private static class CannotAnalyzeException extends RuntimeException { } private final DfaValueFactory myFactory; private ControlFlow myCurrentFlow; private Stack myCatchStack; - private DfaValue myRuntimeException; - private DfaValue myError; - private DfaValue myString; - private PsiType myNpe; - private PsiType myAssertionError; + private final DfaValue myRuntimeException; + private final DfaValue myError; + private final DfaValue myString; + private final PsiType myNpe; + private final PsiType myAssertionError; private final Stack myElementStack = new Stack(); /** @@ -61,50 +63,45 @@ public class ControlFlowAnalyzer extends JavaElementVisitor { */ private FactoryMap myExceptionHolders; - ControlFlowAnalyzer(final DfaValueFactory valueFactory) { + ControlFlowAnalyzer(final DfaValueFactory valueFactory, @NotNull PsiElement codeFragment, boolean ignoreAssertions) { myFactory = valueFactory; - } - - @Nullable - public ControlFlow buildControlFlow(@NotNull PsiElement codeFragment, boolean ignoreAssertions) { - if (PsiTreeUtil.findChildOfType(codeFragment, OuterLanguageElement.class) != null) { - return null; - } - + myCodeFragment = codeFragment; + myProject = codeFragment.getProject(); myIgnoreAssertions = ignoreAssertions; - final PsiManager manager = codeFragment.getManager(); GlobalSearchScope scope = codeFragment.getResolveScope(); - myRuntimeException = myFactory.createTypeValue(createClassType(manager, scope, JAVA_LANG_RUNTIME_EXCEPTION), Nullness.NOT_NULL); - myError = myFactory.createTypeValue(createClassType(manager, scope, JAVA_LANG_ERROR), Nullness.NOT_NULL); - myNpe = createClassType(manager, scope, JAVA_LANG_NULL_POINTER_EXCEPTION); - myAssertionError = createClassType(manager, scope, JAVA_LANG_ASSERTION_ERROR); - myString = myFactory.createTypeValue(createClassType(manager, scope, JAVA_LANG_STRING), Nullness.NOT_NULL); + myRuntimeException = myFactory.createTypeValue(createClassType(scope, JAVA_LANG_RUNTIME_EXCEPTION), Nullness.NOT_NULL); + myError = myFactory.createTypeValue(createClassType(scope, JAVA_LANG_ERROR), Nullness.NOT_NULL); + myNpe = createClassType(scope, JAVA_LANG_NULL_POINTER_EXCEPTION); + myAssertionError = createClassType(scope, JAVA_LANG_ASSERTION_ERROR); + myString = myFactory.createTypeValue(createClassType(scope, JAVA_LANG_STRING), Nullness.NOT_NULL); myExceptionHolders = new FactoryMap() { @Nullable @Override protected DfaVariableValue create(PsiTryStatement key) { String text = "java.lang.Object $exception" + myExceptionHolders.size() + "$"; - PsiParameter mockVar = JavaPsiFacade.getElementFactory(manager.getProject()).createParameterFromText(text, null); + PsiParameter mockVar = JavaPsiFacade.getElementFactory(myProject).createParameterFromText(text, null); return myFactory.getVarFactory().createVariableValue(mockVar, false); } }; + } + @Nullable + public ControlFlow buildControlFlow() { myCatchStack = new Stack(); myCurrentFlow = new ControlFlow(myFactory); - try { - codeFragment.accept(this); + myCodeFragment.accept(this); } catch (CannotAnalyzeException e) { return null; } - PsiElement parent = codeFragment.getParent(); - if (parent instanceof PsiLambdaExpression && codeFragment instanceof PsiExpression) { - generateBoxingUnboxingInstructionFor((PsiExpression)codeFragment, + PsiElement parent = myCodeFragment.getParent(); + if (parent instanceof PsiLambdaExpression && myCodeFragment instanceof PsiExpression) { + generateBoxingUnboxingInstructionFor((PsiExpression)myCodeFragment, LambdaUtil.getFunctionalInterfaceReturnType((PsiLambdaExpression)parent)); - addInstruction(new CheckReturnValueInstruction(codeFragment)); + addInstruction(new CheckReturnValueInstruction(myCodeFragment)); } addInstruction(new ReturnInstruction(false, null)); @@ -117,10 +114,10 @@ public class ControlFlowAnalyzer extends JavaElementVisitor { } - private static PsiClassType createClassType(PsiManager manager, GlobalSearchScope scope, String fqn) { - PsiClass aClass = JavaPsiFacade.getInstance(manager.getProject()).findClass(fqn, scope); - if (aClass != null) return JavaPsiFacade.getElementFactory(manager.getProject()).createType(aClass); - return JavaPsiFacade.getElementFactory(manager.getProject()).createTypeByFQClassName(fqn, scope); + private PsiClassType createClassType(GlobalSearchScope scope, String fqn) { + PsiClass aClass = JavaPsiFacade.getInstance(myProject).findClass(fqn, scope); + if (aClass != null) return JavaPsiFacade.getElementFactory(myProject).createType(aClass); + return JavaPsiFacade.getElementFactory(myProject).createTypeByFQClassName(fqn, scope); } private T addInstruction(T i) { @@ -204,7 +201,7 @@ public class ControlFlowAnalyzer extends JavaElementVisitor { lExpr.accept(this); addInstruction(new DupInstruction()); rExpr.accept(this); - addInstruction(new BinopInstruction(JavaTokenType.PLUS, null, lExpr.getProject())); + addInstruction(new BinopInstruction(JavaTokenType.PLUS, null, myProject)); } else { generateDefaultAssignmentBinOp(lExpr, rExpr, type); @@ -234,7 +231,7 @@ public class ControlFlowAnalyzer extends JavaElementVisitor { generateBoxingUnboxingInstructionFor(lExpr,exprType); rExpr.accept(this); generateBoxingUnboxingInstructionFor(rExpr, exprType); - addInstruction(new BinopInstruction(null, null, lExpr.getProject())); + addInstruction(new BinopInstruction(null, null, myProject)); } @Override public void visitAssertStatement(PsiAssertStatement statement) { @@ -672,7 +669,7 @@ public class ControlFlowAnalyzer extends JavaElementVisitor { addInstruction(new PushInstruction(myFactory.createValue(caseExpression), caseExpression)); caseValue.accept(this); - addInstruction(new BinopInstruction(JavaTokenType.EQEQ, null, caseExpression.getProject())); + addInstruction(new BinopInstruction(JavaTokenType.EQEQ, null, myProject)); } else { pushUnknown(); @@ -750,7 +747,7 @@ public class ControlFlowAnalyzer extends JavaElementVisitor { addConditionalRuntimeThrow(); addInstruction(new DupInstruction()); addInstruction(new PushInstruction(myFactory.getConstFactory().getNull(), null)); - addInstruction(new BinopInstruction(JavaTokenType.EQEQ, null, statement.getProject())); + addInstruction(new BinopInstruction(JavaTokenType.EQEQ, null, myProject)); ConditionalGotoInstruction gotoInstruction = new ConditionalGotoInstruction(null, true, null); addInstruction(gotoInstruction); @@ -972,7 +969,7 @@ public class ControlFlowAnalyzer extends JavaElementVisitor { //if $exception$==null => continue normal execution addInstruction(new PushInstruction(getExceptionHolder(finallyDescriptor), null)); addInstruction(new PushInstruction(myFactory.getConstFactory().getNull(), null)); - addInstruction(new BinopInstruction(JavaTokenType.EQEQ, null, statement.getProject())); + addInstruction(new BinopInstruction(JavaTokenType.EQEQ, null, myProject)); addInstruction(new ConditionalGotoInstruction(getEndOffset(statement), false, null)); // else throw $exception$ @@ -999,7 +996,7 @@ public class ControlFlowAnalyzer extends JavaElementVisitor { for (PsiType catchType : flattened) { addInstruction(new PushInstruction(exceptionHolder, null)); addInstruction(new PushInstruction(myFactory.createTypeValue(catchType, Nullness.UNKNOWN), null)); - addInstruction(new BinopInstruction(JavaTokenType.INSTANCEOF_KEYWORD, null, section.getProject())); + addInstruction(new BinopInstruction(JavaTokenType.INSTANCEOF_KEYWORD, null, myProject)); addInstruction(new ConditionalGotoInstruction(ControlFlow.deltaOffset(getStartOffset(catchBlock), -5), false, null)); } @@ -1179,7 +1176,7 @@ public class ControlFlowAnalyzer extends JavaElementVisitor { PsiType rType = rExpr.getType(); acceptBinaryRightOperand(op, type, lExpr, lType, rExpr, rType); - addInstruction(new BinopInstruction(op, expression.isPhysical() ? expression : null, expression.getProject())); + addInstruction(new BinopInstruction(op, expression.isPhysical() ? expression : null, myProject)); lExpr = rExpr; lType = rType; @@ -1256,7 +1253,7 @@ public class ControlFlowAnalyzer extends JavaElementVisitor { operand.accept(this); generateBoxingUnboxingInstructionFor(operand, exprType); PsiElement psiAnchor = i == operands.length - 1 && expression.isPhysical() ? expression : null; - addInstruction(new BinopInstruction(JavaTokenType.NE, psiAnchor, expression.getProject())); + addInstruction(new BinopInstruction(JavaTokenType.NE, psiAnchor, myProject)); } } @@ -1399,7 +1396,7 @@ public class ControlFlowAnalyzer extends JavaElementVisitor { type = ((PsiClassType)type).rawType(); } addInstruction(new PushInstruction(myFactory.createTypeValue(type, Nullness.UNKNOWN), null)); - addInstruction(new InstanceofInstruction(expression, expression.getProject(), operand, type)); + addInstruction(new InstanceofInstruction(expression, myProject, operand, type)); } else { pushUnknown(); @@ -1481,7 +1478,7 @@ public class ControlFlowAnalyzer extends JavaElementVisitor { // if a contract resulted in 'fail', handle it addInstruction(new DupInstruction()); addInstruction(new PushInstruction(myFactory.getConstFactory().getContractFail(), null)); - addInstruction(new BinopInstruction(JavaTokenType.EQEQ, null, expression.getProject())); + addInstruction(new BinopInstruction(JavaTokenType.EQEQ, null, myProject)); ConditionalGotoInstruction ifNotFail = new ConditionalGotoInstruction(null, true, null); addInstruction(ifNotFail); returnCheckingFinally(true, expression); diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DataFlowRunner.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DataFlowRunner.java index a88985f0fb09..1adc7fa781d2 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DataFlowRunner.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DataFlowRunner.java @@ -34,6 +34,7 @@ import com.intellij.openapi.util.Key; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.registry.Registry; import com.intellij.psi.*; +import com.intellij.psi.templateLanguages.OuterLanguageElement; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.util.Processor; @@ -87,21 +88,23 @@ public class DataFlowRunner { } } - return Arrays.asList(createMemoryState()); + return Collections.singletonList(createMemoryState()); } public final RunnerResult analyzeMethod(@NotNull PsiElement psiBlock, InstructionVisitor visitor) { Collection initialStates = createInitialStates(psiBlock, visitor); return initialStates == null ? RunnerResult.NOT_APPLICABLE : analyzeMethod(psiBlock, visitor, false, initialStates); } - + + @NotNull public final RunnerResult analyzeMethod(@NotNull PsiElement psiBlock, InstructionVisitor visitor, boolean ignoreAssertions, @NotNull Collection initialStates) { + if (PsiTreeUtil.findChildOfType(psiBlock, OuterLanguageElement.class) != null) return RunnerResult.NOT_APPLICABLE; + try { - ControlFlowAnalyzer analyzer = createControlFlowAnalyzer(); - final ControlFlow flow = analyzer.buildControlFlow(psiBlock, ignoreAssertions); + final ControlFlow flow = new ControlFlowAnalyzer(myValueFactory, psiBlock, ignoreAssertions).buildControlFlow(); if (flow == null) return RunnerResult.NOT_APPLICABLE; int[] loopNumber = LoopAnalyzer.calcInLoop(flow); @@ -309,10 +312,6 @@ public class DataFlowRunner { } } - protected ControlFlowAnalyzer createControlFlowAnalyzer() { - return new ControlFlowAnalyzer(myValueFactory); - } - protected DfaMemoryState createMemoryState() { return new DfaMemoryStateImpl(myValueFactory); } diff --git a/java/java-analysis-impl/src/com/intellij/psi/impl/FindSuperElementsHelper.java b/java/java-analysis-impl/src/com/intellij/psi/impl/FindSuperElementsHelper.java index 7d5bfda6dfec..8a468bd71614 100644 --- a/java/java-analysis-impl/src/com/intellij/psi/impl/FindSuperElementsHelper.java +++ b/java/java-analysis-impl/src/com/intellij/psi/impl/FindSuperElementsHelper.java @@ -15,6 +15,7 @@ */ package com.intellij.psi.impl; +import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.Ref; import com.intellij.psi.*; @@ -84,11 +85,14 @@ public class FindSuperElementsHelper { ClassInheritorsSearch.search(containingClass, containingClass.getUseScope(), true, true, false).forEach(new Processor() { @Override public boolean process(PsiClass inheritor) { + ProgressManager.checkCanceled(); for (PsiClassType interfaceType : inheritor.getImplementsListTypes()) { + ProgressManager.checkCanceled(); PsiClassType.ClassResolveResult resolved = interfaceType.resolveGenerics(); PsiClass anInterface = resolved.getElement(); if (anInterface == null || !checkedInterfaces.add(PsiAnchor.create(anInterface))) continue; for (PsiMethod superMethod : anInterface.findMethodsByName(method.getName(), true)) { + ProgressManager.checkCanceled(); PsiClass superInterface = superMethod.getContainingClass(); if (superInterface == null) { continue; diff --git a/java/java-impl/src/com/intellij/psi/impl/smartPointers/ImplicitVariableElementInfoFactory.java b/java/java-impl/src/com/intellij/psi/impl/smartPointers/ImplicitVariableElementInfoFactory.java index 29da83455ee1..a52f6b467f75 100644 --- a/java/java-impl/src/com/intellij/psi/impl/smartPointers/ImplicitVariableElementInfoFactory.java +++ b/java/java-impl/src/com/intellij/psi/impl/smartPointers/ImplicitVariableElementInfoFactory.java @@ -19,16 +19,17 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Segment; import com.intellij.psi.ImplicitVariable; import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; import com.intellij.psi.PsiIdentifier; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -public class ImplicitVariableElementInfoFactory implements SmartPointerElementInfoFactory { +public class ImplicitVariableElementInfoFactory extends SmartPointerElementInfoFactory { @Override @Nullable - public SmartPointerElementInfo createElementInfo(@NotNull final PsiElement element) { - if (element instanceof ImplicitVariable && element.isValid()) { - return new ImplicitVariableInfo((ImplicitVariable) element, element.getProject()); + public SmartPointerElementInfo createElementInfo(@NotNull final PsiElement element, @NotNull PsiFile containingFile) { + if (element instanceof ImplicitVariable) { + return new ImplicitVariableInfo((ImplicitVariable) element, containingFile.getProject()); } return null; } diff --git a/java/java-impl/src/com/intellij/psi/impl/smartPointers/ImportListElementInfoFactory.java b/java/java-impl/src/com/intellij/psi/impl/smartPointers/ImportListElementInfoFactory.java index b2c76903ae03..2677ec64de8a 100644 --- a/java/java-impl/src/com/intellij/psi/impl/smartPointers/ImportListElementInfoFactory.java +++ b/java/java-impl/src/com/intellij/psi/impl/smartPointers/ImportListElementInfoFactory.java @@ -16,17 +16,18 @@ package com.intellij.psi.impl.smartPointers; import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; import com.intellij.psi.PsiImportList; import com.intellij.psi.PsiJavaFile; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -public class ImportListElementInfoFactory implements SmartPointerElementInfoFactory { +public class ImportListElementInfoFactory extends SmartPointerElementInfoFactory { @Override @Nullable - public SmartPointerElementInfo createElementInfo(@NotNull final PsiElement element) { + public SmartPointerElementInfo createElementInfo(@NotNull final PsiElement element, @NotNull PsiFile containingFile) { if (element instanceof PsiImportList) { - return new ImportListInfo((PsiJavaFile)element.getContainingFile()); + return new ImportListInfo((PsiJavaFile)containingFile); } return null; } diff --git a/java/java-indexing-impl/src/com/intellij/psi/impl/file/impl/JavaOutOfSourcesResolveScopeProvider.java b/java/java-indexing-impl/src/com/intellij/psi/impl/file/impl/JavaOutOfSourcesResolveScopeProvider.java new file mode 100644 index 000000000000..a3e9e87f3a4c --- /dev/null +++ b/java/java-indexing-impl/src/com/intellij/psi/impl/file/impl/JavaOutOfSourcesResolveScopeProvider.java @@ -0,0 +1,49 @@ +/* + * 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.psi.impl.file.impl; + +import com.intellij.lang.java.JavaLanguage; +import com.intellij.openapi.fileTypes.FileType; +import com.intellij.openapi.fileTypes.LanguageFileType; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.ProjectFileIndex; +import com.intellij.openapi.roots.ProjectRootManager; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.ResolveScopeProvider; +import com.intellij.psi.search.GlobalSearchScope; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * Limited resolve scope for all java files in module content, but not under source roots. + * For example, java files from test data. + * There is still a possibility to modify this scope choice with the ResolveScopeEnlarger. + */ +public class JavaOutOfSourcesResolveScopeProvider extends ResolveScopeProvider { + @Nullable + @Override + public GlobalSearchScope getResolveScope(@NotNull VirtualFile file, Project project) { + // For java only! For other languages resolve may be implemented with different rules, requiring larger scope. + final FileType type = file.getFileType(); + if (type instanceof LanguageFileType && ((LanguageFileType)type).getLanguage() == JavaLanguage.INSTANCE) { + ProjectFileIndex index = ProjectRootManager.getInstance(project).getFileIndex(); + if (index.isInContent(file) && !index.isInSource(file)) { + return GlobalSearchScope.fileScope(project, file); + } + } + return null; + } +} diff --git a/java/java-indexing-impl/src/com/intellij/psi/impl/search/JavaClassInheritorsSearcher.java b/java/java-indexing-impl/src/com/intellij/psi/impl/search/JavaClassInheritorsSearcher.java index 7846f74651e2..b6f1d08b2111 100644 --- a/java/java-indexing-impl/src/com/intellij/psi/impl/search/JavaClassInheritorsSearcher.java +++ b/java/java-indexing-impl/src/com/intellij/psi/impl/search/JavaClassInheritorsSearcher.java @@ -21,6 +21,7 @@ import com.intellij.openapi.application.ReadActionProcessor; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressIndicatorProvider; +import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.Ref; @@ -81,7 +82,7 @@ public class JavaClassInheritorsSearcher extends QueryExecutorBase() { @Override public boolean process(final PsiClass aClass) { - ProgressIndicatorProvider.checkCanceled(); + ProgressManager.checkCanceled(); return isJavaLangObject(aClass) || consumer.process(aClass); } }); @@ -95,7 +96,7 @@ public class JavaClassInheritorsSearcher extends QueryExecutorBase processor = new ReadActionProcessor() { @Override public boolean processInReadAction(PsiClass candidate) { - ProgressIndicatorProvider.checkCanceled(); + ProgressManager.checkCanceled(); if (parameters.isCheckInheritance() || parameters.isCheckDeep() && !(candidate instanceof PsiAnonymousClass)) { if (!candidate.isInheritor(currentBase.get(), false)) { @@ -130,7 +131,7 @@ public class JavaClassInheritorsSearcher extends QueryExecutorBase() { @Override public boolean process(final PsiClass psiClass) { + ProgressManager.checkCanceled(); if (psiClass.isInterface()) { return consumer.process(psiClass); } @@ -113,7 +114,7 @@ public class JavaDirectInheritorsSearcher implements QueryExecutor> classes = new HashMap>(); for (final PsiReferenceList referenceList : candidates) { - ProgressIndicatorProvider.checkCanceled(); + ProgressManager.checkCanceled(); final PsiClass candidate = (PsiClass)ApplicationManager.getApplication().runReadAction(new Computable() { @Override public PsiElement compute() { @@ -139,6 +140,7 @@ public class JavaDirectInheritorsSearcher implements QueryExecutor sameNamedClasses : classes.values()) { + ProgressManager.checkCanceled(); if (!processSameNamedClasses(consumer, sameNamedClasses, jarFile)) return false; } } @@ -155,7 +157,7 @@ public class JavaDirectInheritorsSearcher implements QueryExecutor() { @@ -210,6 +213,7 @@ public class JavaDirectInheritorsSearcher implements QueryExecutor 1) { for (PsiClass sameNamedClass : sameNamedClasses) { + ProgressManager.checkCanceled(); boolean fromSameJar = Comparing.equal(getJarFile(sameNamedClass), jarFile); if (fromSameJar) { sameJarClassFound = true; diff --git a/java/java-indexing-impl/src/com/intellij/psi/impl/search/MethodUsagesSearcher.java b/java/java-indexing-impl/src/com/intellij/psi/impl/search/MethodUsagesSearcher.java index 8ab27b1b4286..0bc09d7b52f7 100644 --- a/java/java-indexing-impl/src/com/intellij/psi/impl/search/MethodUsagesSearcher.java +++ b/java/java-indexing-impl/src/com/intellij/psi/impl/search/MethodUsagesSearcher.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * 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. @@ -119,7 +119,7 @@ public class MethodUsagesSearcher extends QueryExecutorBase T resolveInReadAction(@NotNull Project p, Computable computable) { + static T resolveInReadAction(@NotNull Project p, @NotNull Computable computable) { return ApplicationManager.getApplication().isReadAccessAllowed() ? computable.compute() : DumbService.getInstance(p).runReadActionInSmartMode(computable); } diff --git a/java/java-psi-api/src/com/intellij/psi/PsiPrimitiveType.java b/java/java-psi-api/src/com/intellij/psi/PsiPrimitiveType.java index ad6bd78e6165..6a3d5c98ab40 100644 --- a/java/java-psi-api/src/com/intellij/psi/PsiPrimitiveType.java +++ b/java/java-psi-api/src/com/intellij/psi/PsiPrimitiveType.java @@ -151,7 +151,7 @@ public class PsiPrimitiveType extends PsiType.Stub { //[ven]previous call returns null for NULL, VOID if (boxedQName == null) return null; JavaPsiFacade facade = JavaPsiFacade.getInstance(file.getProject()); - PsiClass aClass = facade.findClass(boxedQName, context.getResolveScope()); + PsiClass aClass = facade.findClass(boxedQName, file.getResolveScope()); if (aClass == null) return null; PsiElementFactory factory = facade.getElementFactory(); diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/JavaConstantExpressionEvaluator.java b/java/java-psi-impl/src/com/intellij/psi/impl/JavaConstantExpressionEvaluator.java index 1dfb3b57532e..73b72a0943b0 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/JavaConstantExpressionEvaluator.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/JavaConstantExpressionEvaluator.java @@ -117,6 +117,10 @@ public class JavaConstantExpressionEvaluator extends JavaRecursiveElementWalking final PsiConstantEvaluationHelper.AuxEvaluator auxEvaluator) { if (expression == null) return null; + if (expression instanceof PsiLiteralExpression) { + return ((PsiLiteralExpression)expression).getValue(); // don't bother with caching etc + } + JavaConstantExpressionEvaluator evaluator = new JavaConstantExpressionEvaluator(visitedVars, throwExceptionOnOverflow, expression.getProject(), auxEvaluator); if (expression instanceof PsiCompiledElement) { diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiJavaFileImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiJavaFileImpl.java index e56f53cbfbdf..97b43b4db570 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiJavaFileImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiJavaFileImpl.java @@ -16,14 +16,9 @@ package com.intellij.psi.impl.source; import com.intellij.ide.highlighter.JavaFileType; -import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.fileTypes.FileType; -import com.intellij.openapi.roots.FileIndexFacade; -import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.FileViewProvider; import com.intellij.psi.impl.java.stubs.JavaStubElementTypes; -import com.intellij.psi.search.GlobalSearchScope; -import com.intellij.testFramework.LightVirtualFile; import org.jetbrains.annotations.NotNull; public class PsiJavaFileImpl extends PsiJavaFileBaseImpl { @@ -31,19 +26,6 @@ public class PsiJavaFileImpl extends PsiJavaFileBaseImpl { super(JavaStubElementTypes.JAVA_FILE, JavaStubElementTypes.JAVA_FILE, file); } - @NotNull - @Override - public GlobalSearchScope getResolveScope() { - final VirtualFile file = getVirtualFile(); - if (file != null && !(file instanceof LightVirtualFile)) { - final FileIndexFacade index = ServiceManager.getService(getProject(), FileIndexFacade.class); - if (!index.isInSource(file) && !index.isInLibraryClasses(file)) { - return GlobalSearchScope.fileScope(this); - } - } - return super.getResolveScope(); - } - @Override @NotNull public FileType getFileType() { diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/SymbolCollectingProcessor.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/SymbolCollectingProcessor.java index 8a1f32ce83f4..642cbe6fcd79 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/SymbolCollectingProcessor.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/SymbolCollectingProcessor.java @@ -26,6 +26,7 @@ import com.intellij.psi.scope.JavaScopeProcessorEvent; import com.intellij.psi.scope.PsiScopeProcessor; import com.intellij.util.containers.MostlySingularMultiMap; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; /** * @author max @@ -33,6 +34,7 @@ import org.jetbrains.annotations.NotNull; public class SymbolCollectingProcessor extends BaseScopeProcessor implements ElementClassHint { private final MostlySingularMultiMap myResult = new MostlySingularMultiMap(); private PsiElement myCurrentFileContext = null; + private PsiAnchor myCurrentContextAnchor = null; @Override public T getHint(@NotNull Key hintKey) { @@ -47,6 +49,7 @@ public class SymbolCollectingProcessor extends BaseScopeProcessor implements Ele public void handleEvent(@NotNull PsiScopeProcessor.Event event, Object associated) { if (event == JavaScopeProcessorEvent.SET_CURRENT_FILE_CONTEXT) { myCurrentFileContext = (PsiElement)associated; + myCurrentContextAnchor = null; } } @@ -56,7 +59,11 @@ public class SymbolCollectingProcessor extends BaseScopeProcessor implements Ele PsiNamedElement named = (PsiNamedElement)element; String name = named.getName(); if (name != null) { - myResult.add(name, new ResultWithContext(named, myCurrentFileContext)); + PsiAnchor context = myCurrentContextAnchor; + if (context == null && myCurrentFileContext != null) { + myCurrentContextAnchor = context = PsiAnchor.create(myCurrentFileContext); + } + myResult.add(name, new ResultWithContext(named, context)); } } return true; @@ -75,9 +82,9 @@ public class SymbolCollectingProcessor extends BaseScopeProcessor implements Ele private final PsiAnchor myElement; private final PsiAnchor myFileContext; - public ResultWithContext(@NotNull PsiNamedElement element, PsiElement fileContext) { + public ResultWithContext(@NotNull PsiNamedElement element, @Nullable PsiAnchor fileContext) { myElement = PsiAnchor.create(element); - myFileContext = fileContext == null ? null : PsiAnchor.create(fileContext); + myFileContext = fileContext; } @NotNull diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/VariableResolverProcessor.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/VariableResolverProcessor.java index 123e750e0a1a..0630b125125a 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/VariableResolverProcessor.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/VariableResolverProcessor.java @@ -42,12 +42,8 @@ public class VariableResolverProcessor extends ConflictFilterProcessor implement private PsiElement myCurrentFileContext = null; public VariableResolverProcessor(@NotNull PsiJavaCodeReferenceElement place, @NotNull PsiFile placeFile) { - super(place.getText(), ourFilter, new PsiConflictResolver[]{new JavaVariableConflictResolver()}, new SmartList(), place, placeFile); + super(place.getReferenceName(), ourFilter, new PsiConflictResolver[]{new JavaVariableConflictResolver()}, new SmartList(), place, placeFile); - PsiElement referenceName = place.getReferenceNameElement(); - if (referenceName instanceof PsiIdentifier){ - setName(referenceName.getText()); - } PsiClass access = null; PsiElement qualifier = place.getQualifier(); if (qualifier instanceof PsiExpression) { @@ -108,6 +104,7 @@ public class VariableResolverProcessor extends ConflictFilterProcessor implement @Override public T getHint(@NotNull Key hintKey) { if (hintKey == ElementClassHint.KEY) { + //noinspection unchecked return (T)this; } diff --git a/java/java-tests/testData/inspection/unusedLibrary/simple/expected.xml b/java/java-tests/testData/inspection/unusedLibrary/simple/expected.xml index 8184735d55cf..9cd23b0df42b 100644 --- a/java/java-tests/testData/inspection/unusedLibrary/simple/expected.xml +++ b/java/java-tests/testData/inspection/unusedLibrary/simple/expected.xml @@ -1,7 +1,7 @@ - testSimple_0.iml + testSimple.iml Unused library Unused library 'JUnit' diff --git a/java/java-tests/testSrc/com/intellij/execution/ConfigurationsTest.java b/java/java-tests/testSrc/com/intellij/execution/ConfigurationsTest.java index 1aecb65638f9..39d4f6380f0f 100644 --- a/java/java-tests/testSrc/com/intellij/execution/ConfigurationsTest.java +++ b/java/java-tests/testSrc/com/intellij/execution/ConfigurationsTest.java @@ -1,3 +1,18 @@ +/* + * 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.execution; import com.intellij.execution.application.ApplicationConfigurable; @@ -135,7 +150,7 @@ public class ConfigurationsTest extends BaseConfigurationTestCase { PsiClass testA = findTestA(getModule1()); JUnitConfiguration configuration = createConfiguration(testA); JavaParameters parameters = checkCanRun(configuration); - CHECK.empty(parameters.getVMParametersList().getList()); + assertEmpty(parameters.getVMParametersList().getList()); final SegmentedOutputStream notifications = new SegmentedOutputStream(System.out); assertTrue(JUnitStarter.checkVersion(parameters.getProgramParametersList().getArray(), new PrintStream(notifications))); diff --git a/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterMultilineMethodCallParamsTest.java b/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterMultilineMethodCallParamsTest.java index d80b29c25191..1596c605d986 100644 --- a/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterMultilineMethodCallParamsTest.java +++ b/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterMultilineMethodCallParamsTest.java @@ -29,7 +29,7 @@ public class JavaFormatterMultilineMethodCallParamsTest extends AbstractJavaForm ); } - public void IGNORED_testChainedMethodInsideCall_WithRParenOnNewLine() { + public void testChainedMethodInsideCall_WithRParenOnNewLine() { doMethodTest( "call(new StringBuilder()\n" + ".append(\"aaa\")\n" + @@ -41,6 +41,31 @@ public class JavaFormatterMultilineMethodCallParamsTest extends AbstractJavaForm ");" ); } + + public void testLambdas() { + doTextTest( + "public class Main {\n" + + " public static void main(String... args) throws Exception {\n" + + " RatpackServer.start(server -> server\n" + + " .handlers(chain -> chain\n" + + " .get(ctx -> ctx.render(\"Hello World!\"))\n" + + " .get(\":name\", ctx -> ctx.render(\"Hello \" + ctx.getPathTokens().get(\"name\") + \"!\"))\n" + + " )\n" + + " );\n" + + " }\n" + + "}", + "public class Main {\n" + + " public static void main(String... args) throws Exception {\n" + + " RatpackServer.start(server -> server\n" + + " .handlers(chain -> chain\n" + + " .get(ctx -> ctx.render(\"Hello World!\"))\n" + + " .get(\":name\", ctx -> ctx.render(\"Hello \" + ctx.getPathTokens().get(\"name\") + \"!\"))\n" + + " )\n" + + " );\n" + + " }\n" + + "}" + ); + } public void testChainedMethodInsideCall_Shifted() { doMethodTest( diff --git a/java/java-tests/testSrc/com/intellij/refactoring/MultipleJdksMoveClassTest.java b/java/java-tests/testSrc/com/intellij/refactoring/MultipleJdksMoveClassTest.java index e88d816cd7b2..b2e9b9e190a8 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/MultipleJdksMoveClassTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/MultipleJdksMoveClassTest.java @@ -16,36 +16,23 @@ package com.intellij.refactoring; -import com.intellij.JavaTestUtil; import com.intellij.openapi.application.ex.PathManagerEx; -import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.module.Module; -import com.intellij.openapi.module.ModuleUtil; -import com.intellij.openapi.roots.ModifiableRootModel; import com.intellij.openapi.roots.ModuleRootModificationUtil; -import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VfsUtilCore; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.pom.java.LanguageLevel; -import com.intellij.psi.*; -import com.intellij.psi.impl.source.PostprocessReformattingAspect; -import com.intellij.psi.search.GlobalSearchScope; -import com.intellij.refactoring.move.moveClassesOrPackages.MoveClassesOrPackagesProcessor; -import com.intellij.refactoring.move.moveClassesOrPackages.SingleSourceRootMoveDestination; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; import com.intellij.refactoring.util.RefactoringConflictsUtil; -import com.intellij.testFramework.*; +import com.intellij.testFramework.IdeaTestUtil; +import com.intellij.testFramework.UsefulTestCase; import com.intellij.testFramework.builders.JavaModuleFixtureBuilder; import com.intellij.testFramework.fixtures.*; import com.intellij.usageView.UsageInfo; -import com.intellij.util.Consumer; import com.intellij.util.containers.MultiMap; -import org.jetbrains.annotations.NonNls; -import java.io.File; import java.util.Collections; -public class MultipleJdksMoveClassTest extends RefactoringTestCase { - +public class MultipleJdksMoveClassTest extends UsefulTestCase { private CodeInsightTestFixture myFixture; private Module myJava7Module; private Module myJava8Module; diff --git a/java/java-tests/testSrc/com/intellij/roots/RootsChangedTest.java b/java/java-tests/testSrc/com/intellij/roots/RootsChangedTest.java index cddb960084d4..9cf5c67a3b05 100644 --- a/java/java-tests/testSrc/com/intellij/roots/RootsChangedTest.java +++ b/java/java-tests/testSrc/com/intellij/roots/RootsChangedTest.java @@ -127,9 +127,7 @@ public class RootsChangedTest extends ModuleTestCase { public void testEditLibraryForModuleLoadFromXml() throws IOException { final File tempDirectory = createTempDirectory(); ApplicationManager.getApplication().runWriteAction(() -> { - File moduleFile = - PathManagerEx.findFileUnderProjectHome("java/java-tests/testData/moduleRootManager/rootsChanged/emptyModule/a.iml", RootsChangedTest.this.getClass()); - Module a = loadModule(moduleFile, true); + Module a = loadModule(PathManagerEx.getHomePath(getClass()) + "/java/java-tests/testData/moduleRootManager/rootsChanged/emptyModule/a.iml"); assertEventsCount(1); final Sdk jdk = IdeaTestUtil.getMockJdk17(); diff --git a/java/testFramework/src/com/intellij/compiler/CompilerTestUtil.java b/java/testFramework/src/com/intellij/compiler/CompilerTestUtil.java index 60c06b99de2c..5b4f69d6a4ab 100644 --- a/java/testFramework/src/com/intellij/compiler/CompilerTestUtil.java +++ b/java/testFramework/src/com/intellij/compiler/CompilerTestUtil.java @@ -16,8 +16,8 @@ package com.intellij.compiler; import com.intellij.compiler.server.BuildManager; +import com.intellij.openapi.application.AccessToken; import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.application.Result; import com.intellij.openapi.application.WriteAction; import com.intellij.openapi.application.ex.ApplicationManagerEx; @@ -31,9 +31,11 @@ import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.projectRoots.impl.JavaAwareProjectJdkTableImpl; import com.intellij.openapi.roots.ModuleRootManager; import com.intellij.openapi.roots.ModuleRootModificationUtil; +import com.intellij.testFramework.EdtTestUtil; +import com.intellij.util.SmartList; +import com.intellij.util.ThrowableRunnable; import org.jetbrains.annotations.NotNull; -import java.util.ArrayList; import java.util.List; /** @@ -55,22 +57,22 @@ public class CompilerTestUtil { } public static void saveApplicationSettings() { - ApplicationManager.getApplication().invokeAndWait(new Runnable() { + EdtTestUtil.runInEdtAndWait(new Runnable() { @Override public void run() { doSaveComponent(ProjectJdkTable.getInstance()); doSaveComponent(FileTypeManager.getInstance()); } - }, ModalityState.any()); + }); } public static void saveApplicationComponent(final Object appComponent) { - ApplicationManager.getApplication().invokeAndWait(new Runnable() { + EdtTestUtil.runInEdtAndWait(new Runnable() { @Override public void run() { doSaveComponent(appComponent); } - }, ModalityState.any()); + }); } private static void doSaveComponent(Object appComponent) { @@ -89,27 +91,36 @@ public class CompilerTestUtil { }.execute(); } - public static void disableExternalCompiler(final Project project) { - ApplicationManagerEx.getApplicationEx().doNotSave(true); - final JavaAwareProjectJdkTableImpl table = JavaAwareProjectJdkTableImpl.getInstanceEx(); - new WriteAction() { - @Override - protected void run(@NotNull final Result result) { - Module[] modules = ModuleManager.getInstance(project).getModules(); - Sdk internalJdk = table.getInternalJdk(); - List modulesToRestore = new ArrayList(); - for (Module module : modules) { - Sdk sdk = ModuleRootManager.getInstance(module).getSdk(); - if (sdk != null && sdk.equals(internalJdk)) { - modulesToRestore.add(module); + public static void disableExternalCompiler(@NotNull final Project project) { + try { + EdtTestUtil.runInEdtAndWait(new ThrowableRunnable() { + @Override + public void run() throws Throwable { + JavaAwareProjectJdkTableImpl table = JavaAwareProjectJdkTableImpl.getInstanceEx(); + AccessToken token = WriteAction.start(); + try { + Sdk internalJdk = table.getInternalJdk(); + List modulesToRestore = new SmartList(); + for (Module module : ModuleManager.getInstance(project).getModules()) { + Sdk sdk = ModuleRootManager.getInstance(module).getSdk(); + if (sdk != null && sdk.equals(internalJdk)) { + modulesToRestore.add(module); + } + } + table.removeJdk(internalJdk); + for (Module module : modulesToRestore) { + ModuleRootModificationUtil.setModuleSdk(module, internalJdk); + } + BuildManager.getInstance().clearState(project); + } + finally { + token.finish(); } } - table.removeJdk(internalJdk); - for (Module module : modulesToRestore) { - ModuleRootModificationUtil.setModuleSdk(module, internalJdk); - } - BuildManager.getInstance().clearState(project); - } - }.execute(); + }); + } + finally { + ApplicationManagerEx.getApplicationEx().doNotSave(true); + } } } diff --git a/java/testFramework/src/com/intellij/debugger/ExecutionWithDebuggerToolsTestCase.java b/java/testFramework/src/com/intellij/debugger/ExecutionWithDebuggerToolsTestCase.java index ade8358e30dd..68426748e81a 100644 --- a/java/testFramework/src/com/intellij/debugger/ExecutionWithDebuggerToolsTestCase.java +++ b/java/testFramework/src/com/intellij/debugger/ExecutionWithDebuggerToolsTestCase.java @@ -39,10 +39,11 @@ import com.intellij.openapi.editor.Document; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiFile; -import com.intellij.testFramework.CompositeException; import com.intellij.ui.classFilter.ClassFilter; import com.intellij.util.IJSwingUtilities; +import com.intellij.util.SmartList; import com.intellij.util.TimeoutUtil; +import com.intellij.util.lang.CompoundRuntimeException; import com.intellij.util.ui.UIUtil; import com.sun.jdi.Method; import com.sun.jdi.ThreadReference; @@ -58,7 +59,7 @@ public abstract class ExecutionWithDebuggerToolsTestCase extends ExecutionTestCa private final SynchronizationBasedSemaphore myScriptRunnablesSema = new SynchronizationBasedSemaphore(); protected static final int RATHER_LATER_INVOKES_N = 10; public DebugProcessImpl myDebugProcess = null; - private final CompositeException myException = new CompositeException(); + private final List myException = new SmartList(); private static class InvokeRatherLaterRequest { private final DebuggerCommandImpl myDebuggerCommand; @@ -112,13 +113,17 @@ public abstract class ExecutionWithDebuggerToolsTestCase extends ExecutionTestCa @Override protected void tearDown() throws Exception { - super.tearDown(); - throwExceptionsIfAny(); + try { + super.tearDown(); + } + finally { + throwExceptionsIfAny(); + } } - protected void throwExceptionsIfAny() throws CompositeException { + protected void throwExceptionsIfAny() { synchronized (myException) { - myException.throwIfNotEmpty(); + CompoundRuntimeException.throwIfNotEmpty(myException); } } diff --git a/java/testFramework/src/com/intellij/execution/ExecutionTestCase.java b/java/testFramework/src/com/intellij/execution/ExecutionTestCase.java index 81a5ffe6fb3e..339e490c7a86 100644 --- a/java/testFramework/src/com/intellij/execution/ExecutionTestCase.java +++ b/java/testFramework/src/com/intellij/execution/ExecutionTestCase.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * 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. @@ -31,13 +31,10 @@ import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.pom.java.LanguageLevel; -import com.intellij.testFramework.CompilerTester; -import com.intellij.testFramework.IdeaTestCase; -import com.intellij.testFramework.IdeaTestUtil; -import com.intellij.testFramework.PsiTestUtil; +import com.intellij.testFramework.*; import com.intellij.util.Alarm; import com.intellij.util.PathUtil; -import com.intellij.util.ui.UIUtil; +import com.intellij.util.ThrowableRunnable; import org.jetbrains.annotations.NonNls; import java.io.File; @@ -70,16 +67,10 @@ public abstract class ExecutionTestCase extends IdeaTestCase { } myModuleOutputDir = new File(ourOutputRoot, PathUtil.getFileName(getTestAppPath())); myChecker = initOutputChecker(); - UIUtil.invokeAndWaitIfNeeded(new Runnable() { + EdtTestUtil.runInEdtAndWait(new ThrowableRunnable() { @Override - public void run() { - try { - ExecutionTestCase.super.setUp(); - } - catch (Throwable e) { - e.printStackTrace(); - assertTrue(false); - } + public void run() throws Throwable { + ExecutionTestCase.super.setUp(); } }); if (!myModuleOutputDir.exists()) { @@ -129,7 +120,7 @@ public abstract class ExecutionTestCase extends IdeaTestCase { } @Override - protected void runBareRunnable(Runnable runnable) throws Throwable { + protected void runBareRunnable(ThrowableRunnable runnable) throws Throwable { runnable.run(); } @@ -144,15 +135,10 @@ public abstract class ExecutionTestCase extends IdeaTestCase { if (myCompilerTester != null) { myCompilerTester.tearDown(); } - UIUtil.invokeAndWaitIfNeeded(new Runnable() { + EdtTestUtil.runInEdtAndWait(new ThrowableRunnable() { @Override - public void run() { - try { - ExecutionTestCase.super.tearDown(); - } - catch (Exception e) { - LOG.error(e); - } + public void run() throws Throwable { + ExecutionTestCase.super.tearDown(); } }); //myChecker.checkValid(getTestProjectJdk()); diff --git a/java/testFramework/src/com/intellij/testFramework/ModuleTestCase.java b/java/testFramework/src/com/intellij/testFramework/ModuleTestCase.java index 2d6859cb83e6..a2139b376f95 100644 --- a/java/testFramework/src/com/intellij/testFramework/ModuleTestCase.java +++ b/java/testFramework/src/com/intellij/testFramework/ModuleTestCase.java @@ -16,17 +16,15 @@ package com.intellij.testFramework; import com.intellij.ide.highlighter.ModuleFileType; +import com.intellij.openapi.application.AccessToken; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.WriteAction; import com.intellij.openapi.command.WriteCommandAction; -import com.intellij.openapi.components.ComponentsPackage; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleManager; import com.intellij.openapi.module.ModuleType; import com.intellij.openapi.module.StdModuleTypes; import com.intellij.openapi.module.impl.ModuleImpl; -import com.intellij.openapi.project.ex.ProjectEx; -import com.intellij.openapi.project.impl.ProjectImpl; -import com.intellij.openapi.roots.ModuleRootManager; import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.io.FileUtil; @@ -34,6 +32,9 @@ import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFileVisitor; +import com.intellij.util.Consumer; +import com.intellij.util.SmartList; +import com.intellij.util.lang.CompoundRuntimeException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -41,7 +42,7 @@ import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; +import java.util.List; public abstract class ModuleTestCase extends IdeaTestCase { protected final Collection myModulesToDispose = new ArrayList(); @@ -55,18 +56,30 @@ public abstract class ModuleTestCase extends IdeaTestCase { @Override protected void tearDown() throws Exception { try { - final ModuleManager moduleManager = ModuleManager.getInstance(myProject); - ApplicationManager.getApplication().runWriteAction(new Runnable() { - @Override - public void run() { - for (Module module : myModulesToDispose) { + ModuleManager moduleManager = ModuleManager.getInstance(myProject); + List errors = null; + AccessToken token = WriteAction.start(); + try { + for (Module module : myModulesToDispose) { + try { String moduleName = module.getName(); if (moduleManager.findModuleByName(moduleName) != null) { moduleManager.disposeModule(module); } } + catch (Throwable e) { + if (errors == null) { + errors = new SmartList(); + } + errors.add(e); + } } - }); + } + finally { + token.finish(); + } + + CompoundRuntimeException.throwIfNotEmpty(errors); } finally { myModulesToDispose.clear(); @@ -97,53 +110,45 @@ public abstract class ModuleTestCase extends IdeaTestCase { return module; } - protected Module loadModule(final File moduleFile) { - return loadModule(moduleFile, false); - } + protected Module loadModule(@NotNull String modulePath) { + String normalizedPath = FileUtil.toSystemIndependentName(modulePath); + LocalFileSystem.getInstance().refreshAndFindFileByPath(normalizedPath); - protected Module loadModule(final File moduleFile, final boolean loadComponentStates) { - Module module = ApplicationManager.getApplication().runWriteAction( - new Computable() { - @Override - public Module compute() { - ProjectImpl project = (ProjectImpl)myProject; - boolean oldOptimiseTestLoadSpeed = project.isOptimiseTestLoadSpeed(); - if (loadComponentStates) { - project.setOptimiseTestLoadSpeed(false); - } - try { - LocalFileSystem.getInstance().refreshIoFiles(Collections.singletonList(moduleFile)); - return ModuleManager.getInstance(myProject).loadModule(moduleFile.getAbsolutePath()); - } - catch (Exception e) { - LOG.error(e); - return null; - } - finally { - project.setOptimiseTestLoadSpeed(oldOptimiseTestLoadSpeed); - } - } - } - ); + ModuleManager moduleManager = ModuleManager.getInstance(myProject); + Module module; + AccessToken token = WriteAction.start(); + try { + module = moduleManager.loadModule(normalizedPath); + } + catch (Exception e) { + LOG.error(e); + return null; + } + finally { + token.finish(); + } myModulesToDispose.add(module); return module; } - protected Module loadModule(final String modulePath) { - return loadModule(new File(modulePath)); + @Nullable + protected Module loadAllModulesUnder(@NotNull VirtualFile rootDir) { + return loadAllModulesUnder(rootDir, null); } @Nullable - protected Module loadAllModulesUnder(@NotNull VirtualFile rootDir) throws Exception { + protected Module loadAllModulesUnder(@NotNull VirtualFile rootDir, @Nullable final Consumer moduleConsumer) { final Ref result = Ref.create(); VfsUtilCore.visitChildrenRecursively(rootDir, new VirtualFileVisitor() { @Override public boolean visitFile(@NotNull VirtualFile file) { if (!file.isDirectory() && file.getName().endsWith(ModuleFileType.DOT_DEFAULT_EXTENSION)) { - ModuleImpl module = (ModuleImpl)loadModule(new File(file.getPath())); - readJdomExternalizables(module); + ModuleImpl module = (ModuleImpl)loadModule(file.getPath()); + if (moduleConsumer != null) { + moduleConsumer.consume(module); + } result.setIfNull(module); } return true; @@ -153,21 +158,6 @@ public abstract class ModuleTestCase extends IdeaTestCase { return result.get(); } - protected void readJdomExternalizables(@NotNull Module module) { - loadModuleComponentState(module, ModuleRootManager.getInstance(module)); - } - - protected final void loadModuleComponentState(@NotNull Module module, @NotNull Object component) { - ProjectEx project = (ProjectEx)myProject; - project.setOptimiseTestLoadSpeed(false); - try { - ComponentsPackage.getStateStore(module).initComponent(component, false); - } - finally { - project.setOptimiseTestLoadSpeed(true); - } - } - protected Module createModuleFromTestData(final String dirInTestData, final String newModuleFileName, final ModuleType moduleType, final boolean addSourceRoot) throws IOException { diff --git a/java/testFramework/src/com/intellij/testFramework/PsiTestCase.java b/java/testFramework/src/com/intellij/testFramework/PsiTestCase.java index d78c00776528..26153fac55c5 100644 --- a/java/testFramework/src/com/intellij/testFramework/PsiTestCase.java +++ b/java/testFramework/src/com/intellij/testFramework/PsiTestCase.java @@ -62,11 +62,15 @@ public abstract class PsiTestCase extends ModuleTestCase { @Override protected void tearDown() throws Exception { - myPsiManager = null; - myFile = null; - myTestDataBefore = null; - myTestDataAfter = null; - super.tearDown(); + try { + myPsiManager = null; + myFile = null; + myTestDataBefore = null; + myTestDataAfter = null; + } + finally { + super.tearDown(); + } } @NotNull diff --git a/java/testFramework/src/com/intellij/testFramework/fixtures/impl/JavaModuleFixtureBuilderImpl.java b/java/testFramework/src/com/intellij/testFramework/fixtures/impl/JavaModuleFixtureBuilderImpl.java index f527677f23e6..9ee51cf765af 100644 --- a/java/testFramework/src/com/intellij/testFramework/fixtures/impl/JavaModuleFixtureBuilderImpl.java +++ b/java/testFramework/src/com/intellij/testFramework/fixtures/impl/JavaModuleFixtureBuilderImpl.java @@ -27,6 +27,7 @@ import com.intellij.openapi.projectRoots.impl.ProjectJdkImpl; import com.intellij.openapi.roots.*; import com.intellij.openapi.roots.libraries.Library; import com.intellij.openapi.roots.libraries.LibraryTable; +import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.JarFileSystem; import com.intellij.openapi.vfs.LocalFileSystem; @@ -39,6 +40,7 @@ import com.intellij.testFramework.fixtures.IdeaProjectTestFixture; import com.intellij.testFramework.fixtures.ModuleFixture; import com.intellij.testFramework.fixtures.TestFixtureBuilder; import com.intellij.util.ArrayUtil; +import com.intellij.util.Consumer; import org.jetbrains.annotations.NonNls; import java.io.File; @@ -116,51 +118,59 @@ abstract class JavaModuleFixtureBuilderImpl extends Mod protected void initModule(final Module module) { super.initModule(module); - final ModifiableRootModel model = ModuleRootManager.getInstance(module).getModifiableModel(); - final LibraryTable libraryTable = model.getModuleLibraryTable(); - - for (Lib lib : myLibraries) { - String libraryName = lib.getName(); - - final Library library = libraryTable.createLibrary(libraryName); - - final Library.ModifiableModel libraryModel = library.getModifiableModel(); - - for (OrderRootType rootType : OrderRootType.getAllTypes()) { - final String[] roots = lib.getRoots(rootType); - for (String root : roots) { - VirtualFile vRoot = LocalFileSystem.getInstance().refreshAndFindFileByPath(root); - if (vRoot != null && OrderRootType.CLASSES.equals(rootType) && !vRoot.isDirectory()) { - final VirtualFile jar = JarFileSystem.getInstance().refreshAndFindFileByPath(root + "!/"); - if (jar != null) vRoot = jar; + ModuleRootModificationUtil.updateModel(module, new Consumer() { + @Override + public void consume(ModifiableRootModel model) { + LibraryTable libraryTable = model.getModuleLibraryTable(); + for (Lib lib : myLibraries) { + Library library = libraryTable.createLibrary(lib.getName()); + Library.ModifiableModel libraryModel = library.getModifiableModel(); + boolean success = false; + try { + for (OrderRootType rootType : OrderRootType.getAllTypes()) { + for (String root : lib.getRoots(rootType)) { + VirtualFile vRoot = LocalFileSystem.getInstance().refreshAndFindFileByPath(root); + if (vRoot != null && OrderRootType.CLASSES.equals(rootType) && !vRoot.isDirectory()) { + VirtualFile jar = JarFileSystem.getInstance().refreshAndFindFileByPath(root + "!/"); + if (jar != null) { + vRoot = jar; + } + } + if (vRoot != null) { + libraryModel.addRoot(vRoot, rootType); + } + } + } + success = true; } - if (vRoot != null) { - libraryModel.addRoot(vRoot, rootType); + finally { + if (!success) { + Disposer.dispose(libraryModel); + } } + + libraryModel.commit(); + } + + final Sdk jdk; + if (myJdk != null) { + VfsRootAccess.allowRootAccessTemporarily(module, myJdk); + jdk = JavaSdk.getInstance().createJdk(module.getName() + "_jdk", myJdk, false); + ((ProjectJdkImpl)jdk).setVersionString(StringUtil.notNullize(IdeaTestUtil.getMockJdkVersion(myJdk), "java 1.5")); + } + else { + jdk = IdeaTestUtil.getMockJdk17(); + } + model.setSdk(new MockJdkWrapper(CompilerConfigurationImpl.getTestsExternalCompilerHome(), jdk)); + + if (myLanguageLevel != null) { + model.getModuleExtension(LanguageLevelModuleExtension.class).setLanguageLevel(myLanguageLevel); + } + else if (myMockJdkLevel == MockJdkLevel.jdk15) { + model.getModuleExtension(LanguageLevelModuleExtension.class).setLanguageLevel(LanguageLevel.JDK_1_5); } } - libraryModel.commit(); - } - - final Sdk jdk; - if (myJdk != null) { - VfsRootAccess.allowRootAccessTemporarily(module, myJdk); - jdk = JavaSdk.getInstance().createJdk(module.getName() + "_jdk", myJdk, false); - ((ProjectJdkImpl)jdk).setVersionString(StringUtil.notNullize(IdeaTestUtil.getMockJdkVersion(myJdk), "java 1.5")); - } - else { - jdk = IdeaTestUtil.getMockJdk17(); - } - model.setSdk(new MockJdkWrapper(CompilerConfigurationImpl.getTestsExternalCompilerHome(), jdk)); - - if (myLanguageLevel != null) { - model.getModuleExtension(LanguageLevelModuleExtension.class).setLanguageLevel(myLanguageLevel); - } - else if (myMockJdkLevel == MockJdkLevel.jdk15) { - model.getModuleExtension(LanguageLevelModuleExtension.class).setLanguageLevel(LanguageLevel.JDK_1_5); - } - - model.commit(); + }); for (OrderEntry entry : ModuleRootManager.getInstance(module).getOrderEntries()) { if (entry instanceof LibraryOrderEntry) { diff --git a/java/testFramework/testFramework-java.iml b/java/testFramework/testFramework-java.iml index 2ffc1004c739..90a2a5d0ce1f 100644 --- a/java/testFramework/testFramework-java.iml +++ b/java/testFramework/testFramework-java.iml @@ -13,7 +13,7 @@ - + diff --git a/platform/analysis-api/src/com/intellij/profile/DefaultProjectProfileManager.java b/platform/analysis-api/src/com/intellij/profile/DefaultProjectProfileManager.java index 4bfee3617614..13f37ce525e5 100644 --- a/platform/analysis-api/src/com/intellij/profile/DefaultProjectProfileManager.java +++ b/platform/analysis-api/src/com/intellij/profile/DefaultProjectProfileManager.java @@ -59,7 +59,7 @@ public abstract class DefaultProjectProfileManager extends ProjectProfileManager protected final Project myProject; private String myProjectProfile; - /** This field is used for serialization. Do not rename it or make access weaker */ + @OptionTag("USE_PROJECT_PROFILE") private boolean useProjectProfile = true; diff --git a/platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/SeverityRegistrar.java b/platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/SeverityRegistrar.java index 75caebfab82d..b0c423d7c3f9 100644 --- a/platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/SeverityRegistrar.java +++ b/platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/SeverityRegistrar.java @@ -21,7 +21,6 @@ import com.intellij.lang.annotation.HighlightSeverity; import com.intellij.openapi.editor.markup.TextAttributes; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.JDOMExternalizable; import com.intellij.openapi.util.JDOMExternalizableStringList; import com.intellij.profile.codeInspection.InspectionProfileManager; import com.intellij.profile.codeInspection.InspectionProjectProfileManager; @@ -47,7 +46,7 @@ import java.util.List; * User: anna * Date: 24-Feb-2006 */ -public class SeverityRegistrar implements JDOMExternalizable, Comparator { +public class SeverityRegistrar implements Comparator { @NonNls private static final String INFO_TAG = "info"; @NonNls private static final String COLOR_ATTRIBUTE = "color"; private final Map myMap = ContainerUtil.newConcurrentMap(); @@ -132,7 +131,6 @@ public class SeverityRegistrar implements JDOMExternalizable, Comparator list = getOrderAsList(getOrderMap()); for (HighlightSeverity severity : list) { diff --git a/platform/analysis-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/FileReferenceSet.java b/platform/analysis-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/FileReferenceSet.java index f615cba2f29b..29e0cf6c39e6 100644 --- a/platform/analysis-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/FileReferenceSet.java +++ b/platform/analysis-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/FileReferenceSet.java @@ -124,6 +124,15 @@ public class FileReferenceSet { return "/"; } + protected int findSeparatorLength(@NotNull CharSequence sequence, int atOffset) { + return StringUtil.startsWith(sequence, atOffset, getSeparatorString()) ? + getSeparatorString().length() : 0; + } + + protected int findSeparatorOffset(@NotNull CharSequence sequence, int startingFrom) { + return StringUtil.indexOf(sequence, getSeparatorString(), startingFrom); + } + /** * This should be removed. Please use {@link FileReference#getContexts()} instead. */ @@ -216,17 +225,12 @@ public class FileReferenceSet { } protected void reparse() { - String str = myPathStringNonTrimmed; - - final List referencesList = reparse(str, myStartInElement); - + List referencesList = reparse(myPathStringNonTrimmed, myStartInElement); myReferences = referencesList.toArray(new FileReference[referencesList.size()]); } protected List reparse(String str, int startInElement) { - String separatorString = getSeparatorString(); // separator's length can be more then 1 char - int sepLen = separatorString.length(); - int currentSlash = -sepLen; + int wsHead = 0; int wsTail = 0; LiteralTextEscaper escaper; @@ -239,7 +243,7 @@ public class FileReferenceSet { StringBuilder sb = new StringBuilder(); escaper.decode(valueRange, sb); decoded = sb; - currentSlash += startInElement - valueRange.getStartOffset(); + wsHead += Math.max(0, startInElement - valueRange.getStartOffset()); } else { escaper = null; @@ -248,36 +252,38 @@ public class FileReferenceSet { } List referencesList = ContainerUtil.newArrayList(); - // skip head white spaces - for (int i = currentSlash + sepLen; i < decoded.length() && Character.isWhitespace(decoded.charAt(i)); i++) { - currentSlash++; + for (int i = wsHead; i < decoded.length() && Character.isWhitespace(decoded.charAt(i)); i++) { + wsHead++; // skip head white spaces } - // skip tail white spaces for (int i = decoded.length() - 1; i >= 0 && Character.isWhitespace(decoded.charAt(i)); i--) { - wsTail++; + wsTail++; // skip tail white spaces } - if (currentSlash + 2 * sepLen < decoded.length() && - StringUtil.equals(decoded.subSequence(currentSlash + sepLen, currentSlash + 2 * sepLen), separatorString)) { - currentSlash += sepLen; - } int index = 0; + int curSep = findSeparatorOffset(decoded, wsHead); + int sepLen = curSep >= wsHead ? findSeparatorLength(decoded, curSep) : 0; - if (decoded.equals(separatorString)) { - TextRange r = new TextRange(startInElement, offset(sepLen, escaper, valueRange) + 1); - referencesList.add(createFileReference(r, index++, separatorString)); + if (curSep >= 0 && decoded.length() == wsHead + sepLen + wsTail) { + // add extra reference for the only & leading "/" + TextRange r = TextRange.create(startInElement, offset(curSep + Math.max(0, sepLen - 1), escaper, valueRange) + 1); + referencesList.add(createFileReference(r, 0, decoded.subSequence(curSep, curSep + sepLen).toString())); } - - while (true) { - int nextSlash = StringUtil.indexOf(decoded, separatorString, currentSlash + sepLen); - String subReferenceText = decoded.subSequence(currentSlash + sepLen, nextSlash > 0 ? nextSlash : decoded.length()).toString(); - int end = nextSlash > 0 ? nextSlash : Math.max(currentSlash + sepLen, decoded.length() - 1 - wsTail); - TextRange r = new TextRange(offset(currentSlash + sepLen, escaper, valueRange), - offset(end, escaper, valueRange) + (nextSlash > 0 ? 0 : 1)); - referencesList.add(createFileReference(r, index++, subReferenceText)); - if ((currentSlash = nextSlash) < 0) { - break; - } + curSep = curSep == wsHead ? curSep + sepLen : wsHead; // reset offsets & start again for simplicity + sepLen = 0; + while (curSep >= 0) { + int nextSep = findSeparatorOffset(decoded, curSep + sepLen); + int start = curSep + sepLen; + int endTrimmed = nextSep > 0 ? nextSep : Math.max(start, decoded.length() - wsTail); + int endInclusive = nextSep > 0 ? nextSep : Math.max(start, decoded.length() - 1 - wsTail); + // todo move ${placeholder} support (the str usage below) to a reference implementation + // todo reference-set should be bound to exact range & text in a file, consider: ${slash}path${slash}file&.txt + String refText = index == 0 && nextSep < 0 && !StringUtil.contains(decoded, str) ? str : + decoded.subSequence(start, endTrimmed).toString(); + TextRange r = new TextRange(offset(start, escaper, valueRange), + offset(endInclusive, escaper, valueRange) + (nextSep < 0 && refText.length() > 0 ? 1 : 0)); + referencesList.add(createFileReference(r, index++, refText)); + curSep = nextSep; + sepLen = curSep > 0 ? findSeparatorLength(decoded, curSep) : 0; } return referencesList; diff --git a/platform/built-in-server/src/org/jetbrains/builtInWebServer/BuiltInWebServer.kt b/platform/built-in-server/src/org/jetbrains/builtInWebServer/BuiltInWebServer.kt index f032106892ea..e9797d72be3f 100644 --- a/platform/built-in-server/src/org/jetbrains/builtInWebServer/BuiltInWebServer.kt +++ b/platform/built-in-server/src/org/jetbrains/builtInWebServer/BuiltInWebServer.kt @@ -44,9 +44,9 @@ import java.io.File import java.net.InetAddress import java.net.UnknownHostException -public class BuiltInWebServer : HttpRequestHandler() { +class BuiltInWebServer : HttpRequestHandler() { companion object { - val LOG = Logger.getInstance(javaClass()) + val LOG = Logger.getInstance(BuiltInWebServer::class.java) private fun doProcess(request: FullHttpRequest, context: ChannelHandlerContext, projectNameAsHost: String?): Boolean { val decodedPath = URLUtil.unescapePercentSequences(UriUtil.trimParameters(request.uri())) @@ -67,15 +67,15 @@ public class BuiltInWebServer : HttpRequestHandler() { } var candidateByDirectoryName: Project? = null - val project = ProjectManager.getInstance().getOpenProjects().firstOrNull(fun(project: Project): Boolean { - if (project.isDisposed()) { + val project = ProjectManager.getInstance().openProjects.firstOrNull(fun(project: Project): Boolean { + if (project.isDisposed) { return false } - val name = project.getName() + val name = project.name if (isCustomHost) { // domain name is case-insensitive - if (projectName.equals(project.getName(), ignoreCase = true)) { + if (projectName.equals(project.name, ignoreCase = true)) { return true } } @@ -101,7 +101,7 @@ public class BuiltInWebServer : HttpRequestHandler() { if (emptyPath) { if (!SystemInfoRt.isFileSystemCaseSensitive) { // may be passed path is not correct - projectName = project.getName() + projectName = project.name } // we must redirect "jsdebug" to "jsdebug/" as nginx does, otherwise browser will treat it as file instead of directory, so, relative path will not work @@ -110,7 +110,7 @@ public class BuiltInWebServer : HttpRequestHandler() { } val path = FileUtil.toCanonicalPath(decodedPath.substring(offset + 1), '/') - for (pathHandler in WebServerPathHandler.EP_NAME.getExtensions()) { + for (pathHandler in WebServerPathHandler.EP_NAME.extensions) { try { if (pathHandler.process(path, project, request, context, projectName, decodedPath, isCustomHost)) { return true @@ -157,12 +157,12 @@ public class BuiltInWebServer : HttpRequestHandler() { } public fun compareNameAndProjectBasePath(projectName: String, project: Project): Boolean { - val basePath = project.getBasePath() + val basePath = project.basePath return basePath != null && basePath.length() > projectName.length() && basePath.endsWith(projectName) && basePath.charAt(basePath.length() - projectName.length() - 1) == '/' } public fun findIndexFile(basedir: VirtualFile): VirtualFile? { - val children = basedir.getChildren() + val children = basedir.children if (children == null || children.isEmpty()) { return null } @@ -171,8 +171,8 @@ public fun findIndexFile(basedir: VirtualFile): VirtualFile? { var index: VirtualFile? = null val preferredName = indexNamePrefix + "html" for (child in children) { - if (!child.isDirectory()) { - val name = child.getName() + if (!child.isDirectory) { + val name = child.name //noinspection IfStatementWithIdenticalBranches if (name == preferredName) { return child @@ -196,11 +196,11 @@ public fun isOwnHostName(host: String): Boolean { try { val address = InetAddress.getByName(host) - if (host == address.getHostAddress() || host.equals(address.getCanonicalHostName(), ignoreCase = true)) { + if (host == address.hostAddress || host.equals(address.canonicalHostName, ignoreCase = true)) { return true } - val localHostName = InetAddress.getLocalHost().getHostName() + val localHostName = InetAddress.getLocalHost().hostName // WEB-8889 // develar.local is own host name: develar. equals to "develar.labs.intellij.net" (canonical host name) return localHostName.equals(host, ignoreCase = true) || (host.endsWith(".local") && localHostName.regionMatches(0, host, 0, host.length() - ".local".length(), true)) @@ -214,8 +214,8 @@ private class StaticFileHandler : WebServerFileHandler() { private var ssiProcessor: SsiProcessor? = null override fun process(file: VirtualFile, canonicalRequestPath: CharSequence, project: Project, request: FullHttpRequest, channel: Channel, isCustomHost: Boolean): Boolean { - if (file.isInLocalFileSystem()) { - val nameSequence = file.getNameSequence() + if (file.isInLocalFileSystem) { + val nameSequence = file.nameSequence //noinspection SpellCheckingInspection if (StringUtilRt.endsWithIgnoreCase(nameSequence, ".shtml") || StringUtilRt.endsWithIgnoreCase(nameSequence, ".stm") || StringUtilRt.endsWithIgnoreCase(nameSequence, ".shtm")) { processSsi(file, canonicalRequestPath, project, request, channel, isCustomHost) @@ -231,17 +231,17 @@ private class StaticFileHandler : WebServerFileHandler() { } } else { - val response = FileResponses.prepareSend(request, channel, file.getTimeStamp(), file.getPath()) ?: return true + val response = FileResponses.prepareSend(request, channel, file.timeStamp, file.path) ?: return true val keepAlive = addKeepAliveIfNeed(response, request) if (request.method() !== HttpMethod.HEAD) { - HttpUtil.setContentLength(response, file.getLength()) + HttpUtil.setContentLength(response, file.length) } channel.write(response) if (request.method() != HttpMethod.HEAD) { - channel.write(ChunkedStream(file.getInputStream())) + channel.write(ChunkedStream(file.inputStream)) } val future = channel.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT) @@ -267,9 +267,9 @@ private class StaticFileHandler : WebServerFileHandler() { val keepAlive: Boolean var releaseBuffer = true try { - val lastModified = ssiProcessor!!.process(SsiExternalResolver(project, request, path, file.getParent()), VfsUtilCore.loadText(file), file.getTimeStamp(), ByteBufUtf8Writer(buffer)) + val lastModified = ssiProcessor!!.process(SsiExternalResolver(project, request, path, file.parent), VfsUtilCore.loadText(file), file.timeStamp, ByteBufUtf8Writer(buffer)) - val response = FileResponses.prepareSend(request, channel, lastModified, file.getPath()) ?: return + val response = FileResponses.prepareSend(request, channel, lastModified, file.path) ?: return keepAlive = addKeepAliveIfNeed(response, request) if (request.method() !== HttpMethod.HEAD) { @@ -296,5 +296,5 @@ private class StaticFileHandler : WebServerFileHandler() { } // deny access to .htaccess files - private fun hasAccess(result: File) = !result.isDirectory() && result.canRead() && !(result.isHidden() || result.getName().startsWith(".ht")) + private fun hasAccess(result: File) = !result.isDirectory && result.canRead() && !(result.isHidden || result.name.startsWith(".ht")) } \ No newline at end of file diff --git a/platform/built-in-server/src/org/jetbrains/builtInWebServer/NetService.kt b/platform/built-in-server/src/org/jetbrains/builtInWebServer/NetService.kt index 70f69ff5660e..3cd342a7f496 100644 --- a/platform/built-in-server/src/org/jetbrains/builtInWebServer/NetService.kt +++ b/platform/built-in-server/src/org/jetbrains/builtInWebServer/NetService.kt @@ -22,7 +22,7 @@ import org.jetbrains.util.concurrency import org.jetbrains.util.concurrency.toPromise import javax.swing.Icon -val LOG: Logger = Logger.getInstance(javaClass()) +val LOG: Logger = Logger.getInstance(NetService::class.java) public abstract class NetService @jvmOverloads protected constructor(protected val project: Project, private val consoleManager: ConsoleManager = ConsoleManager()) : Disposable { protected val processHandler: AsyncValueLoader = object : AsyncValueLoader() { diff --git a/platform/built-in-server/src/org/jetbrains/io/fastCgi/FastCgiDecoder.kt b/platform/built-in-server/src/org/jetbrains/io/fastCgi/FastCgiDecoder.kt index ddd0bb4c309a..b5c418747977 100644 --- a/platform/built-in-server/src/org/jetbrains/io/fastCgi/FastCgiDecoder.kt +++ b/platform/built-in-server/src/org/jetbrains/io/fastCgi/FastCgiDecoder.kt @@ -76,7 +76,7 @@ class FastCgiDecoder(private val errorOutputConsumer: Consumer, private override fun channelInactive(context: ChannelHandlerContext) { try { - if (!dataBuffers.isEmpty()) { + if (!dataBuffers.isEmpty) { dataBuffers.forEachEntry(object : TIntObjectProcedure { override fun execute(a: Int, buffer: ByteBuf): Boolean { try { @@ -92,7 +92,7 @@ class FastCgiDecoder(private val errorOutputConsumer: Consumer, private } } finally { - super.channelInactive(context) + super.channelInactive(context) } } @@ -136,8 +136,10 @@ class FastCgiDecoder(private val errorOutputConsumer: Consumer, private data.writerIndex(data.writerIndex() + data.readableBytes()) } else { + // must be computed here before we set data to new composite buffer + val newLength = data.readableBytes() + sliced.readableBytes() data = context.alloc().compositeBuffer(Decoder.DEFAULT_MAX_COMPOSITE_BUFFER_COMPONENTS).addComponents(data, sliced) - data.writerIndex(data.writerIndex() + data.readableBytes() + sliced.readableBytes()) + data.writerIndex(data.writerIndex() + newLength) } dataBuffers.put(id, data) } @@ -153,7 +155,7 @@ class FastCgiDecoder(private val errorOutputConsumer: Consumer, private } } - else -> LOG.error("Unknown type " + type) + else -> LOG.error("Unknown type $type") } return null } diff --git a/platform/built-in-server/src/org/jetbrains/io/fastCgi/FastCgiRequest.kt b/platform/built-in-server/src/org/jetbrains/io/fastCgi/FastCgiRequest.kt index 495ef9b6e74f..7b1c62c74fa1 100644 --- a/platform/built-in-server/src/org/jetbrains/io/fastCgi/FastCgiRequest.kt +++ b/platform/built-in-server/src/org/jetbrains/io/fastCgi/FastCgiRequest.kt @@ -12,7 +12,7 @@ import io.netty.handler.codec.http.HttpHeaderNames import org.jetbrains.builtInWebServer.WebServerPathToFileManager import org.jetbrains.io.Responses import java.net.InetSocketAddress -import java.util.Locale +import java.util.* class FastCgiRequest(val requestId: Int, allocator: ByteBufAllocator) { companion object { @@ -37,8 +37,8 @@ class FastCgiRequest(val requestId: Int, allocator: ByteBufAllocator) { public fun writeFileHeaders(file: VirtualFile, project: Project, canonicalRequestPath: CharSequence) { val root = WebServerPathToFileManager.getInstance(project).getRoot(file) LOG.assertTrue(root != null) - addHeader("DOCUMENT_ROOT", root!!.getRoot().getPath()) - addHeader("SCRIPT_FILENAME", file.getPath()) + addHeader("DOCUMENT_ROOT", root!!.root.path) + addHeader("SCRIPT_FILENAME", file.path) addHeader("SCRIPT_NAME", canonicalRequestPath) } @@ -80,19 +80,19 @@ class FastCgiRequest(val requestId: Int, allocator: ByteBufAllocator) { addHeader("REQUEST_METHOD", request.method().name()) val remote = clientChannel.remoteAddress() as InetSocketAddress - addHeader("REMOTE_ADDR", remote.getAddress().getHostAddress()) - addHeader("REMOTE_PORT", Integer.toString(remote.getPort())) + addHeader("REMOTE_ADDR", remote.address.hostAddress) + addHeader("REMOTE_PORT", Integer.toString(remote.port)) val local = clientChannel.localAddress() as InetSocketAddress addHeader("SERVER_SOFTWARE", Responses.getServerHeaderValue()) addHeader("SERVER_NAME", Responses.getServerHeaderValue()) - addHeader("SERVER_ADDR", local.getAddress().getHostAddress()) - addHeader("SERVER_PORT", Integer.toString(local.getPort())) + addHeader("SERVER_ADDR", local.address.hostAddress) + addHeader("SERVER_PORT", Integer.toString(local.port)) addHeader("GATEWAY_INTERFACE", "CGI/1.1") addHeader("SERVER_PROTOCOL", request.protocolVersion().text()) - addHeader("CONTENT_TYPE", request.headers().get(HttpHeaderNames.CONTENT_TYPE)) + addHeader("CONTENT_TYPE", request.headers().getAsString(HttpHeaderNames.CONTENT_TYPE)) // PHP only, required if PHP was built with --enable-force-cgi-redirect addHeader("REDIRECT_STATUS", "200") @@ -106,8 +106,8 @@ class FastCgiRequest(val requestId: Int, allocator: ByteBufAllocator) { addHeader("CONTENT_LENGTH", request.content().readableBytes().toString()) - for (entry in request.headers()) { - addHeader("HTTP_${entry.getKey().replace('-', '_').toUpperCase(Locale.ENGLISH)}", entry.getValue()) + for ((key, value) in request.headers().iteratorAsString()) { + addHeader("HTTP_${key.replace('-', '_').toUpperCase(Locale.ENGLISH)}", value) } } diff --git a/platform/built-in-server/src/org/jetbrains/io/fastCgi/FastCgiService.kt b/platform/built-in-server/src/org/jetbrains/io/fastCgi/FastCgiService.kt index d43952c3f582..e7d54e0210f7 100644 --- a/platform/built-in-server/src/org/jetbrains/io/fastCgi/FastCgiService.kt +++ b/platform/built-in-server/src/org/jetbrains/io/fastCgi/FastCgiService.kt @@ -30,7 +30,7 @@ import org.jetbrains.concurrency.Promise import org.jetbrains.io.* import java.util.concurrent.atomic.AtomicInteger -val LOG: Logger = Logger.getInstance(javaClass()) +val LOG: Logger = Logger.getInstance(FastCgiService::class.java) // todo send FCGI_ABORT_REQUEST if client channel disconnected public abstract class FastCgiService(project: Project) : SingleConnectionNetService(project) { @@ -51,7 +51,7 @@ public abstract class FastCgiService(project: Project) : SingleConnectionNetServ private fun parseHeaders(response: HttpResponse, buffer: ByteBuf) { val builder = StringBuilder() - while (buffer.isReadable()) { + while (buffer.isReadable) { builder.setLength(0) var key: String? = null @@ -149,10 +149,10 @@ public abstract class FastCgiService(project: Project) : SingleConnectionNetServ fastCgiRequest.writeToServerChannel(notEmptyContent, processChannel!!) } }) - .rejected(Consumer { + .rejected { Promise.logError(LOG, it) handleError(fastCgiRequest, notEmptyContent) - }) + } } } catch (e: Throwable) { @@ -187,7 +187,7 @@ public abstract class FastCgiService(project: Project) : SingleConnectionNetServ fun responseReceived(id: Int, buffer: ByteBuf?) { val channel = requests.remove(id) - if (channel == null || !channel.isActive()) { + if (channel == null || !channel.isActive) { buffer?.release() return } diff --git a/platform/built-in-server/testSrc/TestManager.kt b/platform/built-in-server/testSrc/TestManager.kt index 03181ce3ce18..f990a1c751d7 100644 --- a/platform/built-in-server/testSrc/TestManager.kt +++ b/platform/built-in-server/testSrc/TestManager.kt @@ -38,7 +38,7 @@ class TestManager(val projectRule: ProjectRule, private val tempDirManager: Temp public val status: Int = 200) override fun starting(description: Description) { - annotation = description.getAnnotation(javaClass()) + annotation = description.getAnnotation(TestDescriptor::class.java) if (annotation == null) { return } diff --git a/platform/configuration-store-impl/src/ApplicationStoreImpl.kt b/platform/configuration-store-impl/src/ApplicationStoreImpl.kt index e36c1e4aba9c..e3f7c89d51a1 100644 --- a/platform/configuration-store-impl/src/ApplicationStoreImpl.kt +++ b/platform/configuration-store-impl/src/ApplicationStoreImpl.kt @@ -37,6 +37,10 @@ class ApplicationPathMacroManager : BasePathMacroManager(null) class ApplicationStoreImpl(private val application: Application, pathMacroManager: PathMacroManager) : ComponentStoreImpl() { override val storageManager = ApplicationStorageManager(application, pathMacroManager) + // number of app components require some state, so, we load default state in test mode + override val loadPolicy: StateLoadPolicy + get() = if (application.isUnitTestMode()) StateLoadPolicy.LOAD_ONLY_DEFAULT else StateLoadPolicy.LOAD + override fun setPath(path: String) { storageManager.addMacro(ROOT_CONFIG, path) storageManager.addMacro(StoragePathMacros.APP_CONFIG, "$path/${ApplicationStorageManager.FILE_STORAGE_DIR}") diff --git a/platform/configuration-store-impl/src/ComponentStoreImpl.kt b/platform/configuration-store-impl/src/ComponentStoreImpl.kt index 39a54ea75114..2218288cd495 100644 --- a/platform/configuration-store-impl/src/ComponentStoreImpl.kt +++ b/platform/configuration-store-impl/src/ComponentStoreImpl.kt @@ -31,7 +31,10 @@ import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.progress.ProcessCanceledException import com.intellij.openapi.project.Project import com.intellij.openapi.util -import com.intellij.openapi.util.* +import com.intellij.openapi.util.InvalidDataException +import com.intellij.openapi.util.JDOMExternalizable +import com.intellij.openapi.util.JDOMUtil +import com.intellij.openapi.util.NamedJDOMExternalizable import com.intellij.openapi.util.registry.Registry import com.intellij.openapi.vfs.VirtualFile import com.intellij.openapi.vfs.newvfs.impl.VfsRootAccess @@ -49,7 +52,7 @@ import java.io.IOException import java.util.* import java.util.concurrent.CopyOnWriteArrayList -private val LOG = Logger.getInstance(javaClass()) +private val LOG = Logger.getInstance(ComponentStoreImpl::class.java) /** * Note: this class is used in upsource, please notify upsource team in case you change its API. @@ -61,6 +64,9 @@ abstract class ComponentStoreImpl : IComponentStore { protected open val project: Project? get() = null + open val loadPolicy: StateLoadPolicy + get() = StateLoadPolicy.LOAD + abstract val storageManager: StateStorageManager override final fun getStateStorageManager() = storageManager @@ -82,6 +88,7 @@ abstract class ComponentStoreImpl : IComponentStore { componentNameIfStateExists = if (component is PersistentStateComponent<*>) { val stateSpec = StoreUtil.getStateSpec(component) doAddComponent(stateSpec.name, component) + @suppress("UNCHECKED_CAST") initPersistentComponent(stateSpec, component as PersistentStateComponent, null, false) } else { @@ -129,8 +136,10 @@ abstract class ComponentStoreImpl : IComponentStore { } } - errors = doSave(externalizationSession!!.createSaveSessions(), readonlyFiles, errors) - CompoundRuntimeException.doThrow(errors) + if (externalizationSession != null) { + errors = doSave(externalizationSession.createSaveSessions(), readonlyFiles, errors) + } + CompoundRuntimeException.throwIfNotEmpty(errors) } override TestOnly fun saveApplicationComponent(component: Any) { @@ -157,7 +166,7 @@ abstract class ComponentStoreImpl : IComponentStore { val token = WriteAction.start() try { VfsRootAccess.allowRootAccess(file.getAbsolutePath()) - CompoundRuntimeException.doThrow(doSave(sessions)) + CompoundRuntimeException.throwIfNotEmpty(doSave(sessions)) } finally { try { @@ -194,18 +203,18 @@ abstract class ComponentStoreImpl : IComponentStore { val componentName = ComponentManagerImpl.getComponentName(component) doAddComponent(componentName, component) - if (optimizeTestLoading()) { + if (loadPolicy != StateLoadPolicy.LOAD) { return null } try { - getDefaultState(component, componentName, javaClass())?.let { component.readExternal(it) } + getDefaultState(component, componentName, Element::class.java)?.let { component.readExternal(it) } } catch (e: Throwable) { LOG.error(e) } - val element = storageManager.getOldStorage(component, componentName, StateStorageOperation.READ)?.getState(component, componentName, javaClass(), null, false) ?: return null + val element = storageManager.getOldStorage(component, componentName, StateStorageOperation.READ)?.getState(component, componentName, Element::class.java, null, false) ?: return null try { component.readExternal(element) } @@ -224,8 +233,8 @@ abstract class ComponentStoreImpl : IComponentStore { } } - private fun initPersistentComponent(stateSpec: State, component: PersistentStateComponent, changedStorages: Set?, reloadData: Boolean): String? { - if (optimizeTestLoading()) { + private fun initPersistentComponent(stateSpec: State, component: PersistentStateComponent, changedStorages: Set?, reloadData: Boolean): String? { + if (loadPolicy == StateLoadPolicy.NOT_LOAD) { return null } @@ -236,41 +245,44 @@ abstract class ComponentStoreImpl : IComponentStore { } val defaultState = if (stateSpec.defaultStateAsResource) getDefaultState(component, name, stateClass) else null - val storageSpecs = getStorageSpecs(component, stateSpec, StateStorageOperation.READ) - val storageChooser = component as? StateStorageChooserEx - for (storageSpec in storageSpecs) { - if (storageChooser?.getResolution(storageSpec, StateStorageOperation.READ) == Resolution.SKIP) { - continue - } - - val storage = storageManager.getStateStorage(storageSpec) - var stateGetter = if (isUseLoadedStateAsExisting(storage) && (ApplicationManager.getApplication().isUnitTestMode() || Registry.`is`("use.loaded.state.as.existing", false))) { - (storage as? StorageBaseEx<*>)?.createGetSession(component, name, stateClass) - } - else { - null - } - var state = if (stateGetter == null) storage.getState(component, name, stateClass, defaultState, reloadData) else stateGetter.getState(defaultState) - if (state == null) { - if (changedStorages != null && changedStorages.contains(storage)) { - // state will be null if file deleted - // we must create empty (initial) state to reinit component - state = DefaultStateSerializer.deserializeState(Element("state"), stateClass, null)!! - } - else { + if (loadPolicy == StateLoadPolicy.LOAD) { + val storageSpecs = getStorageSpecs(component, stateSpec, StateStorageOperation.READ) + val storageChooser = component as? StateStorageChooserEx + for (storageSpec in storageSpecs) { + if (storageChooser?.getResolution(storageSpec, StateStorageOperation.READ) == Resolution.SKIP) { continue } - } - try { - component.loadState(state) + val storage = storageManager.getStateStorage(storageSpec) + var stateGetter = if (isUseLoadedStateAsExisting(storage) && (ApplicationManager.getApplication().isUnitTestMode() || Registry.`is`("use.loaded.state.as.existing", false))) { + (storage as? StorageBaseEx<*>)?.createGetSession(component, name, stateClass) + } + else { + null + } + var state = if (stateGetter == null) storage.getState(component, name, stateClass, defaultState, reloadData) else stateGetter.getState(defaultState) + if (state == null) { + if (changedStorages != null && changedStorages.contains(storage)) { + // state will be null if file deleted + // we must create empty (initial) state to reinit component + state = DefaultStateSerializer.deserializeState(Element("state"), stateClass, null)!! + } + else { + continue + } + } + + try { + component.loadState(state) + } + finally { + stateGetter?.close() + } + return name } - finally { - stateGetter?.close() - } - return name } + // we load default state even if isLoadComponentState false - required for app components (for example, at least one color scheme must exists) if (defaultState != null) { component.loadState(defaultState) } @@ -298,7 +310,14 @@ abstract class ComponentStoreImpl : IComponentStore { if (storages.size() == 1 || component is StateStorageChooserEx) { return storages } - assert(!storages.isEmpty()) + + if (storages.isEmpty()) { + if (stateSpec.defaultStateAsResource) { + return storages + } + + throw AssertionError("No storage specified") + } val defaultStorages = selectDefaultStorages(storages, operation) if (defaultStorages != null) { @@ -330,8 +349,6 @@ abstract class ComponentStoreImpl : IComponentStore { return sorted } - protected open fun optimizeTestLoading(): Boolean = false - override final fun isReloadPossible(componentNames: MutableSet) = !componentNames.any { isNotReloadable(it) } private fun isNotReloadable(component: Any?) = component != null && (component !is PersistentStateComponent<*> || !StoreUtil.getStateSpec(component).reloadable) @@ -357,6 +374,7 @@ abstract class ComponentStoreImpl : IComponentStore { override final fun reloadState(componentClass: Class>) { val stateSpec = StoreUtil.getStateSpecOrError(componentClass) + @suppress("UNCHECKED_CAST") val component = components.get(stateSpec.name) as PersistentStateComponent? if (component != null) { initPersistentComponent(stateSpec, component, emptySet(), true) @@ -364,6 +382,7 @@ abstract class ComponentStoreImpl : IComponentStore { } private fun reloadState(componentName: String, changedStorages: Set): Boolean { + @suppress("UNCHECKED_CAST") val component = components.get(componentName) as PersistentStateComponent? if (component == null) { return false @@ -447,4 +466,8 @@ abstract class ComponentStoreImpl : IComponentStore { return errors } } +} + +enum class StateLoadPolicy { + LOAD, LOAD_ONLY_DEFAULT, NOT_LOAD } \ No newline at end of file diff --git a/platform/configuration-store-impl/src/DefaultProjectStoreImpl.kt b/platform/configuration-store-impl/src/DefaultProjectStoreImpl.kt index 7a619fee2f95..11f74ad2a33f 100644 --- a/platform/configuration-store-impl/src/DefaultProjectStoreImpl.kt +++ b/platform/configuration-store-impl/src/DefaultProjectStoreImpl.kt @@ -30,6 +30,10 @@ class DefaultProjectStoreImpl(override val project: ProjectImpl, private val pat val FILE_SPEC = "${StoragePathMacros.APP_CONFIG}/project.default.xml" } + // see note about default state in project store + override val loadPolicy: StateLoadPolicy + get() = if (ApplicationManager.getApplication().isUnitTestMode()) StateLoadPolicy.NOT_LOAD else StateLoadPolicy.LOAD + init { service().project = project } diff --git a/platform/configuration-store-impl/src/ModuleStoreImpl.kt b/platform/configuration-store-impl/src/ModuleStoreImpl.kt index 40839c4d9831..6d3258086673 100644 --- a/platform/configuration-store-impl/src/ModuleStoreImpl.kt +++ b/platform/configuration-store-impl/src/ModuleStoreImpl.kt @@ -17,11 +17,11 @@ package com.intellij.configurationStore import com.intellij.openapi.components.PathMacroManager import com.intellij.openapi.components.StoragePathMacros +import com.intellij.openapi.components.stateStore import com.intellij.openapi.module.Module -import com.intellij.openapi.project.ex.ProjectEx import java.io.File -class ModuleStoreImpl(module: Module, private val pathMacroManager: PathMacroManager) : ComponentStoreImpl() { +open private class ModuleStoreImpl(module: Module, private val pathMacroManager: PathMacroManager) : ComponentStoreImpl() { override val project = module.getProject() override val storageManager = ModuleStateStorageManager(pathMacroManager.createTrackingSubstitutor(), module) @@ -32,7 +32,20 @@ class ModuleStoreImpl(module: Module, private val pathMacroManager: PathMacroMan } } - override fun optimizeTestLoading() = (project as ProjectEx).isOptimiseTestLoadSpeed() - override final fun getPathMacroManagerForDefaults() = pathMacroManager +} + +private class TestModuleStore(module: Module, pathMacroManager: PathMacroManager) : ModuleStoreImpl(module, pathMacroManager) { + private var moduleComponentLoadPolicy: StateLoadPolicy? = null + + override fun setPath(path: String) { + super.setPath(path) + + if (File(path).exists()) { + moduleComponentLoadPolicy = StateLoadPolicy.LOAD + } + } + + override val loadPolicy: StateLoadPolicy + get() = moduleComponentLoadPolicy ?: (project.stateStore as ProjectStoreImpl).loadPolicy } \ No newline at end of file diff --git a/platform/configuration-store-impl/src/PlatformProjectStoreClassProvider.kt b/platform/configuration-store-impl/src/PlatformProjectStoreClassProvider.kt index b1a94c0ab065..3b3662c3d735 100644 --- a/platform/configuration-store-impl/src/PlatformProjectStoreClassProvider.kt +++ b/platform/configuration-store-impl/src/PlatformProjectStoreClassProvider.kt @@ -20,6 +20,6 @@ import com.intellij.openapi.project.impl.ProjectStoreClassProvider class PlatformProjectStoreClassProvider : ProjectStoreClassProvider { override fun getProjectStoreClass(isDefaultProject: Boolean): Class { - return if (isDefaultProject) javaClass() else javaClass() + return if (isDefaultProject) DefaultProjectStoreImpl::class.java else ProjectStoreImpl::class.java } } \ No newline at end of file diff --git a/platform/configuration-store-impl/src/ProjectStoreImpl.kt b/platform/configuration-store-impl/src/ProjectStoreImpl.kt index 92d7d2b22143..ae6900ab4570 100644 --- a/platform/configuration-store-impl/src/ProjectStoreImpl.kt +++ b/platform/configuration-store-impl/src/ProjectStoreImpl.kt @@ -19,6 +19,7 @@ import com.intellij.ide.highlighter.ProjectFileType import com.intellij.ide.highlighter.WorkspaceFileType import com.intellij.notification.Notifications import com.intellij.notification.NotificationsManager +import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.application.ReadAction import com.intellij.openapi.application.invokeAndWaitIfNeed import com.intellij.openapi.components.* @@ -41,7 +42,7 @@ import java.io.BufferedReader import java.io.File import java.io.IOException import java.io.InputStreamReader -import java.util.ArrayList +import java.util.* open class ProjectStoreImpl(override val project: ProjectImpl, private val pathMacroManager: PathMacroManager) : ComponentStoreImpl(), IProjectStore { // protected setter used in upsource @@ -50,11 +51,20 @@ open class ProjectStoreImpl(override val project: ProjectImpl, private val pathM private var presentableUrl: String? = null + override var loadPolicy = StateLoadPolicy.LOAD + init { assert(!project.isDefault()) } - override fun optimizeTestLoading() = project.isOptimiseTestLoadSpeed() + override final fun isOptimiseTestLoadSpeed() = loadPolicy != StateLoadPolicy.LOAD + + override final fun setOptimiseTestLoadSpeed(value: Boolean) { + // we don't load default state in tests as app store does because + // 1) we should not do it + // 2) it was so before, so, we preserve old behavior (otherwise RunManager will load template run configurations) + loadPolicy = if (value) StateLoadPolicy.NOT_LOAD else StateLoadPolicy.LOAD + } override final fun getPathMacroManagerForDefaults() = pathMacroManager @@ -74,6 +84,11 @@ open class ProjectStoreImpl(override val project: ProjectImpl, private val pathM invokeAndWaitIfNeed { VfsUtil.markDirtyAndRefresh(false, true, false, fs.refreshAndFindFileByPath(filePath), fs.refreshAndFindFileByPath(workspacePath)) } + + if (ApplicationManager.getApplication().isUnitTestMode()) { + // load state only if there are existing files + setOptimiseTestLoadSpeed(!File(filePath).exists()) + } } else { scheme = StorageScheme.DIRECTORY_BASED @@ -91,6 +106,11 @@ open class ProjectStoreImpl(override val project: ProjectImpl, private val pathM } invokeAndWaitIfNeed { VfsUtil.markDirtyAndRefresh(false, true, true, fs.refreshAndFindFileByPath(projectConfigDir)) } + + if (ApplicationManager.getApplication().isUnitTestMode()) { + // load state only if there are existing files + setOptimiseTestLoadSpeed(!dirStore.exists()) + } } presentableUrl = null @@ -130,7 +150,6 @@ open class ProjectStoreImpl(override val project: ProjectImpl, private val pathM } catch (ignored: IOException) { } - } } @@ -184,7 +203,7 @@ open class ProjectStoreImpl(override val project: ProjectImpl, private val pathM super.doSave(saveSessions, readonlyFiles, errors) - val notifications = NotificationsManager.getNotificationsManager().getNotificationsOfType(javaClass(), project) + val notifications = NotificationsManager.getNotificationsManager().getNotificationsOfType(UnableToSaveProjectNotification::class.java, project) if (readonlyFiles.isEmpty()) { for (notification in notifications) { notification.expire() @@ -216,7 +235,7 @@ open class ProjectStoreImpl(override val project: ProjectImpl, private val pathM } if (errors != null) { - CompoundRuntimeException.doThrow(errors) + CompoundRuntimeException.throwIfNotEmpty(errors) } if (!readonlyFiles.isEmpty()) { @@ -267,7 +286,7 @@ open class ProjectStoreImpl(override val project: ProjectImpl, private val pathM } private fun dropUnableToSaveProjectNotification(project: Project, readOnlyFiles: Array) { - val notifications = NotificationsManager.getNotificationsManager().getNotificationsOfType(javaClass(), project) + val notifications = NotificationsManager.getNotificationsManager().getNotificationsOfType(UnableToSaveProjectNotification::class.java, project) if (notifications.isEmpty()) { Notifications.Bus.notify(UnableToSaveProjectNotification(project, readOnlyFiles), project) } diff --git a/platform/configuration-store-impl/src/ProjectWithModulesStoreImpl.kt b/platform/configuration-store-impl/src/ProjectWithModulesStoreImpl.kt index ee88d24f9a4a..da1e7c58b262 100644 --- a/platform/configuration-store-impl/src/ProjectWithModulesStoreImpl.kt +++ b/platform/configuration-store-impl/src/ProjectWithModulesStoreImpl.kt @@ -28,7 +28,7 @@ import com.intellij.openapi.vfs.VirtualFile class PlatformLangProjectStoreClassProvider : ProjectStoreClassProvider { override fun getProjectStoreClass(isDefaultProject: Boolean): Class { - return if (isDefaultProject) javaClass() else javaClass() + return if (isDefaultProject) DefaultProjectStoreImpl::class.java else ProjectWithModulesStoreImpl::class.java } } diff --git a/platform/configuration-store-impl/src/SchemeManagerFactoryImpl.kt b/platform/configuration-store-impl/src/SchemeManagerFactoryImpl.kt index de4019a335ff..09117da34363 100644 --- a/platform/configuration-store-impl/src/SchemeManagerFactoryImpl.kt +++ b/platform/configuration-store-impl/src/SchemeManagerFactoryImpl.kt @@ -83,7 +83,7 @@ public abstract class SchemeManagerFactoryBase : SchemesManagerFactory(), Settin } } - CompoundRuntimeException.doThrow(errors) + CompoundRuntimeException.throwIfNotEmpty(errors) } } diff --git a/platform/configuration-store-impl/src/SchemeManagerImpl.kt b/platform/configuration-store-impl/src/SchemeManagerImpl.kt index 20846da1dbbe..eb72ce1b69fd 100644 --- a/platform/configuration-store-impl/src/SchemeManagerImpl.kt +++ b/platform/configuration-store-impl/src/SchemeManagerImpl.kt @@ -349,7 +349,7 @@ public class SchemeManagerImpl(private val val fileNameWithoutExtension = fileName.subSequence(0, fileName.length() - extension.length()).toString() if (duringLoad) { if (filesToDelete.isNotEmpty() && filesToDelete.contains(fileName.toString())) { - LOG.warn("Scheme file $fileName is not loaded because marked to delete") + LOG.warn("Scheme file \"$fileName\" is not loaded because marked to delete") return null } @@ -367,7 +367,7 @@ public class SchemeManagerImpl(private val else { // We don't load scheme with duplicated name - if we generate unique name for it, it will be saved then with new name. // It is not what all can expect. Such situation in most cases indicates error on previous level, so, we just warn about it. - LOG.warn("Scheme file $fileName is not loaded because defines duplicated name ${scheme.getName()}") + LOG.warn("Scheme file \"$fileName\" is not loaded because defines duplicated name \"${scheme.getName()}\"") } return null } @@ -428,13 +428,13 @@ public class SchemeManagerImpl(private val @suppress("UNCHECKED_CAST") if (scheme is ExternalizableScheme) { val state = getState(scheme as E) - if (state === BaseSchemeProcessor.State.NON_PERSISTENT) { + if (state == BaseSchemeProcessor.State.NON_PERSISTENT) { continue } hasSchemes = true - if (state !== BaseSchemeProcessor.State.UNCHANGED) { + if (state != BaseSchemeProcessor.State.UNCHANGED) { schemesToSave.add(scheme) } diff --git a/platform/configuration-store-impl/src/StateStorageManagerImpl.kt b/platform/configuration-store-impl/src/StateStorageManagerImpl.kt index ebd0de554a1c..12f8975480c9 100644 --- a/platform/configuration-store-impl/src/StateStorageManagerImpl.kt +++ b/platform/configuration-store-impl/src/StateStorageManagerImpl.kt @@ -36,11 +36,10 @@ import org.jdom.Element import org.jetbrains.annotations.TestOnly import java.io.File import java.io.IOException -import java.util.LinkedHashMap +import java.util.* import java.util.concurrent.locks.ReentrantLock import java.util.regex.Pattern import kotlin.concurrent.withLock -import kotlin.reflect.jvm.java /** * If componentManager not specified, storage will not add file tracker (see VirtualFileTracker) @@ -147,9 +146,9 @@ open class StateStorageManagerImpl(private val rootTagName: String, */ open fun expandNormalizedPath(path: String): String = expandMacros(path) - fun getOrCreateStorage(fileSpec: String, roamingType: RoamingType = RoamingType.DEFAULT, storageClass: Class = javaClass(), @SuppressWarnings("deprecation") stateSplitter: Class = javaClass()): StateStorage { + fun getOrCreateStorage(fileSpec: String, roamingType: RoamingType = RoamingType.DEFAULT, storageClass: Class = StateStorage::class.java, @SuppressWarnings("deprecation") stateSplitter: Class = StateSplitterEx::class.java): StateStorage { val collapsedPath = normalizeFileSpec(fileSpec) - val key = if (storageClass == javaClass()) collapsedPath else storageClass.getName() + val key = if (storageClass == StateStorage::class.java) collapsedPath else storageClass.getName() storageLock.withLock { var storage = storages.get(key) if (storage == null) { @@ -184,7 +183,7 @@ open class StateStorageManagerImpl(private val rootTagName: String, // overridden in upsource protected open fun createStateStorage(storageClass: Class, collapsedPath: String, roamingType: RoamingType, @SuppressWarnings("deprecation") stateSplitter: Class): StateStorage { - if (storageClass != javaClass()) { + if (storageClass != StateStorage::class.java) { val constructor = storageClass.getConstructors()[0]!! constructor.setAccessible(true) return constructor.newInstance(componentManager!!, this) as StateStorage @@ -195,7 +194,7 @@ open class StateStorageManagerImpl(private val rootTagName: String, } val filePath = expandNormalizedPath(collapsedPath) - if (stateSplitter != javaClass() && stateSplitter != javaClass()) { + if (stateSplitter != StateSplitter::class.java && stateSplitter != StateSplitterEx::class.java) { val storage = MyDirectoryStorage(this, File(filePath), ReflectionUtil.newInstance(stateSplitter)) virtualFileTracker?.put(filePath, storage) return storage diff --git a/platform/configuration-store-impl/testSrc/ApplicationStoreTest.kt b/platform/configuration-store-impl/testSrc/ApplicationStoreTest.kt index 3b125e60db94..7278059c44cd 100644 --- a/platform/configuration-store-impl/testSrc/ApplicationStoreTest.kt +++ b/platform/configuration-store-impl/testSrc/ApplicationStoreTest.kt @@ -67,7 +67,7 @@ class ApplicationStoreTest { component.foo = "newValue" componentStore.save(SmartList()) - assertThat(streamProvider.data.get(RoamingType.DEFAULT)!!.get("proxy.xml")).isEqualTo("\n" + " \n" + " \n" + "") + assertThat(streamProvider.data.get(RoamingType.DEFAULT)!!.get("new.xml")).isEqualTo("\n" + " \n" + "") } @Test fun `load from stream provider`() { @@ -75,8 +75,8 @@ class ApplicationStoreTest { val streamProvider = MyStreamProvider() val map = THashMap() - val fileSpec = "proxy.xml" - map.put(fileSpec, "\n \n \n") + val fileSpec = "new.xml" + map.put(fileSpec, "\n \n") streamProvider.data.put(RoamingType.DEFAULT, map) componentStore.storageManager.streamProvider = streamProvider @@ -95,8 +95,8 @@ class ApplicationStoreTest { } private fun doRemoveDeprecatedStorageOnWrite(component: Foo) { - val oldFile = writeConfig("other.xml", "") - writeConfig("proxy.xml", "") + val oldFile = writeConfig("old.xml", "${createComponentData("old")}") + writeConfig("new.xml", "${createComponentData("new")}") testAppConfig.refreshVfs() @@ -109,6 +109,29 @@ class ApplicationStoreTest { assertThat(oldFile).doesNotExist() } + private fun createComponentData(foo: String) = """""" + + @Test fun `remove data from deprecated storage if another component data exists`() { + val data = createComponentData("new") + val oldFile = writeConfig("old.xml", """ + + ${createComponentData("old")} + """) + writeConfig("new.xml", "$data") + + testAppConfig.refreshVfs() + + val component = SeveralStoragesConfigured() + componentStore.initComponent(component, false) + assertThat(component.foo).isEqualTo("new") + + saveStore() + + assertThat(oldFile).hasContent(""" + +""") + } + @State(name = "A", storages = arrayOf(Storage(file = "a.xml"))) private open class A : PersistentStateComponent { data class State(@Attribute var foo: String = "", @Attribute var bar: String = "") @@ -118,7 +141,7 @@ class ApplicationStoreTest { override fun getState() = state.serialize() override fun loadState(state: Element) { - this.state = XmlSerializer.deserialize(state, javaClass())!! + this.state = XmlSerializer.deserialize(state, State::class.java)!! } } @@ -209,10 +232,11 @@ class ApplicationStoreTest { } abstract class Foo { - public var foo: String = "defaultValue" + @Attribute + var foo = "defaultValue" } - @State(name = "HttpConfigurable", storages = arrayOf(Storage(file = "proxy.xml"), Storage(file = StoragePathMacros.APP_CONFIG + "/other.xml", deprecated = true))) + @State(name = "A", storages = arrayOf(Storage(file = "new.xml"), Storage(file = StoragePathMacros.APP_CONFIG + "/old.xml", deprecated = true))) class SeveralStoragesConfigured : Foo(), PersistentStateComponent { override fun getState(): SeveralStoragesConfigured? { return this @@ -223,7 +247,7 @@ class ApplicationStoreTest { } } - @State(name = "HttpConfigurable", storages = arrayOf(Storage(file = "other.xml", deprecated = true), Storage(file = "${StoragePathMacros.APP_CONFIG}/proxy.xml"))) + @State(name = "A", storages = arrayOf(Storage(file = "old.xml", deprecated = true), Storage(file = "${StoragePathMacros.APP_CONFIG}/new.xml"))) class ActualStorageLast : Foo(), PersistentStateComponent { override fun getState() = this diff --git a/platform/configuration-store-impl/testSrc/DefaultProjectStoreTest.kt b/platform/configuration-store-impl/testSrc/DefaultProjectStoreTest.kt index d3b6269745ce..7d96ad1e6ba2 100644 --- a/platform/configuration-store-impl/testSrc/DefaultProjectStoreTest.kt +++ b/platform/configuration-store-impl/testSrc/DefaultProjectStoreTest.kt @@ -5,28 +5,30 @@ import com.intellij.externalDependencies.ExternalDependenciesManager import com.intellij.externalDependencies.ProjectExternalDependency import com.intellij.openapi.application.ex.ApplicationManagerEx import com.intellij.openapi.components.StoragePathMacros +import com.intellij.openapi.components.impl.stores.IComponentStore +import com.intellij.openapi.components.impl.stores.StateStorageManager import com.intellij.openapi.components.service import com.intellij.openapi.components.stateStore import com.intellij.openapi.project.ProjectManager -import com.intellij.openapi.util.io.FileUtil import com.intellij.testFramework.ProjectRule import com.intellij.testFramework.RuleChain import com.intellij.testFramework.TemporaryDirectory +import com.intellij.testFramework.deleteRecursively import org.assertj.core.api.Assertions.assertThat import org.junit.ClassRule import org.junit.Rule import org.junit.Test import org.junit.rules.ExternalResource -import java.io.File +import java.nio.file.Paths class DefaultProjectStoreTest { companion object { - ClassRule val projectRule = ProjectRule() + @ClassRule val projectRule = ProjectRule() } private val tempDirManager = TemporaryDirectory() - private val requiredPlugins: List = listOf(DependencyOnPlugin("fake", "0", "1")) + private val requiredPlugins = listOf(DependencyOnPlugin("fake", "0", "1")) private val ruleChain = RuleChain( tempDirManager, @@ -45,7 +47,7 @@ class DefaultProjectStoreTest { app.doNotSave(isDoNotSave) } finally { - FileUtil.delete(File(app.stateStore.getStateStorageManager().expandMacros(StoragePathMacros.APP_CONFIG))) + Paths.get(app.stateStore.storageManager.expandMacros(StoragePathMacros.APP_CONFIG)).deleteRecursively() } } }, @@ -63,11 +65,14 @@ class DefaultProjectStoreTest { } ) - public Rule fun getChain(): RuleChain = ruleChain + @Rule fun getChain() = ruleChain - public Test fun `new project from default`() { - createProject(tempDirManager) { + @Test fun `new project from default`() { + createProjectAndUseInLoadComponentStateMode(tempDirManager) { assertThat(it.service().getAllDependencies()).isEqualTo(requiredPlugins) } } -} \ No newline at end of file +} + +val IComponentStore.storageManager: StateStorageManager + get() = getStateStorageManager() \ No newline at end of file diff --git a/platform/configuration-store-impl/testSrc/ModuleStoreTest.kt b/platform/configuration-store-impl/testSrc/ModuleStoreTest.kt index 4a6e417e69e7..6ef7d9026071 100644 --- a/platform/configuration-store-impl/testSrc/ModuleStoreTest.kt +++ b/platform/configuration-store-impl/testSrc/ModuleStoreTest.kt @@ -47,7 +47,7 @@ class ModuleStoreTest { private val tempDirManager = TemporaryDirectory() private val ruleChain = RuleChain(tempDirManager, EdtRule(), ActiveStoreRule(projectRule), DisposeModulesRule(projectRule)) - public Rule fun getChain(): RuleChain = ruleChain + @Rule fun getChain() = ruleChain @Test fun `set option`() { val moduleFile = runWriteAction { diff --git a/platform/configuration-store-impl/testSrc/ProjectStoreTest.kt b/platform/configuration-store-impl/testSrc/ProjectStoreTest.kt index e3f4e94c1efe..935edfed2b4a 100644 --- a/platform/configuration-store-impl/testSrc/ProjectStoreTest.kt +++ b/platform/configuration-store-impl/testSrc/ProjectStoreTest.kt @@ -32,11 +32,11 @@ import org.junit.Rule import org.junit.Test import java.io.File -fun createProject(tempDirManager: TemporaryDirectory, task: (Project) -> Unit) { +fun createProjectAndUseInLoadComponentStateMode(tempDirManager: TemporaryDirectory, task: (Project) -> Unit) { createOrLoadProject(tempDirManager, task) } -fun loadProject(tempDirManager: TemporaryDirectory, projectCreator: ((VirtualFile) -> String)? = null, task: (Project) -> Unit) { +fun loadAndUseProject(tempDirManager: TemporaryDirectory, projectCreator: ((VirtualFile) -> String)? = null, task: (Project) -> Unit) { createOrLoadProject(tempDirManager, task, projectCreator) } @@ -51,20 +51,22 @@ private fun createOrLoadProject(tempDirManager: TemporaryDirectory, task: (Proje } val projectManager = ProjectManagerEx.getInstanceEx() as ProjectManagerImpl - var project = if (projectCreator == null) projectManager.newProject(null, filePath, true, false, false)!! else projectManager.loadProject(filePath)!! - try { - projectManager.openTestProject(project) - task(project) - } - finally { - projectManager.closeProject(project, false, true, false) + var project = if (projectCreator == null) projectManager.newProject(null, filePath, true, false)!! else projectManager.loadProject(filePath)!! + project.runInLoadComponentStateMode { + try { + projectManager.openTestProject(project) + task(project) + } + finally { + projectManager.closeProject(project, false, true, false) + } } } } class ProjectStoreTest { companion object { - ClassRule val projectRule = ProjectRule() + @ClassRule val projectRule = ProjectRule() } val tempDirManager = TemporaryDirectory() @@ -72,7 +74,7 @@ class ProjectStoreTest { private val ruleChain = RuleChain(tempDirManager) @Rule fun getChain() = ruleChain - Language("XML") + @Language("XML") private val iprFileContent = "\n" + "\n" + @@ -81,7 +83,7 @@ class ProjectStoreTest { " \n" + "" - State(name = "AATestComponent", storages = arrayOf(Storage(file = StoragePathMacros.PROJECT_FILE))) + @State(name = "AATestComponent", storages = arrayOf(Storage(file = StoragePathMacros.PROJECT_FILE))) private class TestComponent : PersistentStateComponent { private var state: TestState? = null @@ -94,8 +96,8 @@ class ProjectStoreTest { data class TestState(var value: String = "default") - public Test fun directoryBasedStorage() { - loadProject(tempDirManager, { + @Test fun directoryBasedStorage() { + loadAndUseProject(tempDirManager, { it.writeChild("${Project.DIRECTORY_STORE_FOLDER}/misc.xml", iprFileContent) it.path }) { project -> @@ -112,8 +114,8 @@ class ProjectStoreTest { } } - public Test fun fileBasedStorage() { - loadProject(tempDirManager, { it.writeChild("test${ProjectFileType.DOT_DEFAULT_EXTENSION}", iprFileContent).path }) { project -> + @Test fun fileBasedStorage() { + loadAndUseProject(tempDirManager, { it.writeChild("test${ProjectFileType.DOT_DEFAULT_EXTENSION}", iprFileContent).path }) { project -> test(project) } } diff --git a/platform/configuration-store-impl/testSrc/SchemeManagerTest.kt b/platform/configuration-store-impl/testSrc/SchemeManagerTest.kt index 91c25b201d02..da842436ca58 100644 --- a/platform/configuration-store-impl/testSrc/SchemeManagerTest.kt +++ b/platform/configuration-store-impl/testSrc/SchemeManagerTest.kt @@ -49,26 +49,26 @@ val FILE_SPEC = "REMOTE" */ class SchemeManagerTest { companion object { - ClassRule val projectRule = ProjectRule() + @ClassRule val projectRule = ProjectRule() } private val tempDirManager = TemporaryDirectory() - public Rule fun getTemporaryFolder(): TemporaryDirectory = tempDirManager + @Rule fun getTemporaryFolder() = tempDirManager private var localBaseDir: File? = null private var remoteBaseDir: File? = null private fun getTestDataPath() = PlatformTestUtil.getCommunityPath().replace(File.separatorChar, '/') + "/platform/platform-tests/testData/options" - public Test fun testLoadSchemes() { + @Test fun testLoadSchemes() { doLoadSaveTest("options1", "1->first;2->second") } - public Test fun testLoadSimpleSchemes() { + @Test fun testLoadSimpleSchemes() { doLoadSaveTest("options", "1->1") } - public Test fun testDeleteScheme() { + @Test fun testDeleteScheme() { val manager = createAndLoad("options1") manager.removeScheme(TestScheme("first")) manager.save() @@ -76,7 +76,7 @@ class SchemeManagerTest { checkSchemes("2->second") } - public Test fun testRenameScheme() { + @Test fun testRenameScheme() { val manager = createAndLoad("options1") val scheme = manager.findSchemeByName("first") @@ -87,7 +87,7 @@ class SchemeManagerTest { checkSchemes("2->second;renamed->renamed") } - public Test fun testRenameScheme2() { + @Test fun testRenameScheme2() { val manager = createAndLoad("options1") val first = manager.findSchemeByName("first") @@ -103,7 +103,7 @@ class SchemeManagerTest { checkSchemes("1->1;2->2") } - public Test fun testDeleteRenamedScheme() { + @Test fun testDeleteRenamedScheme() { val manager = createAndLoad("options1") val firstScheme = manager.findSchemeByName("first") @@ -123,7 +123,7 @@ class SchemeManagerTest { checkSchemes(localBaseDir!!, "", false) } - public Test fun testDeleteAndCreateSchemeWithTheSameName() { + @Test fun testDeleteAndCreateSchemeWithTheSameName() { val manager = createAndLoad("options1") val firstScheme = manager.findSchemeByName("first") assertThat(firstScheme).isNotNull() @@ -134,7 +134,7 @@ class SchemeManagerTest { checkSchemes("2->second;first->first") } - public Test fun testGenerateUniqueSchemeName() { + @Test fun testGenerateUniqueSchemeName() { val manager = createAndLoad("options1") val scheme = TestScheme("first") manager.addNewScheme(scheme, false) @@ -146,7 +146,7 @@ class SchemeManagerTest { FileUtil.writeToFile(file, _serialize().toByteArray()) } - public Test fun `different extensions`() { + @Test fun `different extensions`() { val dir = tempDirManager.newDirectory() val scheme = TestScheme("local", "true") @@ -159,7 +159,7 @@ class SchemeManagerTest { override fun getSchemeExtension() = ".icls" }, null, dir) schemesManager.loadSchemes() - assertThat(schemesManager.getAllSchemes()).containsOnly(scheme) + assertThat(schemesManager.allSchemes).containsOnly(scheme) assertThat(File(dir, "1.icls")).isFile() assertThat(File(dir, "1.xml")).isFile() @@ -171,16 +171,16 @@ class SchemeManagerTest { assertThat(File(dir, "1.xml")).doesNotExist() } - public Test fun setSchemes() { + @Test fun setSchemes() { val dir = tempDirManager.newDirectory() val schemeManager = createSchemeManager(dir) schemeManager.loadSchemes() - assertThat(schemeManager.getAllSchemes()).isEmpty() + assertThat(schemeManager.allSchemes).isEmpty() val scheme = TestScheme("s1") schemeManager.setSchemes(listOf(scheme)) - val schemes = schemeManager.getAllSchemes() + val schemes = schemeManager.allSchemes assertThat(schemes).containsOnly(scheme) assertThat(File(dir, "s1.xml")).doesNotExist() @@ -197,13 +197,13 @@ class SchemeManagerTest { assertThat(dir).doesNotExist() } - public Test fun `save only if scheme differs from bundled`() { + @Test fun `save only if scheme differs from bundled`() { val dir = tempDirManager.newDirectory() var schemeManager = createSchemeManager(dir) - val converter: (Element) -> TestScheme = { XmlSerializer.deserialize(it, javaClass())!! } + val converter: (Element) -> TestScheme = { XmlSerializer.deserialize(it, TestScheme::class.java)!! } val bundledPath = "/bundledSchemes/default" schemeManager.loadBundledScheme(bundledPath, this, converter) - var schemes = schemeManager.getAllSchemes() + var schemes = schemeManager.allSchemes val customScheme = TestScheme("default") assertThat(schemes).containsOnly(customScheme) @@ -214,7 +214,7 @@ class SchemeManagerTest { schemeManager.setSchemes(listOf(customScheme)) assertThat(dir).doesNotExist() - schemes = schemeManager.getAllSchemes() + schemes = schemeManager.allSchemes assertThat(schemes).containsOnly(customScheme) customScheme.data = "foo" @@ -225,11 +225,11 @@ class SchemeManagerTest { schemeManager.loadBundledScheme(bundledPath, this, converter) schemeManager.loadSchemes() - schemes = schemeManager.getAllSchemes() + schemes = schemeManager.allSchemes assertThat(schemes).containsOnly(customScheme) } - public Test fun `don't remove dir if no schemes but at least one non-hidden file exists`() { + @Test fun `don't remove dir if no schemes but at least one non-hidden file exists`() { val dir = tempDirManager.newDirectory() val schemeManager = createSchemeManager(dir) @@ -251,7 +251,7 @@ class SchemeManagerTest { assertThat(dir).isDirectory() } - public Test fun `remove empty directory only if some file was deleted`() { + @Test fun `remove empty directory only if some file was deleted`() { val dir = tempDirManager.newDirectory() val schemeManager = createSchemeManager(dir) schemeManager.loadSchemes() @@ -269,16 +269,16 @@ class SchemeManagerTest { assertThat(dir).doesNotExist() } - public Test fun rename() { + @Test fun rename() { val dir = tempDirManager.newDirectory() val schemeManager = createSchemeManager(dir) schemeManager.loadSchemes() - assertThat(schemeManager.getAllSchemes()).isEmpty() + assertThat(schemeManager.allSchemes).isEmpty() val scheme = TestScheme("s1") schemeManager.setSchemes(listOf(scheme)) - val schemes = schemeManager.getAllSchemes() + val schemes = schemeManager.allSchemes assertThat(schemes).containsOnly(scheme) assertThat(File(dir, "s1.xml")).doesNotExist() @@ -296,11 +296,11 @@ class SchemeManagerTest { assertThat(File(dir, "s2.xml")).isFile() } - public Test fun `path must not contains ROOT_CONFIG macro`() { + @Test fun `path must not contains ROOT_CONFIG macro`() { assertThatThrownBy({ SchemesManagerFactory.getInstance().create("\$ROOT_CONFIG$/foo", TestSchemesProcessor()) }).hasMessage("Path must not contains ROOT_CONFIG macro, corrected: foo") } - public Test fun `path must be system-independent`() { + @Test fun `path must be system-independent`() { assertThatThrownBy({SchemesManagerFactory.getInstance().create("foo\\bar", TestSchemesProcessor())}).hasMessage("Path must be system-independent, use forward slash instead of backslash") } @@ -369,20 +369,20 @@ private fun checkSchemes(baseDir: File, expected: String, ignoreDeleted: Boolean } } -Tag("scheme") -public data class TestScheme(@Attribute private var name: String = "", @Attribute public var data: String? = null) : ExternalizableScheme { +@Tag("scheme") +data class TestScheme(@field:Attribute private var name: String = "", @field:Attribute var data: String? = null) : ExternalizableScheme { override fun getName() = name - override Transient fun setName(newName: String) { + override @Transient fun setName(newName: String) { name = newName } - @suppress("DEPRECATED_SYMBOL_WITH_MESSAGE") + @Suppress("DEPRECATED_SYMBOL_WITH_MESSAGE") override fun getExternalInfo() = null } public open class TestSchemesProcessor : BaseSchemeProcessor() { - override fun readScheme(element: Element) = XmlSerializer.deserialize(element, javaClass()) + override fun readScheme(element: Element) = XmlSerializer.deserialize(element, TestScheme::class.java) override fun writeScheme(scheme: TestScheme) = scheme._serialize() } @@ -390,7 +390,7 @@ public open class TestSchemesProcessor : BaseSchemeProcessor() { fun SchemeManagerImpl<*, *>.save() { val errors = SmartList() save(errors) - CompoundRuntimeException.doThrow(errors) + CompoundRuntimeException.throwIfNotEmpty(errors) } public fun T._serialize(filter: SerializationFilter? = SkipDefaultValuesSerializationFilters()): Element = XmlSerializer.serialize(this, filter) \ No newline at end of file diff --git a/platform/configuration-store-impl/testSrc/StoreTestSuite.kt b/platform/configuration-store-impl/testSrc/StoreTestSuite.kt index 07759bbd03fb..e9cfdcae4c69 100644 --- a/platform/configuration-store-impl/testSrc/StoreTestSuite.kt +++ b/platform/configuration-store-impl/testSrc/StoreTestSuite.kt @@ -19,8 +19,8 @@ import org.junit.runner.RunWith import org.junit.runners.Suite // All in package is very slow, so, we have to use Suite to speedup -RunWith(Suite::class) -Suite.SuiteClasses( +@RunWith(Suite::class) +@Suite.SuiteClasses( ApplicationStoreTest::class, ProjectStoreTest::class, DefaultProjectStoreTest::class, ModuleStoreTest::class, ModuleStoreRenameTest::class, diff --git a/platform/configuration-store-impl/testSrc/XmlElementStorageTest.kt b/platform/configuration-store-impl/testSrc/XmlElementStorageTest.kt index f94298331401..7a80a34c7c3d 100644 --- a/platform/configuration-store-impl/testSrc/XmlElementStorageTest.kt +++ b/platform/configuration-store-impl/testSrc/XmlElementStorageTest.kt @@ -24,7 +24,7 @@ import org.junit.Test class XmlElementStorageTest { @Test fun testGetStateSucceeded() { val storage = MyXmlElementStorage(tag("root", tag("component", attr("name", "test"), tag("foo")))) - val state = storage.getState(this, "test", javaClass()) + val state = storage.getState(this, "test", Element::class.java) assertThat(state).isNotNull() assertThat(state!!.getName()).isEqualTo("component") assertThat(state.getChild("foo")).isNotNull() @@ -32,7 +32,7 @@ class XmlElementStorageTest { @Test fun `get state not succeeded`() { val storage = MyXmlElementStorage(tag("root")) - val state = storage.getState(this, "test", javaClass()) + val state = storage.getState(this, "test", Element::class.java) assertThat(state).isNull() } diff --git a/platform/core-api/src/com/intellij/psi/PsiDocumentManager.java b/platform/core-api/src/com/intellij/psi/PsiDocumentManager.java index 36299685bc51..7ae80097923f 100644 --- a/platform/core-api/src/com/intellij/psi/PsiDocumentManager.java +++ b/platform/core-api/src/com/intellij/psi/PsiDocumentManager.java @@ -125,6 +125,17 @@ public abstract class PsiDocumentManager { */ public abstract long getLastCommittedStamp(@NotNull Document document); + /** + * Returns the document for specified PsiFile intended to be used when working with committed PSI, e.g. outside dispatch thread. + * @param file the file for which the document is requested. + * @return an immutable document corresponding to the current PSI state. For committed documents, the contents and timestamp are equal to + * the ones of {@link #getDocument(PsiFile)}. For uncommitted documents, the text is {@link #getLastCommittedText(Document)} and + * the modification stamp is {@link #getLastCommittedStamp(Document)}. + * @since 143.* builds + */ + @Nullable + public abstract Document getLastCommittedDocument(@NotNull PsiFile file); + /** * Returns the list of documents which have been modified but not committed. * diff --git a/platform/core-api/src/com/intellij/psi/tree/ILazyParseableElementType.java b/platform/core-api/src/com/intellij/psi/tree/ILazyParseableElementType.java index 27a39aeec605..6c64dd0165cf 100644 --- a/platform/core-api/src/com/intellij/psi/tree/ILazyParseableElementType.java +++ b/platform/core-api/src/com/intellij/psi/tree/ILazyParseableElementType.java @@ -47,6 +47,23 @@ public class ILazyParseableElementType extends IElementType { super(debugName, language, register); } + /** + * Parses the contents of the specified chameleon node and returns PsiBuilder. + * In future this method should deprecate all other parsing methods: parseContents(), doParseContents(), etc. + * It provides more flexible and CPU/memory efficient access to parser algorithms for all needs: + * editing, indexing and analysis. + *

+ * + * The parseContent() implementation in terms of parseLight() is just the following: + * {@code}parseLight().getTreeBuilt().getFirstChildNode(){@code} + * + * @param chameleon the node to parse. + * @return the parsed contents of the node in the form PsiBuilder. + */ + public PsiBuilder parseLight(ASTNode chameleon) { + throw new UnsupportedOperationException(String.valueOf(chameleon)); + } + /** * Parses the contents of the specified chameleon node and returns the AST tree * representing the parsed contents. @@ -54,13 +71,13 @@ public class ILazyParseableElementType extends IElementType { * @param chameleon the node to parse. * @return the parsed contents of the node. */ - public ASTNode parseContents(final ASTNode chameleon) { - final PsiElement parentElement = chameleon.getTreeParent().getPsi(); - assert parentElement != null : "Bad chameleon: " + chameleon; + public ASTNode parseContents(ASTNode chameleon) { + PsiElement parentElement = chameleon.getTreeParent().getPsi(); + assert parentElement != null : "parent psi is null: " + chameleon; return doParseContents(chameleon, parentElement); } - protected ASTNode doParseContents(@NotNull final ASTNode chameleon, @NotNull final PsiElement psi) { + protected ASTNode doParseContents(@NotNull ASTNode chameleon, @NotNull PsiElement psi) { Project project = psi.getProject(); Language languageForParser = getLanguageForParser(psi); PsiBuilder builder = PsiBuilderFactory.getInstance().createBuilder(project, chameleon, null, languageForParser, chameleon.getChars()); diff --git a/platform/core-api/src/com/intellij/psi/util/CachedValuesManager.java b/platform/core-api/src/com/intellij/psi/util/CachedValuesManager.java index 84064746e0b6..a5c23298b670 100644 --- a/platform/core-api/src/com/intellij/psi/util/CachedValuesManager.java +++ b/platform/core-api/src/com/intellij/psi/util/CachedValuesManager.java @@ -123,8 +123,13 @@ public abstract class CachedValuesManager { * @return The cached value */ public static T getCachedValue(@NotNull final PsiElement psi, @NotNull final CachedValueProvider provider) { - CachedValuesManager manager = getManager(psi.getProject()); - return manager.getCachedValue(psi, manager.getKeyForClass(provider.getClass()), new CachedValueProvider() { + Key> key = getKeyForClass(provider.getClass(), globalKeyForProvider); + CachedValue value = psi.getUserData(key); + if (value != null) { + return value.getValue(); + } + + return getManager(psi.getProject()).getCachedValue(psi, key, new CachedValueProvider() { @Nullable @Override public Result compute() { @@ -138,8 +143,15 @@ public abstract class CachedValuesManager { } private final ConcurrentMap> keyForProvider = ContainerUtil.newConcurrentMap(); + private static final ConcurrentMap> globalKeyForProvider = ContainerUtil.newConcurrentMap(); + @NotNull public Key> getKeyForClass(@NotNull Class providerClass) { + return getKeyForClass(providerClass, keyForProvider); + } + + @NotNull + private static Key> getKeyForClass(@NotNull Class providerClass, ConcurrentMap> keyForProvider) { String name = providerClass.getName(); assert name != null : providerClass + " doesn't have a name; can't be used for cache value provider"; Key key = keyForProvider.get(name); diff --git a/platform/core-api/src/com/intellij/util/ExecutorsQuery.java b/platform/core-api/src/com/intellij/util/ExecutorsQuery.java index 1b4bedc24fbb..fda929cc77ab 100644 --- a/platform/core-api/src/com/intellij/util/ExecutorsQuery.java +++ b/platform/core-api/src/com/intellij/util/ExecutorsQuery.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * 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. @@ -17,6 +17,7 @@ package com.intellij.util; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.ProcessCanceledException; +import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.IndexNotReadyException; import org.jetbrains.annotations.NotNull; @@ -40,6 +41,7 @@ public final class ExecutorsQuery extends AbstractQuery consumer) { for (QueryExecutor executor : myExecutors) { try { + ProgressManager.checkCanceled(); if (!executor.execute(myParameters, consumer)) { return false; } diff --git a/platform/core-impl/src/com/intellij/openapi/application/impl/ApplicationInfoImpl.java b/platform/core-impl/src/com/intellij/openapi/application/impl/ApplicationInfoImpl.java index d42d26f24198..b544bfef1dad 100644 --- a/platform/core-impl/src/com/intellij/openapi/application/impl/ApplicationInfoImpl.java +++ b/platform/core-impl/src/com/intellij/openapi/application/impl/ApplicationInfoImpl.java @@ -19,9 +19,9 @@ import com.intellij.ide.plugins.PluginManagerCore; import com.intellij.openapi.application.ApplicationNamesInfo; import com.intellij.openapi.application.PathManager; import com.intellij.openapi.application.ex.ApplicationInfoEx; -import com.intellij.openapi.components.NamedComponent; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.util.*; +import com.intellij.openapi.util.BuildNumber; +import com.intellij.openapi.util.JDOMUtil; import com.intellij.openapi.util.text.StringUtil; import com.intellij.ui.JBColor; import com.intellij.util.ArrayUtil; @@ -45,7 +45,7 @@ import java.util.List; import java.util.jar.JarEntry; import java.util.jar.JarFile; -public class ApplicationInfoImpl extends ApplicationInfoEx implements JDOMExternalizable, NamedComponent { +public class ApplicationInfoImpl extends ApplicationInfoEx { private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.application.impl.ApplicationInfoImpl"); private String myCodeName = null; @@ -187,6 +187,19 @@ public class ApplicationInfoImpl extends ApplicationInfoEx implements JDOMExtern private static final String DEFAULT_PLUGINS_HOST = "http://plugins.jetbrains.com"; + ApplicationInfoImpl() { + try { + Document doc = JDOMUtil.loadDocument(ApplicationInfoImpl.class, IDEA_PATH + ApplicationNamesInfo.getComponentName() + XML_EXTENSION); + loadState(doc.getRootElement()); + } + catch (FileNotFoundException e) { + LOG.error("Resource is not in classpath or wrong platform prefix: " + System.getProperty(PlatformUtils.PLATFORM_PREFIX_KEY), e); + } + catch (Exception e) { + LOG.error(e); + } + } + @Override public Calendar getBuildDate() { return myBuildDate; @@ -536,22 +549,11 @@ public class ApplicationInfoImpl extends ApplicationInfoEx implements JDOMExtern public static ApplicationInfoEx getShadowInstance() { if (ourShadowInstance == null) { ourShadowInstance = new ApplicationInfoImpl(); - try { - Document doc = JDOMUtil.loadDocument(ApplicationInfoImpl.class, IDEA_PATH + ApplicationNamesInfo.getComponentName() + XML_EXTENSION); - ourShadowInstance.readExternal(doc.getRootElement()); - } - catch (FileNotFoundException e) { - LOG.error("Resource is not in classpath or wrong platform prefix: " + System.getProperty(PlatformUtils.PLATFORM_PREFIX_KEY), e); - } - catch (Exception e) { - LOG.error(e); - } } return ourShadowInstance; } - @Override - public void readExternal(Element parentNode) throws InvalidDataException { + private void loadState(Element parentNode) { Element versionElement = parentNode.getChild(ELEMENT_VERSION); if (versionElement != null) { myMajorVersion = versionElement.getAttributeValue(ATTRIBUTE_MAJOR); @@ -845,11 +847,6 @@ public class ApplicationInfoImpl extends ApplicationInfoEx implements JDOMExtern return new Color((int)rgb, rgb > 0xffffff); } - @Override - public void writeExternal(Element element) throws WriteExternalException { - throw new WriteExternalException(); - } - @Override public List getPluginChooserPages() { return myPluginChooserPages; @@ -860,12 +857,6 @@ public class ApplicationInfoImpl extends ApplicationInfoEx implements JDOMExtern return PluginManagerCore.CORE_PLUGIN_ID.equals(pluginId) || ArrayUtil.contains(pluginId, myEssentialPluginsIds); } - @Override - @NotNull - public String getComponentName() { - return ApplicationNamesInfo.getComponentName(); - } - private static class UpdateUrlsImpl implements UpdateUrls { private String myCheckingUrl; private String myPatchesUrl; diff --git a/platform/core-impl/src/com/intellij/pom/core/impl/PomModelImpl.java b/platform/core-impl/src/com/intellij/pom/core/impl/PomModelImpl.java index a37613c76fb0..9761e4882cc5 100644 --- a/platform/core-impl/src/com/intellij/pom/core/impl/PomModelImpl.java +++ b/platform/core-impl/src/com/intellij/pom/core/impl/PomModelImpl.java @@ -210,7 +210,7 @@ public class PomModelImpl extends UserDataHolderBase implements PomModel { finally { DebugUtil.finishPsiModification(); } - if (!throwables.isEmpty()) CompoundRuntimeException.doThrow(throwables); + if (!throwables.isEmpty()) CompoundRuntimeException.throwIfNotEmpty(throwables); } } } diff --git a/platform/core-impl/src/com/intellij/psi/PsiAnchor.java b/platform/core-impl/src/com/intellij/psi/PsiAnchor.java index 635754871769..e99ef0920388 100644 --- a/platform/core-impl/src/com/intellij/psi/PsiAnchor.java +++ b/platform/core-impl/src/com/intellij/psi/PsiAnchor.java @@ -38,7 +38,6 @@ import com.intellij.psi.stubs.StubElement; import com.intellij.psi.stubs.StubTree; import com.intellij.psi.tree.IElementType; import com.intellij.psi.tree.IStubFileElementType; -import com.intellij.psi.util.PsiModificationTracker; import com.intellij.psi.util.PsiUtilCore; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -456,8 +455,6 @@ public abstract class PsiAnchor { private final int myIndex; private final Language myLanguage; private final IStubElementType myElementType; - private final short myCreationModCount; - private final short myCreationStamp; private StubIndexReference(@NotNull final PsiFile file, final int index, @NotNull Language language, IStubElementType elementType) { myLanguage = language; @@ -465,16 +462,6 @@ public abstract class PsiAnchor { myVirtualFile = file.getVirtualFile(); myProject = file.getProject(); myIndex = index; - myCreationModCount = getModCount(); - myCreationStamp = (short)file.getModificationStamp(); - } - - private short getModCount() { - final PsiModificationTracker tracker = PsiManager.getInstance(getProject()).getModificationTracker(); - if (myVirtualFile.getName().endsWith(".java")) { - return (short)tracker.getJavaStructureModificationCount(); - } - return (short)tracker.getModificationCount(); } @Override @@ -521,11 +508,10 @@ public abstract class PsiAnchor { } catch (AssertionError e) { String msg = e.getMessage(); - msg += "\n current (java)modCount=" + getModCount() + "; creation (java)modCount=" + myCreationModCount; if (file == null) { msg += "\n no PSI file"; } else { - msg += "\n current file stamp=" + (short)file.getModificationStamp() + "; creation file stamp=" + myCreationStamp; + msg += "\n current file stamp=" + (short)file.getModificationStamp(); } final Document document = FileDocumentManager.getInstance().getCachedDocument(myVirtualFile); if (document != null) { diff --git a/platform/core-impl/src/com/intellij/psi/impl/PsiCachedValue.java b/platform/core-impl/src/com/intellij/psi/impl/PsiCachedValue.java index 67aef5c6c605..f9f6b0d0115a 100644 --- a/platform/core-impl/src/com/intellij/psi/impl/PsiCachedValue.java +++ b/platform/core-impl/src/com/intellij/psi/impl/PsiCachedValue.java @@ -17,12 +17,15 @@ package com.intellij.psi.impl; import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.ProjectRootModificationTracker; +import com.intellij.openapi.util.Condition; import com.intellij.psi.PsiDirectory; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiManager; import com.intellij.psi.util.PsiModificationTracker; import com.intellij.util.CachedValueBase; +import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -38,8 +41,23 @@ public abstract class PsiCachedValue extends CachedValueBase { } @Override - protected void valueUpdated() { - myLastPsiTimeStamp = myManager.getModificationTracker().getModificationCount(); + protected void valueUpdated(@Nullable Object[] dependencies) { + myLastPsiTimeStamp = hasOnlyPhysicalPsiDependencies(dependencies) ? myManager.getModificationTracker().getModificationCount() : -1; + } + + private static boolean hasOnlyPhysicalPsiDependencies(@Nullable Object[] dependencies) { + return dependencies != null && dependencies.length > 0 && ContainerUtil.and(dependencies, new Condition() { + @Override + public boolean value(Object o) { + return o instanceof PsiElement && ((PsiElement)o).isValid() && ((PsiElement)o).isPhysical() || + o instanceof ProjectRootModificationTracker || + o instanceof PsiModificationTracker || + o == PsiModificationTracker.MODIFICATION_COUNT || + o == PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT || + o == PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT || + o == PsiModificationTracker.JAVA_STRUCTURE_MODIFICATION_COUNT; + } + }); } @Nullable @@ -55,10 +73,7 @@ public abstract class PsiCachedValue extends CachedValueBase { @Override protected boolean isDependencyOutOfDate(Object dependency, long oldTimeStamp) { - if (dependency instanceof PsiElement && - myLastPsiTimeStamp == myManager.getModificationTracker().getModificationCount() && - ((PsiElement)dependency).isValid() && - ((PsiElement)dependency).isPhysical()) { + if (myLastPsiTimeStamp != -1 && myLastPsiTimeStamp == myManager.getModificationTracker().getModificationCount()) { return false; } diff --git a/platform/core-impl/src/com/intellij/psi/impl/PsiDocumentManagerBase.java b/platform/core-impl/src/com/intellij/psi/impl/PsiDocumentManagerBase.java index 6422e6203f1d..2180454bc6c5 100644 --- a/platform/core-impl/src/com/intellij/psi/impl/PsiDocumentManagerBase.java +++ b/platform/core-impl/src/com/intellij/psi/impl/PsiDocumentManagerBase.java @@ -578,6 +578,13 @@ public abstract class PsiDocumentManagerBase extends PsiDocumentManager implemen return getLastCommittedDocument(document).getModificationStamp(); } + @Override + @Nullable + public Document getLastCommittedDocument(@NotNull PsiFile file) { + Document document = getDocument(file); + return document == null ? null : getLastCommittedDocument(document); + } + @NotNull public DocumentEx getLastCommittedDocument(@NotNull Document document) { if (document instanceof FrozenDocument) return (DocumentEx)document; diff --git a/platform/core-impl/src/com/intellij/psi/impl/ResolveScopeManager.java b/platform/core-impl/src/com/intellij/psi/impl/ResolveScopeManager.java index 33b2593a4a52..057b7d6b4514 100644 --- a/platform/core-impl/src/com/intellij/psi/impl/ResolveScopeManager.java +++ b/platform/core-impl/src/com/intellij/psi/impl/ResolveScopeManager.java @@ -19,6 +19,7 @@ import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; import com.intellij.psi.search.GlobalSearchScope; import org.jetbrains.annotations.NotNull; @@ -45,6 +46,10 @@ public abstract class ResolveScopeManager { @NotNull public static GlobalSearchScope getElementResolveScope(@NotNull PsiElement element) { + PsiFile file = element.getContainingFile(); + if (file != null) { + return getInstance(file.getProject()).getResolveScope(file); + } return getInstance(element.getProject()).getResolveScope(element); } } diff --git a/platform/core-impl/src/com/intellij/psi/impl/smartPointers/AnchorElementInfoFactory.java b/platform/core-impl/src/com/intellij/psi/impl/smartPointers/AnchorElementInfoFactory.java index 4c45d1ceed16..a58a58e4aa9b 100644 --- a/platform/core-impl/src/com/intellij/psi/impl/smartPointers/AnchorElementInfoFactory.java +++ b/platform/core-impl/src/com/intellij/psi/impl/smartPointers/AnchorElementInfoFactory.java @@ -29,11 +29,10 @@ import com.intellij.psi.util.PsiUtilCore; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -public class AnchorElementInfoFactory implements SmartPointerElementInfoFactory { +public class AnchorElementInfoFactory extends SmartPointerElementInfoFactory { @Override @Nullable - public SmartPointerElementInfo createElementInfo(@NotNull PsiElement element) { - PsiFile containingFile = element.getContainingFile(); + public SmartPointerElementInfo createElementInfo(@NotNull PsiElement element, @NotNull PsiFile containingFile) { if (element instanceof StubBasedPsiElement && containingFile instanceof PsiFileWithStubSupport) { PsiFileWithStubSupport stubFile = (PsiFileWithStubSupport)containingFile; StubTree stubTree = stubFile.getStubTree(); diff --git a/platform/core-impl/src/com/intellij/psi/impl/smartPointers/SmartPointerElementInfoFactory.java b/platform/core-impl/src/com/intellij/psi/impl/smartPointers/SmartPointerElementInfoFactory.java index 0cc69adb1972..55047f44f9f3 100644 --- a/platform/core-impl/src/com/intellij/psi/impl/smartPointers/SmartPointerElementInfoFactory.java +++ b/platform/core-impl/src/com/intellij/psi/impl/smartPointers/SmartPointerElementInfoFactory.java @@ -18,15 +18,16 @@ package com.intellij.psi.impl.smartPointers; import com.intellij.openapi.extensions.ExtensionPointName; import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; /** * @author yole */ -public interface SmartPointerElementInfoFactory { - ExtensionPointName EP_NAME = ExtensionPointName.create("com.intellij.smartPointerElementInfoFactory"); +public abstract class SmartPointerElementInfoFactory { + public static final ExtensionPointName EP_NAME = ExtensionPointName.create("com.intellij.smartPointerElementInfoFactory"); @Nullable - SmartPointerElementInfo createElementInfo(@NotNull PsiElement element); + public abstract SmartPointerElementInfo createElementInfo(@NotNull PsiElement element, @NotNull PsiFile containingFile); } diff --git a/platform/core-impl/src/com/intellij/psi/impl/smartPointers/SmartPsiElementPointerImpl.java b/platform/core-impl/src/com/intellij/psi/impl/smartPointers/SmartPsiElementPointerImpl.java index e19b364f3cc3..6a0260d5c6f0 100644 --- a/platform/core-impl/src/com/intellij/psi/impl/smartPointers/SmartPsiElementPointerImpl.java +++ b/platform/core-impl/src/com/intellij/psi/impl/smartPointers/SmartPsiElementPointerImpl.java @@ -183,7 +183,7 @@ class SmartPsiElementPointerImpl implements SmartPointerEx } for(SmartPointerElementInfoFactory factory: Extensions.getExtensions(SmartPointerElementInfoFactory.EP_NAME)) { - final SmartPointerElementInfo result = factory.createElementInfo(element); + final SmartPointerElementInfo result = factory.createElementInfo(element, containingFile); if (result != null) return result; } diff --git a/platform/core-impl/src/com/intellij/util/CachedValueBase.java b/platform/core-impl/src/com/intellij/util/CachedValueBase.java index b40dee4b26b6..eae0032d5b20 100644 --- a/platform/core-impl/src/com/intellij/util/CachedValueBase.java +++ b/platform/core-impl/src/com/intellij/util/CachedValueBase.java @@ -182,11 +182,11 @@ public abstract class CachedValueBase { public T setValue(final CachedValueProvider.Result result) { Data data = computeData(result); setData(data); - valueUpdated(); + valueUpdated(result.getDependencyItems()); return data.myValue; } - protected void valueUpdated() {} + protected void valueUpdated(@Nullable Object[] dependencies) {} public abstract boolean isFromMyProject(Project project); @@ -227,7 +227,7 @@ public abstract class CachedValueBase { boolean reuse = alreadyComputed != null && isUpToDate(alreadyComputed); Data toReturn = cacheOrGetData(alreadyComputed, reuse ? null : data); if (toReturn != null) { - valueUpdated(); + valueUpdated(toReturn.myDependencies); return toReturn.myValue; } } diff --git a/platform/diff-impl/src/com/intellij/diff/merge/MergeUtil.java b/platform/diff-impl/src/com/intellij/diff/merge/MergeUtil.java index 004915250a35..bc196709a352 100644 --- a/platform/diff-impl/src/com/intellij/diff/merge/MergeUtil.java +++ b/platform/diff-impl/src/com/intellij/diff/merge/MergeUtil.java @@ -16,12 +16,16 @@ package com.intellij.diff.merge; import com.intellij.diff.DiffContext; +import com.intellij.diff.util.DiffUserDataKeysEx; +import com.intellij.diff.util.DiffUtil; import com.intellij.diff.util.ThreeSide; import com.intellij.openapi.diff.DiffBundle; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.Messages; +import com.intellij.openapi.util.Couple; import com.intellij.openapi.util.Key; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.util.Function; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -32,6 +36,10 @@ import java.util.List; public class MergeUtil { @NotNull public static String getResolveActionTitle(@NotNull MergeResult result, @NotNull MergeRequest request, @NotNull MergeContext context) { + Function getter = DiffUtil.getUserData(request, context, DiffUserDataKeysEx.MERGE_ACTION_CAPTIONS); + String message = getter != null ? getter.fun(result) : null; + if (message != null) return message; + switch (result) { case CANCEL: return "Abort"; @@ -95,9 +103,15 @@ public class MergeUtil { } public static boolean showExitWithoutApplyingChangesDialog(@NotNull JComponent component, @NotNull MergeRequest request, @NotNull MergeContext context) { - return Messages.showYesNoDialog(component.getRootPane(), - DiffBundle.message("merge.dialog.exit.without.applying.changes.confirmation.message"), - DiffBundle.message("cancel.visual.merge.dialog.title"), Messages.getQuestionIcon()) == - Messages.YES; + String message = DiffBundle.message("merge.dialog.exit.without.applying.changes.confirmation.message"); + String title = DiffBundle.message("cancel.visual.merge.dialog.title"); + + Couple customMessage = DiffUtil.getUserData(request, context, DiffUserDataKeysEx.MERGE_CANCEL_MESSAGE); + if (customMessage != null) { + title = customMessage.first; + message = customMessage.second; + } + + return Messages.showYesNoDialog(component.getRootPane(), message, title, Messages.getQuestionIcon()) == Messages.YES; } } diff --git a/platform/diff-impl/src/com/intellij/diff/merge/TextMergeChange.java b/platform/diff-impl/src/com/intellij/diff/merge/TextMergeChange.java index 65ca19ba277f..d73116dd8d71 100644 --- a/platform/diff-impl/src/com/intellij/diff/merge/TextMergeChange.java +++ b/platform/diff-impl/src/com/intellij/diff/merge/TextMergeChange.java @@ -299,7 +299,7 @@ public class TextMergeChange extends ThreesideDiffChangeBase { @Nullable private GutterIconRenderer createApplyRenderer(@NotNull final Side side, final boolean modifier) { if (isResolved(side)) return null; - Icon icon = isOnesideAppliedConflict() ? AllIcons.Diff.ArrowLeftDown : AllIcons.Diff.Arrow; + Icon icon = isOnesideAppliedConflict() ? DiffUtil.getArrowDownIcon(side) : DiffUtil.getArrowIcon(side); return createIconRenderer(DiffBundle.message("merge.dialog.apply.change.action.name"), icon, isConflict(), new Runnable() { @Override public void run() { diff --git a/platform/diff-impl/src/com/intellij/diff/merge/TextMergeTool.java b/platform/diff-impl/src/com/intellij/diff/merge/TextMergeTool.java index 4bef4e6374d2..b4c332bbdabe 100644 --- a/platform/diff-impl/src/com/intellij/diff/merge/TextMergeTool.java +++ b/platform/diff-impl/src/com/intellij/diff/merge/TextMergeTool.java @@ -417,7 +417,7 @@ public class TextMergeTool implements MergeTool { return apply(mergeFragments, outputModificationStamp); } catch (DiffTooBigException e) { - return applyNotification(DiffNotifications.DIFF_TOO_BIG); + return applyNotification(DiffNotifications.createDiffTooBig()); } catch (ProcessCanceledException e) { throw e; diff --git a/platform/diff-impl/src/com/intellij/diff/tools/binary/OnesideBinaryDiffViewer.java b/platform/diff-impl/src/com/intellij/diff/tools/binary/OnesideBinaryDiffViewer.java index 685244df70d9..faad7f9b8ff7 100644 --- a/platform/diff-impl/src/com/intellij/diff/tools/binary/OnesideBinaryDiffViewer.java +++ b/platform/diff-impl/src/com/intellij/diff/tools/binary/OnesideBinaryDiffViewer.java @@ -43,7 +43,7 @@ public class OnesideBinaryDiffViewer extends OnesideDiffViewer() { @@ -98,14 +98,14 @@ public class TwosideBinaryDiffViewer extends TwosideDiffViewer group = new ArrayList(); group.add(new ReplaceSelectedChangesAction(Side.LEFT, false)); - group.add(new AppendSelectedChangesAction(Side.LEFT, false)); group.add(new ReplaceSelectedChangesAction(Side.RIGHT, false)); + group.add(new AppendSelectedChangesAction(Side.LEFT, false)); group.add(new AppendSelectedChangesAction(Side.RIGHT, false)); - group.add(new RevertSelectedChangesAction(Side.LEFT)); - group.add(new RevertSelectedChangesAction(Side.RIGHT)); group.add(Separator.getInstance()); group.addAll(TextDiffViewerUtil.createEditorPopupActions()); @@ -383,7 +380,7 @@ public class UnifiedDiffViewer extends ListenerDiffViewerBase { myFoldingModel.updateContext(myRequest, getFoldingModelSettings()); clearDiffPresentation(); - if (isEqual) myPanel.addNotification(DiffNotifications.EQUAL_CONTENTS); + if (isEqual) myPanel.addNotification(DiffNotifications.createEqualContents()); TIntFunction separatorLines = myFoldingModel.getLineNumberConvertor(); myEditor.getGutterComponentEx().setLineNumberConvertor(mergeConverters(data.getLineConvertor1(), separatorLines), @@ -648,7 +645,7 @@ public class UnifiedDiffViewer extends ListenerDiffViewerBase { private abstract class ApplySelectedChangesActionBase extends AnAction implements DumbAware { @NotNull protected final Side myModifiedSide; - private final boolean myShortcut; + protected final boolean myShortcut; public ApplySelectedChangesActionBase(@NotNull Side modifiedSide, boolean shortcut) { myModifiedSide = modifiedSide; @@ -674,6 +671,7 @@ public class UnifiedDiffViewer extends ListenerDiffViewerBase { return; } + e.getPresentation().setText(getText()); e.getPresentation().setVisible(true); e.getPresentation().setEnabled(isSomeChangeSelected()); } @@ -714,6 +712,9 @@ public class UnifiedDiffViewer extends ListenerDiffViewerBase { return false; } + @NotNull + public abstract String getText(); + @CalledWithWriteLock protected abstract void apply(@NotNull List changes); } @@ -723,8 +724,19 @@ public class UnifiedDiffViewer extends ListenerDiffViewerBase { super(focusedSide.other(), shortcut); setShortcutSet(ActionManager.getInstance().getAction(focusedSide.select("Diff.ApplyLeftSide", "Diff.ApplyRightSide")).getShortcutSet()); - getTemplatePresentation().setText("Replace"); - getTemplatePresentation().setIcon(focusedSide.select(AllIcons.Diff.ArrowRight, AllIcons.Diff.Arrow)); + getTemplatePresentation().setIcon(DiffUtil.getArrowIcon(focusedSide)); + } + + @NotNull + @Override + public String getText() { + boolean bothEditable = isEditable(Side.LEFT, true) && isEditable(Side.RIGHT, true); + if (bothEditable) { + return myModifiedSide.select("Apply After", "Apply Before"); + } + else { + return "Apply"; + } } @Override @@ -740,8 +752,19 @@ public class UnifiedDiffViewer extends ListenerDiffViewerBase { super(focusedSide.other(), shortcut); setShortcutSet(ActionManager.getInstance().getAction(focusedSide.select("Diff.AppendLeftSide", "Diff.AppendRightSide")).getShortcutSet()); - getTemplatePresentation().setText("Insert"); - getTemplatePresentation().setIcon(focusedSide.select(AllIcons.Diff.ArrowRightDown, AllIcons.Diff.ArrowLeftDown)); + getTemplatePresentation().setIcon(DiffUtil.getArrowDownIcon(focusedSide)); + } + + @NotNull + @Override + public String getText() { + boolean bothEditable = isEditable(Side.LEFT, true) && isEditable(Side.RIGHT, true); + if (bothEditable) { + return myModifiedSide.select("Append Right Side", "Append Left Side"); + } + else { + return "Append"; + } } @Override @@ -752,21 +775,6 @@ public class UnifiedDiffViewer extends ListenerDiffViewerBase { } } - private class RevertSelectedChangesAction extends ApplySelectedChangesActionBase { - public RevertSelectedChangesAction(@NotNull Side focusedSide) { - super(focusedSide, false); - getTemplatePresentation().setText("Revert"); - getTemplatePresentation().setIcon(AllIcons.Diff.Remove); - } - - @Override - protected void apply(@NotNull List changes) { - for (UnifiedDiffChange change : changes) { - replaceChange(change, myModifiedSide.other()); - } - } - } - @CalledWithWriteLock public void replaceChange(@NotNull UnifiedDiffChange change, @NotNull Side sourceSide) { Side outputSide = sourceSide.other(); diff --git a/platform/diff-impl/src/com/intellij/diff/tools/simple/SimpleDiffChange.java b/platform/diff-impl/src/com/intellij/diff/tools/simple/SimpleDiffChange.java index 1e4c1f15476a..18fca2dd16e6 100644 --- a/platform/diff-impl/src/com/intellij/diff/tools/simple/SimpleDiffChange.java +++ b/platform/diff-impl/src/com/intellij/diff/tools/simple/SimpleDiffChange.java @@ -267,7 +267,7 @@ public class SimpleDiffChange { @Nullable private GutterIconRenderer createApplyRenderer(@NotNull final Side side) { - return createIconRenderer(side, "Replace", AllIcons.Diff.Arrow, new Runnable() { + return createIconRenderer(side, "Replace", DiffUtil.getArrowIcon(side), new Runnable() { @Override public void run() { myViewer.replaceChange(SimpleDiffChange.this, side); @@ -277,7 +277,7 @@ public class SimpleDiffChange { @Nullable private GutterIconRenderer createAppendRenderer(@NotNull final Side side) { - return createIconRenderer(side, "Insert", AllIcons.Diff.ArrowLeftDown, new Runnable() { + return createIconRenderer(side, "Insert", DiffUtil.getArrowDownIcon(side), new Runnable() { @Override public void run() { myViewer.appendChange(SimpleDiffChange.this, side); diff --git a/platform/diff-impl/src/com/intellij/diff/tools/simple/SimpleDiffViewer.java b/platform/diff-impl/src/com/intellij/diff/tools/simple/SimpleDiffViewer.java index d33009779ff7..362e67da80a8 100644 --- a/platform/diff-impl/src/com/intellij/diff/tools/simple/SimpleDiffViewer.java +++ b/platform/diff-impl/src/com/intellij/diff/tools/simple/SimpleDiffViewer.java @@ -216,14 +216,14 @@ public class SimpleDiffViewer extends TwosideTextDiffViewer { return apply(new CompareData(lineFragments, isEqualContents)); } catch (DiffTooBigException e) { - return applyNotification(DiffNotifications.DIFF_TOO_BIG); + return applyNotification(DiffNotifications.createDiffTooBig()); } catch (ProcessCanceledException e) { throw e; } catch (Throwable e) { LOG.error(e); - return applyNotification(DiffNotifications.ERROR); + return applyNotification(DiffNotifications.createError()); } } @@ -235,7 +235,7 @@ public class SimpleDiffViewer extends TwosideTextDiffViewer { myFoldingModel.updateContext(myRequest, getFoldingModelSettings()); clearDiffPresentation(); - if (data.isEqualContent()) myPanel.addNotification(DiffNotifications.EQUAL_CONTENTS); + if (data.isEqualContent()) myPanel.addNotification(DiffNotifications.createEqualContents()); if (data.getFragments() != null) { for (LineFragment fragment : data.getFragments()) { @@ -589,7 +589,7 @@ public class SimpleDiffViewer extends TwosideTextDiffViewer { setShortcutSet(ActionManager.getInstance().getAction(focusedSide.select("Diff.ApplyLeftSide", "Diff.ApplyRightSide")).getShortcutSet()); getTemplatePresentation().setText("Replace"); - getTemplatePresentation().setIcon(focusedSide.select(AllIcons.Diff.ArrowRight, AllIcons.Diff.Arrow)); + getTemplatePresentation().setIcon(DiffUtil.getArrowIcon(focusedSide)); } @Override @@ -611,7 +611,7 @@ public class SimpleDiffViewer extends TwosideTextDiffViewer { setShortcutSet(ActionManager.getInstance().getAction(focusedSide.select("Diff.AppendLeftSide", "Diff.AppendRightSide")).getShortcutSet()); getTemplatePresentation().setText("Insert"); - getTemplatePresentation().setIcon(focusedSide.select(AllIcons.Diff.ArrowRightDown, AllIcons.Diff.ArrowLeftDown)); + getTemplatePresentation().setIcon(DiffUtil.getArrowDownIcon(focusedSide)); } @Override diff --git a/platform/diff-impl/src/com/intellij/diff/tools/simple/SimpleThreesideDiffViewer.java b/platform/diff-impl/src/com/intellij/diff/tools/simple/SimpleThreesideDiffViewer.java index bf76d6ca144d..19373a473717 100644 --- a/platform/diff-impl/src/com/intellij/diff/tools/simple/SimpleThreesideDiffViewer.java +++ b/platform/diff-impl/src/com/intellij/diff/tools/simple/SimpleThreesideDiffViewer.java @@ -145,14 +145,14 @@ public class SimpleThreesideDiffViewer extends ThreesideTextDiffViewerEx { return apply(mergeFragments, comparisonPolicy); } catch (DiffTooBigException e) { - return applyNotification(DiffNotifications.DIFF_TOO_BIG); + return applyNotification(DiffNotifications.createDiffTooBig()); } catch (ProcessCanceledException e) { throw e; } catch (Throwable e) { LOG.error(e); - return applyNotification(DiffNotifications.ERROR); + return applyNotification(DiffNotifications.createError()); } } diff --git a/platform/diff-impl/src/com/intellij/diff/tools/util/DiffNotifications.java b/platform/diff-impl/src/com/intellij/diff/tools/util/DiffNotifications.java index 1d5f6565baea..091c801c1429 100644 --- a/platform/diff-impl/src/com/intellij/diff/tools/util/DiffNotifications.java +++ b/platform/diff-impl/src/com/intellij/diff/tools/util/DiffNotifications.java @@ -25,19 +25,46 @@ import javax.swing.*; import java.awt.*; public class DiffNotifications { - @NotNull public static final JPanel INSERTED_CONTENT = - createNotification("Content added", TextDiffType.INSERTED.getColor(null)); - @NotNull public static final JPanel REMOVED_CONTENT = - createNotification("Content removed", TextDiffType.DELETED.getColor(null)); + @Deprecated @NotNull public static final JPanel INSERTED_CONTENT = createInsertedContent(); + @Deprecated @NotNull public static final JPanel REMOVED_CONTENT = createRemovedContent(); + @Deprecated @NotNull public static final JPanel EQUAL_CONTENTS = createEqualContents(); + @Deprecated @NotNull public static final JPanel ERROR = createError(); + @Deprecated @NotNull public static final JPanel OPERATION_CANCELED = createOperationCanceled(); + @Deprecated @NotNull public static final JPanel DIFF_TOO_BIG = createDiffTooBig(); - @NotNull public static final JPanel EQUAL_CONTENTS = - createNotification(DiffBundle.message("diff.contents.are.identical.message.text")); - @NotNull public static final JPanel ERROR = - createNotification("Can not calculate diff"); - @NotNull public static final JPanel OPERATION_CANCELED = - createNotification("Can not calculate diff. Operation canceled."); - @NotNull public static final JPanel DIFF_TOO_BIG = - createNotification("Can not calculate diff. " + DiffTooBigException.MESSAGE); + @NotNull + public static JPanel createInsertedContent() { + return createNotification("Content added", TextDiffType.INSERTED.getColor(null)); + } + + @NotNull + public static JPanel createRemovedContent() { + return createNotification("Content removed", TextDiffType.DELETED.getColor(null)); + } + + @NotNull + public static JPanel createEqualContents() { + return createNotification(DiffBundle.message("diff.contents.are.identical.message.text")); + } + + @NotNull + public static JPanel createError() { + return createNotification("Can not calculate diff"); + } + + @NotNull + public static JPanel createOperationCanceled() { + return createNotification("Can not calculate diff. Operation canceled."); + } + + @NotNull + public static JPanel createDiffTooBig() { + return createNotification("Can not calculate diff. " + DiffTooBigException.MESSAGE); + } + + // + // Impl + // @NotNull public static JPanel createNotification(@NotNull String text) { diff --git a/platform/diff-impl/src/com/intellij/diff/util/DiffUserDataKeysEx.java b/platform/diff-impl/src/com/intellij/diff/util/DiffUserDataKeysEx.java index a2c90ce8e5b2..9b914d7f3f24 100644 --- a/platform/diff-impl/src/com/intellij/diff/util/DiffUserDataKeysEx.java +++ b/platform/diff-impl/src/com/intellij/diff/util/DiffUserDataKeysEx.java @@ -15,9 +15,12 @@ */ package com.intellij.diff.util; +import com.intellij.diff.merge.MergeResult; import com.intellij.openapi.diff.DiffNavigationContext; import com.intellij.openapi.editor.LogicalPosition; +import com.intellij.openapi.util.Couple; import com.intellij.openapi.util.Key; +import com.intellij.util.Function; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -53,4 +56,13 @@ public interface DiffUserDataKeysEx extends DiffUserDataKeys { Key BOTTOM_PANEL = Key.create("Diff.BottomPanel"); // Could implement Disposable Key SHOW_READ_ONLY_LOCK = Key.create("Diff.ShowReadOnlyLock"); + + // + // MergeContext / MergeRequest + // + + // (title, message) + Key> MERGE_CANCEL_MESSAGE = Key.create("Diff.MergeCancelMessage"); + // null -> default + Key> MERGE_ACTION_CAPTIONS = Key.create("Diff.MergeActionCaptions"); } diff --git a/platform/diff-impl/src/com/intellij/diff/util/DiffUtil.java b/platform/diff-impl/src/com/intellij/diff/util/DiffUtil.java index d23457c4e25a..b9dfda2faf40 100644 --- a/platform/diff-impl/src/com/intellij/diff/util/DiffUtil.java +++ b/platform/diff-impl/src/com/intellij/diff/util/DiffUtil.java @@ -32,6 +32,7 @@ import com.intellij.diff.requests.ContentDiffRequest; import com.intellij.diff.requests.DiffRequest; import com.intellij.diff.tools.util.base.HighlightPolicy; import com.intellij.diff.tools.util.base.IgnorePolicy; +import com.intellij.icons.AllIcons; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.DataProvider; import com.intellij.openapi.actionSystem.DefaultActionGroup; @@ -241,6 +242,20 @@ public class DiffUtil { return editor != null ? editor.getCaretModel().getLogicalPosition() : new LogicalPosition(0, 0); } + // + // Icons + // + + @NotNull + public static Icon getArrowIcon(@NotNull Side sourceSide) { + return sourceSide.select(AllIcons.Diff.ArrowRight, AllIcons.Diff.Arrow); + } + + @NotNull + public static Icon getArrowDownIcon(@NotNull Side sourceSide) { + return sourceSide.select(AllIcons.Diff.ArrowRightDown, AllIcons.Diff.ArrowLeftDown); + } + // // UI // @@ -916,25 +931,13 @@ public class DiffUtil { return false; } - public static T getUserData(@Nullable DiffRequest request, @Nullable DiffContext context, @NotNull Key key) { - if (request != null) { - T data = request.getUserData(key); + public static T getUserData(@Nullable UserDataHolder first, @Nullable UserDataHolder second, @NotNull Key key) { + if (first != null) { + T data = first.getUserData(key); if (data != null) return data; } - if (context != null) { - T data = context.getUserData(key); - if (data != null) return data; - } - return null; - } - - public static T getUserData(@Nullable DiffContext context, @Nullable DiffRequest request, @NotNull Key key) { - if (context != null) { - T data = context.getUserData(key); - if (data != null) return data; - } - if (request != null) { - T data = request.getUserData(key); + if (second != null) { + T data = second.getUserData(key); if (data != null) return data; } return null; diff --git a/platform/external-system-impl/testSrc/com/intellij/openapi/externalSystem/test/ExternalSystemTestCase.java b/platform/external-system-impl/testSrc/com/intellij/openapi/externalSystem/test/ExternalSystemTestCase.java index a49845557889..8f7b66b9fec7 100644 --- a/platform/external-system-impl/testSrc/com/intellij/openapi/externalSystem/test/ExternalSystemTestCase.java +++ b/platform/external-system-impl/testSrc/com/intellij/openapi/externalSystem/test/ExternalSystemTestCase.java @@ -44,13 +44,11 @@ import com.intellij.openapi.vfs.*; import com.intellij.openapi.vfs.newvfs.impl.VfsRootAccess; import com.intellij.packaging.artifacts.Artifact; import com.intellij.packaging.impl.compiler.ArtifactCompileScope; -import com.intellij.testFramework.CompilerTester; -import com.intellij.testFramework.IdeaTestUtil; -import com.intellij.testFramework.PsiTestUtil; -import com.intellij.testFramework.UsefulTestCase; +import com.intellij.testFramework.*; import com.intellij.testFramework.fixtures.IdeaProjectTestFixture; import com.intellij.testFramework.fixtures.IdeaTestFixtureFactory; import com.intellij.util.ArrayUtil; +import com.intellij.util.ThrowableRunnable; import com.intellij.util.io.TestFileSystemItem; import gnu.trove.THashSet; import org.jetbrains.annotations.NonNls; @@ -176,16 +174,11 @@ public abstract class ExternalSystemTestCase extends UsefulTestCase { @Override public void tearDown() throws Exception { try { - edt(new Runnable() { + EdtTestUtil.runInEdtAndWait(new ThrowableRunnable() { @Override - public void run() { - try { - CompilerTestUtil.disableExternalCompiler(myProject); - tearDownFixtures(); - } - catch (Exception e) { - throw new RuntimeException(e); - } + public void run() throws Throwable { + CompilerTestUtil.disableExternalCompiler(myProject); + tearDownFixtures(); } }); myProject = null; diff --git a/platform/indexing-api/src/com/intellij/psi/search/searches/ReferenceDescriptor.java b/platform/indexing-api/src/com/intellij/psi/search/searches/ReferenceDescriptor.java index 153b34b8a46b..64fd476aaa16 100644 --- a/platform/indexing-api/src/com/intellij/psi/search/searches/ReferenceDescriptor.java +++ b/platform/indexing-api/src/com/intellij/psi/search/searches/ReferenceDescriptor.java @@ -15,6 +15,7 @@ */ package com.intellij.psi.search.searches; +import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiReference; @@ -31,13 +32,13 @@ public class ReferenceDescriptor { public ReferenceDescriptor fun(PsiReference psiReference) { final PsiElement element = psiReference.getElement(); final PsiFile file = element.getContainingFile(); - return new ReferenceDescriptor(file, element.getTextRange().getStartOffset() + psiReference.getRangeInElement().getStartOffset()); + return new ReferenceDescriptor(file.getViewProvider().getVirtualFile(), element.getTextRange().getStartOffset() + psiReference.getRangeInElement().getStartOffset()); } }; - private final PsiFile file; + private final VirtualFile file; private final int offset; - private ReferenceDescriptor(@NotNull PsiFile file, int offset) { + private ReferenceDescriptor(@NotNull VirtualFile file, int offset) { this.file = file; this.offset = offset; } diff --git a/platform/lang-api/src/com/intellij/usageView/UsageTreeColorsScheme.java b/platform/lang-api/src/com/intellij/usageView/UsageTreeColorsScheme.java index 5eb526877ba6..cfe4274aea92 100644 --- a/platform/lang-api/src/com/intellij/usageView/UsageTreeColorsScheme.java +++ b/platform/lang-api/src/com/intellij/usageView/UsageTreeColorsScheme.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * 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. @@ -15,18 +15,18 @@ */ package com.intellij.usageView; -import com.intellij.openapi.components.NamedComponent; +import com.intellij.openapi.components.PersistentStateComponent; import com.intellij.openapi.components.ServiceManager; +import com.intellij.openapi.components.State; import com.intellij.openapi.editor.colors.EditorColorsManager; import com.intellij.openapi.editor.colors.EditorColorsScheme; import com.intellij.openapi.editor.colors.EditorColorsUtil; -import com.intellij.openapi.util.JDOMExternalizable; -import com.intellij.openapi.util.WriteExternalException; import com.intellij.util.ui.UIUtil; import org.jdom.Element; -import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; -public class UsageTreeColorsScheme implements NamedComponent, JDOMExternalizable { +@State(name = "FindViewColorsScheme", defaultStateAsResource = true, storages = {}) +public class UsageTreeColorsScheme implements PersistentStateComponent { private EditorColorsScheme myColorsScheme; /** @@ -39,26 +39,21 @@ public class UsageTreeColorsScheme implements NamedComponent, JDOMExternalizable return ServiceManager.getService(UsageTreeColorsScheme.class); } - @Override - @NotNull - public String getComponentName() { - return "FindViewColorsScheme"; - } - public EditorColorsScheme getScheme() { return myColorsScheme; } + @Nullable @Override - public void readExternal(Element element) { - if (myColorsScheme == null) { - myColorsScheme = (EditorColorsScheme)EditorColorsUtil.getColorSchemeForBackground(UIUtil.getTreeTextBackground()).clone(); - } - myColorsScheme.readExternal(element); + public Element getState() { + return null; } @Override - public void writeExternal(Element element) throws WriteExternalException { - throw new WriteExternalException(); + public void loadState(Element state) { + if (myColorsScheme == null) { + myColorsScheme = (EditorColorsScheme)EditorColorsUtil.getColorSchemeForBackground(UIUtil.getTreeTextBackground()).clone(); + } + myColorsScheme.readExternal(state); } } diff --git a/platform/lang-impl/src/com/intellij/application/options/colors/ColorAndFontDescriptionPanel.java b/platform/lang-impl/src/com/intellij/application/options/colors/ColorAndFontDescriptionPanel.java index 983677cb4b42..2fcf41cc7901 100644 --- a/platform/lang-impl/src/com/intellij/application/options/colors/ColorAndFontDescriptionPanel.java +++ b/platform/lang-impl/src/com/intellij/application/options/colors/ColorAndFontDescriptionPanel.java @@ -23,14 +23,12 @@ import com.intellij.openapi.options.colors.AttributesDescriptor; import com.intellij.openapi.options.colors.ColorSettingsPage; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.Pair; -import com.intellij.ui.CollectionComboBoxModel; -import com.intellij.ui.ColorPanel; -import com.intellij.ui.HyperlinkAdapter; -import com.intellij.ui.ListCellRendererWrapper; +import com.intellij.ui.*; import com.intellij.ui.components.JBCheckBox; import com.intellij.util.FontUtil; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.ui.UIUtil; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; @@ -38,8 +36,8 @@ import javax.swing.event.HyperlinkEvent; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; -import java.util.Collections; -import java.util.Map; +import java.util.*; +import java.util.List; /** * @author cdr @@ -70,6 +68,7 @@ public class ColorAndFontDescriptionPanel extends JPanel { myEffectsMap = Collections.unmodifiableMap(map); } private JComboBox myEffectsCombo; + private final EffectsComboModel myEffectsModel; private JBCheckBox myCbBold; private JBCheckBox myCbItalic; @@ -83,7 +82,10 @@ public class ColorAndFontDescriptionPanel extends JPanel { add(myPanel, BorderLayout.CENTER); setBorder(BorderFactory.createEmptyBorder(4, 0, 4, 4)); - myEffectsCombo.setModel(new CollectionComboBoxModel(ContainerUtil.newArrayList(myEffectsMap.keySet()))); + myEffectsModel = new EffectsComboModel(ContainerUtil.newArrayList(myEffectsMap.keySet())); + //noinspection unchecked + myEffectsCombo.setModel(myEffectsModel); + //noinspection unchecked myEffectsCombo.setRenderer(new ListCellRendererWrapper() { @Override public void customize(JList list, String value, int index, boolean selected, boolean hasFocus) { @@ -152,7 +154,7 @@ public class ColorAndFontDescriptionPanel extends JPanel { colorPanel.setSelectedColor(color); } else { - colorPanel.setSelectedColor(Color.white); + colorPanel.setSelectedColor(JBColor.WHITE); } colorPanel.setEnabled(isChecked); } @@ -189,7 +191,7 @@ public class ColorAndFontDescriptionPanel extends JPanel { if (description.isEffectsColorEnabled() && description.isEffectsColorChecked()) { myEffectsCombo.setEnabled(true); - myEffectsCombo.getModel().setSelectedItem(ContainerUtil.reverseMap(myEffectsMap).get(effectType)); + myEffectsModel.setEffectName(ContainerUtil.reverseMap(myEffectsMap).get(effectType)); } else { myEffectsCombo.setEnabled(false); @@ -293,4 +295,20 @@ public class ColorAndFontDescriptionPanel extends JPanel { description.apply(scheme); } } + + private static class EffectsComboModel extends CollectionComboBoxModel { + public EffectsComboModel(List names) { + super(names); + } + + /** + * Set the current effect name when a text attribute selection changes without notifying the listeners since otherwise it will + * be considered as an actual change and lead to unnecessary evens including 'read-only scheme' check. + * + * @param effectName + */ + public void setEffectName(@NotNull String effectName) { + mySelection = effectName; + } + } } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/LegacyCompletionContributor.java b/platform/lang-impl/src/com/intellij/codeInsight/completion/LegacyCompletionContributor.java index 2568dca92ffe..3a71bd4129c4 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/completion/LegacyCompletionContributor.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/LegacyCompletionContributor.java @@ -73,6 +73,10 @@ public class LegacyCompletionContributor extends CompletionContributor { completionData.completeReference(reference, lookupSet, parameters.getPosition(), parameters.getOriginalFile()); for (final LookupElement item : lookupSet) { if (resultSet.getPrefixMatcher().prefixMatches(item)) { + if (!item.isValid()) { + LOG.error(completionData + " has returned an invalid lookup element " + item + " of " + item.getClass() + + " in " + parameters.getOriginalFile() + " of " + parameters.getOriginalFile().getClass()); + } hasVariants.set(true); resultSet.addElement(item); } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/impl/CompletionServiceImpl.java b/platform/lang-impl/src/com/intellij/codeInsight/completion/impl/CompletionServiceImpl.java index 3714449054b1..d84f431a65aa 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/completion/impl/CompletionServiceImpl.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/impl/CompletionServiceImpl.java @@ -125,7 +125,8 @@ public class CompletionServiceImpl extends CompletionService{ @Override public void addElement(@NotNull final LookupElement element) { if (!element.isValid()) { - LOG.error("Invalid lookup element: " + element); + LOG.error("Invalid lookup element: " + element + " of " + element.getClass() + + " in " + myParameters.getOriginalFile() + " of " + myParameters.getOriginalFile().getClass()); return; } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/LiveTemplateTree.java b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/LiveTemplateTree.java index c54d9b837980..0b84a914e8dc 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/LiveTemplateTree.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/LiveTemplateTree.java @@ -22,7 +22,6 @@ import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.actionSystem.DataProvider; import com.intellij.openapi.actionSystem.PlatformDataKeys; import com.intellij.openapi.ide.CopyPasteManager; -import com.intellij.openapi.util.InvalidDataException; import com.intellij.openapi.util.JDOMUtil; import com.intellij.openapi.util.text.StringUtil; import com.intellij.ui.CheckboxTree; @@ -144,15 +143,13 @@ class LiveTemplateTree extends CheckboxTree implements DataProvider, CopyProvide assert buffer != null; try { - for (Element templateElement : JDOMUtil.load(new StringReader("" + buffer + "")).getChildren()) { - try { - TemplateImpl template = TemplateSettings.readTemplateFromElement(group.getName(), templateElement, getClass().getClassLoader()); - myConfigurable.addTemplate(template); - } - catch (InvalidDataException ignore) { } + for (Element templateElement : JDOMUtil.load(new StringReader("" + buffer + "")).getChildren(TemplateSettings.TEMPLATE)) { + myConfigurable.addTemplate(TemplateSettings.readTemplateFromElement(group.getName(), templateElement, getClass().getClassLoader())); } } - catch (JDOMException ignore) { } - catch (IOException ignore) { } + catch (JDOMException ignore) { + } + catch (IOException ignore) { + } } } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateContext.java b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateContext.java index 24d085ea928c..98c20d4b69df 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateContext.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateContext.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * 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. @@ -19,7 +19,6 @@ package com.intellij.codeInsight.template.impl; import com.intellij.codeInsight.template.EverywhereContextType; import com.intellij.codeInsight.template.TemplateContextType; -import com.intellij.openapi.util.InvalidDataException; import com.intellij.openapi.util.WriteExternalException; import com.intellij.util.containers.ContainerUtil; import org.jdom.Element; @@ -27,7 +26,6 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.HashMap; -import java.util.List; import java.util.Map; public class TemplateContext { @@ -103,16 +101,12 @@ public class TemplateContext { } // used during initialization => no sync - void readTemplateContext(Element element) throws InvalidDataException { - List options = element.getChildren("option"); - for (Object e : options) { - if (e instanceof Element) { - Element option = (Element)e; - String name = option.getAttributeValue("name"); - String value = option.getAttributeValue("value"); - if (name != null && value != null) { - myContextStates.put(name, Boolean.parseBoolean(value)); - } + void readTemplateContext(Element element) { + for (Element option : element.getChildren("option")) { + String name = option.getAttributeValue("name"); + String value = option.getAttributeValue("value"); + if (name != null && value != null) { + myContextStates.put(name, Boolean.parseBoolean(value)); } } } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateGroup.java b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateGroup.java index e86ac895ea47..eb81b6ca6d6d 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateGroup.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateGroup.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * 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. @@ -13,14 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.intellij.codeInsight.template.impl; import com.intellij.openapi.options.CompoundScheme; import org.jetbrains.annotations.Nullable; public class TemplateGroup extends CompoundScheme { - private final String myReplace; public TemplateGroup(final String name) { diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateImpl.java b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateImpl.java index 964cba3df726..8cafa29d13e8 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateImpl.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * 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. @@ -172,6 +172,7 @@ public class TemplateImpl extends Template implements SchemeElement { return myId; } + @NotNull @Override public TemplateImpl copy() { TemplateImpl template = new TemplateImpl(myKey, myString, myGroupName); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateListPanel.java b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateListPanel.java index b5feef2ac32e..9dfe1501454d 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateListPanel.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateListPanel.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * 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. @@ -24,6 +24,7 @@ import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.options.CompoundScheme; import com.intellij.openapi.options.ConfigurationException; import com.intellij.openapi.project.DumbAwareAction; import com.intellij.openapi.ui.*; @@ -88,6 +89,8 @@ public class TemplateListPanel extends JPanel implements Disposable { private LiveTemplateSettingsEditor myCurrentTemplateEditor; private final JLabel myEmptyCardLabel = new JLabel(); + private final CompoundScheme.MutatorHelper mutatorHelper = new CompoundScheme.MutatorHelper(); + public TemplateListPanel() { super(new BorderLayout()); @@ -173,10 +176,8 @@ public class TemplateListPanel extends JPanel implements Disposable { } } TemplateSettings templateSettings = TemplateSettings.getInstance(); - templateSettings.setTemplates(templateGroups); + templateSettings.setTemplates(mutatorHelper.apply(templateGroups)); templateSettings.setDefaultShortcutChar(myExpandByDefaultPanel.getSelectedChar()); - - reset(); } private final boolean isTest = ApplicationManager.getApplication().isUnitTestMode(); @@ -220,8 +221,8 @@ public class TemplateListPanel extends JPanel implements Disposable { return null; } - private static List collectTemplates(final List groups) { - ArrayList result = new ArrayList(); + private static List collectTemplates(@NotNull List groups) { + List result = new ArrayList(); for (TemplateGroup group : groups) { result.addAll(group.getElements()); } @@ -238,7 +239,7 @@ public class TemplateListPanel extends JPanel implements Disposable { return result; } - private String checkAreEqual(List originalGroup, List newGroup) { + private String checkAreEqual(@NotNull List originalGroup, @NotNull List newGroup) { if (originalGroup.size() != newGroup.size()) return "different sizes"; for (int i = 0; i < newGroup.size(); i++) { @@ -260,7 +261,7 @@ public class TemplateListPanel extends JPanel implements Disposable { return null; } - private boolean areOptionsEqual(final TemplateImpl newTemplate, final TemplateImpl originalTemplate) { + private boolean areOptionsEqual(@NotNull TemplateImpl newTemplate, @NotNull TemplateImpl originalTemplate) { Map templateOptions = getTemplateOptions(newTemplate); for (TemplateOptionalProcessor processor : templateOptions.keySet()) { if (processor.isEnabled(originalTemplate) != templateOptions.get(processor).booleanValue()) return false; @@ -272,7 +273,7 @@ public class TemplateListPanel extends JPanel implements Disposable { return myTemplateContext.get(newTemplate); } - private Map getTemplateOptions(final TemplateImpl newTemplate) { + private Map getTemplateOptions(@NotNull TemplateImpl newTemplate) { return myTemplateOptions.get(newTemplate); } @@ -922,8 +923,9 @@ public class TemplateListPanel extends JPanel implements Disposable { private void initTemplates(List groups, String lastSelectedGroup, String lastSelectedKey) { myTreeRoot.removeAllChildren(); myTemplateGroups.clear(); + mutatorHelper.clear(); for (TemplateGroup group : groups) { - myTemplateGroups.add((TemplateGroup)group.copy()); + myTemplateGroups.add(mutatorHelper.copy(group)); } for (TemplateGroup group : myTemplateGroups) { diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateSettings.java b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateSettings.java index c1498426fe8c..397e3c309f90 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateSettings.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateSettings.java @@ -55,7 +55,7 @@ public class TemplateSettings implements PersistentStateComponent myDefaultTemplates = new LinkedHashMap(); private int myMaxKeyLength = 0; - private final SchemesManager mySchemesManager; + private final SchemesManager mySchemeManager; private State myState = new State(); @@ -184,7 +184,7 @@ public class TemplateSettings implements PersistentStateComponent() { + mySchemeManager = schemesManagerFactory.create(TEMPLATES_DIR_PATH, new BaseSchemeProcessor() { @Nullable @Override public TemplateGroup readScheme(@NotNull Element element) throws InvalidDataException { @@ -241,7 +241,7 @@ public class TemplateSettings implements PersistentStateComponent getTemplateGroups() { - return mySchemesManager.getAllSchemes(); + return mySchemeManager.getAllSchemes(); } public List collectMatchingCandidates(String key, @Nullable Character shortcutChar, boolean hasArgument) { diff --git a/platform/lang-impl/src/com/intellij/formatting/FormatProcessor.java b/platform/lang-impl/src/com/intellij/formatting/FormatProcessor.java index 162f64c2008b..cc076c5d1708 100644 --- a/platform/lang-impl/src/com/intellij/formatting/FormatProcessor.java +++ b/platform/lang-impl/src/com/intellij/formatting/FormatProcessor.java @@ -1629,14 +1629,48 @@ public class FormatProcessor { } if (last != null) { - AbstractBlockWrapper prev = getPreviousBlock(last); - return prev != null && prev.getWhiteSpace().containsLineFeeds(); + AbstractBlockWrapper next = getNextBlock(last); + if (next != null && next.getWhiteSpace().containsLineFeeds()) { + int nextNewLineBlockIndent = next.getNumberOfSymbolsBeforeBlock().getTotalSpaces(); + if (nextNewLineBlockIndent >= finMinNewLineIndent(blocksToExpandIndent)) { + return true; + } + } } return false; } + + private int finMinNewLineIndent(@NotNull Collection wrappers) { + int totalMinimum = Integer.MAX_VALUE; + for (AbstractBlockWrapper wrapper : wrappers) { + int minNewLineIndent = findMinNewLineIndent(wrapper); + if (minNewLineIndent < totalMinimum) { + totalMinimum = minNewLineIndent; + } + } + return totalMinimum; + } - private AbstractBlockWrapper getPreviousBlock(AbstractBlockWrapper block) { + private int findMinNewLineIndent(@NotNull AbstractBlockWrapper block) { + if (block instanceof LeafBlockWrapper && block.getWhiteSpace().containsLineFeeds()) { + return block.getNumberOfSymbolsBeforeBlock().getTotalSpaces(); + } + else if (block instanceof CompositeBlockWrapper) { + List children = ((CompositeBlockWrapper)block).getChildren(); + int currentMin = Integer.MAX_VALUE; + for (AbstractBlockWrapper child : children) { + int childIndent = findMinNewLineIndent(child); + if (childIndent < currentMin) { + currentMin = childIndent; + } + } + return currentMin; + } + return Integer.MAX_VALUE; + } + + private AbstractBlockWrapper getNextBlock(AbstractBlockWrapper block) { List children = block.getParent().getChildren(); int nextBlockIndex = children.indexOf(block) + 1; if (nextBlockIndex < children.size()) { diff --git a/platform/lang-impl/src/com/intellij/ide/actions/QuickChangeCodeStyleSchemeAction.java b/platform/lang-impl/src/com/intellij/ide/actions/QuickChangeCodeStyleSchemeAction.java index da3499735e35..2473f422a52d 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/QuickChangeCodeStyleSchemeAction.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/QuickChangeCodeStyleSchemeAction.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * 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. @@ -17,6 +17,7 @@ package com.intellij.ide.actions; import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.editor.EditorFactory; +import com.intellij.openapi.project.DumbAwareAction; import com.intellij.openapi.project.Project; import com.intellij.psi.codeStyle.CodeStyleScheme; import com.intellij.psi.codeStyle.CodeStyleSchemes; @@ -52,8 +53,8 @@ public class QuickChangeCodeStyleSchemeAction extends QuickSwitchSchemeAction { final CodeStyleScheme currentScheme, final CodeStyleScheme scheme, final boolean addScheme) { - group.add(new AnAction(scheme.getName(), "", - scheme == currentScheme && !manager.USE_PER_PROJECT_SETTINGS ? ourCurrentAction : ourNotCurrentAction) { + group.add(new DumbAwareAction(scheme.getName(), "", + scheme == currentScheme && !manager.USE_PER_PROJECT_SETTINGS ? ourCurrentAction : ourNotCurrentAction) { @Override public void actionPerformed(@NotNull AnActionEvent e) { if (addScheme) { diff --git a/platform/lang-impl/src/com/intellij/ide/structureView/impl/TemplateLanguageStructureViewBuilder.java b/platform/lang-impl/src/com/intellij/ide/structureView/impl/TemplateLanguageStructureViewBuilder.java index 849b01b703b9..c3f74727270e 100644 --- a/platform/lang-impl/src/com/intellij/ide/structureView/impl/TemplateLanguageStructureViewBuilder.java +++ b/platform/lang-impl/src/com/intellij/ide/structureView/impl/TemplateLanguageStructureViewBuilder.java @@ -50,7 +50,7 @@ import java.util.List; public abstract class TemplateLanguageStructureViewBuilder implements StructureViewBuilder { private final VirtualFile myVirtualFile; private final Project myProject; - private Language myTemplateDataLanguage; + @Nullable private Language myTemplateDataLanguage; private StructureViewComposite.StructureViewDescriptor myBaseStructureViewDescriptor; private FileEditor myFileEditor; private StructureViewComposite myStructureViewComposite; @@ -59,8 +59,7 @@ public abstract class TemplateLanguageStructureViewBuilder implements StructureV protected TemplateLanguageStructureViewBuilder(PsiElement psiElement) { myVirtualFile = psiElement.getContainingFile().getVirtualFile(); myProject = psiElement.getProject(); - - myTemplateDataLanguage = getNotNullViewProvider().getTemplateDataLanguage(); + myTemplateDataLanguage = getTemplateDataLanguage(); } private void updateAfterPsiChange() { @@ -69,15 +68,12 @@ public abstract class TemplateLanguageStructureViewBuilder implements StructureV ApplicationManager.getApplication().runReadAction(new Runnable(){ @Override public void run() { - if (!myVirtualFile.isValid()) return; - - final TemplateLanguageFileViewProvider provider = getViewProvider(); - if (provider == null) return; + if (!myVirtualFile.isValid() || getViewProvider() == null) return; StructureViewWrapper structureViewWrapper = StructureViewFactoryEx.getInstanceEx(myProject).getStructureViewWrapper(); if (structureViewWrapper == null) return; - Language baseLanguage = provider.getTemplateDataLanguage(); + Language baseLanguage = getTemplateDataLanguage(); if (baseLanguage == myTemplateDataLanguage && (myBaseStructureViewDescriptor == null || isPsiValid(myBaseStructureViewDescriptor))) { updateBaseLanguageView(); @@ -108,18 +104,15 @@ public abstract class TemplateLanguageStructureViewBuilder implements StructureV } @Nullable - private TemplateLanguageFileViewProvider getViewProvider() { - final FileViewProvider provider = PsiManager.getInstance(myProject).findViewProvider(myVirtualFile); - return provider instanceof TemplateLanguageFileViewProvider ? (TemplateLanguageFileViewProvider)provider : null; + private FileViewProvider getViewProvider() { + return PsiManager.getInstance(myProject).findViewProvider(myVirtualFile); } - @NotNull - private TemplateLanguageFileViewProvider getNotNullViewProvider() { - final FileViewProvider provider = PsiManager.getInstance(myProject).findViewProvider(myVirtualFile); - if (provider == null || !(provider instanceof TemplateLanguageFileViewProvider)) { - throw new AssertionError("Not a template view provider for " + myVirtualFile + ": " + provider); - } - return (TemplateLanguageFileViewProvider)provider; + @Nullable + private Language getTemplateDataLanguage() { + FileViewProvider provider = getViewProvider(); + return provider instanceof TemplateLanguageFileViewProvider + ? ((TemplateLanguageFileViewProvider)provider).getTemplateDataLanguage() : null; } private void updateBaseLanguageView() { @@ -165,13 +158,13 @@ public abstract class TemplateLanguageStructureViewBuilder implements StructureV public StructureView createStructureView(FileEditor fileEditor, @NotNull Project project) { myFileEditor = fileEditor; List viewDescriptors = new ArrayList(); - final TemplateLanguageFileViewProvider provider = getNotNullViewProvider(); + final FileViewProvider provider = getViewProvider(); + assert provider != null : myVirtualFile; final StructureViewComposite.StructureViewDescriptor structureViewDescriptor = createMainView(fileEditor, provider.getPsi(provider.getBaseLanguage())); if (structureViewDescriptor != null) viewDescriptors.add(structureViewDescriptor); myBaseLanguageViewDescriptorIndex = -1; - final Language dataLanguage = provider.getTemplateDataLanguage(); updateTemplateDataFileView(); if (myBaseStructureViewDescriptor != null) { @@ -179,9 +172,12 @@ public abstract class TemplateLanguageStructureViewBuilder implements StructureV myBaseLanguageViewDescriptorIndex = viewDescriptors.size() - 1; } - for (final Language language : provider.getLanguages()) { - if (language != dataLanguage && language != provider.getBaseLanguage()) { - ContainerUtil.addIfNotNull(createBaseLanguageStructureView(fileEditor, language), viewDescriptors); + if (provider instanceof TemplateLanguageFileViewProvider) { + final Language dataLanguage = ((TemplateLanguageFileViewProvider)provider).getTemplateDataLanguage(); + for (final Language language : provider.getLanguages()) { + if (language != dataLanguage && language != provider.getBaseLanguage()) { + ContainerUtil.addIfNotNull(createBaseLanguageStructureView(fileEditor, language), viewDescriptors); + } } } @@ -210,7 +206,7 @@ public abstract class TemplateLanguageStructureViewBuilder implements StructureV private StructureViewComposite.StructureViewDescriptor createBaseLanguageStructureView(final FileEditor fileEditor, final Language language) { if (!myVirtualFile.isValid()) return null; - final TemplateLanguageFileViewProvider viewProvider = getViewProvider(); + final FileViewProvider viewProvider = getViewProvider(); if (viewProvider == null) return null; final PsiFile dataFile = viewProvider.getPsi(language); @@ -231,8 +227,7 @@ public abstract class TemplateLanguageStructureViewBuilder implements StructureV } private void updateTemplateDataFileView() { - final TemplateLanguageFileViewProvider provider = getViewProvider(); - final Language newDataLanguage = provider == null ? null : provider.getTemplateDataLanguage(); + final Language newDataLanguage = getTemplateDataLanguage(); if (myBaseStructureViewDescriptor != null) { if (myTemplateDataLanguage == newDataLanguage) return; diff --git a/platform/lang-impl/src/com/intellij/ide/structureView/newStructureView/StructureViewComponent.java b/platform/lang-impl/src/com/intellij/ide/structureView/newStructureView/StructureViewComponent.java index ac5eef43e7cf..a3b45f166fc3 100644 --- a/platform/lang-impl/src/com/intellij/ide/structureView/newStructureView/StructureViewComponent.java +++ b/platform/lang-impl/src/com/intellij/ide/structureView/newStructureView/StructureViewComponent.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * 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. @@ -27,7 +27,6 @@ import com.intellij.ide.ui.customization.CustomizationUtil; import com.intellij.ide.util.FileStructurePopup; import com.intellij.ide.util.treeView.*; import com.intellij.ide.util.treeView.smartTree.*; -import com.intellij.ide.util.treeView.smartTree.TreeModel; import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.application.ApplicationManager; @@ -60,7 +59,10 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; -import javax.swing.tree.*; +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.DefaultTreeModel; +import javax.swing.tree.TreePath; +import javax.swing.tree.TreeSelectionModel; import java.awt.*; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; @@ -518,17 +520,6 @@ public class StructureViewComponent extends SimpleToolWindowPanel implements Tre return false; } - private static DefaultMutableTreeNode findInChildren(DefaultMutableTreeNode currentTreeNode, AbstractTreeNode topPathElement) { - for (int i = 0; i < currentTreeNode.getChildCount(); i++) { - TreeNode child = currentTreeNode.getChildAt(i); - if (((DefaultMutableTreeNode)child).getUserObject().equals(topPathElement)) - { - return (DefaultMutableTreeNode)child; - } - } - return null; - } - private void scrollToSelectedElement() { if (myAutoscrollFeedback) { myAutoscrollFeedback = false; @@ -814,8 +805,6 @@ public class StructureViewComponent extends SimpleToolWindowPanel implements Tre return value == null ? this : value; } - - @Override @NotNull public Collection getChildren() { @@ -910,7 +899,7 @@ public class StructureViewComponent extends SimpleToolWindowPanel implements Tre return o != null ? o.hashCode() : 0; } - private class StructureViewGroup extends GroupWrapper { + private static class StructureViewGroup extends GroupWrapper { public StructureViewGroup(Project project, Group group, TreeModel treeModel) { super(project, group, treeModel); } diff --git a/platform/lang-impl/src/com/intellij/openapi/options/CompoundScheme.java b/platform/lang-impl/src/com/intellij/openapi/options/CompoundScheme.java new file mode 100644 index 000000000000..dc07520f338f --- /dev/null +++ b/platform/lang-impl/src/com/intellij/openapi/options/CompoundScheme.java @@ -0,0 +1,152 @@ +/* + * 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.openapi.options; + +import com.intellij.util.containers.ContainerUtil; +import gnu.trove.THashMap; +import gnu.trove.TObjectObjectProcedure; +import org.jetbrains.annotations.NotNull; + +import java.lang.reflect.Constructor; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + +public class CompoundScheme extends ExternalizableSchemeAdapter { + protected final ArrayList myElements = new ArrayList(); + + public CompoundScheme(final String name) { + myName = name; + } + + public final void addElement(E t) { + if (!contains(t)) { + myElements.add(t); + } + } + + @NotNull + public final List getElements() { + return Collections.unmodifiableList(new ArrayList(myElements)); + } + + @Override + public final void setName(@NotNull final String name) { + myName = name; + for (E template : myElements) { + template.setGroupName(name); + } + } + + public final void removeElement(final E template) { + for (Iterator templateIterator = myElements.iterator(); templateIterator.hasNext();) { + E t = templateIterator.next(); + if (t.getKey() != null && t.getKey().equals(template.getKey())) { + templateIterator.remove(); + } + } + } + + public final boolean isEmpty() { + return myElements.isEmpty(); + } + + @NotNull + private CompoundScheme createNewInstance(String name) { + try { + Constructor constructor = getClass().getConstructor(String.class); + try { + constructor.setAccessible(true); + } + catch (Exception ignored) { + } + //noinspection unchecked + return constructor.newInstance(name); + } + catch (Exception e) { + throw new RuntimeException(e); + } + } + + @NotNull + CompoundScheme copy() { + CompoundScheme result = createNewInstance(getName()); + result.resetFrom(this); + return result; + } + + void resetFrom(@NotNull CompoundScheme template) { + myElements.clear(); + myElements.ensureCapacity(template.myElements.size()); + for (E element : template.myElements) { + //noinspection unchecked + myElements.add((E)element.copy()); + } + } + + public boolean contains(@NotNull E element) { + for (E t : myElements) { + String key = t.getKey(); + if (key != null && key.equals(element.getKey())) { + return true; + } + } + return false; + } + + public static final class MutatorHelper, E extends SchemeElement> { + private final THashMap copiedToOriginal = new THashMap(ContainerUtil.identityStrategy()); + + @NotNull + public T copy(@NotNull T scheme) { + //noinspection unchecked + T copied = (T)scheme.copy(); + copiedToOriginal.put(copied, scheme); + return copied; + } + + @NotNull + public List apply(@NotNull final List copiedSchemes) { + copiedToOriginal.retainEntries(new TObjectObjectProcedure() { + @Override + public boolean execute(T copied, T original) { + return ContainerUtil.containsIdentity(copiedSchemes, copied); + } + }); + + List originals = new ArrayList(copiedSchemes.size()); + for (T copied : copiedSchemes) { + T original = copiedToOriginal.remove(copied); + if (original == null) { + //noinspection unchecked + original = (T)copied.copy(); + copiedToOriginal.put(copied, original); + } + else { + original.resetFrom(copied); + } + + originals.add(original); + } + return originals; + } + + public void clear() { + copiedToOriginal.clear(); + } + } +} diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/tree/injected/MultiHostRegistrarImpl.java b/platform/lang-impl/src/com/intellij/psi/impl/source/tree/injected/MultiHostRegistrarImpl.java index 954d0532cbc9..4984df7d49e7 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/source/tree/injected/MultiHostRegistrarImpl.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/source/tree/injected/MultiHostRegistrarImpl.java @@ -312,7 +312,13 @@ public class MultiHostRegistrarImpl implements MultiHostRegistrar, ModificationT @NotNull SmartPsiElementPointer pointer) { FileDocumentManagerImpl.registerDocument(documentWindow, viewProvider.getVirtualFile()); - viewProvider.forceCachedPsi(psiFile); + DebugUtil.startPsiModification("MultiHostRegistrar cacheEverything"); + try { + viewProvider.forceCachedPsi(psiFile); + } + finally { + DebugUtil.finishPsiModification(); + } psiFile.putUserData(FileContextUtil.INJECTED_IN_ELEMENT, pointer); PsiDocumentManagerBase.cachePsi(documentWindow, psiFile); diff --git a/platform/lang-impl/src/com/intellij/tools/BaseToolsPanel.java b/platform/lang-impl/src/com/intellij/tools/BaseToolsPanel.java index 28a30c563162..2898f112e5a5 100644 --- a/platform/lang-impl/src/com/intellij/tools/BaseToolsPanel.java +++ b/platform/lang-impl/src/com/intellij/tools/BaseToolsPanel.java @@ -18,6 +18,7 @@ package com.intellij.tools; import com.intellij.CommonBundle; import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.options.CompoundScheme; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.Comparing; import com.intellij.ui.*; @@ -75,6 +76,8 @@ public abstract class BaseToolsPanel extends JPanel { private final AnActionButton myRemoveButton; private boolean myIsModified = false; + private final CompoundScheme.MutatorHelper, T> mutatorHelper = new CompoundScheme.MutatorHelper, T>(); + protected BaseToolsPanel() { myTree = new CheckboxTree( new CheckboxTree.CheckboxTreeCellRenderer() { @@ -198,8 +201,9 @@ public abstract class BaseToolsPanel extends JPanel { } public void reset() { - for (ToolsGroup group : getToolsGroups()) { - insertNewGroup((ToolsGroup)group.copy()); + mutatorHelper.clear(); + for (ToolsGroup group : getToolManager().getGroups()) { + insertNewGroup(mutatorHelper.copy(group)); } if ((getTreeRoot()).getChildCount() > 0) { @@ -219,20 +223,17 @@ public abstract class BaseToolsPanel extends JPanel { protected abstract BaseToolManager getToolManager(); - protected List> getToolsGroups() { - return getToolManager().getGroups(); - } - - private CheckedTreeNode insertNewGroup(@NotNull ToolsGroup groupCopy) { + @NotNull + private CheckedTreeNode insertNewGroup(@NotNull ToolsGroup groupCopy) { CheckedTreeNode groupNode = new CheckedTreeNode(groupCopy); getTreeRoot().add(groupNode); - for (Tool tool : groupCopy.getElements()) { + for (T tool : groupCopy.getElements()) { insertNewTool(groupNode, tool); } return groupNode; } - private CheckedTreeNode insertNewTool(final CheckedTreeNode groupNode, final Tool toolCopy) { + private CheckedTreeNode insertNewTool(@NotNull CheckedTreeNode groupNode, @NotNull Tool toolCopy) { CheckedTreeNode toolNode = new CheckedTreeNode(toolCopy); toolNode.setChecked(toolCopy.isEnabled()); ((ToolsGroup)groupNode.getUserObject()).addElement(toolCopy); @@ -246,14 +247,14 @@ public abstract class BaseToolsPanel extends JPanel { } public void apply() { - // unregister removed tools - getToolManager().setTools(getGroupList()); + getToolManager().setTools(mutatorHelper.apply(getGroupList())); myIsModified = false; } + @NotNull private List> getGroupList() { - List> result = new ArrayList>(); MutableTreeNode root = (MutableTreeNode)myTree.getModel().getRoot(); + List> result = new ArrayList>(root.getChildCount()); for (int i = 0; i < root.getChildCount(); i++) { final CheckedTreeNode node = (CheckedTreeNode)root.getChildAt(i); for (int j = 0; j < node.getChildCount(); j++) { @@ -313,7 +314,7 @@ public abstract class BaseToolsPanel extends JPanel { return dir.isAvailable(index, parent.getChildCount()); } - private void insertNewTool(final Tool newTool, boolean setSelection) { + private void insertNewTool(@NotNull Tool newTool, boolean setSelection) { CheckedTreeNode groupNode = findGroupNode(newTool.getGroup()); if (groupNode == null) { groupNode = insertNewGroup(new ToolsGroup(newTool.getGroup())); diff --git a/platform/lang-impl/src/com/intellij/tools/Tool.java b/platform/lang-impl/src/com/intellij/tools/Tool.java index 4e512989212f..fb85782906c6 100644 --- a/platform/lang-impl/src/com/intellij/tools/Tool.java +++ b/platform/lang-impl/src/com/intellij/tools/Tool.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * 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. @@ -353,6 +353,7 @@ public class Tool implements SchemeElement { return getName(); } + @NotNull @Override public SchemeElement copy() { Tool copy = new Tool(); diff --git a/platform/lang-impl/src/com/intellij/tools/ToolsGroup.java b/platform/lang-impl/src/com/intellij/tools/ToolsGroup.java index 0a4254ad1d5d..5b69cc05be97 100644 --- a/platform/lang-impl/src/com/intellij/tools/ToolsGroup.java +++ b/platform/lang-impl/src/com/intellij/tools/ToolsGroup.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * 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. @@ -24,14 +24,20 @@ public class ToolsGroup extends CompoundScheme { } public void moveElementUp(final T tool) { - int index = getElements().indexOf(tool); + int index = myElements.indexOf(tool); removeElement(tool); insertElement(tool, index - 1); } public void moveElementDown(final T tool) { - int index = getElements().indexOf(tool); + int index = myElements.indexOf(tool); removeElement(tool); insertElement(tool, index + 1); } + + public void insertElement(T element, final int i) { + if (!contains(element)) { + myElements.add(i, element); + } + } } diff --git a/platform/platform-api/src/com/intellij/openapi/options/CompoundScheme.java b/platform/platform-api/src/com/intellij/openapi/options/CompoundScheme.java deleted file mode 100644 index c6ea9f7de2b0..000000000000 --- a/platform/platform-api/src/com/intellij/openapi/options/CompoundScheme.java +++ /dev/null @@ -1,99 +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.openapi.options; - -import org.jetbrains.annotations.NotNull; - -import java.lang.reflect.Constructor; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; - -public class CompoundScheme extends ExternalizableSchemeAdapter { - private final List myElements = new ArrayList(); - - public CompoundScheme(final String name) { - myName = name; - } - - public void addElement(T t) { - if (!contains(t)) { - myElements.add(t); - } - } - - public void insertElement(T element, final int i) { - if (!contains(element)) { - myElements.add(i, element); - } - } - - public List getElements() { - return Collections.unmodifiableList(new ArrayList(myElements)); - } - - @Override - public void setName(@NotNull final String name) { - myName = name; - for (T template : myElements) { - template.setGroupName(name); - } - } - - public void removeElement(final T template) { - for (Iterator templateIterator = myElements.iterator(); templateIterator.hasNext();) { - T t = templateIterator.next(); - if (t.getKey() != null && t.getKey().equals(template.getKey())) { - templateIterator.remove(); - } - } - } - - public boolean isEmpty() { - return myElements.isEmpty(); - } - - private CompoundScheme createNewInstance(final String name) { - try { - Constructor constructor = getClass().getConstructor(String.class); - return constructor.newInstance(name); - } - catch (Exception e) { - throw new RuntimeException(e); - } - } - - @NotNull - public CompoundScheme copy() { - //noinspection unchecked - CompoundScheme result = createNewInstance(getName()); - for (T element : myElements) { - //noinspection unchecked - result.addElement((T)element.copy()); - } - return result; - } - - public boolean contains(@NotNull T element) { - for (T t : myElements) { - if (t.getKey() != null && t.getKey().equals(element.getKey())) { - return true; - } - } - return false; - } -} diff --git a/platform/platform-api/src/com/intellij/openapi/options/SchemeElement.java b/platform/platform-api/src/com/intellij/openapi/options/SchemeElement.java index 5720b7af38cd..3f390a34a88d 100644 --- a/platform/platform-api/src/com/intellij/openapi/options/SchemeElement.java +++ b/platform/platform-api/src/com/intellij/openapi/options/SchemeElement.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * 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. @@ -15,14 +15,13 @@ */ package com.intellij.openapi.options; - import org.jetbrains.annotations.NotNull; public interface SchemeElement { void setGroupName(@NotNull String name); - String getKey(); + @NotNull SchemeElement copy(); } diff --git a/platform/platform-api/src/com/intellij/ui/ExpandedItemRendererComponentWrapper.java b/platform/platform-api/src/com/intellij/ui/ExpandedItemRendererComponentWrapper.java index b743d444157a..0c7996b3573b 100644 --- a/platform/platform-api/src/com/intellij/ui/ExpandedItemRendererComponentWrapper.java +++ b/platform/platform-api/src/com/intellij/ui/ExpandedItemRendererComponentWrapper.java @@ -47,15 +47,16 @@ public class ExpandedItemRendererComponentWrapper extends JComponent { public static ExpandedItemRendererComponentWrapper wrap(@NotNull Component rendererComponent) { if (rendererComponent instanceof Accessible) { - return new MyAccessibleComponent((Accessible)rendererComponent); + return new MyAccessibleComponent(rendererComponent, (Accessible)rendererComponent); } return new ExpandedItemRendererComponentWrapper(rendererComponent); } private static class MyAccessibleComponent extends ExpandedItemRendererComponentWrapper implements Accessible { private Accessible myAccessible; - MyAccessibleComponent(Accessible comp) { - myAccessible = comp; + MyAccessibleComponent(@NotNull Component comp, @NotNull Accessible accessible) { + super(comp); + myAccessible = accessible; } @Override public AccessibleContext getAccessibleContext() { diff --git a/platform/platform-api/src/com/intellij/ui/SimpleColoredComponent.java b/platform/platform-api/src/com/intellij/ui/SimpleColoredComponent.java index b65b8a8836f6..1a2587543d99 100644 --- a/platform/platform-api/src/com/intellij/ui/SimpleColoredComponent.java +++ b/platform/platform-api/src/com/intellij/ui/SimpleColoredComponent.java @@ -1033,7 +1033,7 @@ public class SimpleColoredComponent extends JComponent implements Accessible, Co private class MyAccessibleContext extends JComponent.AccessibleJComponent { @Override public String getAccessibleName() { - return StringUtil.join(myFragments, " "); + return SimpleColoredComponent.this.toString(); } } diff --git a/platform/platform-api/src/com/intellij/ui/tabs/TabInfo.java b/platform/platform-api/src/com/intellij/ui/tabs/TabInfo.java index acd90ef58dcb..91536d53deaa 100644 --- a/platform/platform-api/src/com/intellij/ui/tabs/TabInfo.java +++ b/platform/platform-api/src/com/intellij/ui/tabs/TabInfo.java @@ -17,6 +17,7 @@ package com.intellij.ui.tabs; import com.intellij.icons.AllIcons; import com.intellij.openapi.actionSystem.ActionGroup; +import com.intellij.openapi.editor.markup.TextAttributes; import com.intellij.openapi.ui.Queryable; import com.intellij.openapi.util.Comparing; import com.intellij.reference.SoftReference; @@ -107,22 +108,24 @@ public final class TabInfo implements Queryable, PlaceProvider { public TabInfo setText(String text) { List attributes = myText.getAttributes(); - SimpleTextAttributes textAttributes = attributes.isEmpty() ? null : attributes.get(0); - SimpleTextAttributes defaultAttributes = getDefaultAttributes(); + TextAttributes textAttributes = attributes.isEmpty() ? null : attributes.get(0).toTextAttributes(); + TextAttributes defaultAttributes = getDefaultAttributes().toTextAttributes(); if (!myText.toString().equals(text) || !Comparing.equal(textAttributes, defaultAttributes)) { clearText(false); - append(text, defaultAttributes); + append(text, getDefaultAttributes()); } return this; } + @NotNull private SimpleTextAttributes getDefaultAttributes() { - if (myDefaultAttributes != null) return myDefaultAttributes; + SimpleTextAttributes attributes = myDefaultAttributes; + if (attributes == null) { + myDefaultAttributes = attributes = new SimpleTextAttributes(myDefaultStyle != -1 ? myDefaultStyle : SimpleTextAttributes.STYLE_PLAIN, + myDefaultForeground, myDefaultWaveColor); - myDefaultAttributes = new SimpleTextAttributes(myDefaultStyle != -1 ? myDefaultStyle : SimpleTextAttributes.STYLE_PLAIN, - myDefaultForeground, myDefaultWaveColor); - - return myDefaultAttributes; + } + return attributes; } public TabInfo clearText(final boolean invalidate) { diff --git a/platform/platform-impl/src/com/intellij/execution/DelayedDocumentWatcher.java b/platform/platform-impl/src/com/intellij/execution/DelayedDocumentWatcher.java index 1a573cd5b663..787d60fbdaeb 100644 --- a/platform/platform-impl/src/com/intellij/execution/DelayedDocumentWatcher.java +++ b/platform/platform-impl/src/com/intellij/execution/DelayedDocumentWatcher.java @@ -26,6 +26,7 @@ import com.intellij.openapi.editor.event.DocumentEvent; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.fileEditor.FileDocumentManagerAdapter; import com.intellij.openapi.project.Project; +import com.intellij.openapi.project.ProjectCoreUtil; import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.Disposer; @@ -128,7 +129,9 @@ public class DelayedDocumentWatcher { return; } if (!myChangedFiles.contains(file)) { - // optimization: if possible, avoid possible expensive 'myChangedFileFilter.value(file)' call + if (ProjectCoreUtil.isProjectOrWorkspaceFile(file)) { + return; + } if (myChangedFileFilter != null && !myChangedFileFilter.value(file)) { return; } diff --git a/platform/platform-impl/src/com/intellij/ide/ApplicationActivationStateManager.java b/platform/platform-impl/src/com/intellij/ide/ApplicationActivationStateManager.java index 68376bf37518..4a216b7557f6 100644 --- a/platform/platform-impl/src/com/intellij/ide/ApplicationActivationStateManager.java +++ b/platform/platform-impl/src/com/intellij/ide/ApplicationActivationStateManager.java @@ -99,7 +99,7 @@ public class ApplicationActivationStateManager { // windowEvent could just be showing a popup or another transient window. // So let's postpone the application deactivation for a while state = State.DEACTIVATING; - LOG.info("SET APP DEACTIVATING"); + LOG.debug("The app is in the deactivating state"); Timer timer = new Timer(Registry.intValue("application.deactivation.timeout"), new ActionListener() { public void actionPerformed(ActionEvent evt) { @@ -107,7 +107,7 @@ public class ApplicationActivationStateManager { if (state.equals(State.DEACTIVATING)) { state = State.DEACTIVATED; - LOG.info("SET APP DEACTIVATED"); + LOG.debug("The app is in the deactivated state"); IdeFrame ideFrame = getIdeFrameFromWindow(windowEvent.getWindow()); if (ideFrame != null) { @@ -129,7 +129,7 @@ public class ApplicationActivationStateManager { IdeFrame ideFrame = getIdeFrameFromWindow(window); state = State.ACTIVE; - LOG.info("SET APP ACTIVE"); + LOG.debug("The app is in the active state"); if (ideFrame != null) { application.getMessageBus().syncPublisher(ApplicationActivationListener.TOPIC).applicationActivated(ideFrame); diff --git a/platform/platform-impl/src/com/intellij/ide/actions/QuickChangeKeymapAction.java b/platform/platform-impl/src/com/intellij/ide/actions/QuickChangeKeymapAction.java index bd1820570a07..4f4c18cac90d 100644 --- a/platform/platform-impl/src/com/intellij/ide/actions/QuickChangeKeymapAction.java +++ b/platform/platform-impl/src/com/intellij/ide/actions/QuickChangeKeymapAction.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * 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. @@ -15,13 +15,13 @@ */ package com.intellij.ide.actions; -import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.actionSystem.DefaultActionGroup; import com.intellij.openapi.keymap.Keymap; import com.intellij.openapi.keymap.KeymapManager; import com.intellij.openapi.keymap.ex.KeymapManagerEx; +import com.intellij.openapi.project.DumbAwareAction; import com.intellij.openapi.project.Project; import org.jetbrains.annotations.NotNull; @@ -39,7 +39,7 @@ public class QuickChangeKeymapAction extends QuickSwitchSchemeAction { } private static void addKeymapAction(final DefaultActionGroup group, final KeymapManagerEx manager, final Keymap current, final Keymap keymap, final boolean addScheme) { - group.add(new AnAction(keymap.getPresentableName(), "", keymap == current ? ourCurrentAction : ourNotCurrentAction) { + group.add(new DumbAwareAction(keymap.getPresentableName(), "", keymap == current ? ourCurrentAction : ourNotCurrentAction) { @Override public void actionPerformed(AnActionEvent e) { if (addScheme) { diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/buttonComboLeft.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/buttonComboLeft.png index 16eb5e083f60..1444d54054c0 100644 Binary files a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/buttonComboLeft.png and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/buttonComboLeft.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/buttonComboMiddle.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/buttonComboMiddle.png index 0e759578621f..0c4a27f989d2 100644 Binary files a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/buttonComboMiddle.png and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/buttonComboMiddle.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/buttonComboRight.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/buttonComboRight.png index c945a5839a33..b7f85b561e88 100644 Binary files a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/buttonComboRight.png and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/buttonComboRight.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/buttonLeft.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/buttonLeft.png index a0360b323836..3dc0fb1f2418 100644 Binary files a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/buttonLeft.png and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/buttonLeft.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/buttonLeftFocused.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/buttonLeftFocused.png index 8f7d4c64e4d8..70ba7a202a6f 100644 Binary files a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/buttonLeftFocused.png and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/buttonLeftFocused.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/buttonLeftSelected.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/buttonLeftSelected.png index f23a9720ff6c..ce8ef940f9f0 100644 Binary files a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/buttonLeftSelected.png and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/buttonLeftSelected.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/buttonLeftSelectedFocused.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/buttonLeftSelectedFocused.png index ddbd2a5f9aed..4ca54c232e3d 100644 Binary files a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/buttonLeftSelectedFocused.png and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/buttonLeftSelectedFocused.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/buttonMiddle.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/buttonMiddle.png index 5e6e01824d84..e93b2eb1d954 100644 Binary files a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/buttonMiddle.png and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/buttonMiddle.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/buttonMiddleFocused.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/buttonMiddleFocused.png index fa5528304d64..c6aba3e96cd2 100644 Binary files a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/buttonMiddleFocused.png and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/buttonMiddleFocused.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/buttonMiddleSelected.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/buttonMiddleSelected.png index b4e90fb76b8e..417b30b4c7b5 100644 Binary files a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/buttonMiddleSelected.png and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/buttonMiddleSelected.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/buttonMiddleSelectedFocused.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/buttonMiddleSelectedFocused.png index cb49c468673d..ce4ee9b76e46 100644 Binary files a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/buttonMiddleSelectedFocused.png and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/buttonMiddleSelectedFocused.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/buttonRight.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/buttonRight.png index 29d733d404da..4d18a8c8cb49 100644 Binary files a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/buttonRight.png and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/buttonRight.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/buttonRightFocused.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/buttonRightFocused.png index e59ebb6c9944..fcbeba38d7b8 100644 Binary files a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/buttonRightFocused.png and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/buttonRightFocused.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/buttonRightSelected.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/buttonRightSelected.png index 9471e2325532..ef1759ba03dc 100644 Binary files a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/buttonRightSelected.png and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/buttonRightSelected.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/buttonRightSelectedFocused.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/buttonRightSelectedFocused.png index df2acedf4a21..db9b7e2cd6f2 100644 Binary files a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/buttonRightSelectedFocused.png and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/buttonRightSelectedFocused.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/checkBox.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/checkBox.png index 0983672a77d9..61fa7902edad 100644 Binary files a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/checkBox.png and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/checkBox.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/checkBoxDisabled.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/checkBoxDisabled.png new file mode 100644 index 000000000000..ad426c88fe64 Binary files /dev/null and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/checkBoxDisabled.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/checkBoxDisabled@2x.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/checkBoxDisabled@2x.png new file mode 100644 index 000000000000..7ae37c9093c1 Binary files /dev/null and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/checkBoxDisabled@2x.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/checkBoxFocused.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/checkBoxFocused.png index c1b5d0472600..a0c093a7f39d 100644 Binary files a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/checkBoxFocused.png and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/checkBoxFocused.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/checkBoxIndeterminateSelected.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/checkBoxIndeterminateSelected.png new file mode 100644 index 000000000000..38f74ff4026f Binary files /dev/null and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/checkBoxIndeterminateSelected.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/checkBoxIndeterminateSelected@2x.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/checkBoxIndeterminateSelected@2x.png new file mode 100644 index 000000000000..1c9f162db0b3 Binary files /dev/null and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/checkBoxIndeterminateSelected@2x.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/checkBoxIndeterminateSelectedDisabled.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/checkBoxIndeterminateSelectedDisabled.png new file mode 100644 index 000000000000..04f47991b6b8 Binary files /dev/null and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/checkBoxIndeterminateSelectedDisabled.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/checkBoxIndeterminateSelectedDisabled@2x.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/checkBoxIndeterminateSelectedDisabled@2x.png new file mode 100644 index 000000000000..710a3d437aff Binary files /dev/null and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/checkBoxIndeterminateSelectedDisabled@2x.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/checkBoxIndeterminateSelectedFocused.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/checkBoxIndeterminateSelectedFocused.png new file mode 100644 index 000000000000..848f60ee0af6 Binary files /dev/null and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/checkBoxIndeterminateSelectedFocused.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/checkBoxIndeterminateSelectedFocused@2x.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/checkBoxIndeterminateSelectedFocused@2x.png new file mode 100644 index 000000000000..e4ebd3e7c233 Binary files /dev/null and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/checkBoxIndeterminateSelectedFocused@2x.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/checkBoxSelected.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/checkBoxSelected.png index 01ed1ca592b5..491b812561d6 100644 Binary files a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/checkBoxSelected.png and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/checkBoxSelected.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/checkBoxSelectedDisabled.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/checkBoxSelectedDisabled.png new file mode 100644 index 000000000000..7bfb238f7bf4 Binary files /dev/null and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/checkBoxSelectedDisabled.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/checkBoxSelectedDisabled@2x.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/checkBoxSelectedDisabled@2x.png new file mode 100644 index 000000000000..6432647323bf Binary files /dev/null and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/checkBoxSelectedDisabled@2x.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/checkBoxSelectedFocused.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/checkBoxSelectedFocused.png index c3b33c79614e..45fa2c46835b 100644 Binary files a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/checkBoxSelectedFocused.png and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/checkBoxSelectedFocused.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/comboLeft.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/comboLeft.png index 56f1d65380b0..91f069b3db56 100644 Binary files a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/comboLeft.png and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/comboLeft.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/comboLeftDisabled.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/comboLeftDisabled.png index 430e3e5d7443..8f81b3ef1867 100644 Binary files a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/comboLeftDisabled.png and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/comboLeftDisabled.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/comboLeftFocused.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/comboLeftFocused.png index d732f8ac2902..83486235503b 100644 Binary files a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/comboLeftFocused.png and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/comboLeftFocused.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/comboMiddle.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/comboMiddle.png index 3305d9853977..fa96b894c1e3 100644 Binary files a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/comboMiddle.png and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/comboMiddle.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/comboMiddleDisabled.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/comboMiddleDisabled.png index 3ac500fe1451..1813cd16f50d 100644 Binary files a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/comboMiddleDisabled.png and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/comboMiddleDisabled.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/comboMiddleFocused.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/comboMiddleFocused.png index adc3a4d2b319..3c039723239c 100644 Binary files a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/comboMiddleFocused.png and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/comboMiddleFocused.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/comboRight.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/comboRight.png index 29c74153b421..084618a0725f 100644 Binary files a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/comboRight.png and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/comboRight.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/comboRightDisabled.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/comboRightDisabled.png index 0ad8b9499dbd..6abfee344695 100644 Binary files a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/comboRightDisabled.png and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/comboRightDisabled.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/comboRightFocused.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/comboRightFocused.png index 83c3813bb9d3..d3c448a855c1 100644 Binary files a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/comboRightFocused.png and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/comboRightFocused.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/buttonLeftFocused.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/buttonLeftFocused.png index fb911a612527..d9f7824c07ba 100644 Binary files a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/buttonLeftFocused.png and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/buttonLeftFocused.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/buttonLeftSelected.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/buttonLeftSelected.png index 94ed84aa55c3..4716ced7977a 100644 Binary files a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/buttonLeftSelected.png and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/buttonLeftSelected.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/buttonLeftSelectedFocused.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/buttonLeftSelectedFocused.png index 8afc902f8118..c2cb61084721 100644 Binary files a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/buttonLeftSelectedFocused.png and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/buttonLeftSelectedFocused.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/buttonMiddleFocused.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/buttonMiddleFocused.png index 079e29220c4e..b310695df72b 100644 Binary files a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/buttonMiddleFocused.png and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/buttonMiddleFocused.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/buttonMiddleSelected.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/buttonMiddleSelected.png index 3d4aee44a76c..ee5e439d2dea 100644 Binary files a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/buttonMiddleSelected.png and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/buttonMiddleSelected.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/buttonMiddleSelectedFocused.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/buttonMiddleSelectedFocused.png index 3d52f0790b40..18e21bb5007d 100644 Binary files a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/buttonMiddleSelectedFocused.png and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/buttonMiddleSelectedFocused.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/buttonRightFocused.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/buttonRightFocused.png index 9cf707c6022f..dbd1b76e4407 100644 Binary files a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/buttonRightFocused.png and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/buttonRightFocused.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/buttonRightSelected.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/buttonRightSelected.png index 3397c49e7902..ef0375895631 100644 Binary files a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/buttonRightSelected.png and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/buttonRightSelected.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/buttonRightSelectedFocused.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/buttonRightSelectedFocused.png index d261fbf0df36..e5e6f7f1cd52 100644 Binary files a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/buttonRightSelectedFocused.png and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/buttonRightSelectedFocused.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/checkBoxDisabled.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/checkBoxDisabled.png new file mode 100644 index 000000000000..ad426c88fe64 Binary files /dev/null and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/checkBoxDisabled.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/checkBoxDisabled@2x.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/checkBoxDisabled@2x.png new file mode 100644 index 000000000000..7ae37c9093c1 Binary files /dev/null and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/checkBoxDisabled@2x.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/checkBoxFocused.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/checkBoxFocused.png index b2cf55a50a4f..8135aca27793 100644 Binary files a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/checkBoxFocused.png and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/checkBoxFocused.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/checkBoxGraphite.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/checkBoxGraphite.png index 1b432036cf50..61fa7902edad 100644 Binary files a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/checkBoxGraphite.png and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/checkBoxGraphite.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/checkBoxIndeterminateSelected.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/checkBoxIndeterminateSelected.png new file mode 100644 index 000000000000..0a2c75225096 Binary files /dev/null and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/checkBoxIndeterminateSelected.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/checkBoxIndeterminateSelected@2x.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/checkBoxIndeterminateSelected@2x.png new file mode 100644 index 000000000000..01a8853b8d4b Binary files /dev/null and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/checkBoxIndeterminateSelected@2x.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/checkBoxIndeterminateSelectedDisabled.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/checkBoxIndeterminateSelectedDisabled.png new file mode 100644 index 000000000000..04f47991b6b8 Binary files /dev/null and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/checkBoxIndeterminateSelectedDisabled.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/checkBoxIndeterminateSelectedDisabled@2x.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/checkBoxIndeterminateSelectedDisabled@2x.png new file mode 100644 index 000000000000..710a3d437aff Binary files /dev/null and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/checkBoxIndeterminateSelectedDisabled@2x.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/checkBoxIndeterminateSelectedFocused.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/checkBoxIndeterminateSelectedFocused.png new file mode 100644 index 000000000000..ed3e0ed31fb4 Binary files /dev/null and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/checkBoxIndeterminateSelectedFocused.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/checkBoxIndeterminateSelectedFocused@2x.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/checkBoxIndeterminateSelectedFocused@2x.png new file mode 100644 index 000000000000..3c2f02b8cdaa Binary files /dev/null and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/checkBoxIndeterminateSelectedFocused@2x.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/checkBoxSelected.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/checkBoxSelected.png index c590775c3a29..86d6dac33d56 100644 Binary files a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/checkBoxSelected.png and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/checkBoxSelected.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/checkBoxSelectedDisabled.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/checkBoxSelectedDisabled.png new file mode 100644 index 000000000000..7bfb238f7bf4 Binary files /dev/null and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/checkBoxSelectedDisabled.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/checkBoxSelectedDisabled@2x.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/checkBoxSelectedDisabled@2x.png new file mode 100644 index 000000000000..6432647323bf Binary files /dev/null and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/checkBoxSelectedDisabled@2x.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/checkBoxSelectedFocused.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/checkBoxSelectedFocused.png index b5344701d163..d8b1843626dd 100644 Binary files a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/checkBoxSelectedFocused.png and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/checkBoxSelectedFocused.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/comboLeftFocused.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/comboLeftFocused.png index d732f8ac2902..d9f7824c07ba 100644 Binary files a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/comboLeftFocused.png and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/comboLeftFocused.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/comboMiddleFocused.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/comboMiddleFocused.png index adc3a4d2b319..902c6d062e02 100644 Binary files a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/comboMiddleFocused.png and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/comboMiddleFocused.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/comboRight.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/comboRight.png index ea04e5346271..d89d36f022db 100644 Binary files a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/comboRight.png and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/comboRight.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/comboRightFocused.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/comboRightFocused.png index 83c3813bb9d3..b6b0ce86111f 100644 Binary files a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/comboRightFocused.png and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/comboRightFocused.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/helpButtonFocused.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/helpButtonFocused.png index acd2d7aa1b06..6b0c82cc45c0 100644 Binary files a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/helpButtonFocused.png and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/helpButtonFocused.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/macBorderBottom.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/macBorderBottom.png index 2b8c0afbed79..68a3a8a3a3f6 100644 Binary files a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/macBorderBottom.png and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/macBorderBottom.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/macBorderBottomLeft.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/macBorderBottomLeft.png index 018f141c8c76..761dfd42669f 100644 Binary files a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/macBorderBottomLeft.png and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/macBorderBottomLeft.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/macBorderBottomRight.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/macBorderBottomRight.png index 0fd1bcbdb2ca..db5c031e9213 100644 Binary files a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/macBorderBottomRight.png and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/macBorderBottomRight.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/macBorderLeft.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/macBorderLeft.png index 463acba3b17a..b4251f12964b 100644 Binary files a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/macBorderLeft.png and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/macBorderLeft.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/macBorderRight.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/macBorderRight.png index 284d4142a53d..c5c17f14d7d3 100644 Binary files a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/macBorderRight.png and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/macBorderRight.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/macBorderTop.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/macBorderTop.png index fccd5aa516a6..f1894c59f36d 100644 Binary files a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/macBorderTop.png and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/macBorderTop.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/macBorderTopLeft.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/macBorderTopLeft.png index 9f4ae60ac6f0..2cacc7eb4144 100644 Binary files a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/macBorderTopLeft.png and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/macBorderTopLeft.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/macBorderTopRight.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/macBorderTopRight.png index 6e185b0eced5..5219ba54222b 100644 Binary files a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/macBorderTopRight.png and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/macBorderTopRight.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/progressLeftSelected.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/progressLeftSelected.png index fe83f11b32be..b10d30ca34a2 100644 Binary files a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/progressLeftSelected.png and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/progressLeftSelected.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/progressMiddleSelected.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/progressMiddleSelected.png index 22f6283a6194..6f5af6f217bf 100644 Binary files a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/progressMiddleSelected.png and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/progressMiddleSelected.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/progressRightSelected.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/progressRightSelected.png index 6858682c3fef..bead76a2ed54 100644 Binary files a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/progressRightSelected.png and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/progressRightSelected.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/radioFocused.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/radioFocused.png index abbd87c55377..bee4372fad27 100644 Binary files a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/radioFocused.png and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/radioFocused.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/radioSelected.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/radioSelected.png index a252b2fddc8e..67b7cce73acf 100644 Binary files a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/radioSelected.png and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/radioSelected.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/radioSelectedFocused.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/radioSelectedFocused.png index 5682e883c313..c6d5ba7871ee 100644 Binary files a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/radioSelectedFocused.png and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/graphite/radioSelectedFocused.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/helpButton.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/helpButton.png index c390f92d5016..af66d4902619 100644 Binary files a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/helpButton.png and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/helpButton.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/macBorderBottom.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/macBorderBottom.png index 2b8c0afbed79..5b57c480d0af 100644 Binary files a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/macBorderBottom.png and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/macBorderBottom.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/macBorderBottomLeft.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/macBorderBottomLeft.png index 018f141c8c76..f01b02740b30 100644 Binary files a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/macBorderBottomLeft.png and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/macBorderBottomLeft.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/macBorderBottomRight.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/macBorderBottomRight.png index 0fd1bcbdb2ca..766153e6fed1 100644 Binary files a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/macBorderBottomRight.png and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/macBorderBottomRight.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/macBorderLeft.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/macBorderLeft.png index 463acba3b17a..c5c17f14d7d3 100644 Binary files a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/macBorderLeft.png and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/macBorderLeft.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/macBorderRight.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/macBorderRight.png index 284d4142a53d..b4251f12964b 100644 Binary files a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/macBorderRight.png and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/macBorderRight.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/macBorderTop.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/macBorderTop.png index fccd5aa516a6..49e5555eb7fb 100644 Binary files a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/macBorderTop.png and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/macBorderTop.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/macBorderTopLeft.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/macBorderTopLeft.png index 9f4ae60ac6f0..f57239d62e64 100644 Binary files a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/macBorderTopLeft.png and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/macBorderTopLeft.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/macBorderTopRight.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/macBorderTopRight.png index 6e185b0eced5..62a373b6f5d3 100644 Binary files a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/macBorderTopRight.png and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/macBorderTopRight.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/progressLeft.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/progressLeft.png index de79a6179a0d..a5da5ab03719 100644 Binary files a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/progressLeft.png and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/progressLeft.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/progressLeftSelected.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/progressLeftSelected.png index 5b955519192e..d7dd4df2319e 100644 Binary files a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/progressLeftSelected.png and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/progressLeftSelected.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/progressMiddle.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/progressMiddle.png index 6b0d24e91f80..9185971a4723 100644 Binary files a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/progressMiddle.png and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/progressMiddle.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/progressMiddleSelected.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/progressMiddleSelected.png index 84fc001f0ece..a9df6a3ac2e8 100644 Binary files a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/progressMiddleSelected.png and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/progressMiddleSelected.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/progressRight.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/progressRight.png index 10eddd5f84e4..01451a62b716 100644 Binary files a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/progressRight.png and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/progressRight.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/progressRightSelected.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/progressRightSelected.png index e928c5ec8c33..b9bd5805387a 100644 Binary files a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/progressRightSelected.png and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/progressRightSelected.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/radio.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/radio.png index 13e0f9cc9410..543bb9aeb34c 100644 Binary files a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/radio.png and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/radio.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/radioDisabled.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/radioDisabled.png index 7b4e744ea442..4290059902e8 100644 Binary files a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/radioDisabled.png and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/radioDisabled.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/radioFocused.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/radioFocused.png index c2911a251cda..e08304b74190 100644 Binary files a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/radioFocused.png and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/radioFocused.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/radioSelected.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/radioSelected.png index 7520f030456e..b24222543461 100644 Binary files a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/radioSelected.png and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/radioSelected.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/radioSelectedDisabled.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/radioSelectedDisabled.png index 66de4bb09053..498bc798ad53 100644 Binary files a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/radioSelectedDisabled.png and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/radioSelectedDisabled.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/radioSelectedFocused.png b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/radioSelectedFocused.png index 6b5460862a64..78343eeb051e 100644 Binary files a/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/radioSelectedFocused.png and b/platform/platform-impl/src/com/intellij/ide/ui/laf/icons/radioSelectedFocused.png differ diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/MacIntelliJButtonUI.java b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/MacIntelliJButtonUI.java index 39f384c30933..f6c919566fc8 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/MacIntelliJButtonUI.java +++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/MacIntelliJButtonUI.java @@ -43,7 +43,7 @@ public class MacIntelliJButtonUI extends DarculaButtonUI { int w = c.getWidth(); int h = c.getHeight(); if (isHelpButton(c)) { - Icon icon = MacIntelliJIconCache.getIcon("helpButton", false, c.hasFocus(), false); + Icon icon = MacIntelliJIconCache.getIcon("helpButton", false, c.hasFocus()); int x = (w - icon.getIconWidth()) / 2; int y = (h - icon.getIconHeight()) / 2; icon.paintIcon(c, g, x, y); @@ -114,7 +114,7 @@ public class MacIntelliJButtonUI extends DarculaButtonUI { boolean combo = button.getClientProperty("styleCombo") == Boolean.TRUE; String comboPrefix = combo ? "Combo" : ""; String iconName = "button" + comboPrefix + suffix; - return MacIntelliJIconCache.getIcon(iconName, isDefault, isFocused && !combo, false); + return MacIntelliJIconCache.getIcon(iconName, isDefault, isFocused && !combo); } private String layout(AbstractButton b, FontMetrics fm, diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/MacIntelliJCheckBoxUI.java b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/MacIntelliJCheckBoxUI.java index d36e84d36bcb..96f9114781ed 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/MacIntelliJCheckBoxUI.java +++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/MacIntelliJCheckBoxUI.java @@ -41,9 +41,13 @@ public class MacIntelliJCheckBoxUI extends IntelliJCheckBoxUI { @Override protected void drawCheckIcon(JComponent c, Graphics2D g, JCheckBox b, Rectangle iconRect, boolean selected, boolean enabled) { - MacIntelliJIconCache - .getIcon("checkBox", selected, c.hasFocus()) - .paintIcon(c, g, iconRect.x, iconRect.y); + String iconName = isIndeterminate(b) ? "checkBoxIndeterminate" : "checkBox"; + Icon icon = MacIntelliJIconCache.getIcon(iconName, selected || isIndeterminate(b), c.hasFocus(), b.isEnabled()); + icon.paintIcon(c, g, iconRect.x, iconRect.y); + } + + private static boolean isIndeterminate(JCheckBox checkBox) { + return "indeterminate".equals(checkBox.getClientProperty("JButton.selectedState")); } @Override diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/MacIntelliJComboBoxUI.java b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/MacIntelliJComboBoxUI.java index e795023a53b5..4ef6f71f8f3c 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/MacIntelliJComboBoxUI.java +++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/MacIntelliJComboBoxUI.java @@ -61,7 +61,7 @@ public class MacIntelliJComboBoxUI extends BasicComboBoxUI { JButton button = new BasicArrowButton(SwingConstants.SOUTH, bg, fg, fg, fg) { @Override public void paint(Graphics g2) { - Icon icon = MacIntelliJIconCache.getIcon("comboRight", false, myComboBox.hasFocus(), !myComboBox.isEnabled()); + Icon icon = MacIntelliJIconCache.getIcon("comboRight", false, myComboBox.hasFocus(), myComboBox.isEnabled()); icon.paintIcon(this, g2, 0, 0); } @@ -239,18 +239,18 @@ public class MacIntelliJComboBoxUI extends BasicComboBoxUI { int stop = r.x; Insets clip = getInsets(); Graphics gg = g.create(clip.left, r.y, stop - clip.left, DEFAULT_ICON.getIconHeight()); - boolean disabled = !c.isEnabled(); + boolean enabled = c.isEnabled(); boolean hasFocus = c.hasFocus(); - Icon icon = MacIntelliJIconCache.getIcon("comboLeft", false, hasFocus, disabled); + Icon icon = MacIntelliJIconCache.getIcon("comboLeft", false, hasFocus, enabled); icon.paintIcon(c,gg,0,0); int x = icon.getIconWidth(); - icon = MacIntelliJIconCache.getIcon("comboMiddle", false, hasFocus, disabled); + icon = MacIntelliJIconCache.getIcon("comboMiddle", false, hasFocus, enabled); while (x < stop) { icon.paintIcon(c, gg, x, 0); x+=icon.getIconWidth(); } gg.dispose(); - icon = MacIntelliJIconCache.getIcon("comboRight", false, hasFocus, disabled); + icon = MacIntelliJIconCache.getIcon("comboRight", false, hasFocus, enabled); icon.paintIcon(c, g, r.x, r.y); if ( !comboBox.isEditable() ) { diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/MacIntelliJIconCache.java b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/MacIntelliJIconCache.java index 100ccbd61a4e..15cc44cf8ed1 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/MacIntelliJIconCache.java +++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/MacIntelliJIconCache.java @@ -27,11 +27,11 @@ import javax.swing.*; public class MacIntelliJIconCache { private static final HashMap cache = new HashMap(); - public static Icon getIcon(String name, boolean selected, boolean focused, boolean disabled) { + public static Icon getIcon(String name, boolean selected, boolean focused, boolean enabled) { String key = name; if (selected) key+= "Selected"; if (focused) key+= "Focused"; - else if (disabled) key+="Disabled"; + else if (!enabled) key+="Disabled"; if (IntelliJLaf.isGraphite()) key= "graphite/" + key; Icon icon = cache.get(key); if (icon == null) { @@ -42,9 +42,9 @@ public class MacIntelliJIconCache { } public static Icon getIcon(String name, boolean selected, boolean focused) { - return getIcon(name, selected, focused, false); + return getIcon(name, selected, focused, true); } public static Icon getIcon(String name) { - return getIcon(name, false, false, false); + return getIcon(name, false, false, true); } } diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/MacIntelliJRadioButtonUI.java b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/MacIntelliJRadioButtonUI.java index b8b3c1a21de9..fd86f4e86376 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/MacIntelliJRadioButtonUI.java +++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/MacIntelliJRadioButtonUI.java @@ -35,7 +35,7 @@ public class MacIntelliJRadioButtonUI extends DarculaRadioButtonUI { @Override protected void paintIcon(JComponent c, Graphics2D g, Rectangle viewRect, Rectangle iconRect) { - Icon icon = MacIntelliJIconCache.getIcon("radio", ((AbstractButton)c).isSelected(), c.hasFocus(), !c.isEnabled()); + Icon icon = MacIntelliJIconCache.getIcon("radio", ((AbstractButton)c).isSelected(), c.hasFocus(), c.isEnabled()); icon.paintIcon(c, g, iconRect.x, iconRect.y); } diff --git a/platform/platform-impl/src/com/intellij/ide/util/GotoLineNumberDialog.java b/platform/platform-impl/src/com/intellij/ide/util/GotoLineNumberDialog.java index 1c8a887bb0d6..2cfe3ec9266a 100644 --- a/platform/platform-impl/src/com/intellij/ide/util/GotoLineNumberDialog.java +++ b/platform/platform-impl/src/com/intellij/ide/util/GotoLineNumberDialog.java @@ -15,88 +15,57 @@ */ package com.intellij.ide.util; -import com.intellij.ide.IdeBundle; import com.intellij.openapi.application.ex.ApplicationManagerEx; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.LogicalPosition; import com.intellij.openapi.editor.ScrollType; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.DialogWrapper; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.wm.IdeFocusManager; +import com.intellij.ui.DocumentAdapter; +import com.intellij.util.PatternUtil; +import org.jetbrains.annotations.Nullable; import javax.swing.*; +import javax.swing.event.DocumentEvent; import java.awt.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; public class GotoLineNumberDialog extends DialogWrapper { private JTextField myField; private JTextField myOffsetField; private final Editor myEditor; + private final Pattern myPattern = PatternUtil.compileSafe("\\s*(\\d+)\\s*(?:[,:]?\\s*(\\d+)?)?\\s*", null); - public GotoLineNumberDialog(Project project, Editor editor){ + public GotoLineNumberDialog(Project project, Editor editor) { super(project, true); myEditor = editor; - setTitle(IdeBundle.message("title.go.to.line")); + setTitle("Go to Line"); init(); } - protected void doOKAction(){ - final LogicalPosition currentPosition = myEditor.getCaretModel().getLogicalPosition(); - int lineNumber = getLineNumber(currentPosition.line + 1); - if (isInternal() && myOffsetField.getText().length() > 0) { - try { - final int offset = Integer.parseInt(myOffsetField.getText()); - if (offset < myEditor.getDocument().getTextLength()) { - myEditor.getCaretModel().removeSecondaryCarets(); - myEditor.getCaretModel().moveToOffset(offset); - myEditor.getScrollingModel().scrollToCaret(ScrollType.CENTER); - myEditor.getSelectionModel().removeSelection(); - IdeFocusManager.getGlobalInstance().requestFocus(myEditor.getContentComponent(), true); - super.doOKAction(); - } - return; - } - catch (NumberFormatException e) { - return; - } - } + protected void doOKAction() { + LogicalPosition position = getLogicalPosition(); + if (position == null) return; - if (lineNumber < 0) return; - - int columnNumber = getColumnNumber(currentPosition.column); myEditor.getCaretModel().removeSecondaryCarets(); - myEditor.getCaretModel().moveToLogicalPosition(new LogicalPosition(Math.max(0, lineNumber - 1), Math.max(0, columnNumber - 1))); + myEditor.getCaretModel().moveToLogicalPosition(position); myEditor.getScrollingModel().scrollToCaret(ScrollType.CENTER); myEditor.getSelectionModel().removeSelection(); IdeFocusManager.getGlobalInstance().requestFocus(myEditor.getContentComponent(), true); super.doOKAction(); } - private int getColumnNumber(int defaultValue) { - String text = getText(); - int columnIndex = columnSeparatorIndex(text); - if (columnIndex == -1) return defaultValue; - try { - return Integer.parseInt(text.substring(columnIndex + 1)); - } catch (NumberFormatException e) { - return defaultValue; - } - } + @Nullable + private LogicalPosition getLogicalPosition() { + Matcher m = myPattern.matcher(getText()); + if (!m.matches()) return null; - private static int columnSeparatorIndex(final String text) { - final int colonIndex = text.indexOf(':'); - return colonIndex >= 0 ? colonIndex : text.indexOf(','); - } - - private int getLineNumber(int defaultLine) { - try { - String text = getText(); - int columnIndex = columnSeparatorIndex(text); - text = columnIndex == -1 ? text : text.substring(0, columnIndex); - if (text.trim().length() == 0) return defaultLine; - return Integer.parseInt(text); - } catch (NumberFormatException e) { - return -1; - } + int l = StringUtil.parseInt(m.group(1), -1); + int c = StringUtil.parseInt(m.group(2), -1); + return l > 0 ? new LogicalPosition(l - 1, Math.max(0, c - 1)) : null; } private static boolean isInternal() { @@ -135,14 +104,13 @@ public class GotoLineNumberDialog extends DialogWrapper { gbConstraints.weightx = 0; gbConstraints.weighty = 1; gbConstraints.anchor = GridBagConstraints.EAST; - JLabel label = new JLabel(IdeBundle.message("editbox.line.number")); + JLabel label = new JLabel("Line [:column]:"); panel.add(label, gbConstraints); gbConstraints.fill = GridBagConstraints.BOTH; gbConstraints.weightx = 1; myField = new MyTextField(); panel.add(myField, gbConstraints); - myField.setToolTipText(IdeBundle.message("tooltip.syntax.linenumber.columnnumber")); LogicalPosition position = myEditor.getCaretModel().getLogicalPosition(); myField.setText(String.format("%d:%d", position.line + 1, position.column + 1)); @@ -159,6 +127,41 @@ public class GotoLineNumberDialog extends DialogWrapper { myOffsetField = new MyTextField(); panel.add(myOffsetField, gbConstraints); myOffsetField.setText(String.valueOf(myEditor.getCaretModel().getOffset())); + + DocumentAdapter valueSync = new DocumentAdapter() { + boolean inSync; + + @Override + protected void textChanged(DocumentEvent e) { + if (inSync) return; + inSync = true; + String s = ""; + JTextField f = null; + try { + if (e.getDocument() == myField.getDocument()) { + f = myOffsetField; + LogicalPosition p = getLogicalPosition(); + s = p == null ? s : String.valueOf(myEditor.logicalPositionToOffset(p)); + } + else { + f = myField; + int offset = StringUtil.parseInt(myOffsetField.getText(), -1); + LogicalPosition p = offset >= 0 ? myEditor.offsetToLogicalPosition( + Math.min(myEditor.getDocument().getTextLength() - 1, offset)) : null; + s = p == null ? s : String.format("%d:%d", p.line + 1, p.column + 1); + } + f.setText(s); + } + catch (IndexOutOfBoundsException ignored) { + if (f != null) f.setText(s); + } + finally { + inSync = false; + } + } + }; + myField.getDocument().addDocumentListener(valueSync); + myOffsetField.getDocument().addDocumentListener(valueSync); } return panel; diff --git a/platform/platform-impl/src/com/intellij/ide/util/TipUIUtil.java b/platform/platform-impl/src/com/intellij/ide/util/TipUIUtil.java index f98ce8b1d826..ffd9cff6ec70 100644 --- a/platform/platform-impl/src/com/intellij/ide/util/TipUIUtil.java +++ b/platform/platform-impl/src/com/intellij/ide/util/TipUIUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * 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. @@ -124,7 +124,8 @@ public class TipUIUtil { private static final String TIP_HTML_TEXT_TAGS = "h1, p, pre, ul"; private static void adjustFontSize(StyleSheet styleSheet) { - float scale = (float)UISettings.getInstance().FONT_SIZE / UIUtil.getSystemFontData().getSecond(); + Pair systemFontData = UIUtil.getSystemFontData(); + float scale = systemFontData == null ? 0 : (float)UISettings.getInstance().FONT_SIZE / systemFontData.getSecond(); if (scale <= 1) return; // don't bother about decreasing // When the primary font is increased we should take care of the visibility of the tips font diff --git a/platform/platform-impl/src/com/intellij/internal/inspector/UiInspectorAction.java b/platform/platform-impl/src/com/intellij/internal/inspector/UiInspectorAction.java index 65c1c14861ae..c4c18045e9ea 100644 --- a/platform/platform-impl/src/com/intellij/internal/inspector/UiInspectorAction.java +++ b/platform/platform-impl/src/com/intellij/internal/inspector/UiInspectorAction.java @@ -302,6 +302,7 @@ public class UiInspectorAction extends ToggleAction implements DumbAware { if (component.isDoubleBuffered()) { append(", double-buffered", SimpleTextAttributes.GRAYED_ATTRIBUTES); } + componentNode.setText(toString()); setIcon(new TwoColorsIcon(11, component.getForeground(), component.getBackground())); } @@ -366,6 +367,7 @@ public class UiInspectorAction extends ToggleAction implements DumbAware { private static class ComponentNode extends DefaultMutableTreeNode { private final Component myComponent; + String myText; private ComponentNode(@NotNull Component component) { super(component); @@ -379,7 +381,11 @@ public class UiInspectorAction extends ToggleAction implements DumbAware { @Override public String toString() { - return myComponent.getClass().getName(); + return myText != null ? myText : myComponent.getClass().getName(); + } + + public void setText(String value) { + myText = value; } @Override diff --git a/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java b/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java index b8bfe9ff8765..7b51b4af34de 100644 --- a/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java @@ -65,8 +65,9 @@ import com.intellij.util.concurrency.Semaphore; import com.intellij.util.containers.Stack; import com.intellij.util.io.storage.HeavyProcessLatch; import com.intellij.util.ui.UIUtil; -import gnu.trove.TLongArrayList; -import gnu.trove.TLongProcedure; +import gnu.trove.TIntArrayList; +import gnu.trove.TIntProcedure; +import jsr166e.StampedLock; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.TestOnly; @@ -78,22 +79,18 @@ import java.awt.*; import java.io.File; import java.io.IOException; import java.lang.reflect.Method; +import java.util.ArrayList; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.locks.ReentrantReadWriteLock; public class ApplicationImpl extends PlatformComponentManagerImpl implements ApplicationEx { private static final Logger LOG = Logger.getInstance("#com.intellij.application.impl.ApplicationImpl"); private final ModalityState MODALITY_STATE_NONE = ModalityState.NON_MODAL; - // about writer preference: the way the j.u.c.l.ReentrantReadWriteLock.NonfairSync is implemented, the - // writer thread will be always at the queue head and therefore, j.u.c.l.ReentrantReadWriteLock.NonfairSync.readerShouldBlock() - // will return true if the write action is pending, exactly as we need - private final ReentrantReadWriteLock myLock = new ReentrantReadWriteLock(false); + private final StampedLock myLock = new StampedLock(); private final ModalityInvokator myInvokator = new ModalityInvokatorImpl(); @@ -126,12 +123,13 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App private static final String WAS_EVER_SHOWN = "was.ever.shown"; private static final int IS_EDT_FLAG = 1<<30; // we don't mess with sign bit since we want to do arithmetic - private static final int IS_READ_LOCK_ACQUIRED_FLAG = 1<<29; private static class Status { // higher three bits are for IS_* flags // lower bits are for edtSafe counter private int flags; + // StampedLock' acquired sequence or zero if not locked + private long stamp; } private static final ThreadLocal status = new ThreadLocal(){ @@ -145,9 +143,6 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App private static Status getStatus() { return status.get(); } - private static void setReadLockAcquired(Status status, boolean acquired) { - status.flags = BitUtil.set(status.flags, IS_READ_LOCK_ACQUIRED_FLAG, acquired); - } private static final ModalityState ANY = new ModalityState() { @Override @@ -319,7 +314,7 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App } private static boolean holdsReadLock(Status status) { - return BitUtil.isSet(status.flags, IS_READ_LOCK_ACQUIRED_FLAG); + return status.stamp != 0; } @NotNull @@ -542,10 +537,10 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App Disposer.dispose(myLastDisposable); // dispose it last if (LOG.isDebugEnabled()) { - final long[] sum = {0}; - writePauses.forEach(new TLongProcedure() { + final int[] sum = {0}; + writePauses.forEach(new TIntProcedure() { @Override - public boolean execute(long value) { + public boolean execute(int value) { sum[0] += value; return true; } @@ -554,8 +549,7 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App "\nTotal write actions: " + writePauses.size() + "\nTotal write pauses : " + sum[0] + "ms"+ "\nAverage write pause: " + sum[0] / writePauses.size() + "ms" + - "\nMedian write pause: " + ArrayUtil.averageAmongMedians(writePauses.toNativeArray(), 3) + "ms" + - "" + "\nMedian write pause: " + ArrayUtil.averageAmongMedians(writePauses.toNativeArray(), 3) + "ms" ); } } @@ -981,8 +975,7 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App private void startRead(Status status) { assertNoPsiLock(); try { - myLock.readLock().lockInterruptibly(); - setReadLockAcquired(status, true); + status.stamp = myLock.readLockInterruptibly(); } catch (InterruptedException e) { throw new RuntimeInterruptedException(e); @@ -990,8 +983,8 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App } private void endRead(Status status) { - setReadLockAcquired(status, false); - myLock.readLock().unlock(); + myLock.unlockRead(status.stamp); + status.stamp = 0; } @Override @@ -1074,7 +1067,7 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App } private static boolean isReadAccessAllowed(Status status) { - return (status.flags & (IS_EDT_FLAG | IS_READ_LOCK_ACQUIRED_FLAG)) != 0; + return BitUtil.isSet(status.flags, IS_EDT_FLAG) || status.stamp != 0; } @Override @@ -1155,14 +1148,7 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App if (mustAcquire) { assertNoPsiLock(); - try { - // timed version of tryLock() respects fairness unlike the no-args method - if (!myLock.readLock().tryLock(0, TimeUnit.MILLISECONDS)) return false; - setReadLockAcquired(status, true); - } - catch (InterruptedException e) { - throw new RuntimeInterruptedException(e); - } + if ((status.stamp = myLock.tryReadLock()) == 0) return false; } try { @@ -1207,9 +1193,10 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App return myWriteActionPending; } - private final TLongArrayList writePauses = new TLongArrayList(); + private final TIntArrayList writePauses = new TIntArrayList(); private void startWrite(@Nullable Class clazz) { - assertIsDispatchThread(getStatus(), "Write access is allowed from event dispatch thread only"); + Status status = getStatus(); + assertIsDispatchThread(status, "Write access is allowed from event dispatch thread only"); boolean writeActionPending = myWriteActionPending; myWriteActionPending = true; long start = System.currentTimeMillis(); @@ -1218,26 +1205,26 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App fireBeforeWriteActionStart(clazz); try { - if (!isWriteAccessAllowed()) { + if (!myLock.isWriteLocked()) { assertNoPsiLock(); - } - if (!myLock.writeLock().tryLock()) { - final AtomicBoolean lockAcquired = new AtomicBoolean(false); - if (ourDumpThreadsOnLongWriteActionWaiting > 0) { - executeOnPooledThread(new Runnable() { - @Override - public void run() { - while (!lockAcquired.get()) { - TimeoutUtil.sleep(ourDumpThreadsOnLongWriteActionWaiting); - if (!lockAcquired.get()) { - PerformanceWatcher.getInstance().dumpThreads("waiting", true); + if ((status.stamp = myLock.tryWriteLock()) == 0) { + final AtomicBoolean lockAcquired = new AtomicBoolean(false); + if (ourDumpThreadsOnLongWriteActionWaiting > 0) { + executeOnPooledThread(new Runnable() { + @Override + public void run() { + while (!lockAcquired.get()) { + TimeoutUtil.sleep(ourDumpThreadsOnLongWriteActionWaiting); + if (!lockAcquired.get()) { + PerformanceWatcher.getInstance().dumpThreads("waiting", true); + } } } - } - }); + }); + } + status.stamp = myLock.writeLockInterruptibly(); + lockAcquired.set(true); } - myLock.writeLock().lockInterruptibly(); - lockAcquired.set(true); } } catch (InterruptedException e) { @@ -1251,18 +1238,22 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App myWriteActionsStack.push(clazz); if (LOG.isDebugEnabled()) { long end = System.currentTimeMillis(); - writePauses.add(end - start); + writePauses.add((int)(end - start)); } fireWriteActionStarted(clazz); } private void endWrite(@Nullable Class clazz) { try { - myWriteActionsStack.pop(); fireWriteActionFinished(clazz); } finally { - myLock.writeLock().unlock(); + myWriteActionsStack.pop(); + if (myWriteActionsStack.isEmpty()) { + Status status = getStatus(); + myLock.unlockWrite(status.stamp); + status.stamp = 0; + } } } @@ -1363,7 +1354,7 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App @Override public boolean isWriteAccessAllowed() { - return myLock.isWriteLockedByCurrentThread(); + return isDispatchThread() && myLock.isWriteLocked(); } // cheaper version of isWriteAccessAllowed(). must be called from EDT @@ -1494,4 +1485,16 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App (isHeadlessEnvironment() ? " (Headless)" : "") + (isCommandLine() ? " (Command line)" : ""); } + + @TestOnly + public void disableEventsUntil(@NotNull Disposable disposable) { + final List listeners = new ArrayList(myDispatcher.getListeners()); + myDispatcher.getListeners().removeAll(listeners); + Disposer.register(disposable, new Disposable() { + @Override + public void dispose() { + myDispatcher.getListeners().addAll(listeners); + } + }); + } } diff --git a/platform/platform-impl/src/com/intellij/openapi/application/impl/TransferToPooledThreadQueue.java b/platform/platform-impl/src/com/intellij/openapi/application/impl/TransferToPooledThreadQueue.java index 79435a4c7166..d07aeb2b6e6e 100644 --- a/platform/platform-impl/src/com/intellij/openapi/application/impl/TransferToPooledThreadQueue.java +++ b/platform/platform-impl/src/com/intellij/openapi/application/impl/TransferToPooledThreadQueue.java @@ -16,13 +16,14 @@ package com.intellij.openapi.application.impl; import com.intellij.openapi.util.Condition; -import com.intellij.util.ConcurrencyUtil; import com.intellij.util.Processor; +import com.intellij.util.concurrency.BoundedTaskExecutor; import com.intellij.util.containers.TransferToEDTQueue; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; +import org.jetbrains.ide.PooledThreadExecutor; -import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.Executor; /** * Passes elements for processing in the dedicated thread. @@ -30,14 +31,14 @@ import java.util.concurrent.ThreadPoolExecutor; * Usage: {@link #offer(Object)}} : schedules element for processing in a pooled thread */ public class TransferToPooledThreadQueue extends TransferToEDTQueue { - private final ThreadPoolExecutor myExecutor; + private final Executor myExecutor; public TransferToPooledThreadQueue(@NonNls @NotNull String name, @NotNull Condition shutUpCondition, int maxUnitOfWorkThresholdMs, @NotNull Processor processor) { super(name, processor, shutUpCondition, maxUnitOfWorkThresholdMs); - myExecutor = ConcurrencyUtil.newSingleThreadExecutor(name); + myExecutor = new BoundedTaskExecutor(PooledThreadExecutor.INSTANCE, 1); } @Override diff --git a/platform/platform-impl/src/com/intellij/openapi/command/impl/UndoManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/command/impl/UndoManagerImpl.java index af6da88acfb6..466c0f8d431b 100644 --- a/platform/platform-impl/src/com/intellij/openapi/command/impl/UndoManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/command/impl/UndoManagerImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * 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. @@ -647,11 +647,12 @@ public class UndoManagerImpl extends UndoManager implements ProjectComponent, Ap } @TestOnly - public void setEditorProvider(CurrentEditorProvider p) { + public void setEditorProvider(@NotNull CurrentEditorProvider p) { myEditorProvider = p; } @TestOnly + @NotNull public CurrentEditorProvider getEditorProvider() { return myEditorProvider; } diff --git a/platform/platform-impl/src/com/intellij/openapi/components/ServiceDescriptor.java b/platform/platform-impl/src/com/intellij/openapi/components/ServiceDescriptor.java index 16105e50d367..86c5669f6bf3 100644 --- a/platform/platform-impl/src/com/intellij/openapi/components/ServiceDescriptor.java +++ b/platform/platform-impl/src/com/intellij/openapi/components/ServiceDescriptor.java @@ -16,6 +16,7 @@ package com.intellij.openapi.components; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.util.xmlb.annotations.Attribute; public class ServiceDescriptor { @@ -25,6 +26,9 @@ public class ServiceDescriptor { @Attribute("serviceImplementation") public String serviceImplementation; + @Attribute("testServiceImplementation") + public String testServiceImplementation; + @Attribute("overrides") public boolean overrides; @@ -36,6 +40,6 @@ public class ServiceDescriptor { } public String getImplementation() { - return serviceImplementation; + return testServiceImplementation != null && ApplicationManager.getApplication().isUnitTestMode() ? testServiceImplementation : serviceImplementation; } } diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/ServiceManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/components/impl/ServiceManagerImpl.java index 9798cb0a86d7..cd4904a749c2 100644 --- a/platform/platform-impl/src/com/intellij/openapi/components/impl/ServiceManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/ServiceManagerImpl.java @@ -86,7 +86,7 @@ public class ServiceManagerImpl implements BaseComponent { } // empty serviceImplementation means we want to unregister service - if (!StringUtil.isEmpty(descriptor.serviceImplementation)) { + if (!StringUtil.isEmpty(descriptor.getImplementation())) { picoContainer.registerComponent(new MyComponentAdapter(descriptor, pluginDescriptor, (ComponentManagerEx)componentManager)); } } diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/IProjectStore.java b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/IProjectStore.java index c711e37c40a2..8736913168a0 100644 --- a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/IProjectStore.java +++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/IProjectStore.java @@ -61,4 +61,8 @@ public interface IProjectStore extends IComponentStore { void loadProjectFromTemplate(@NotNull Project project); void clearStorages(); + + boolean isOptimiseTestLoadSpeed(); + + void setOptimiseTestLoadSpeed(boolean optimiseTestLoadSpeed); } diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StateStorageBase.kt b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StateStorageBase.kt index 7bcfe136c750..03f9840274fb 100644 --- a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StateStorageBase.kt +++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StateStorageBase.kt @@ -20,24 +20,24 @@ import com.intellij.openapi.diagnostic.Logger import org.jdom.Element import java.util.concurrent.atomic.AtomicReference -public abstract class StateStorageBase : StateStorage { +abstract class StateStorageBase : StateStorage { companion object { - private val LOG: Logger = Logger.getInstance(javaClass>()) + private val LOG: Logger = Logger.getInstance(StateStorageBase::class.java) } private var mySavingDisabled = false protected val storageDataRef: AtomicReference = AtomicReference() - override final fun getState(component: Any?, componentName: String, stateClass: Class, mergeInto: S?, reload: Boolean): S? { + override final fun getState(component: Any?, componentName: String, stateClass: Class, mergeInto: S?, reload: Boolean): S? { return getState(component, componentName, stateClass, true, reload, mergeInto) } - fun getState(component: Any?, componentName: String, stateClass: Class, archive: Boolean = true, reload: Boolean = false, mergeInto: S? = null): S? { + fun getState(component: Any?, componentName: String, stateClass: Class, archive: Boolean = true, reload: Boolean = false, mergeInto: S? = null): S? { return deserializeState(getSerializedState(getStorageData(reload), component, componentName, archive), stateClass, mergeInto) } - open fun deserializeState(serializedState: Element?, stateClass: Class, mergeInto: S?): S? { + open fun deserializeState(serializedState: Element?, stateClass: Class, mergeInto: S?): S? { return DefaultStateSerializer.deserializeState(serializedState, stateClass, mergeInto) } diff --git a/platform/platform-impl/src/com/intellij/openapi/components/service.kt b/platform/platform-impl/src/com/intellij/openapi/components/service.kt index f5818f0f37be..a8e27387c272 100644 --- a/platform/platform-impl/src/com/intellij/openapi/components/service.kt +++ b/platform/platform-impl/src/com/intellij/openapi/components/service.kt @@ -19,11 +19,12 @@ import com.intellij.openapi.components.ex.ComponentManagerEx import com.intellij.openapi.components.impl.stores.IComponentStore import com.intellij.openapi.project.Project -public inline fun service(): T = ServiceManager.getService(javaClass()) +inline fun service(): T = ServiceManager.getService(T::class.java) -public inline fun Project.service(): T = ServiceManager.getService(this, javaClass()) +inline fun Project.service(): T = ServiceManager.getService(this, T::class.java) -public val ComponentManager.stateStore: IComponentStore - get() = if (this is Project) getPicoContainer().getComponentInstance(javaClass()) as IComponentStore else getPicoContainer().getComponentInstance(javaClass().getName()) as IComponentStore +val ComponentManager.stateStore: IComponentStore + get() = if (this is Project) getPicoContainer().getComponentInstance(IComponentStore::class.java) as IComponentStore else getPicoContainer().getComponentInstance(IComponentStore::class.java.getName()) as IComponentStore -public fun ComponentManager.getComponents(baseClass: Class): List = (this as ComponentManagerEx).getComponentInstancesOfType(baseClass) \ No newline at end of file +@Suppress("DEPRECATED_SYMBOL_WITH_MESSAGE") +fun ComponentManager.getComponents(baseClass: Class): List = (this as ComponentManagerEx).getComponentInstancesOfType(baseClass) \ No newline at end of file diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/actions/MergeOperations.java b/platform/platform-impl/src/com/intellij/openapi/diff/actions/MergeOperations.java index b68c3fb251b1..8fdd8438af49 100644 --- a/platform/platform-impl/src/com/intellij/openapi/diff/actions/MergeOperations.java +++ b/platform/platform-impl/src/com/intellij/openapi/diff/actions/MergeOperations.java @@ -64,8 +64,8 @@ public class MergeOperations { if (isWritable(mySide)) operations.add(removeOperation(range, getDocument())); TextRange otherRange = fragment.getRange(mySide.otherSide()); boolean otherIsWritable = isWritable(mySide.otherSide()); - if (otherIsWritable) operations.add(insertOperation(range, otherRange.getEndOffset(), getDocument(), getOtherDocument())); - if (otherRange.getLength() > 0 && otherIsWritable) operations.add(replaceOperation(range, otherRange, getDocument(), getOtherDocument())); + if (otherIsWritable) operations.add(insertOperation(range, otherRange.getEndOffset(), getDocument(), getOtherDocument(), mySide)); + if (otherRange.getLength() > 0 && otherIsWritable) operations.add(replaceOperation(range, otherRange, getDocument(), getOtherDocument(), mySide)); } return operations; } @@ -99,21 +99,21 @@ public class MergeOperations { myDiffPanel.getEditor(side).getSelectionModel().setSelection(range.getStartOffset(), range.getEndOffset()); } - private static Operation replaceOperation(TextRange range, TextRange otherRange, Document document, Document otherDocument) { + private static Operation replaceOperation(TextRange range, TextRange otherRange, Document document, Document otherDocument, FragmentSide base) { return new Operation(DiffBundle.message("merge.editor.replace.operation.name"), - AllIcons.Diff.Arrow, + base == FragmentSide.SIDE1 ? AllIcons.Diff.ArrowRight : AllIcons.Diff.Arrow, otherDocument, replaceModification(range, document, otherRange, otherDocument)); } @Nullable - public static Operation mostSensible(Document document, Document otherDocument, TextRange range, TextRange otherRange) { + public static Operation mostSensible(Document document, Document otherDocument, TextRange range, TextRange otherRange, FragmentSide base) { if (!canMakeWritable(document) && !canMakeWritable(otherDocument)) return null; if (range.getLength() != 0) { if (canMakeWritable(otherDocument)) return otherRange.getLength() != 0 ? - replaceOperation(range, otherRange, document, otherDocument) : - insertOperation(range, otherRange.getEndOffset(), document, otherDocument); + replaceOperation(range, otherRange, document, otherDocument, base) : + insertOperation(range, otherRange.getEndOffset(), document, otherDocument, base); else return otherRange.getLength() == 0 ? removeOperation(range, document) : null; } return null; @@ -129,9 +129,9 @@ public class MergeOperations { }; } - private static Operation insertOperation(TextRange range, int offset, Document document, Document otherDocument) { + private static Operation insertOperation(TextRange range, int offset, Document document, Document otherDocument, FragmentSide base) { return new Operation(DiffBundle.message("merge.editor.insert.operation.name"), - AllIcons.Diff.ArrowLeftDown, + base == FragmentSide.SIDE1 ? AllIcons.Diff.ArrowRightDown : AllIcons.Diff.ArrowLeftDown, otherDocument, insertModification(range, document, offset, otherDocument)); } diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/impl/fragments/FragmentHighlighterImpl.java b/platform/platform-impl/src/com/intellij/openapi/diff/impl/fragments/FragmentHighlighterImpl.java index a376b03dc70b..0223afb133eb 100644 --- a/platform/platform-impl/src/com/intellij/openapi/diff/impl/fragments/FragmentHighlighterImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/diff/impl/fragments/FragmentHighlighterImpl.java @@ -18,6 +18,7 @@ package com.intellij.openapi.diff.impl.fragments; import com.intellij.openapi.diff.actions.MergeOperations; import com.intellij.openapi.diff.impl.DiffUtil; import com.intellij.openapi.diff.impl.highlighting.DiffMarkup; +import com.intellij.openapi.diff.impl.highlighting.FragmentSide; import com.intellij.openapi.diff.impl.util.TextDiffTypeEnum; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.markup.SeparatorPlacement; @@ -69,12 +70,13 @@ public class FragmentHighlighterImpl implements FragmentHighlighter { private static void addModifyActions(final LineFragment fragment, DiffMarkup wrapper, DiffMarkup otherWrapper) { if (fragment.isEqual()) return; if (fragment.isHasLineChildren()) return; - TextRange range = fragment.getRange(wrapper.getSide()); - TextRange otherRange = fragment.getRange(wrapper.getSide().otherSide()); + FragmentSide side = wrapper.getSide(); + TextRange range = fragment.getRange(side); + TextRange otherRange = fragment.getRange(side.otherSide()); Document document = wrapper.getDocument(); Document otherDocument = otherWrapper.getDocument(); - wrapper.addAction(MergeOperations.mostSensible(document, otherDocument, range, otherRange), range.getStartOffset()); - otherWrapper.addAction(MergeOperations.mostSensible(otherDocument, document, otherRange, range), otherRange.getStartOffset()); + wrapper.addAction(MergeOperations.mostSensible(document, otherDocument, range, otherRange, side), range.getStartOffset()); + otherWrapper.addAction(MergeOperations.mostSensible(otherDocument, document, otherRange, range, side.otherSide()), otherRange.getStartOffset()); } private static void addSeparatingLine(@NotNull LineFragment fragment, @NotNull DiffMarkup appender, int startLine, int endLine) { diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/impl/incrementalMerge/MergeList.java b/platform/platform-impl/src/com/intellij/openapi/diff/impl/incrementalMerge/MergeList.java index 106daac84ee8..82d79e0d8766 100644 --- a/platform/platform-impl/src/com/intellij/openapi/diff/impl/incrementalMerge/MergeList.java +++ b/platform/platform-impl/src/com/intellij/openapi/diff/impl/incrementalMerge/MergeList.java @@ -42,6 +42,7 @@ import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import javax.swing.*; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; @@ -237,7 +238,8 @@ public class MergeList implements UserDataHolder { for (int i = 0; i < changeList.getCount(); i++) { final Change change = changeList.getChange(i); if (!change.canHasActions(originalSide)) continue; - AnAction applyAction = new DumbAwareAction(DiffBundle.message("merge.dialog.apply.change.action.name"), null, AllIcons.Diff.Arrow) { + Icon arrowIcon = side == FragmentSide.SIDE1 ? AllIcons.Diff.ArrowRight : AllIcons.Diff.Arrow; + AnAction applyAction = new DumbAwareAction(DiffBundle.message("merge.dialog.apply.change.action.name"), null, arrowIcon) { @Override public void actionPerformed(@Nullable AnActionEvent e) { apply(change); diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorGutterComponentImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorGutterComponentImpl.java index 97c1203b8af2..fc3aa066684e 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorGutterComponentImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorGutterComponentImpl.java @@ -353,23 +353,15 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse paintBackground(g, clip, getAnnotationsAreaOffset(), w, backgroundColor); } - private void paintAnnotations(Graphics g, Rectangle clip) { + private void paintAnnotations(Graphics2D g, Rectangle clip) { int x = getAnnotationsAreaOffset(); int w = getAnnotationsAreaWidthEx(); if (w == 0) return; - Graphics2D g2 = (Graphics2D)g; - AffineTransform old = g2.getTransform(); + AffineTransform old = g.getTransform(); + g.setTransform(getMirrorTransform(old, x, w)); try { - if (isMirrored()) { - final AffineTransform transform = new AffineTransform(old); - transform.scale(-1, 1); - int shift = -getWidth() + (getWidth() - x - getAnnotationsAreaWidth()) - x; - transform.translate(shift, 0); - g2.setTransform(transform); - } - Color color = myEditor.getColorsScheme().getColor(EditorColors.ANNOTATIONS_COLOR); g.setColor(color != null ? color : JBColor.blue); g.setFont(myEditor.getColorsScheme().getFont(EditorFontType.PLAIN)); @@ -410,7 +402,7 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse } finally { - g2.setTransform(old); + g.setTransform(old); } } @@ -426,7 +418,7 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse } } - private void paintLineMarkers(Graphics g, int firstVisibleOffset, int lastVisibleOffset) { + private void paintLineMarkers(Graphics2D g, int firstVisibleOffset, int lastVisibleOffset) { if (isLineMarkersShown()) { paintGutterRenderers(g, firstVisibleOffset, lastVisibleOffset); } @@ -454,7 +446,7 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse } } - private void paintLineNumbers(Graphics g, Rectangle clip) { + private void paintLineNumbers(Graphics2D g, Rectangle clip) { if (isLineNumbersShown()) { int offset = getLineNumberAreaOffset() + myLineNumberAreaWidth; doPaintLineNumbers(g, clip, offset, myLineNumberConvertor); @@ -479,7 +471,7 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse return color != null ? color : EditorColors.GUTTER_BACKGROUND.getDefaultColor(); } - private void doPaintLineNumbers(Graphics g, Rectangle clip, int offset, @NotNull TIntFunction convertor) { + private void doPaintLineNumbers(Graphics2D g, Rectangle clip, int offset, @NotNull TIntFunction convertor) { if (!isLineNumbersShown()) { return; } @@ -498,41 +490,36 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse g.setColor(color != null ? color : JBColor.blue); g.setFont(myEditor.getColorsScheme().getFont(EditorFontType.PLAIN)); - Graphics2D g2 = (Graphics2D)g; - AffineTransform old = g2.getTransform(); - - if (isMirrored()) { - AffineTransform originalTransform = new AffineTransform(old); - originalTransform.scale(-1, 1); - originalTransform.translate(-getLineNumberAreaWidth() - 1, 0); - g2.setTransform(originalTransform); - } - - for (int i = startLineNumber; i < endLineNumber; i++) { - LogicalPosition logicalPosition = myEditor.visualToLogicalPosition(new VisualPosition(i, 0)); - if (EditorUtil.getSoftWrapCountAfterLineStart(myEditor, logicalPosition) > 0) { - continue; - } - int logLine = convertor.execute(logicalPosition.line); - if (logLine >= 0) { - String s = String.valueOf(logLine + 1); - int startY = (i + 1) * lineHeight; - if (myEditor.isInDistractionFreeMode()) { - Color fgColor = myTextFgColors.get(i); - g.setColor(fgColor != null ? fgColor : color != null ? color : JBColor.blue); + AffineTransform old = g.getTransform(); + g.setTransform(getMirrorTransform(old, getLineNumberAreaOffset(), getLineNumberAreaWidth())); + try { + for (int i = startLineNumber; i < endLineNumber; i++) { + LogicalPosition logicalPosition = myEditor.visualToLogicalPosition(new VisualPosition(i, 0)); + if (EditorUtil.getSoftWrapCountAfterLineStart(myEditor, logicalPosition) > 0) { + continue; } + int logLine = convertor.execute(logicalPosition.line); + if (logLine >= 0) { + String s = String.valueOf(logLine + 1); + int startY = (i + 1) * lineHeight; + if (myEditor.isInDistractionFreeMode()) { + Color fgColor = myTextFgColors.get(i); + g.setColor(fgColor != null ? fgColor : color != null ? color : JBColor.blue); + } - int textOffset = isMirrored() ? - offset - getLineNumberAreaWidth() + GAP_AFTER_LINE_NUMBERS : - offset - myEditor.getFontMetrics(Font.PLAIN).stringWidth(s) - GAP_AFTER_LINE_NUMBERS; + int textOffset = isMirrored() ? + offset - getLineNumberAreaWidth() + GAP_AFTER_LINE_NUMBERS - 1 : + offset - myEditor.getFontMetrics(Font.PLAIN).stringWidth(s) - GAP_AFTER_LINE_NUMBERS; - g.drawString(s, - textOffset, - startY - myEditor.getDescent()); + g.drawString(s, + textOffset, + startY - myEditor.getDescent()); + } } } - - g2.setTransform(old); + finally { + g.setTransform(old); + } } private int endLineNumber() { @@ -779,11 +766,9 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse return foldRegion == null || foldRegion.getEndOffset() < endOffset; } - private void paintGutterRenderers(final Graphics g, int firstVisibleOffset, int lastVisibleOffset) { - Graphics2D g2 = (Graphics2D)g; - - Object hint = g2.getRenderingHint(RenderingHints.KEY_ANTIALIASING); - g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + private void paintGutterRenderers(final Graphics2D g, int firstVisibleOffset, int lastVisibleOffset) { + Object hint = g.getRenderingHint(RenderingHints.KEY_ANTIALIASING); + g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); try { processRangeHighlighters(firstVisibleOffset, lastVisibleOffset, new RangeHighlighterProcessor() { @Override @@ -793,7 +778,7 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse }); } finally { - g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, hint); + g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, hint); } int firstVisibleLine = myEditor.getDocument().getLineNumber(firstVisibleOffset); @@ -801,7 +786,7 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse paintIcons(firstVisibleLine, lastVisibleLine, g); } - private void paintIcons(final int firstVisibleLine, final int lastVisibleLine, final Graphics g) { + private void paintIcons(final int firstVisibleLine, final int lastVisibleLine, final Graphics2D g) { for (int line = firstVisibleLine; line <= lastVisibleLine; line++) { List renderers = myLineToGutterRenderers.get(line); if (renderers != null) { @@ -810,12 +795,20 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse } } - private void paintIconRow(int line, List row, final Graphics g) { + private void paintIconRow(int line, List row, final Graphics2D g) { processIconsRow(line, row, new LineGutterIconRendererProcessor() { @Override public void process(int x, int y, GutterMark renderer) { Icon icon = scaleIcon(renderer.getIcon()); - icon.paintIcon(EditorGutterComponentImpl.this, g, x, y); + + AffineTransform old = g.getTransform(); + g.setTransform(getMirrorTransform(old, x, icon.getIconWidth())); + try { + icon.paintIcon(EditorGutterComponentImpl.this, g, x, y); + } + finally { + g.setTransform(old); + } } }); } @@ -1264,6 +1257,21 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse return myEditor.getVerticalScrollbarOrientation() != EditorEx.VERTICAL_SCROLLBAR_RIGHT; } + @NotNull + private AffineTransform getMirrorTransform(@NotNull AffineTransform old, int offset, int width) { + final AffineTransform transform = new AffineTransform(old); + if (isMirrored()) { + //transform.translate(getWidth(), 0); // revert mirroring transform + //transform.scale(-1, 1); // revert mirroring transform + //transform.translate(getWidth() - offset - width, 0); // move range start to the X==0 + //transform.translate(-offset, 0); + + transform.scale(-1, 1); + transform.translate(-offset * 2 - width, 0); + } + return transform; + } + @Nullable @Override public FoldRegion findFoldingAnchorAt(int x, int y) { diff --git a/platform/platform-impl/src/com/intellij/openapi/project/ex/ProjectEx.java b/platform/platform-impl/src/com/intellij/openapi/project/ex/ProjectEx.java index 90facde40980..a44339933569 100644 --- a/platform/platform-impl/src/com/intellij/openapi/project/ex/ProjectEx.java +++ b/platform/platform-impl/src/com/intellij/openapi/project/ex/ProjectEx.java @@ -27,9 +27,5 @@ public interface ProjectEx extends Project { void init(); - boolean isOptimiseTestLoadSpeed(); - - void setOptimiseTestLoadSpeed(boolean optimiseTestLoadSpeed); - void setProjectName(@NotNull String name); } diff --git a/platform/platform-impl/src/com/intellij/openapi/project/ex/ProjectManagerEx.java b/platform/platform-impl/src/com/intellij/openapi/project/ex/ProjectManagerEx.java index 8abeb689ba4a..ed44bae8514c 100644 --- a/platform/platform-impl/src/com/intellij/openapi/project/ex/ProjectManagerEx.java +++ b/platform/platform-impl/src/com/intellij/openapi/project/ex/ProjectManagerEx.java @@ -56,7 +56,10 @@ public abstract class ProjectManagerEx extends ProjectManager { @TestOnly @NotNull - // returns remaining open test projects + /** + * Without save and "check can close". + * Returns remaining open test projects. + */ public abstract Collection closeTestProject(@NotNull Project project); // returns true on success diff --git a/platform/platform-impl/src/com/intellij/openapi/project/impl/DefaultProject.java b/platform/platform-impl/src/com/intellij/openapi/project/impl/DefaultProject.java index 0e60d4421212..5de4c4079c2e 100644 --- a/platform/platform-impl/src/com/intellij/openapi/project/impl/DefaultProject.java +++ b/platform/platform-impl/src/com/intellij/openapi/project/impl/DefaultProject.java @@ -24,8 +24,8 @@ import org.jetbrains.annotations.NotNull; class DefaultProject extends ProjectImpl { private static final String TEMPLATE_PROJECT_NAME = "Default (Template) Project"; - protected DefaultProject(@NotNull ProjectManager manager, @NotNull String filePath, boolean optimiseTestLoadSpeed) { - super(manager, filePath, optimiseTestLoadSpeed, TEMPLATE_PROJECT_NAME); + protected DefaultProject(@NotNull ProjectManager manager, @NotNull String filePath) { + super(manager, filePath, TEMPLATE_PROJECT_NAME); } @Override diff --git a/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectImpl.java b/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectImpl.java index 7158a5c424fd..c3684b90f236 100644 --- a/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectImpl.java @@ -42,7 +42,6 @@ import com.intellij.openapi.project.ex.ProjectManagerEx; import com.intellij.openapi.startup.StartupManager; import com.intellij.openapi.util.Key; import com.intellij.openapi.util.io.FileUtil; -import com.intellij.openapi.util.io.FileUtilRt; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.wm.WindowManager; import com.intellij.openapi.wm.impl.FrameTitleBuilder; @@ -70,14 +69,17 @@ public class ProjectImpl extends PlatformComponentManagerImpl implements Project private ProjectManager myProjectManager; private MyProjectManagerListener myProjectManagerListener; private final AtomicBoolean mySavingInProgress = new AtomicBoolean(false); - public boolean myOptimiseTestLoadSpeed; private String myName; private String myOldName; private final boolean myLight; + /** + * @param projectManager + * @param filePath System-independent path + * @param projectName + */ protected ProjectImpl(@NotNull ProjectManager projectManager, @NotNull String filePath, - boolean optimiseTestLoadSpeed, @Nullable String projectName) { super(ApplicationManager.getApplication(), "Project " + (projectName == null ? filePath : projectName)); @@ -89,10 +91,9 @@ public class ProjectImpl extends PlatformComponentManagerImpl implements Project getPicoContainer().registerComponentInstance(Project.class, this); if (!isDefault()) { - getStateStore().setPath(FileUtilRt.toSystemIndependentName(filePath)); + getStateStore().setPath(filePath); } - myOptimiseTestLoadSpeed = optimiseTestLoadSpeed; myProjectManager = projectManager; myName = projectName == null ? getStateStore().getProjectName() : projectName; @@ -271,16 +272,6 @@ public class ProjectImpl extends PlatformComponentManagerImpl implements Project return isDefault() ? null : getStateStore().getWorkspaceFile(); } - @Override - public boolean isOptimiseTestLoadSpeed() { - return myOptimiseTestLoadSpeed; - } - - @Override - public void setOptimiseTestLoadSpeed(final boolean optimiseTestLoadSpeed) { - myOptimiseTestLoadSpeed = optimiseTestLoadSpeed; - } - @Override public void init() { long start = System.currentTimeMillis(); diff --git a/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectManagerImpl.java index 30c25c643d8c..e15b6450558b 100644 --- a/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectManagerImpl.java @@ -43,6 +43,7 @@ import com.intellij.openapi.startup.StartupManager; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.*; import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.util.io.FileUtilRt; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.impl.local.FileWatcher; @@ -142,15 +143,8 @@ public class ProjectManagerImpl extends ProjectManagerEx implements Disposable { private static final int MAX_LEAKY_PROJECTS = 42; @SuppressWarnings("FieldCanBeLocal") private final Map myProjects = new WeakHashMap(); - @Override @Nullable - public Project newProject(final String projectName, @NotNull String filePath, boolean useDefaultProjectSettings, boolean isDummy) { - return newProject(projectName, filePath, useDefaultProjectSettings, isDummy, ApplicationManager.getApplication().isUnitTestMode()); - } - - @Nullable - public Project newProject(@Nullable String projectName, @NotNull String filePath, boolean useDefaultProjectSettings, boolean isDummy, - boolean optimiseTestLoadSpeed) { + public Project newProject(@Nullable String projectName, @NotNull String filePath, boolean useDefaultProjectSettings, boolean isDummy) { filePath = toCanonicalName(filePath); //noinspection ConstantConditions @@ -184,7 +178,7 @@ public class ProjectManagerImpl extends ProjectManagerEx implements Disposable { } } } - ProjectImpl project = createProject(projectName, filePath, false, optimiseTestLoadSpeed); + ProjectImpl project = createProject(projectName, filePath, false); try { initProject(project, useDefaultProjectSettings ? getDefaultProject() : null); if (LOG_PROJECT_LEAKAGE_IN_TESTS) { @@ -241,12 +235,13 @@ public class ProjectManagerImpl extends ProjectManagerEx implements Disposable { } } - private ProjectImpl createProject(@Nullable String projectName, - @NotNull String filePath, - boolean isDefault, - boolean isOptimiseTestLoadSpeed) { - return isDefault ? new DefaultProject(this, "", isOptimiseTestLoadSpeed) - : new ProjectImpl(this, new File(filePath).getAbsolutePath(), isOptimiseTestLoadSpeed, projectName); + private ProjectImpl createProject(@Nullable String projectName, @NotNull String filePath, boolean isDefault) { + if (isDefault) { + return new DefaultProject(this, ""); + } + else { + return new ProjectImpl(this, FileUtilRt.toSystemIndependentName(filePath), projectName); + } } private static void scheduleDispose(@NotNull final ProjectImpl project) { @@ -273,7 +268,7 @@ public class ProjectManagerImpl extends ProjectManagerEx implements Disposable { @Nullable public Project loadProject(@NotNull String filePath) throws IOException { try { - ProjectImpl project = createProject(null, filePath, false, false); + ProjectImpl project = createProject(null, new File(filePath).getAbsolutePath(), false); initProject(project, null); return project; } @@ -309,7 +304,7 @@ public class ProjectManagerImpl extends ProjectManagerEx implements Disposable { @Override public void run() { try { - myDefaultProject = createProject(null, "", true, ApplicationManager.getApplication().isUnitTestMode()); + myDefaultProject = createProject(null, "", true); initProject(myDefaultProject, null); } catch (Throwable t) { @@ -519,7 +514,7 @@ public class ProjectManagerImpl extends ProjectManagerEx implements Disposable { */ @Nullable private Project loadProjectWithProgress(@NotNull final String filePath) { - final ProjectImpl project = createProject(null, toCanonicalName(filePath), false, false); + final ProjectImpl project = createProject(null, toCanonicalName(filePath), false); try { myProgressManager.runProcessWithProgressSynchronously(new ThrowableComputable() { @Override @@ -555,8 +550,9 @@ public class ProjectManagerImpl extends ProjectManagerEx implements Disposable { @TestOnly public Collection closeTestProject(@NotNull final Project project) { assert ApplicationManager.getApplication().isUnitTestMode(); - closeProject(project); - return Arrays.asList(getOpenProjects()); + closeProject(project, false, false, false); + Project[] projects = getOpenProjects(); + return projects.length == 0 ? Collections.emptyList() : Arrays.asList(projects); } @Override diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowManagerImpl.java index 3eda40a485ee..10dba93165a8 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowManagerImpl.java @@ -2583,7 +2583,7 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements } public boolean isShowStripeButton(String id) { - checkId(id); - return getInfo(id).isShowStripeButton(); + WindowInfoImpl info = getInfo(id); + return info == null || info.isShowStripeButton(); } } diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/status/IdeStatusBarImpl.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/status/IdeStatusBarImpl.java index 5c7202df1414..7c5c475f8fba 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/status/IdeStatusBarImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/status/IdeStatusBarImpl.java @@ -36,6 +36,7 @@ import com.intellij.ui.awt.RelativePoint; import com.intellij.ui.popup.NotificationPopup; import com.intellij.util.ArrayUtil; import com.intellij.util.Consumer; +import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.HashMap; import com.intellij.util.ui.JBUI; import com.intellij.util.ui.UIUtil; diff --git a/platform/platform-impl/src/com/intellij/ui/messages/SheetController.java b/platform/platform-impl/src/com/intellij/ui/messages/SheetController.java index 6efa86e292bf..3ce09cb88210 100755 --- a/platform/platform-impl/src/com/intellij/ui/messages/SheetController.java +++ b/platform/platform-impl/src/com/intellij/ui/messages/SheetController.java @@ -187,7 +187,11 @@ public class SheetController { IdeFocusManager.getGlobalInstance().doWhenFocusSettlesDown(new Runnable() { @Override public void run() { - myFocusedComponent.requestFocus(); + if (myFocusedComponent != null) { + myFocusedComponent.requestFocus(); + } else { + LOG.debug("My focused component is null for the next message: " + messageTextPane.getText()); + } } }); } diff --git a/platform/platform-impl/src/org/jetbrains/io/netty.kt b/platform/platform-impl/src/org/jetbrains/io/netty.kt index 17377e63e398..46236aacfea0 100644 --- a/platform/platform-impl/src/org/jetbrains/io/netty.kt +++ b/platform/platform-impl/src/org/jetbrains/io/netty.kt @@ -19,7 +19,7 @@ import io.netty.bootstrap.Bootstrap import io.netty.channel.Channel import io.netty.channel.ChannelInitializer -public inline fun Bootstrap.handler(@inlineOptions(InlineOption.ONLY_LOCAL_RETURN) task: (Channel) -> Unit): Bootstrap { +public inline fun Bootstrap.handler(crossinline task: (Channel) -> Unit): Bootstrap { handler(object : ChannelInitializer() { override fun initChannel(channel: Channel) { task(channel) diff --git a/platform/platform-impl/src/org/jetbrains/util/concurrency/AsyncPromise.kt b/platform/platform-impl/src/org/jetbrains/util/concurrency/AsyncPromise.kt index f6cff5324b3c..8a68d09acc77 100644 --- a/platform/platform-impl/src/org/jetbrains/util/concurrency/AsyncPromise.kt +++ b/platform/platform-impl/src/org/jetbrains/util/concurrency/AsyncPromise.kt @@ -19,11 +19,11 @@ import com.intellij.openapi.diagnostic.Logger import org.jetbrains.concurrency.Obsolescent import java.util.* -public class AsyncPromise : Promise { +class AsyncPromise : Promise { companion object { - private val LOG = Logger.getInstance(javaClass>()) + private val LOG = Logger.getInstance(AsyncPromise::class.java) - public val OBSOLETE_ERROR: RuntimeException = MessageError("Obsolete") + val OBSOLETE_ERROR = MessageError("Obsolete") private fun setHandler(oldConsumer: ((T) -> Unit)?, newConsumer: (T) -> Unit): (T) -> Unit { return when (oldConsumer) { @@ -68,14 +68,14 @@ public class AsyncPromise : Promise { } } - private volatile var done: ((T) -> Unit)? = null - private volatile var rejected: ((Throwable) -> Unit)? = null + private @Volatile var done: ((T) -> Unit)? = null + private @Volatile var rejected: ((Throwable) -> Unit)? = null - override volatile var state = Promise.State.PENDING + override @Volatile var state = Promise.State.PENDING private set // result object or error message - private volatile var result: Any? = null + private @Volatile var result: Any? = null override fun done(done: (T) -> Unit): Promise { if (done.isObsolete()) { @@ -86,7 +86,7 @@ public class AsyncPromise : Promise { Promise.State.PENDING -> { } Promise.State.FULFILLED -> { - @suppress("UNCHECKED_CAST") + @Suppress("UNCHECKED_CAST") done(result as T) return this } @@ -116,8 +116,9 @@ public class AsyncPromise : Promise { return this } + @Suppress("BASE_WITH_NULLABLE_UPPER_BOUND") public fun get(): T? { - @suppress("UNCHECKED_CAST") + @Suppress("UNCHECKED_CAST") return when (state) { Promise.State.FULFILLED -> result as T else -> null @@ -133,7 +134,7 @@ public class AsyncPromise : Promise { Promise.State.PENDING -> { } Promise.State.FULFILLED -> { - @suppress("UNCHECKED_CAST") + @Suppress("UNCHECKED_CAST") return if (asyncResult) done(result as T) as Promise else DonePromise(done(result as T) as SUB_RESULT) } Promise.State.REJECTED -> return RejectedPromise(result as Throwable) @@ -142,7 +143,7 @@ public class AsyncPromise : Promise { val promise = AsyncPromise() addHandlers({ promise.catchError { - if (done is Obsolescent && done.isObsolete()) { + if (done is Obsolescent && done.isObsolete) { promise.setError(OBSOLETE_ERROR) } else { @@ -151,12 +152,12 @@ public class AsyncPromise : Promise { (subResult as Promise<*>).notify(promise) if (subResult is AsyncPromise<*> && subResult.state == Promise.State.PENDING) { // if promise fulfilled separately from sub result - @suppress("UNCHECKED_CAST") + @Suppress("UNCHECKED_CAST") promise.notify(subResult as AsyncPromise) } } else { - @suppress("UNCHECKED_CAST") + @Suppress("UNCHECKED_CAST") promise.setResult(subResult as SUB_RESULT) } } @@ -176,7 +177,7 @@ public class AsyncPromise : Promise { Promise.State.PENDING -> { } Promise.State.FULFILLED -> { - @suppress("UNCHECKED_CAST") + @Suppress("UNCHECKED_CAST") child.setResult(result as T) return this } @@ -195,7 +196,7 @@ public class AsyncPromise : Promise { this.rejected = setHandler(this.rejected, rejected) } - public fun setResult(result: T) { + fun setResult(result: T) { if (state != Promise.State.PENDING) { return } @@ -210,9 +211,9 @@ public class AsyncPromise : Promise { } } - public fun setError(error: String): Boolean = setError(MessageError(error)) + fun setError(error: String): Boolean = setError(MessageError(error)) - public fun setError(error: Throwable): Boolean { + fun setError(error: Throwable): Boolean { if (state != Promise.State.PENDING) { return false } @@ -238,16 +239,16 @@ public class AsyncPromise : Promise { rejected = null } - override fun processed(processed: (T?) -> Unit): Promise { + override fun processed(@Suppress("BASE_WITH_NULLABLE_UPPER_BOUND") processed: (T?) -> Unit): Promise { done(processed) rejected { processed(null) } return this } } -fun ((T) -> Unit).isObsolete() = this is Obsolescent && this.isObsolete() +internal fun ((T) -> Unit).isObsolete() = this is Obsolescent && this.isObsolete -public inline fun AsyncPromise.catchError(task: () -> Unit) { +inline fun AsyncPromise.catchError(task: () -> Unit) { try { task() } diff --git a/platform/platform-impl/src/org/jetbrains/util/concurrency/DonePromise.kt b/platform/platform-impl/src/org/jetbrains/util/concurrency/DonePromise.kt index 7671d7595c2b..8cbaa5b18081 100644 --- a/platform/platform-impl/src/org/jetbrains/util/concurrency/DonePromise.kt +++ b/platform/platform-impl/src/org/jetbrains/util/concurrency/DonePromise.kt @@ -17,7 +17,7 @@ package org.jetbrains.util.concurrency import org.jetbrains.concurrency.Obsolescent -private class DonePromise(private val result: T) : Promise { +internal class DonePromise(private val result: T) : Promise { override val state: Promise.State get() = Promise.State.FULFILLED diff --git a/platform/platform-impl/src/org/jetbrains/util/concurrency/Promise.kt b/platform/platform-impl/src/org/jetbrains/util/concurrency/Promise.kt index cdd2ff18bcc1..253fc5cf360f 100644 --- a/platform/platform-impl/src/org/jetbrains/util/concurrency/Promise.kt +++ b/platform/platform-impl/src/org/jetbrains/util/concurrency/Promise.kt @@ -17,45 +17,44 @@ package org.jetbrains.util.concurrency import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.diagnostic.Logger -import com.intellij.util.Consumer import org.jetbrains.concurrency -public interface Promise { - public enum class State { +interface Promise { + enum class State { PENDING, FULFILLED, REJECTED } - public val state: State + val state: State - public fun done(done: (T) -> Unit): Promise + fun done(done: (T) -> Unit): Promise - public fun rejected(rejected: (Throwable) -> Unit): Promise + fun rejected(rejected: (Throwable) -> Unit): Promise - public fun processed(processed: (T?) -> Unit): Promise + fun processed(processed: (T?) -> Unit): Promise - public fun then(done: (T) -> SUB_RESULT): Promise + fun then(done: (T) -> SUB_RESULT): Promise - public fun thenAsync(done: (T) -> Promise): Promise + fun thenAsync(done: (T) -> Promise): Promise - public fun notify(child: AsyncPromise): Promise + fun notify(child: AsyncPromise): Promise companion object { /** * Log error if not message error */ - public fun logError(logger: Logger, e: Throwable) { - if (e !is MessageError || ApplicationManager.getApplication().isUnitTestMode()) { + fun logError(logger: Logger, e: Throwable) { + if (e !is MessageError || ApplicationManager.getApplication().isUnitTestMode) { logger.error(e) } } - public fun all(promises: Collection>): Promise<*> = all(promises, null) + fun all(promises: Collection>): Promise<*> = all(promises, null) - public fun all(promises: Collection>, totalResult: T): Promise { + fun all(promises: Collection>, totalResult: T): Promise { if (promises.isEmpty()) { - @suppress("UNCHECKED_CAST") + @Suppress("UNCHECKED_CAST") return DONE as Promise } @@ -80,21 +79,21 @@ public interface Promise { private val DONE: Promise<*> = DonePromise(null) private val REJECTED: Promise<*> = RejectedPromise(MessageError("rejected")) -private class MessageError(error: String) : RuntimeException(error) { - public synchronized fun fillInStackTrace(): Throwable? = this +internal class MessageError(error: String) : RuntimeException(error) { + @Synchronized fun fillInStackTrace(): Throwable? = this } -public fun RejectedPromise(error: String): Promise = RejectedPromise(MessageError(error)) +fun RejectedPromise(error: String): Promise = RejectedPromise(MessageError(error)) -public fun ResolvedPromise(): Promise<*> = DONE +fun ResolvedPromise(): Promise<*> = DONE -public fun ResolvedPromise(result: T): Promise = DonePromise(result) +fun ResolvedPromise(result: T): Promise = DonePromise(result) -public fun concurrency.Promise.toPromise(): AsyncPromise { +fun concurrency.Promise.toPromise(): AsyncPromise { val promise = AsyncPromise() val oldPromise = this - done(Consumer { promise.setResult(it) }) - .rejected(Consumer { promise.setError(it) }) + done({ promise.setResult(it) }) + .rejected({ promise.setError(it) }) if (oldPromise is concurrency.AsyncPromise) { promise @@ -104,14 +103,14 @@ public fun concurrency.Promise.toPromise(): AsyncPromise { return promise } -public fun Promise.toPromise(): concurrency.AsyncPromise { +fun Promise.toPromise(): concurrency.AsyncPromise { val promise = concurrency.AsyncPromise() done { promise.setResult(it) } .rejected { promise.setError(it) } return promise } -private class CountDownConsumer(private volatile var countDown: Int, private val promise: AsyncPromise, private val totalResult: T) : (T) -> Unit { +private class CountDownConsumer(private @field:Volatile var countDown: Int, private val promise: AsyncPromise, private val totalResult: T) : (T) -> Unit { override fun invoke(p1: T) { if (--countDown == 0) { promise.setResult(totalResult) @@ -119,8 +118,8 @@ private class CountDownConsumer(private volatile var countDown: Int, private } } -public val Promise<*>.isPending: Boolean +val Promise<*>.isPending: Boolean get() = state == Promise.State.PENDING -public val Promise<*>.isRejected: Boolean +val Promise<*>.isRejected: Boolean get() = state == Promise.State.REJECTED \ No newline at end of file diff --git a/platform/platform-impl/src/org/jetbrains/util/concurrency/RejectedPromise.kt b/platform/platform-impl/src/org/jetbrains/util/concurrency/RejectedPromise.kt index 9976543ba903..08b523a31adf 100644 --- a/platform/platform-impl/src/org/jetbrains/util/concurrency/RejectedPromise.kt +++ b/platform/platform-impl/src/org/jetbrains/util/concurrency/RejectedPromise.kt @@ -34,12 +34,12 @@ class RejectedPromise(private val error: Throwable) : Promise { } override fun then(done: (T) -> SUB_RESULT): Promise { - @suppress("UNCHECKED_CAST") + @Suppress("UNCHECKED_CAST") return this as Promise } override fun thenAsync(done: (T) -> Promise): Promise { - @suppress("UNCHECKED_CAST") + @Suppress("UNCHECKED_CAST") return this as Promise } diff --git a/platform/platform-resources-en/src/messages/ActionsBundle.properties b/platform/platform-resources-en/src/messages/ActionsBundle.properties index 35af1b7ecf06..cd52bace6af4 100644 --- a/platform/platform-resources-en/src/messages/ActionsBundle.properties +++ b/platform/platform-resources-en/src/messages/ActionsBundle.properties @@ -709,6 +709,8 @@ action.ForceRunToCursor.text=Force Run to Cur_sor action.ForceRunToCursor.description=Run to the line where the caret is, ignoring any breakpoints action.Debugger.PopFrame.text=Drop _Frame action.Debugger.PopFrame.description=Moves execution point back to the method call dropping current method frames from the stack +action.Debugger.ForceEarlyReturn.text=Force Early Return +action.Debugger.ForceEarlyReturn.description=Force a method to return before it reaches a return statement action.Debugger.ShowLibraryFrames.text=Show/Hide Library Frames action.Pause.text=_Pause Program action.Pause.description=Suspend program execution and enable debugging diff --git a/platform/platform-resources-en/src/messages/IdeBundle.properties b/platform/platform-resources-en/src/messages/IdeBundle.properties index 682e3ef9e6db..310ee6487eda 100644 --- a/platform/platform-resources-en/src/messages/IdeBundle.properties +++ b/platform/platform-resources-en/src/messages/IdeBundle.properties @@ -818,9 +818,6 @@ error.unable.to.read.tip.of.the.day=Unable to read Tip Of The Day ({ label.did.you.know=Did you know ... ? checkbox.show.tips.on.startup=Show Tips on Startup error.tips.not.found=Tips not found. Make sure you installed {0} correctly. -title.go.to.line=Go to Line -editbox.line.number=Line number: -tooltip.syntax.linenumber.columnnumber=Syntax: [][:] or [][, - + + diff --git a/platform/platform-tests/testSrc/com/intellij/application/ApplicationImplTest.java b/platform/platform-tests/testSrc/com/intellij/application/ApplicationImplTest.java index 6ba1cceca1d4..38114c10f651 100644 --- a/platform/platform-tests/testSrc/com/intellij/application/ApplicationImplTest.java +++ b/platform/platform-tests/testSrc/com/intellij/application/ApplicationImplTest.java @@ -15,20 +15,22 @@ */ package com.intellij.application; +import com.intellij.openapi.Disposable; import com.intellij.openapi.application.AccessToken; import com.intellij.openapi.application.Application; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ex.ApplicationEx; +import com.intellij.openapi.application.impl.ApplicationImpl; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.progress.Task; import com.intellij.openapi.progress.impl.ProgressManagerImpl; +import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.EmptyRunnable; import com.intellij.openapi.util.ThrowableComputable; import com.intellij.testFramework.PlatformTestCase; import com.intellij.testFramework.PlatformTestUtil; import com.intellij.testFramework.Timings; -import com.intellij.util.ThrowableRunnable; import com.intellij.util.TimeoutUtil; import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NotNull; @@ -58,50 +60,38 @@ public class ApplicationImplTest extends PlatformTestCase { String err = null; for (int i=0; i<4; i++) { - Callable runnable = new Callable() { - @Override - public String call() throws Exception { - try { - assertFalse(application.isReadAccessAllowed()); - long l2 = PlatformTestUtil.measure(new Runnable() { - @Override - public void run() { - for (int i = 0; i < N; i++) { - AccessToken token = application.acquireReadActionLock(); - try { - // do it - } - finally { - token.finish(); - } - } + Callable runnable = () -> { + try { + assertFalse(application.isReadAccessAllowed()); + long l2 = PlatformTestUtil.measure(() -> { + for (int i1 = 0; i1 < N; i1++) { + AccessToken token = application.acquireReadActionLock(); + try { + // do it } - }); - - long l1 = PlatformTestUtil.measure(new Runnable() { - @Override - public void run() { - for (int i=0; i 20) { - return "Suspiciously different times for acquireReadActionLock(" +l2 + "ms) vs runReadAction(" + l1 + "ms). Ratio: "+ ratioPercent + "%"; } + }); + + long l1 = PlatformTestUtil.measure(() -> { + for (int i1 = 0; i1 < N; i1++) { + application.runReadAction(() -> { + }); + } + }); + + assertFalse(application.isReadAccessAllowed()); + int ratioPercent = (int)((l1 - l2) * 100.0 / l1); + if (Math.abs(ratioPercent) > 20) { + return "Suspiciously different times for acquireReadActionLock(" +l2 + "ms) vs runReadAction(" + l1 + "ms). Ratio: "+ ratioPercent + "%"; } - catch (Throwable e) { - exception = e; - } - return null; } + catch (Throwable e) { + exception = e; + } + return null; }; err = application.executeOnPooledThread(runnable).get(); @@ -114,49 +104,61 @@ public class ApplicationImplTest extends PlatformTestCase { } - public void testLockPerformance() throws InterruptedException { - int iterations = Timings.adjustAccordingToMySpeed(3000, true); + public void testReadWriteLockPerformance() throws InterruptedException { + int iterations = Timings.adjustAccordingToMySpeed(300000, true); System.out.println("iterations = " + iterations); final int readIterations = iterations; final int writeIterations = iterations; - final int numOfThreads = 10; - PlatformTestUtil.startPerformanceTest("lock performance", 200, new ThrowableRunnable() { - @Override - public void run() throws Throwable { + runReadWrites(readIterations, writeIterations, 2000); + } + + public void testReadLockPerformance() throws InterruptedException { + int iterations = Timings.adjustAccordingToMySpeed(300000, true); + System.out.println("iterations = " + iterations); + final int readIterations = iterations; + final int writeIterations = 0; + + runReadWrites(readIterations, writeIterations, 1000); + } + + private static void runReadWrites(final int readIterations, final int writeIterations, int expectedMs) { + final ApplicationImpl application = (ApplicationImpl)ApplicationManager.getApplication(); + Disposable disposable = Disposer.newDisposable(); + application.disableEventsUntil(disposable); + + try { + final int numOfThreads = 10; + PlatformTestUtil.startPerformanceTest("lock performance", expectedMs, () -> { final CountDownLatch reads = new CountDownLatch(numOfThreads); for (int i = 0; i < numOfThreads; i++) { final String name = "stress thread " + i; - new Thread(new Runnable() { - @Override - public void run() { - System.out.println(name); - for (int i = 0; i < readIterations; i++) { - ApplicationManager.getApplication().runReadAction(new Runnable() { - @Override - public void run() { + new Thread(() -> { + System.out.println(name); + for (int i1 = 0; i1 < readIterations; i1++) { + application.runReadAction(() -> { - } - }); - } - - reads.countDown(); + }); } + + reads.countDown(); }, name).start(); } - System.out.println("write start"); - for (int i = 0; i < writeIterations; i++) { - ApplicationManager.getApplication().runWriteAction(new Runnable() { - @Override - public void run() { - } - }); + if (writeIterations > 0) { + System.out.println("write start"); + for (int i = 0; i < writeIterations; i++) { + ApplicationManager.getApplication().runWriteAction(() -> { + }); + } + System.out.println("write end"); } - System.out.println("write end"); reads.await(); - } - }).assertTiming(); + }).assertTiming(); + } + finally { + Disposer.dispose(disposable); + } } private volatile boolean tryingToStartWriteAction; @@ -170,62 +172,50 @@ public class ApplicationImplTest extends PlatformTestCase { anotherThreadStarted[i] = new AtomicBoolean(); } final StringBuffer LOG = new StringBuffer(); - new Thread(new Runnable() { - @Override - public void run() { - try { - ApplicationManager.getApplication().runReadAction(new Runnable() { - @Override - public void run() { - LOG.append("inside read action\n"); - readStarted = true; - while (!tryingToStartWriteAction); - TimeoutUtil.sleep(100); + new Thread(() -> { + try { + ApplicationManager.getApplication().runReadAction(() -> { + LOG.append("inside read action\n"); + readStarted = true; + while (!tryingToStartWriteAction); + TimeoutUtil.sleep(100); - for (int i = 0; i < anotherReadActionStarted.length; i++) { - final int finalI = i; - new Thread(new Runnable() { - @Override - public void run() { - LOG.append("\nanother thread started " + finalI); - anotherThreadStarted[finalI].set(true); - ApplicationManager.getApplication().runReadAction(new Runnable() { - @Override - public void run() { - LOG.append("\ninside another thread read action " + finalI); - anotherReadActionStarted[finalI].set(true); - try { - Thread.sleep(100); - } - catch (InterruptedException e) { - throw new RuntimeException(e); - } - anotherReadActionStarted[finalI].set(false); - LOG.append("\nfinished another thread read action " + finalI); - } - }); - LOG.append("\nanother thread finished " + finalI); - } - },"another read action "+i).start(); - } - - for (AtomicBoolean threadStarted : anotherThreadStarted) { - while (!threadStarted.get()) ; - } - // now the other threads try to get read lock. we should not let them - for (int i=0; i<10; i++) { - for (AtomicBoolean readStarted : anotherReadActionStarted) { - assertThat(!readStarted.get(), "must not start another read action while write is pending"); + for (int i = 0; i < anotherReadActionStarted.length; i++) { + final int finalI = i; + new Thread(() -> { + LOG.append("\nanother thread started " + finalI); + anotherThreadStarted[finalI].set(true); + ApplicationManager.getApplication().runReadAction(() -> { + LOG.append("\ninside another thread read action " + finalI); + anotherReadActionStarted[finalI].set(true); + try { + Thread.sleep(100); } - TimeoutUtil.sleep(20); - } - LOG.append("\nfinished read action"); + catch (InterruptedException e) { + throw new RuntimeException(e); + } + anotherReadActionStarted[finalI].set(false); + LOG.append("\nfinished another thread read action " + finalI); + }); + LOG.append("\nanother thread finished " + finalI); + }, "another read action " + i).start(); + } + + for (AtomicBoolean threadStarted : anotherThreadStarted) { + while (!threadStarted.get()) ; + } + // now the other threads try to get read lock. we should not let them + for (int i=0; i<10; i++) { + for (AtomicBoolean readStarted1 : anotherReadActionStarted) { + assertThat(!readStarted1.get(), "must not start another read action while write is pending"); } - }); - } - catch (Throwable e) { - exception = e; - } + TimeoutUtil.sleep(20); + } + LOG.append("\nfinished read action"); + }); + } + catch (Throwable e) { + exception = e; } }, "read").start(); @@ -233,15 +223,12 @@ public class ApplicationImplTest extends PlatformTestCase { while (!readStarted); tryingToStartWriteAction = true; LOG.append("\nwrite about to start"); - ApplicationManager.getApplication().runWriteAction(new Runnable() { - @Override - public void run() { - LOG.append("\ninside write action"); - for (AtomicBoolean readStarted : anotherReadActionStarted) { - assertThat(!readStarted.get(), "must not start another read action while write is running"); - } - LOG.append("\nfinished write action"); + ApplicationManager.getApplication().runWriteAction(() -> { + LOG.append("\ninside write action"); + for (AtomicBoolean readStarted1 : anotherReadActionStarted) { + assertThat(!readStarted1.get(), "must not start another read action while write is running"); } + LOG.append("\nfinished write action"); }); if (exception != null) { System.err.println(LOG); @@ -257,37 +244,23 @@ public class ApplicationImplTest extends PlatformTestCase { } public void testProgressVsReadAction() throws Throwable { - ProgressManager.getInstance().runProcessWithProgressSynchronously(new ThrowableComputable() { - @Override - public Void compute() throws Exception { - try { - assertFalse(ApplicationManager.getApplication().isReadAccessAllowed()); - assertFalse(ApplicationManager.getApplication().isDispatchThread()); - for (int i=0; i<100;i++) { - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - ApplicationManager.getApplication().runWriteAction(new Runnable() { - @Override - public void run() { - TimeoutUtil.sleep(20); - } - }); - } - }); - ApplicationManager.getApplication().runReadAction(new Runnable() { - @Override - public void run() { - TimeoutUtil.sleep(20); - } - }); - } + ProgressManager.getInstance().runProcessWithProgressSynchronously((ThrowableComputable)() -> { + try { + assertFalse(ApplicationManager.getApplication().isReadAccessAllowed()); + assertFalse(ApplicationManager.getApplication().isDispatchThread()); + for (int i=0; i<100;i++) { + SwingUtilities.invokeLater(() -> ApplicationManager.getApplication().runWriteAction(() -> { + TimeoutUtil.sleep(20); + })); + ApplicationManager.getApplication().runReadAction(() -> { + TimeoutUtil.sleep(20); + }); } - catch (Exception e) { - exception = e; - } - return null; } + catch (Exception e) { + exception = e; + } + return null; }, "cc", false, getProject()); if (exception != null) throw exception; } @@ -329,16 +302,13 @@ public class ApplicationImplTest extends PlatformTestCase { public void testRunProcessWithProgressSynchronouslyInReadAction() throws Throwable { boolean result = ((ApplicationEx)ApplicationManager.getApplication()) - .runProcessWithProgressSynchronouslyInReadAction(getProject(), "title", true, "cancel", null, new Runnable() { - @Override - public void run() { - try { - assertFalse(SwingUtilities.isEventDispatchThread()); - assertTrue(ApplicationManager.getApplication().isReadAccessAllowed()); - } - catch (Throwable e) { - exception = e; - } + .runProcessWithProgressSynchronouslyInReadAction(getProject(), "title", true, "cancel", null, () -> { + try { + assertFalse(SwingUtilities.isEventDispatchThread()); + assertTrue(ApplicationManager.getApplication().isReadAccessAllowed()); + } + catch (Throwable e) { + exception = e; } }); assertTrue(result); @@ -346,19 +316,9 @@ public class ApplicationImplTest extends PlatformTestCase { } public void testRunProcessWithProgressSynchronouslyInReadActionWithPendingWriteAction() throws Throwable { - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - ApplicationManager.getApplication().runWriteAction(EmptyRunnable.getInstance()); - } - }); + SwingUtilities.invokeLater(() -> ApplicationManager.getApplication().runWriteAction(EmptyRunnable.getInstance())); boolean result = ((ApplicationEx)ApplicationManager.getApplication()) - .runProcessWithProgressSynchronouslyInReadAction(getProject(), "title", true, "cancel", null, new Runnable() { - @Override - public void run() { - TimeoutUtil.sleep(10000); - } - }); + .runProcessWithProgressSynchronouslyInReadAction(getProject(), "title", true, "cancel", null, () -> TimeoutUtil.sleep(10000)); assertTrue(result); UIUtil.dispatchAllInvocationEvents(); if (exception != null) throw exception; diff --git a/platform/platform-tests/testSrc/com/intellij/history/integration/ExternalChangesAndRefreshingTest.java b/platform/platform-tests/testSrc/com/intellij/history/integration/ExternalChangesAndRefreshingTest.java index 74cfc98bde23..0ec801c52a9c 100644 --- a/platform/platform-tests/testSrc/com/intellij/history/integration/ExternalChangesAndRefreshingTest.java +++ b/platform/platform-tests/testSrc/com/intellij/history/integration/ExternalChangesAndRefreshingTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * 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. @@ -20,7 +20,8 @@ import com.intellij.history.core.revisions.Revision; import com.intellij.openapi.command.CommandProcessor; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vfs.*; -import com.intellij.util.ui.UIUtil; +import com.intellij.testFramework.EdtTestUtil; +import com.intellij.util.ThrowableRunnable; import org.jetbrains.annotations.NotNull; import java.io.File; @@ -43,17 +44,7 @@ public class ExternalChangesAndRefreshingTest extends IntegrationTestCase { // this methods waits for another thread to finish, that leads // to deadlock in swing-thread. Therefore we have to run this test // outside of swing-thread - UIUtil.invokeAndWaitIfNeeded(new Runnable() { - @Override - public void run() { - try { - ExternalChangesAndRefreshingTest.super.setUp(); - } - catch (Exception e) { - throw new RuntimeException(e); - } - } - }); + EdtTestUtil.runInEdtAndWait((ThrowableRunnable)ExternalChangesAndRefreshingTest.super::setUp); } else { super.setUp(); @@ -66,25 +57,16 @@ public class ExternalChangesAndRefreshingTest extends IntegrationTestCase { // this methods waits for another thread to finish, that leads // to deadlock in swing-thread. Therefore we have to run this test // outside of swing-thread - UIUtil.invokeAndWaitIfNeeded(new Runnable() { - @Override - public void run() { - try { - ExternalChangesAndRefreshingTest.super.tearDown(); - } - catch (Exception e) { - throw new RuntimeException(e); - } - } - }); + EdtTestUtil.runInEdtAndWait((ThrowableRunnable)ExternalChangesAndRefreshingTest.super::tearDown); } else { + //noinspection SuperTearDownInFinally super.tearDown(); } } @Override - protected void runBareRunnable(Runnable r) throws Throwable { + protected void runBareRunnable(ThrowableRunnable r) throws Throwable { if (getName().equals("testRefreshingAsynchronously")) { // this method waits for another thread to finish, that leads // to deadlock in swing-thread. Therefore we have to run this test @@ -118,12 +100,7 @@ public class ExternalChangesAndRefreshingTest extends IntegrationTestCase { public void testRefreshDuringCommand() { // shouldn't throw - CommandProcessor.getInstance().executeCommand(myProject, new Runnable() { - @Override - public void run() { - refreshVFS(); - } - }, "", null); + CommandProcessor.getInstance().executeCommand(myProject, ExternalChangesAndRefreshingTest::refreshVFS, "", null); } public void testCommandDuringRefresh() throws Exception { @@ -137,19 +114,11 @@ public class ExternalChangesAndRefreshingTest extends IntegrationTestCase { }; // shouldn't throw - addFileListenerDuring(l, new Runnable() { - @Override - public void run() { - refreshVFS(); - } - }); + addFileListenerDuring(l, ExternalChangesAndRefreshingTest::refreshVFS); } private void executeSomeCommand() { - CommandProcessor.getInstance().executeCommand(myProject, new Runnable() { - @Override - public void run() { - } + CommandProcessor.getInstance().executeCommand(myProject, () -> { }, "", null); } @@ -163,7 +132,7 @@ public class ExternalChangesAndRefreshingTest extends IntegrationTestCase { public void fileCreated(@NotNull VirtualFileEvent e) { try { if (!e.getFile().getPath().equals(path)) return; - content[0] = new String(e.getFile().contentsToByteArray()); + content[0] = new String(e.getFile().contentsToByteArray(), CharsetToolkit.UTF8_CHARSET); } catch (IOException ex) { throw new RuntimeException(ex); @@ -171,12 +140,7 @@ public class ExternalChangesAndRefreshingTest extends IntegrationTestCase { } }; - addFileListenerDuring(l, new Runnable() { - @Override - public void run() { - refreshVFS(); - } - }); + addFileListenerDuring(l, ExternalChangesAndRefreshingTest::refreshVFS); assertEquals("content", content[0]); } @@ -232,12 +196,7 @@ public class ExternalChangesAndRefreshingTest extends IntegrationTestCase { VirtualFileManager fm = VirtualFileManager.getInstance(); if (async) { - fm.asyncRefresh(new Runnable() { - @Override - public void run() { - s.release(); - } - }); + fm.asyncRefresh(s::release); } else { try { diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/application/impl/LaterInvocatorTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/application/impl/LaterInvocatorTest.java index 0a785f1ecd38..500b5844ffaf 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/application/impl/LaterInvocatorTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/application/impl/LaterInvocatorTest.java @@ -1,3 +1,18 @@ +/* + * 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.openapi.application.impl; import com.intellij.openapi.application.ApplicationManager; @@ -7,6 +22,7 @@ import com.intellij.openapi.util.Conditions; import com.intellij.testFramework.PlatformTestCase; import com.intellij.testFramework.SkipInHeadlessEnvironment; import com.intellij.testFramework.UsefulTestCase; +import com.intellij.util.ThrowableRunnable; import com.intellij.util.ui.UIUtil; import junit.framework.TestCase; @@ -20,7 +36,7 @@ import java.util.ArrayList; public class LaterInvocatorTest extends PlatformTestCase { private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.application.impl.LaterInvokatorTest"); - private final ArrayList myOrder = new ArrayList(); + private final ArrayList myOrder = new ArrayList<>(); @SuppressWarnings("FieldAccessedSynchronizedAndUnsynchronized") private Window myWindow1; private Window myWindow2; @@ -59,35 +75,27 @@ public class LaterInvocatorTest extends PlatformTestCase { } }; final Exception[] exception = {null}; - UIUtil.invokeAndWaitIfNeeded(new Runnable() { - @Override - public void run() { - try { - LaterInvocatorTest.super.setUp(); - final Object[] modalEntities = LaterInvocator.getCurrentModalEntities(); - if (modalEntities.length > 0) { - LOG.error( - "Expect no modal entries. Probably some of the previous tests didn't left their entries. Top entry is: " + modalEntities[0]); - } - } - catch (Exception e) { - exception[0] = e; + UIUtil.invokeAndWaitIfNeeded((Runnable)() -> { + try { + LaterInvocatorTest.super.setUp(); + final Object[] modalEntities = LaterInvocator.getCurrentModalEntities(); + if (modalEntities.length > 0) { + LOG.error( + "Expect no modal entries. Probably some of the previous tests didn't left their entries. Top entry is: " + modalEntities[0]); } } + catch (Exception e) { + exception[0] = e; + } }); if (exception[0] != null) throw exception[0]; - UIUtil.invokeAndWaitIfNeeded(new Runnable() { - @Override - public void run() { - TestCase.assertFalse("Can't run test", LaterInvocator.isInModalContext()); - } - }); + UIUtil.invokeAndWaitIfNeeded((Runnable)() -> TestCase.assertFalse("Can't run test", LaterInvocator.isInModalContext())); flushSwingQueue(); } @Override - protected void runBareRunnable(Runnable runnable) throws Throwable { + protected void runBareRunnable(ThrowableRunnable runnable) throws Throwable { runnable.run(); } @@ -95,27 +103,21 @@ public class LaterInvocatorTest extends PlatformTestCase { protected void tearDown() throws Exception { myOrder.clear(); final boolean[] inModalState = {true}; - ApplicationManager.getApplication().invokeLater(new Runnable() { - @Override - public void run() { - synchronized (inModalState) { - inModalState[0] = false; - } + ApplicationManager.getApplication().invokeLater(() -> { + synchronized (inModalState) { + inModalState[0] = false; } }, ModalityState.NON_MODAL); flushSwingQueue(); flushSwingQueue(); - UIUtil.invokeAndWaitIfNeeded(new Runnable() { - @Override - public void run() { - while (true) { - synchronized (inModalState) { - if (!inModalState[0]) break; - } - flushSwingQueue(); - synchronized (inModalState) { - if (inModalState[0] && LaterInvocator.isInModalContext()) LaterInvocator.leaveAllModals(); - } + UIUtil.invokeAndWaitIfNeeded((Runnable)() -> { + while (true) { + synchronized (inModalState) { + if (!inModalState[0]) break; + } + flushSwingQueue(); + synchronized (inModalState) { + if (inModalState[0] && LaterInvocator.isInModalContext()) LaterInvocator.leaveAllModals(); } } }); @@ -140,35 +142,29 @@ public class LaterInvocatorTest extends PlatformTestCase { } public void testReorder() throws InterruptedException, InvocationTargetException { - UIUtil.invokeAndWaitIfNeeded(new Runnable() { - @Override - public void run() { - LaterInvocator.enterModal(myWindow1); - synchronized (LaterInvocatorTest.this) { - blockSwingThread(); - ApplicationManager.getApplication().invokeLater(new MyRunnable("1"), ModalityState.NON_MODAL); - SwingUtilities.invokeLater(ENTER_MODAL); - LaterInvocator.leaveModal(myWindow1); - SwingUtilities.invokeLater(LEAVE_MODAL); - ApplicationManager.getApplication().invokeLater(new MyRunnable("2"), ModalityState.NON_MODAL); - } - flushSwingQueue(); - checkOrder(2); - } - }); - } - - public void testTrueReorder() throws InvocationTargetException, InterruptedException { - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - LaterInvocator.enterModal(myWindow1); + UIUtil.invokeAndWaitIfNeeded((Runnable)() -> { + LaterInvocator.enterModal(myWindow1); + synchronized (this) { + blockSwingThread(); ApplicationManager.getApplication().invokeLater(new MyRunnable("1"), ModalityState.NON_MODAL); SwingUtilities.invokeLater(ENTER_MODAL); LaterInvocator.leaveModal(myWindow1); SwingUtilities.invokeLater(LEAVE_MODAL); ApplicationManager.getApplication().invokeLater(new MyRunnable("2"), ModalityState.NON_MODAL); } + flushSwingQueue(); + checkOrder(2); + }); + } + + public void testTrueReorder() throws InvocationTargetException, InterruptedException { + SwingUtilities.invokeLater(() -> { + LaterInvocator.enterModal(myWindow1); + ApplicationManager.getApplication().invokeLater(new MyRunnable("1"), ModalityState.NON_MODAL); + SwingUtilities.invokeLater(ENTER_MODAL); + LaterInvocator.leaveModal(myWindow1); + SwingUtilities.invokeLater(LEAVE_MODAL); + ApplicationManager.getApplication().invokeLater(new MyRunnable("2"), ModalityState.NON_MODAL); }); flushSwingQueue(); flushSwingQueue(); @@ -176,39 +172,33 @@ public class LaterInvocatorTest extends PlatformTestCase { } public void testEverInvoked() throws InvocationTargetException, InterruptedException { - UIUtil.invokeAndWaitIfNeeded(new Runnable() { - @Override - public void run() { - LaterInvocator.enterModal(myWindow1); - ApplicationManager.getApplication().invokeLater(ENTER_MODAL, ModalityState.NON_MODAL); - ApplicationManager.getApplication().invokeLater(new MyRunnable("1"), ModalityState.NON_MODAL); - LaterInvocator.leaveModal(myWindow1); - flushSwingQueue(); - flushSwingQueue(); - checkOrder(0); - SwingUtilities.invokeLater(LEAVE_MODAL); - flushSwingQueue(); - flushSwingQueue(); - checkOrder(1); - } + UIUtil.invokeAndWaitIfNeeded((Runnable)() -> { + LaterInvocator.enterModal(myWindow1); + ApplicationManager.getApplication().invokeLater(ENTER_MODAL, ModalityState.NON_MODAL); + ApplicationManager.getApplication().invokeLater(new MyRunnable("1"), ModalityState.NON_MODAL); + LaterInvocator.leaveModal(myWindow1); + flushSwingQueue(); + flushSwingQueue(); + checkOrder(0); + SwingUtilities.invokeLater(LEAVE_MODAL); + flushSwingQueue(); + flushSwingQueue(); + checkOrder(1); }); } public void testDoesNotInvokeWhenModal() throws InvocationTargetException, InterruptedException { - UIUtil.invokeAndWaitIfNeeded(new Runnable() { - @Override - public void run() { - LaterInvocator.enterModal(myWindow1); + UIUtil.invokeAndWaitIfNeeded((Runnable)() -> { + LaterInvocator.enterModal(myWindow1); - ApplicationManager.getApplication().invokeLater(ENTER_MODAL, ModalityState.NON_MODAL); - ApplicationManager.getApplication().invokeLater(new MyRunnable("1"), ModalityState.NON_MODAL); - LaterInvocator.leaveModal(myWindow1); - flushSwingQueue(); - checkOrder(0); - LaterInvocator.leaveModal(myWindow1); - flushSwingQueue(); - checkOrder(1); - } + ApplicationManager.getApplication().invokeLater(ENTER_MODAL, ModalityState.NON_MODAL); + ApplicationManager.getApplication().invokeLater(new MyRunnable("1"), ModalityState.NON_MODAL); + LaterInvocator.leaveModal(myWindow1); + flushSwingQueue(); + checkOrder(0); + LaterInvocator.leaveModal(myWindow1); + flushSwingQueue(); + checkOrder(1); }); } @@ -242,111 +232,99 @@ public class LaterInvocatorTest extends PlatformTestCase { } public void testStress() throws Exception { - UIUtil.invokeAndWaitIfNeeded(new Runnable() { - @Override - public void run() { - int N = 1000; - //long start = System.currentTimeMillis(); - for (int i = 0; i < N; i++) { - /* - if (i % 10 == 0) { - long elapsed = System.currentTimeMillis() - start; - System.out.println("i = " + i+"; elapsed="+elapsed); - start = System.currentTimeMillis(); - } - */ - - //assertEquals(null, Toolkit.getDefaultToolkit().getSystemEventQueue().peekEvent()); - //assertEquals(null, LaterInvocator.dumpQueue()); - - UsefulTestCase.assertEmpty(LaterInvocator.getCurrentModalEntities()); - LaterInvocator.enterModal(myWindow2); - //some weird things like MyFireIdleRequest may still sneak in - //assertEquals(null, LaterInvocator.dumpQueue()); - TestCase.assertTrue(LaterInvocator.isInModalContext()); - TestCase.assertEquals(1, LaterInvocator.getCurrentModalEntities().length); - - LaterInvocator.invokeLater(new Runnable() { - @Override - public void run() { - TestCase.assertTrue(!LaterInvocator.isInModalContext()); - } - - public String toString() { - return "ass2"; - } - }, ModalityState.NON_MODAL); - LaterInvocator.invokeLater(ENTER_MODAL, ModalityState.NON_MODAL); - - LaterInvocator.invokeLater(new MyRunnable("1"), ModalityState.NON_MODAL); - - //some weird things like MyFireIdleRequest may still sneak in - //java.util.List dump = LaterInvocator.dumpQueue(); - //assertEquals(dump.toString(), 3, dump.size()); - - LaterInvocator.leaveModal(myWindow2); - flushSwingQueue(); - if (!LaterInvocator.isInModalContext()) { - //System.out.println("inv queue" + LaterInvocator.dumpQueue()); - TestCase.fail(); - } - - checkOrder(0); - - SwingUtilities.invokeLater(LEAVE_MODAL); - flushSwingQueue(); - TestCase.assertTrue(!LaterInvocator.isInModalContext()); - - checkOrder(1); - - - LaterInvocator.leaveAllModals(); - myOrder.clear(); - flushSwingQueue(); + UIUtil.invokeAndWaitIfNeeded((Runnable)() -> { + int N = 1000; + //long start = System.currentTimeMillis(); + for (int i = 0; i < N; i++) { + /* + if (i % 10 == 0) { + long elapsed = System.currentTimeMillis() - start; + System.out.println("i = " + i+"; elapsed="+elapsed); + start = System.currentTimeMillis(); } + */ + + //assertEquals(null, Toolkit.getDefaultToolkit().getSystemEventQueue().peekEvent()); + //assertEquals(null, LaterInvocator.dumpQueue()); + + UsefulTestCase.assertEmpty(LaterInvocator.getCurrentModalEntities()); + LaterInvocator.enterModal(myWindow2); + //some weird things like MyFireIdleRequest may still sneak in + //assertEquals(null, LaterInvocator.dumpQueue()); + TestCase.assertTrue(LaterInvocator.isInModalContext()); + TestCase.assertEquals(1, LaterInvocator.getCurrentModalEntities().length); + + LaterInvocator.invokeLater(new Runnable() { + @Override + public void run() { + TestCase.assertTrue(!LaterInvocator.isInModalContext()); + } + + public String toString() { + return "ass2"; + } + }, ModalityState.NON_MODAL); + LaterInvocator.invokeLater(ENTER_MODAL, ModalityState.NON_MODAL); + + LaterInvocator.invokeLater(new MyRunnable("1"), ModalityState.NON_MODAL); + + //some weird things like MyFireIdleRequest may still sneak in + //java.util.List dump = LaterInvocator.dumpQueue(); + //assertEquals(dump.toString(), 3, dump.size()); + + LaterInvocator.leaveModal(myWindow2); + flushSwingQueue(); + if (!LaterInvocator.isInModalContext()) { + //System.out.println("inv queue" + LaterInvocator.dumpQueue()); + TestCase.fail(); + } + + checkOrder(0); + + SwingUtilities.invokeLater(LEAVE_MODAL); + flushSwingQueue(); + TestCase.assertTrue(!LaterInvocator.isInModalContext()); + + checkOrder(1); + + + LaterInvocator.leaveAllModals(); + myOrder.clear(); + flushSwingQueue(); } }); } public void testOrderWithSwingInvokeLater2() throws InterruptedException, InvocationTargetException { - UIUtil.invokeAndWaitIfNeeded(new Runnable() { - @Override - public void run() { - LaterInvocator.enterModal(myWindow1); - synchronized (LaterInvocatorTest.this) { - blockSwingThread(); - ApplicationManager.getApplication().invokeLater(new MyRunnable("2"), ModalityState.NON_MODAL); - SwingUtilities.invokeLater(LEAVE_MODAL); - SwingUtilities.invokeLater(new MyRunnable("1")); - ApplicationManager.getApplication().invokeLater(new MyRunnable("3"), ModalityState.NON_MODAL); - } - flushSwingQueue(); - checkOrder(3); + UIUtil.invokeAndWaitIfNeeded((Runnable)() -> { + LaterInvocator.enterModal(myWindow1); + synchronized (this) { + blockSwingThread(); + ApplicationManager.getApplication().invokeLater(new MyRunnable("2"), ModalityState.NON_MODAL); + SwingUtilities.invokeLater(LEAVE_MODAL); + SwingUtilities.invokeLater(new MyRunnable("1")); + ApplicationManager.getApplication().invokeLater(new MyRunnable("3"), ModalityState.NON_MODAL); } + flushSwingQueue(); + checkOrder(3); }); } public void testOrderWithSwingInvokeLater3() throws InterruptedException, InvocationTargetException { - UIUtil.invokeAndWaitIfNeeded(new Runnable() { - @Override - public void run() { - LaterInvocator.enterModal(myWindow1); - synchronized (LaterInvocatorTest.this) { - blockSwingThread(); - SwingUtilities.invokeLater(new MyRunnable("1")); - ApplicationManager.getApplication().invokeLater(new Runnable() { - @Override - public void run() { - ApplicationManager.getApplication().invokeLater(new MyRunnable("3"), ModalityState.NON_MODAL); - } - }, ModalityState.NON_MODAL); - SwingUtilities.invokeLater(LEAVE_MODAL); - ApplicationManager.getApplication().invokeLater(new MyRunnable("2"), ModalityState.NON_MODAL); - } - flushSwingQueue(); - checkOrder(3); + UIUtil.invokeAndWaitIfNeeded((Runnable)() -> { + LaterInvocator.enterModal(myWindow1); + synchronized (this) { + blockSwingThread(); + SwingUtilities.invokeLater(new MyRunnable("1")); + ApplicationManager.getApplication().invokeLater(() -> { + ApplicationManager.getApplication().invokeLater(new MyRunnable("3"), ModalityState.NON_MODAL); + }, ModalityState.NON_MODAL); + SwingUtilities.invokeLater(LEAVE_MODAL); + ApplicationManager.getApplication().invokeLater(new MyRunnable("2"), ModalityState.NON_MODAL); } + flushSwingQueue(); + checkOrder(3); }); } @@ -354,7 +332,7 @@ public class LaterInvocatorTest extends PlatformTestCase { UIUtil.invokeAndWaitIfNeeded(new Runnable() { @Override public void run() { - final ArrayList consumed = new ArrayList(); + final ArrayList consumed = new ArrayList<>(); synchronized (LaterInvocatorTest.this) { blockSwingThread(); ApplicationManager.getApplication().getInvokator().invokeLater(new Runnable() { @@ -368,19 +346,9 @@ public class LaterInvocatorTest extends PlatformTestCase { } }, Conditions.alwaysTrue()); } - }, ModalityState.NON_MODAL).doWhenDone(new Runnable() { - @Override - public void run() { - consumed.add("1"); - } - }); + }, ModalityState.NON_MODAL).doWhenDone(() -> consumed.add("1")); ApplicationManager.getApplication().getInvokator().invokeLater(new MyRunnable("2"), ModalityState.NON_MODAL) - .doWhenDone(new Runnable() { - @Override - public void run() { - consumed.add("2"); - } - }); + .doWhenDone(() -> consumed.add("2")); } flushSwingQueue(); @@ -390,31 +358,25 @@ public class LaterInvocatorTest extends PlatformTestCase { } public void testOrderWithSwingInvokeLater4() throws InterruptedException, InvocationTargetException { - UIUtil.invokeAndWaitIfNeeded(new Runnable() { - @Override - public void run() { - SwingUtilities.invokeLater(ENTER_MODAL); - flushSwingQueue(); - synchronized (LaterInvocatorTest.this) { - blockSwingThread(); - SwingUtilities.invokeLater(new MyRunnable("1")); - ApplicationManager.getApplication().invokeLater(new MyRunnable("3"), ModalityState.NON_MODAL); - SwingUtilities.invokeLater(LEAVE_MODAL); - SwingUtilities.invokeLater(ENTER_MODAL); - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - SwingUtilities.invokeLater(new MyRunnable("2")); - ApplicationManager.getApplication().invokeLater(new MyRunnable("5"), ModalityState.NON_MODAL); - } - }); - ApplicationManager.getApplication().invokeLater(new MyRunnable("4"), ModalityState.NON_MODAL); - } - flushSwingQueue(); + UIUtil.invokeAndWaitIfNeeded((Runnable)() -> { + SwingUtilities.invokeLater(ENTER_MODAL); + flushSwingQueue(); + synchronized (this) { + blockSwingThread(); + SwingUtilities.invokeLater(new MyRunnable("1")); + ApplicationManager.getApplication().invokeLater(new MyRunnable("3"), ModalityState.NON_MODAL); SwingUtilities.invokeLater(LEAVE_MODAL); - flushSwingQueue(); - checkOrder(5); + SwingUtilities.invokeLater(ENTER_MODAL); + SwingUtilities.invokeLater(() -> { + SwingUtilities.invokeLater(new MyRunnable("2")); + ApplicationManager.getApplication().invokeLater(new MyRunnable("5"), ModalityState.NON_MODAL); + }); + ApplicationManager.getApplication().invokeLater(new MyRunnable("4"), ModalityState.NON_MODAL); } + flushSwingQueue(); + SwingUtilities.invokeLater(LEAVE_MODAL); + flushSwingQueue(); + checkOrder(5); }); } @@ -432,34 +394,28 @@ public class LaterInvocatorTest extends PlatformTestCase { } }; - UIUtil.invokeAndWaitIfNeeded(new Runnable() { - @Override - public void run() { - synchronized (LaterInvocatorTest.this) { - blockSwingThread(); - ApplicationManager.getApplication().invokeLater(new Runnable() { - @Override - public void run() { - thread.start(); - while (!started[0]) { - try { - //noinspection BusyWait - Thread.sleep(5); - } - catch (InterruptedException e) { - TestCase.fail(e.getMessage()); - } - } - synchronized (lock) { - checkOrder(0); - } + UIUtil.invokeAndWaitIfNeeded((Runnable)() -> { + synchronized (this) { + blockSwingThread(); + ApplicationManager.getApplication().invokeLater(() -> { + thread.start(); + while (!started[0]) { + try { + //noinspection BusyWait + Thread.sleep(5); } - }, ModalityState.NON_MODAL); - } - flushSwingQueue(); - flushSwingQueue(); - checkOrder(1); + catch (InterruptedException e) { + TestCase.fail(e.getMessage()); + } + } + synchronized (lock) { + checkOrder(0); + } + }, ModalityState.NON_MODAL); } + flushSwingQueue(); + flushSwingQueue(); + checkOrder(1); }); } @@ -558,26 +514,23 @@ public class LaterInvocatorTest extends PlatformTestCase { } public void testInvokeLaterWithNonexistentModalityStateIsInvokedInLowerModalityState() throws Exception { - SwingUtilities.invokeAndWait(new Runnable() { - @Override - public void run() { - LaterInvocator.enterModal(myWindow2); - ModalityState window2State = ModalityState.current(); - LaterInvocator.leaveModal(myWindow2); - LaterInvocator.invokeLater(new MyRunnable("1"), window2State); + SwingUtilities.invokeAndWait(() -> { + LaterInvocator.enterModal(myWindow2); + ModalityState window2State = ModalityState.current(); + LaterInvocator.leaveModal(myWindow2); + LaterInvocator.invokeLater(new MyRunnable("1"), window2State); - LaterInvocator.enterModal(myWindow1); - flushSwingQueue(); - checkOrder(0); + LaterInvocator.enterModal(myWindow1); + flushSwingQueue(); + checkOrder(0); - LaterInvocator.leaveModal(myWindow1); - flushSwingQueue(); - checkOrder(1); + LaterInvocator.leaveModal(myWindow1); + flushSwingQueue(); + checkOrder(1); - LaterInvocator.invokeLater(new MyRunnable("2"), window2State); - flushSwingQueue(); - checkOrder(2); - } + LaterInvocator.invokeLater(new MyRunnable("2"), window2State); + flushSwingQueue(); + checkOrder(2); }); } } diff --git a/platform/platform-tests/testSrc/com/intellij/psi/impl/PsiDocumentManagerImplTest.java b/platform/platform-tests/testSrc/com/intellij/psi/impl/PsiDocumentManagerImplTest.java index de66bb0dd321..c03cad6488f7 100644 --- a/platform/platform-tests/testSrc/com/intellij/psi/impl/PsiDocumentManagerImplTest.java +++ b/platform/platform-tests/testSrc/com/intellij/psi/impl/PsiDocumentManagerImplTest.java @@ -226,7 +226,7 @@ public class PsiDocumentManagerImplTest extends PlatformTestCase { final Document document = getPsiDocumentManager().getDocument(file); File temp = createTempDirectory(); - final Project alienProject = createProject(new File(temp, "alien.ipr"), DebugUtil.currentStackTrace()); + final Project alienProject = createProject(temp + "/alien.ipr", DebugUtil.currentStackTrace()); boolean succ2 = ProjectManagerEx.getInstanceEx().openProject(alienProject); assertTrue(succ2); UIUtil.dispatchAllInvocationEvents(); // startup activities @@ -368,7 +368,7 @@ public class PsiDocumentManagerImplTest extends PlatformTestCase { final Document document = getPsiDocumentManager().getDocument(file); File temp = createTempDirectory(); - final Project alienProject = createProject(new File(temp, "alien.ipr"), DebugUtil.currentStackTrace()); + final Project alienProject = createProject(temp + "/alien.ipr", DebugUtil.currentStackTrace()); boolean succ2 = ProjectManagerEx.getInstanceEx().openProject(alienProject); assertTrue(succ2); UIUtil.dispatchAllInvocationEvents(); // startup activities diff --git a/platform/projectModel-api/src/com/intellij/openapi/components/State.java b/platform/projectModel-api/src/com/intellij/openapi/components/State.java index 05e21d4c3a5e..1f76209076bb 100644 --- a/platform/projectModel-api/src/com/intellij/openapi/components/State.java +++ b/platform/projectModel-api/src/com/intellij/openapi/components/State.java @@ -24,6 +24,9 @@ import java.lang.annotation.RetentionPolicy; public @interface State { String name(); + /** + * Could be specified as empty list if you need to load only default state ({@link #defaultStateAsResource()} must be true in this case) + */ Storage[] storages(); boolean reloadable() default true; diff --git a/platform/script-debugger/backend/src/org/jetbrains/debugger/BreakpointManagerBase.kt b/platform/script-debugger/backend/src/org/jetbrains/debugger/BreakpointManagerBase.kt index df6064c96767..d7f7845dfcef 100644 --- a/platform/script-debugger/backend/src/org/jetbrains/debugger/BreakpointManagerBase.kt +++ b/platform/script-debugger/backend/src/org/jetbrains/debugger/BreakpointManagerBase.kt @@ -42,7 +42,7 @@ public abstract class BreakpointManagerBase> : BreakpointM override fun equals(b1: T, b2: T) = b1.target.javaClass == b2.target.javaClass && b1.target == b2.target && b1.line == b2.line && b1.column == b2.column && StringUtil.equals(b1.condition, b2.condition) }) - protected val dispatcher: EventDispatcher = EventDispatcher.create(javaClass()) + protected val dispatcher: EventDispatcher = EventDispatcher.create(BreakpointManager.BreakpointListener::class.java) protected abstract fun createBreakpoint(target: BreakpointTarget, line: Int, column: Int, condition: String?, ignoreCount: Int, enabled: Boolean): T diff --git a/platform/script-debugger/backend/src/org/jetbrains/debugger/Vm.kt b/platform/script-debugger/backend/src/org/jetbrains/debugger/Vm.kt index cabd52952ea5..5476b51bcae9 100644 --- a/platform/script-debugger/backend/src/org/jetbrains/debugger/Vm.kt +++ b/platform/script-debugger/backend/src/org/jetbrains/debugger/Vm.kt @@ -29,6 +29,8 @@ public interface Vm { public val attachStateManager: AttachStateManager + public val evaluateContext: EvaluateContext? + public fun getScriptManager(): ScriptManager public fun getBreakpointManager(): BreakpointManager @@ -39,6 +41,4 @@ public interface Vm { * Controls whether VM stops on exceptions */ public fun setBreakOnException(catchMode: ExceptionCatchMode): Promise<*> - - public fun getEvaluateContext(): EvaluateContext? } \ No newline at end of file diff --git a/platform/script-debugger/backend/src/org/jetbrains/debugger/VmBase.kt b/platform/script-debugger/backend/src/org/jetbrains/debugger/VmBase.kt index 8cba8e08bc33..ebfd940479b2 100644 --- a/platform/script-debugger/backend/src/org/jetbrains/debugger/VmBase.kt +++ b/platform/script-debugger/backend/src/org/jetbrains/debugger/VmBase.kt @@ -15,20 +15,13 @@ */ package org.jetbrains.debugger -import org.jetbrains.util.concurrency.Promise +import kotlin.properties.Delegates public abstract class VmBase protected constructor(override val debugListener: DebugEventListener) : Vm, AttachStateManager { - private var evaluateContext: EvaluateContext? = null + override val evaluateContext: EvaluateContext? by Delegates.lazy { computeEvaluateContext() } override val attachStateManager: AttachStateManager get() = this - override synchronized fun getEvaluateContext(): EvaluateContext? { - if (evaluateContext == null) { - evaluateContext = computeEvaluateContext() - } - return evaluateContext - } - protected open fun computeEvaluateContext(): EvaluateContext? = null } \ No newline at end of file diff --git a/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/ProcessHandlerWrapper.kt b/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/ProcessHandlerWrapper.kt index cd4ee74d8a07..775e59c6ac49 100644 --- a/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/ProcessHandlerWrapper.kt +++ b/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/ProcessHandlerWrapper.kt @@ -20,9 +20,7 @@ import com.intellij.execution.process.ProcessAdapter import com.intellij.execution.process.ProcessEvent import com.intellij.execution.process.ProcessHandler import com.intellij.openapi.diagnostic.Logger -import com.intellij.util.Consumer import com.intellij.xdebugger.XDebugProcess -import org.jetbrains.debugger.connection.VmConnection public class ProcessHandlerWrapper(private val debugProcess: XDebugProcess, private val handler: ProcessHandler) : ProcessHandler(), KillableProcess { init { @@ -42,7 +40,7 @@ public class ProcessHandlerWrapper(private val debugProcess: XDebugProcess, priv } companion object { - private val LOG: Logger = Logger.getInstance(javaClass()) + private val LOG: Logger = Logger.getInstance(ProcessHandlerWrapper::class.java) } override fun isSilentlyDestroyOnClose() = handler.isSilentlyDestroyOnClose() diff --git a/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/connection/VmConnection.kt b/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/connection/VmConnection.kt index b8da252bb115..582c27ac279d 100644 --- a/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/connection/VmConnection.kt +++ b/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/connection/VmConnection.kt @@ -34,8 +34,8 @@ import javax.swing.event.HyperlinkListener public abstract class VmConnection : Disposable, BrowserConnection { private val state = AtomicReference(ConnectionState(ConnectionStatus.NOT_CONNECTED)) - private val dispatcher = EventDispatcher.create(javaClass()) - private val connectionDispatcher = EventDispatcher.create(javaClass()) + private val dispatcher = EventDispatcher.create(DebugEventListener::class.java) + private val connectionDispatcher = EventDispatcher.create(SocketConnectionListener::class.java) public volatile var vm: T? = null protected set diff --git a/platform/testFramework/src/com/intellij/mock/MockProjectEx.java b/platform/testFramework/src/com/intellij/mock/MockProjectEx.java index e67df90b5462..52f8288a142c 100644 --- a/platform/testFramework/src/com/intellij/mock/MockProjectEx.java +++ b/platform/testFramework/src/com/intellij/mock/MockProjectEx.java @@ -32,14 +32,4 @@ public class MockProjectEx extends MockProject implements ProjectEx { @Override public void init() { } - - @Override - public boolean isOptimiseTestLoadSpeed() { - return false; - } - - @Override - public void setOptimiseTestLoadSpeed(final boolean optimiseTestLoadSpeed) { - throw new UnsupportedOperationException("Method setOptimiseTestLoadSpeed not implemented in " + getClass()); - } } \ No newline at end of file diff --git a/platform/testFramework/src/com/intellij/mock/MockPsiDocumentManager.java b/platform/testFramework/src/com/intellij/mock/MockPsiDocumentManager.java index 1318032fdcb6..3c655748bc71 100644 --- a/platform/testFramework/src/com/intellij/mock/MockPsiDocumentManager.java +++ b/platform/testFramework/src/com/intellij/mock/MockPsiDocumentManager.java @@ -67,6 +67,12 @@ public class MockPsiDocumentManager extends PsiDocumentManager { return document.getModificationStamp(); } + @Nullable + @Override + public Document getLastCommittedDocument(@NotNull PsiFile file) { + return null; + } + @Override @NotNull public Document[] getUncommittedDocuments() { diff --git a/platform/testFramework/src/com/intellij/testFramework/CompositeException.java b/platform/testFramework/src/com/intellij/testFramework/CompositeException.java deleted file mode 100644 index 4e1e38301e70..000000000000 --- a/platform/testFramework/src/com/intellij/testFramework/CompositeException.java +++ /dev/null @@ -1,153 +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.testFramework; - -import com.intellij.util.CommonProcessors; -import com.intellij.util.Function; -import com.intellij.util.Processor; -import org.jetbrains.annotations.NotNull; - -import java.io.PrintStream; -import java.io.PrintWriter; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -public class CompositeException extends Exception { - private final List myExceptions = new ArrayList(); - public CompositeException(@NotNull Throwable... e) { - myExceptions.addAll(Arrays.asList(e)); - } - - public void add(@NotNull Throwable e) { - if (e instanceof CompositeException) { - myExceptions.addAll(((CompositeException)e).myExceptions); - } - else { - myExceptions.add(e); - } - } - - public void addAll(@NotNull List errors) { - myExceptions.addAll(errors); - } - - public boolean isEmpty() { - return myExceptions.isEmpty(); - } - - @Override - public String getMessage() { - return processAll(new Function() { - @Override - public String fun(Throwable throwable) { - return throwable.getMessage(); - } - }, CommonProcessors.alwaysTrue()); - } - - @Override - public String getLocalizedMessage() { - return processAll(new Function() { - @Override - public String fun(Throwable throwable) { - return throwable.getLocalizedMessage(); - } - }, CommonProcessors.alwaysTrue()); - } - - @Override - public String toString() { - return processAll(new Function() { - @Override - public String fun(Throwable throwable) { - return throwable.toString(); - } - }, CommonProcessors.alwaysTrue()); - } - - @Override - public void printStackTrace(final PrintStream s) { - processAll(new Function() { - @Override - public String fun(Throwable throwable) { - throwable.printStackTrace(s); - return ""; - } - }, new Processor() { - @Override - public boolean process(String str) { - s.print(str); - return false; - } - }); - } - - @Override - public void printStackTrace(final PrintWriter s) { - processAll(new Function() { - @Override - public String fun(Throwable throwable) { - throwable.printStackTrace(s); - return ""; - } - }, new Processor() { - @Override - public boolean process(String str) { - s.print(str); - return false; - } - }); - } - - private String processAll(Function exceptionProcessor, Processor stringProcessor) { - if (myExceptions.size() == 1) { - Throwable throwable = myExceptions.get(0); - String s = exceptionProcessor.fun(throwable); - stringProcessor.process(s); - return s; - } - - StringBuilder sb = new StringBuilder(); - String line = "CompositeException ("+myExceptions.size() +" nested):\n------------------------------\n"; - stringProcessor.process(line); - sb.append(line); - - for (int i = 0; i < myExceptions.size(); i++) { - Throwable exception = myExceptions.get(i); - - line = "[" + i + "]: "; - stringProcessor.process(line); - sb.append(line); - - line = exceptionProcessor.fun(exception); - if (line == null) line = "null\n"; - else if (!line.endsWith("\n")) line += '\n'; - stringProcessor.process(line); - sb.append(line); - } - - line = "------------------------------\n"; - stringProcessor.process(line); - sb.append(line); - - return sb.toString(); - } - - public void throwIfNotEmpty() throws CompositeException { - if (!isEmpty()) throw this; - } -} diff --git a/platform/testFramework/src/com/intellij/testFramework/EdtTestUtil.kt b/platform/testFramework/src/com/intellij/testFramework/EdtTestUtil.kt index 82d09e99bb03..1fe4187e62c8 100644 --- a/platform/testFramework/src/com/intellij/testFramework/EdtTestUtil.kt +++ b/platform/testFramework/src/com/intellij/testFramework/EdtTestUtil.kt @@ -18,18 +18,21 @@ package com.intellij.testFramework import com.intellij.util.ThrowableRunnable import java.lang.reflect.InvocationTargetException import javax.swing.SwingUtilities -import kotlin.platform.platformStatic class EdtTestUtil { companion object { - public platformStatic fun runInEdtAndWait(runnable: ThrowableRunnable) { + @JvmStatic fun runInEdtAndWait(runnable: ThrowableRunnable) { + runInEdtAndWait({ runnable.run() }) + } + + @JvmStatic fun runInEdtAndWait(runnable: Runnable) { runInEdtAndWait({ runnable.run() }) } // Test only because in production you must use Application.invokeAndWait(Runnable, ModalityState). // The problem is - Application logs errors, but not throws. But in tests must be thrown. // In any case name "runInEdtAndWait" is better than "invokeAndWait". - public platformStatic fun runInEdtAndWait(runnable: () -> Unit) { + @JvmStatic fun runInEdtAndWait(runnable: () -> Unit) { if (SwingUtilities.isEventDispatchThread()) { runnable() } diff --git a/platform/testFramework/src/com/intellij/testFramework/LightPlatformCodeInsightTestCase.java b/platform/testFramework/src/com/intellij/testFramework/LightPlatformCodeInsightTestCase.java index 7fafca562698..80d55e2251f8 100644 --- a/platform/testFramework/src/com/intellij/testFramework/LightPlatformCodeInsightTestCase.java +++ b/platform/testFramework/src/com/intellij/testFramework/LightPlatformCodeInsightTestCase.java @@ -268,16 +268,20 @@ public abstract class LightPlatformCodeInsightTestCase extends LightPlatformTest @Override protected void tearDown() throws Exception { - FileEditorManager editorManager = FileEditorManager.getInstance(getProject()); - VirtualFile[] openFiles = editorManager.getOpenFiles(); - for (VirtualFile openFile : openFiles) { - editorManager.closeFile(openFile); + try { + FileEditorManager editorManager = FileEditorManager.getInstance(getProject()); + VirtualFile[] openFiles = editorManager.getOpenFiles(); + for (VirtualFile openFile : openFiles) { + editorManager.closeFile(openFile); + } + deleteVFile(); + myEditor = null; + myFile = null; + myVFile = null; + } + finally { + super.tearDown(); } - deleteVFile(); - myEditor = null; - myFile = null; - myVFile = null; - super.tearDown(); } /** diff --git a/platform/testFramework/src/com/intellij/testFramework/LightPlatformTestCase.java b/platform/testFramework/src/com/intellij/testFramework/LightPlatformTestCase.java index beed5a3a3145..b3a5892ce05d 100644 --- a/platform/testFramework/src/com/intellij/testFramework/LightPlatformTestCase.java +++ b/platform/testFramework/src/com/intellij/testFramework/LightPlatformTestCase.java @@ -95,10 +95,7 @@ import com.intellij.psi.impl.PsiManagerImpl; import com.intellij.psi.impl.source.tree.injected.InjectedLanguageManagerImpl; import com.intellij.psi.templateLanguages.TemplateDataLanguageMappings; import com.intellij.testFramework.fixtures.impl.CodeInsightTestFixtureImpl; -import com.intellij.util.GCUtil; -import com.intellij.util.IncorrectOperationException; -import com.intellij.util.LocalTimeCounter; -import com.intellij.util.ThrowableRunnable; +import com.intellij.util.*; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.indexing.UnindexedFilesUpdater; import com.intellij.util.lang.CompoundRuntimeException; @@ -446,95 +443,117 @@ public abstract class LightPlatformTestCase extends UsefulTestCase implements Da protected void tearDown() throws Exception { Project project = getProject(); CodeStyleSettingsManager.getInstance(project).dropTemporarySettings(); - List errors = checkForSettingsDamage(); - VirtualFilePointerManagerImpl filePointerManager = (VirtualFilePointerManagerImpl)VirtualFilePointerManager.getInstance(); - doTearDown(project, ourApplication, true); + List errors = new SmartList(); + try { + checkForSettingsDamage(errors); + doTearDown(project, ourApplication, true, errors); + } + catch (Throwable e) { + errors.add(e); + } try { + //noinspection SuperTearDownInFinally super.tearDown(); } - finally { + catch (Throwable e) { + errors.add(e); + } + + try { myThreadTracker.checkLeak(); InjectedLanguageManagerImpl.checkInjectorsAreDisposed(project); - filePointerManager.assertPointersAreDisposed(); + ((VirtualFilePointerManagerImpl)VirtualFilePointerManager.getInstance()).assertPointersAreDisposed(); + } + catch (Throwable e) { + errors.add(e); + } + finally { + CompoundRuntimeException.throwIfNotEmpty(errors); } - CompoundRuntimeException.doThrow(errors); } - public static void doTearDown(@NotNull final Project project, @NotNull IdeaTestApplication application, boolean checkForEditors) throws Exception { - ((FileTypeManagerImpl)FileTypeManager.getInstance()).drainReDetectQueue(); - DocumentCommitThread.getInstance().clearQueue(); - CodeStyleSettingsManager.getInstance(project).dropTemporarySettings(); - checkAllTimersAreDisposed(); - UsefulTestCase.doPostponedFormatting(project); + public static void doTearDown(@NotNull final Project project, @NotNull IdeaTestApplication application, boolean checkForEditors, @NotNull List exceptions) throws Exception { + PsiDocumentManagerImpl documentManager; + try { + ((FileTypeManagerImpl)FileTypeManager.getInstance()).drainReDetectQueue(); + DocumentCommitThread.getInstance().clearQueue(); + CodeStyleSettingsManager.getInstance(project).dropTemporarySettings(); - LookupManager lookupManager = LookupManager.getInstance(project); - if (lookupManager != null) { - lookupManager.hideActiveLookup(); - } - ((StartupManagerImpl)StartupManager.getInstance(project)).prepareForNextTest(); - InspectionProfileManager.getInstance().deleteProfile(PROFILE); - assertNotNull("Application components damaged", ProjectManager.getInstance()); + checkAllTimersAreDisposed(exceptions); - new WriteCommandAction.Simple(project) { - @Override - protected void run() throws Throwable { - if (ourSourceRoot != null) { - try { - final VirtualFile[] children = ourSourceRoot.getChildren(); - for (VirtualFile child : children) { - child.delete(this); + UsefulTestCase.doPostponedFormatting(project); + + LookupManager lookupManager = LookupManager.getInstance(project); + if (lookupManager != null) { + lookupManager.hideActiveLookup(); + } + ((StartupManagerImpl)StartupManager.getInstance(project)).prepareForNextTest(); + InspectionProfileManager.getInstance().deleteProfile(PROFILE); + if (ProjectManager.getInstance() == null) { + exceptions.add(new AssertionError("Application components damaged")); + } + + ContainerUtil.addIfNotNull(exceptions, new WriteCommandAction.Simple(project) { + @Override + protected void run() throws Throwable { + if (ourSourceRoot != null) { + try { + final VirtualFile[] children = ourSourceRoot.getChildren(); + for (VirtualFile child : children) { + child.delete(this); + } + } + catch (IOException e) { + //noinspection CallToPrintStackTrace + e.printStackTrace(); } } - catch (IOException e) { - //noinspection CallToPrintStackTrace - e.printStackTrace(); + EncodingManager encodingManager = EncodingManager.getInstance(); + if (encodingManager instanceof EncodingManagerImpl) ((EncodingManagerImpl)encodingManager).clearDocumentQueue(); + + FileDocumentManager manager = FileDocumentManager.getInstance(); + + ApplicationManager.getApplication().runWriteAction(EmptyRunnable.getInstance()); // Flush postponed formatting if any. + manager.saveAllDocuments(); + if (manager instanceof FileDocumentManagerImpl) { + ((FileDocumentManagerImpl)manager).dropAllUnsavedDocuments(); } } - EncodingManager encodingManager = EncodingManager.getInstance(); - if (encodingManager instanceof EncodingManagerImpl) ((EncodingManagerImpl)encodingManager).clearDocumentQueue(); + }.execute().getThrowable()); - FileDocumentManager manager = FileDocumentManager.getInstance(); - - ApplicationManager.getApplication().runWriteAction(EmptyRunnable.getInstance()); // Flush postponed formatting if any. - manager.saveAllDocuments(); - if (manager instanceof FileDocumentManagerImpl) { - ((FileDocumentManagerImpl)manager).dropAllUnsavedDocuments(); + assertFalse(PsiManager.getInstance(project).isDisposed()); + if (!ourAssertionsInTestDetected) { + if (IdeaLogger.ourErrorsOccurred != null) { + throw IdeaLogger.ourErrorsOccurred; } } - }.execute().throwException(); + documentManager = clearUncommittedDocuments(project); + ((HintManagerImpl)HintManager.getInstance()).cleanup(); + DocumentCommitThread.getInstance().clearQueue(); - assertFalse(PsiManager.getInstance(project).isDisposed()); - if (!ourAssertionsInTestDetected) { - if (IdeaLogger.ourErrorsOccurred != null) { - throw IdeaLogger.ourErrorsOccurred; - } + EdtTestUtil.runInEdtAndWait(new Runnable() { + @Override + public void run() { + ((UndoManagerImpl)UndoManager.getGlobalInstance()).dropHistoryInTests(); + ((UndoManagerImpl)UndoManager.getInstance(project)).dropHistoryInTests(); + + UIUtil.dispatchAllInvocationEvents(); + } + }); + + TemplateDataLanguageMappings.getInstance(project).cleanupForNextTest(); + } + finally { + ProjectManagerEx.getInstanceEx().closeTestProject(project); + application.setDataProvider(null); + ourTestCase = null; + ((PsiManagerImpl)PsiManager.getInstance(project)).cleanupForNextTest(); + CompletionProgressIndicator.cleanupForNextTest(); } - PsiDocumentManagerImpl documentManager = clearUncommittedDocuments(project); - ((HintManagerImpl)HintManager.getInstance()).cleanup(); - DocumentCommitThread.getInstance().clearQueue(); - - UIUtil.invokeAndWaitIfNeeded(new Runnable() { - @Override - public void run() { - ((UndoManagerImpl)UndoManager.getGlobalInstance()).dropHistoryInTests(); - ((UndoManagerImpl)UndoManager.getInstance(project)).dropHistoryInTests(); - - UIUtil.dispatchAllInvocationEvents(); - } - }); - - TemplateDataLanguageMappings.getInstance(project).cleanupForNextTest(); - - ProjectManagerEx.getInstanceEx().closeTestProject(project); - application.setDataProvider(null); - ourTestCase = null; - ((PsiManagerImpl)PsiManager.getInstance(project)).cleanupForNextTest(); - - CompletionProgressIndicator.cleanupForNextTest(); if (checkForEditors) { - checkEditorsReleased(); + checkEditorsReleased(exceptions); } documentManager.clearUncommittedDocuments(); @@ -559,30 +578,30 @@ public abstract class LightPlatformTestCase extends UsefulTestCase implements Da return documentManager; } - public static void checkEditorsReleased() throws Exception { - CompositeException result = new CompositeException(); - final Editor[] allEditors = EditorFactory.getInstance().getAllEditors(); - if (allEditors.length > 0) { - for (Editor editor : allEditors) { - try { - EditorFactoryImpl.throwNotReleasedError(editor); - } - catch (Throwable e) { - result.add(e); - } - finally { - EditorFactory.getInstance().releaseEditor(editor); - } - } + public static void checkEditorsReleased(@NotNull List exceptions) { + Editor[] allEditors = EditorFactory.getInstance().getAllEditors(); + if (allEditors.length == 0) { + return; + } + + for (Editor editor : allEditors) { try { - ((EditorImpl)allEditors[0]).throwDisposalError("Unreleased editors: " + allEditors.length); + EditorFactoryImpl.throwNotReleasedError(editor); } catch (Throwable e) { - e.printStackTrace(); - result.add(e); + exceptions.add(e); + } + finally { + EditorFactory.getInstance().releaseEditor(editor); } } - if (!result.isEmpty()) throw result; + + try { + ((EditorImpl)allEditors[0]).throwDisposalError("Unreleased editors: " + allEditors.length); + } + catch (Throwable e) { + exceptions.add(e); + } } @Override diff --git a/platform/testFramework/src/com/intellij/testFramework/PlatformTestCase.java b/platform/testFramework/src/com/intellij/testFramework/PlatformTestCase.java index ab2d6ce3cc49..0084621f5409 100644 --- a/platform/testFramework/src/com/intellij/testFramework/PlatformTestCase.java +++ b/platform/testFramework/src/com/intellij/testFramework/PlatformTestCase.java @@ -22,6 +22,7 @@ import com.intellij.idea.IdeaLogger; import com.intellij.idea.IdeaTestApplication; import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.DataProvider; +import com.intellij.openapi.application.AccessToken; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.Result; import com.intellij.openapi.application.WriteAction; @@ -53,6 +54,7 @@ import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VfsUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.impl.local.LocalFileSystemImpl; +import com.intellij.openapi.vfs.newvfs.NewVirtualFile; import com.intellij.openapi.vfs.newvfs.impl.VirtualDirectoryImpl; import com.intellij.openapi.vfs.newvfs.persistent.PersistentFS; import com.intellij.openapi.vfs.newvfs.persistent.PersistentFSImpl; @@ -65,9 +67,13 @@ import com.intellij.psi.codeStyle.CodeStyleSettingsManager; import com.intellij.psi.impl.DocumentCommitThread; import com.intellij.psi.impl.PsiManagerImpl; import com.intellij.psi.impl.source.tree.injected.InjectedLanguageManagerImpl; +import com.intellij.util.PathUtilRt; import com.intellij.util.PlatformUtils; +import com.intellij.util.SmartList; +import com.intellij.util.ThrowableRunnable; import com.intellij.util.indexing.IndexableSetContributor; import com.intellij.util.indexing.IndexedRootsProvider; +import com.intellij.util.lang.CompoundRuntimeException; import com.intellij.util.ui.UIUtil; import junit.framework.TestCase; import org.jetbrains.annotations.NonNls; @@ -88,6 +94,7 @@ import java.net.URL; import java.nio.charset.Charset; import java.util.Collection; import java.util.HashSet; +import java.util.List; import java.util.Set; /** @@ -125,7 +132,7 @@ public abstract class PlatformTestCase extends UsefulTestCase implements DataPro * If a temp directory is reused from some previous test run, there might be cached children in its VFS. * Ensure they're removed */ - public static void synchronizeTempDirVfs(VirtualFile tempDir) { + public static void synchronizeTempDirVfs(@NotNull VirtualFile tempDir) { tempDir.getChildren(); tempDir.refresh(false, true); } @@ -185,6 +192,7 @@ public abstract class PlatformTestCase extends UsefulTestCase implements DataPro @Override protected void setUp() throws Exception { super.setUp(); + myFilesToDelete.add(new File(FileUtilRt.getTempDirectory())); if (ourTestCase != null) { String message = "Previous test " + ourTestCase + " hasn't called tearDown(). Probably overridden without super call."; ourTestCase = null; @@ -213,7 +221,7 @@ public abstract class PlatformTestCase extends UsefulTestCase implements DataPro UIUtil.dispatchAllInvocationEvents(); } - public Project getProject() { + public final Project getProject() { return myProject; } @@ -251,8 +259,24 @@ public abstract class PlatformTestCase extends UsefulTestCase implements DataPro @NotNull public static Project createProject(File projectFile, String creationPlace) { + return createProject(projectFile.getPath(), creationPlace); + } + + @NotNull + public static Project createProject(@NotNull String path, String creationPlace) { + String fileName = PathUtilRt.getFileName(path); + String projectName = FileUtilRt.getNameWithoutExtension(fileName); + VirtualFile projectBase = LocalFileSystem.getInstance().findFileByPath(FileUtil.toSystemIndependentName(fileName.endsWith( + ProjectFileType.DOT_DEFAULT_EXTENSION) ? PathUtilRt.getParentPath(path) : path)); + if (projectBase != null) { + // must be leftovers from the previous test run + for (VirtualFile file : ((NewVirtualFile)projectBase).iterInDbChildren()) { + delete(file); + } + } + try { - Project project = ProjectManagerEx.getInstanceEx().newProject(FileUtil.getNameWithoutExtension(projectFile), projectFile.getPath(), false, false); + Project project = ProjectManagerEx.getInstanceEx().newProject(projectName, path, false, false); assert project != null; project.putUserData(CREATION_PLACE, creationPlace); @@ -293,7 +317,7 @@ public abstract class PlatformTestCase extends UsefulTestCase implements DataPro } protected File getIprFile() throws IOException { - File tempFile = FileUtil.createTempFile(getName() + "_", ProjectFileType.DOT_DEFAULT_EXTENSION); + File tempFile = FileUtil.createTempFile(getName(), ProjectFileType.DOT_DEFAULT_EXTENSION); myFilesToDelete.add(tempFile); return tempFile; } @@ -408,32 +432,32 @@ public abstract class PlatformTestCase extends UsefulTestCase implements DataPro @Override protected void tearDown() throws Exception { - CompositeException result = new CompositeException(); - if (myProject != null) { + List exceptions = new SmartList(); + Project project = myProject; + if (project != null) { try { - LightPlatformTestCase.doTearDown(getProject(), ourApplication, false); + LightPlatformTestCase.doTearDown(project, ourApplication, false, exceptions); } catch (Throwable e) { - result.add(e); + exceptions.add(e); } + + disposeProject(exceptions); } try { - result.addAll(checkForSettingsDamage()); + checkForSettingsDamage(exceptions); } catch (Throwable e) { - result.add(e); + exceptions.add(e); } try { - Project project = getProject(); - disposeProject(result); - if (project != null) { try { InjectedLanguageManagerImpl.checkInjectorsAreDisposed(project); } catch (AssertionError e) { - result.add(e); + exceptions.add(e); } } try { @@ -443,12 +467,12 @@ public abstract class PlatformTestCase extends UsefulTestCase implements DataPro LocalFileSystem.getInstance().refreshIoFiles(myFilesToDelete); } catch (Throwable e) { - result.add(e); + exceptions.add(e); } if (!myAssertionsInTestDetected) { if (IdeaLogger.ourErrorsOccurred != null) { - result.add(IdeaLogger.ourErrorsOccurred); + exceptions.add(IdeaLogger.ourErrorsOccurred); } } @@ -456,7 +480,7 @@ public abstract class PlatformTestCase extends UsefulTestCase implements DataPro super.tearDown(); } catch (Throwable e) { - result.add(e); + exceptions.add(e); } try { @@ -465,7 +489,7 @@ public abstract class PlatformTestCase extends UsefulTestCase implements DataPro } } catch (AssertionError error) { - result.add(error); + exceptions.add(error); } try { if (myThreadTracker != null) { @@ -473,13 +497,13 @@ public abstract class PlatformTestCase extends UsefulTestCase implements DataPro } } catch (AssertionError error) { - result.add(error); + exceptions.add(error); } try { - LightPlatformTestCase.checkEditorsReleased(); + LightPlatformTestCase.checkEditorsReleased(exceptions); } catch (Throwable error) { - result.add(error); + exceptions.add(error); } } finally { @@ -491,10 +515,10 @@ public abstract class PlatformTestCase extends UsefulTestCase implements DataPro myThreadTracker = null; ourTestCase = null; } - if (!result.isEmpty()) throw result; + CompoundRuntimeException.throwIfNotEmpty(exceptions); } - private void disposeProject(@NotNull CompositeException result) /* throws nothing */ { + private void disposeProject(@NotNull List exceptions) { try { DocumentCommitThread.getInstance().clearQueue(); // sometimes SwingUtilities maybe confused about EDT at this point @@ -502,39 +526,54 @@ public abstract class PlatformTestCase extends UsefulTestCase implements DataPro UIUtil.dispatchAllInvocationEvents(); } } - catch (Exception e) { - result.add(e); + catch (Throwable e) { + exceptions.add(e); } + + Project project = myProject; + if (project == null) { + return; + } + + closeAndDisposeProjectAndCheckThatNoOpenProjects(project, exceptions); + myProject = null; + } + + public static void closeAndDisposeProjectAndCheckThatNoOpenProjects(@NotNull Project projectToClose) { + List exceptions = new SmartList(); + closeAndDisposeProjectAndCheckThatNoOpenProjects(projectToClose, exceptions); + CompoundRuntimeException.throwIfNotEmpty(exceptions); + } + + public static void closeAndDisposeProjectAndCheckThatNoOpenProjects(@NotNull Project projectToClose, @NotNull List exceptions) { try { - if (myProject != null) { - ApplicationManager.getApplication().runWriteAction(new Runnable() { - @Override - public void run() { - ProjectManagerEx projectManager = ProjectManagerEx.getInstanceEx(); - if (projectManager instanceof ProjectManagerImpl) { - Collection projectsStillOpen = projectManager.closeTestProject(myProject); - if (!projectsStillOpen.isEmpty()) { - Project project = projectsStillOpen.iterator().next(); - String message = "Test project is not disposed: " + project + ";\n created in: " + getCreationPlace(project); - try { - projectManager.closeAndDispose(project); - } - catch (Exception e) { - // ignore, we already have something to throw - } - throw new AssertionError(message); - } - } - Disposer.dispose(myProject); + ProjectManagerEx projectManager = ProjectManagerEx.getInstanceEx(); + if (projectManager instanceof ProjectManagerImpl) { + for (Project project : projectManager.closeTestProject(projectToClose)) { + exceptions.add(new IllegalStateException("Test project is not disposed: " + project + ";\n created in: " + getCreationPlace(project))); + try { + ((ProjectManagerImpl)projectManager).closeProject(project, false, true, false); } - }); + catch (Throwable e) { + exceptions.add(e); + } + } } } - catch (Exception e) { - result.add(e); + catch (Throwable e) { + exceptions.add(e); } finally { - myProject = null; + AccessToken token = WriteAction.start(); + try { + Disposer.dispose(projectToClose); + } + catch (Throwable e) { + exceptions.add(e); + } + finally { + token.finish(); + } } } @@ -611,10 +650,9 @@ public abstract class PlatformTestCase extends UsefulTestCase implements DataPro } private void runBareImpl() throws Throwable { - final Throwable[] throwables = new Throwable[1]; - Runnable runnable = new Runnable() { + ThrowableRunnable runnable = new ThrowableRunnable() { @Override - public void run() { + public void run() throws Throwable { ourTestThread = Thread.currentThread(); ourTestTime = getTimeRequired(); try { @@ -622,31 +660,37 @@ public abstract class PlatformTestCase extends UsefulTestCase implements DataPro setUp(); } catch (Throwable e) { - CompositeException result = new CompositeException(e); try { tearDown(); } - catch (Throwable th) { - result.add(th); + catch (Throwable ignored) { } - throw result; + + throw e; } + + Throwable exception = null; try { myAssertionsInTestDetected = true; runTest(); myAssertionsInTestDetected = false; } catch (Throwable e) { - throwables[0] = e; - throw e; + exception = e; } finally { - tearDown(); + try { + tearDown(); + } + catch (Throwable e) { + if (exception == null) { + exception = e; + } + } } - } - catch (Throwable throwable) { - if (throwables[0] == null) { // report tearDown() problems if only no exceptions thrown from runTest() - throwables[0] = throwable; + + if (exception != null) { + throw exception; } } finally { @@ -661,10 +705,6 @@ public abstract class PlatformTestCase extends UsefulTestCase implements DataPro throw IdeaLogger.ourErrorsOccurred; } - if (throwables[0] != null) { - throw throwables[0]; - } - // just to make sure all deferred Runnable's to finish waitForAllLaters(); if (IdeaLogger.ourErrorsOccurred != null) { @@ -695,9 +735,9 @@ public abstract class PlatformTestCase extends UsefulTestCase implements DataPro return true; } - protected void runBareRunnable(Runnable runnable) throws Throwable { + protected void runBareRunnable(ThrowableRunnable runnable) throws Throwable { if (isRunInEdt()) { - SwingUtilities.invokeAndWait(runnable); + EdtTestUtil.runInEdtAndWait(runnable); } else { runnable.run(); diff --git a/platform/testFramework/src/com/intellij/testFramework/PsiTestUtil.java b/platform/testFramework/src/com/intellij/testFramework/PsiTestUtil.java index afa500ee4c7e..5a69144fe091 100644 --- a/platform/testFramework/src/com/intellij/testFramework/PsiTestUtil.java +++ b/platform/testFramework/src/com/intellij/testFramework/PsiTestUtil.java @@ -15,10 +15,7 @@ */ package com.intellij.testFramework; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.application.Result; -import com.intellij.openapi.application.RunResult; -import com.intellij.openapi.application.WriteAction; +import com.intellij.openapi.application.*; import com.intellij.openapi.command.WriteCommandAction; import com.intellij.openapi.module.ModifiableModuleModel; import com.intellij.openapi.module.Module; @@ -43,6 +40,7 @@ import com.intellij.psi.PsiFileFactory; import com.intellij.psi.impl.DebugUtil; import com.intellij.util.Consumer; import com.intellij.util.IncorrectOperationException; +import com.intellij.util.ThrowableRunnable; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -53,6 +51,7 @@ import org.jetbrains.jps.model.module.JpsModuleSourceRootType; import org.junit.Assert; import java.io.File; +import java.io.IOException; import java.util.*; @@ -65,7 +64,7 @@ public class PsiTestUtil { return createTestProjectStructure(project, module, rootPath, filesToDelete, true); } - public static VirtualFile createTestProjectStructure(Project project, Module module, Collection filesToDelete) throws Exception { + public static VirtualFile createTestProjectStructure(Project project, Module module, Collection filesToDelete) throws IOException { return createTestProjectStructure(project, module, null, filesToDelete, true); } @@ -73,7 +72,7 @@ public class PsiTestUtil { Module module, String rootPath, Collection filesToDelete, - boolean addProjectRoots) throws Exception { + boolean addProjectRoots) throws IOException { VirtualFile vDir = createTestProjectStructure(module, rootPath, filesToDelete, addProjectRoots); PsiDocumentManager.getInstance(project).commitAllDocuments(); return vDir; @@ -82,7 +81,7 @@ public class PsiTestUtil { public static VirtualFile createTestProjectStructure(Module module, String rootPath, Collection filesToDelete, - boolean addProjectRoots) throws Exception { + boolean addProjectRoots) throws IOException { return createTestProjectStructure("unitTest", module, rootPath, filesToDelete, addProjectRoots); } @@ -90,33 +89,37 @@ public class PsiTestUtil { final Module module, final String rootPath, final Collection filesToDelete, - final boolean addProjectRoots) throws Exception { + final boolean addProjectRoots) throws IOException { File dir = FileUtil.createTempDirectory(tempName, null, false); filesToDelete.add(dir); final VirtualFile vDir = LocalFileSystem.getInstance().refreshAndFindFileByPath(dir.getCanonicalPath().replace(File.separatorChar, '/')); - PlatformTestCase.synchronizeTempDirVfs(vDir); assert vDir != null && vDir.isDirectory() : dir; + PlatformTestCase.synchronizeTempDirVfs(vDir); - Project project = module != null ? module.getProject() : null; - new WriteCommandAction.Simple(project) { + EdtTestUtil.runInEdtAndWait(new ThrowableRunnable() { @Override - protected void run() throws Throwable { - if (rootPath != null) { - VirtualFile vDir1 = LocalFileSystem.getInstance().findFileByPath(rootPath.replace(File.separatorChar, '/')); - if (vDir1 == null) { - throw new Exception(rootPath + " not found"); + public void run() throws Throwable { + AccessToken token = WriteAction.start(); + try { + if (rootPath != null) { + VirtualFile vDir1 = LocalFileSystem.getInstance().findFileByPath(rootPath.replace(File.separatorChar, '/')); + if (vDir1 == null) { + throw new Exception(rootPath + " not found"); + } + VfsUtil.copyDirectory(null, vDir1, vDir, null); } - VfsUtil.copyDirectory(null, vDir1, vDir, null); - } - if (addProjectRoots) { - addSourceContentToRoots(module, vDir); + if (addProjectRoots) { + addSourceContentToRoots(module, vDir); + } + } + finally { + token.finish(); } } - }.execute().throwException(); - + }); return vDir; } diff --git a/platform/testFramework/src/com/intellij/testFramework/UsefulTestCase.java b/platform/testFramework/src/com/intellij/testFramework/UsefulTestCase.java index aad28bc65d90..193eae27b047 100644 --- a/platform/testFramework/src/com/intellij/testFramework/UsefulTestCase.java +++ b/platform/testFramework/src/com/intellij/testFramework/UsefulTestCase.java @@ -139,7 +139,8 @@ public abstract class UsefulTestCase extends TestCase { String testName = getTestName(true); if (StringUtil.isEmptyOrSpaces(testName)) testName = ""; testName = new File(testName).getName(); // in case the test name contains file separators - myTempDir = FileUtil.toSystemDependentName(ORIGINAL_TEMP_DIR + "/" + TEMP_DIR_MARKER + testName + "_"+ RNG.nextInt(1000)); + File tempDirectory = FileUtil.createTempDirectory(new File(ORIGINAL_TEMP_DIR), TEMP_DIR_MARKER + testName, ""); + myTempDir = tempDirectory.getPath(); FileUtil.resetCanonicalTempPathCache(myTempDir); } ApplicationInfoImpl.setInPerformanceTest(isPerformanceTest()); @@ -232,26 +233,23 @@ public abstract class UsefulTestCase extends TestCase { containerMap.clear(); } - @NotNull - protected List checkForSettingsDamage() throws Exception { + protected void checkForSettingsDamage(@NotNull List exceptions) { Application app = ApplicationManager.getApplication(); if (isPerformanceTest() || app == null || app instanceof MockApplication) { - return Collections.emptyList(); + return; } CodeStyleSettings oldCodeStyleSettings = myOldCodeStyleSettings; if (oldCodeStyleSettings == null) { - return Collections.emptyList(); + return; } myOldCodeStyleSettings = null; - return doCheckForSettingsDamage(oldCodeStyleSettings, getCurrentCodeStyleSettings()); + doCheckForSettingsDamage(oldCodeStyleSettings, getCurrentCodeStyleSettings(), exceptions); } - @NotNull - public static List doCheckForSettingsDamage(@NotNull CodeStyleSettings oldCodeStyleSettings, @NotNull CodeStyleSettings currentCodeStyleSettings) throws Exception { - List result = new SmartList(); + public static void doCheckForSettingsDamage(@NotNull CodeStyleSettings oldCodeStyleSettings, @NotNull CodeStyleSettings currentCodeStyleSettings, @NotNull List exceptions) { final CodeInsightSettings settings = CodeInsightSettings.getInstance(); try { Element newS = new Element("temp"); @@ -267,15 +265,15 @@ public abstract class UsefulTestCase extends TestCase { catch (Exception ignored) { } } - result.add(error); + exceptions.add(error); } currentCodeStyleSettings.getIndentOptions(StdFileTypes.JAVA); try { checkSettingsEqual(oldCodeStyleSettings, currentCodeStyleSettings, "Code style settings damaged"); } - catch (AssertionError e) { - result.add(e); + catch (Throwable e) { + exceptions.add(e); } finally { currentCodeStyleSettings.clearCodeStyleSettings(); @@ -285,16 +283,14 @@ public abstract class UsefulTestCase extends TestCase { InplaceRefactoring.checkCleared(); } catch (AssertionError e) { - result.add(e); + exceptions.add(e); } try { StartMarkAction.checkCleared(); } catch (AssertionError e) { - result.add(e); + exceptions.add(e); } - - return result; } protected void storeSettings() { @@ -348,49 +344,35 @@ public abstract class UsefulTestCase extends TestCase { return PlatformTestUtil.canRunTest(getClass()); } - public static void edt(@NotNull final ThrowableRunnable r) { - try { - UIUtil.invokeAndWaitIfNeeded(r); - } - catch (RuntimeException re) { - throw re; - } - catch (Throwable throwable) { - throw new RuntimeException(throwable); - } - } - - public static void edt(@NotNull final Runnable r) { - edt(new ThrowableRunnable() { - @Override - public void run() throws Throwable { - r.run(); - } - }); + public static void edt(@NotNull Runnable r) { + EdtTestUtil.runInEdtAndWait(r); } protected void invokeTestRunnable(@NotNull Runnable runnable) throws Exception { - edt(runnable); + EdtTestUtil.runInEdtAndWait(runnable); } protected void defaultRunBare() throws Throwable { Throwable exception = null; - long setupStart = System.nanoTime(); - setUp(); - long setupCost = (System.nanoTime() - setupStart) / 1000000; - logPerClassCost(setupCost, TOTAL_SETUP_COST_MILLIS); - try { + long setupStart = System.nanoTime(); + setUp(); + long setupCost = (System.nanoTime() - setupStart) / 1000000; + logPerClassCost(setupCost, TOTAL_SETUP_COST_MILLIS); + runTest(); - } catch (Throwable running) { + } + catch (Throwable running) { exception = running; - } finally { + } + finally { try { long teardownStart = System.nanoTime(); tearDown(); long teardownCost = (System.nanoTime() - teardownStart) / 1000000; logPerClassCost(teardownCost, TOTAL_TEARDOWN_COST_MILLIS); - } catch (Throwable tearingDown) { + } + catch (Throwable tearingDown) { if (exception == null) exception = tearingDown; } } @@ -871,7 +853,7 @@ public abstract class UsefulTestCase extends TestCase { }); } - protected static void checkAllTimersAreDisposed() { + protected static void checkAllTimersAreDisposed(@NotNull List exceptions) { Field firstTimerF; Object timerQueue; Object timer; @@ -894,8 +876,10 @@ public abstract class UsefulTestCase extends TestCase { } } catch (Throwable e) { - throw new RuntimeException(e); + exceptions.add(e); + return; } + if (timer != null) { if (firstTimerF != null) { ReflectionUtil.resetField(timerQueue, firstTimerF); @@ -910,13 +894,13 @@ public abstract class UsefulTestCase extends TestCase { timer = getTimer.invoke(timer); } catch (Exception e) { - throw new RuntimeException(e); + exceptions.add(e); + return; } } Timer t = (Timer)timer; text = "Timer (listeners: "+Arrays.asList(t.getActionListeners()) + ") "+text; - - fail("Not disposed Timer: " + text + "; queue:" + timerQueue); + exceptions.add(new AssertionFailedError("Not disposed Timer: " + text + "; queue:" + timerQueue)); } } diff --git a/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/BaseFixture.java b/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/BaseFixture.java index 2b6236a27a09..b8506d06e19d 100644 --- a/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/BaseFixture.java +++ b/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/BaseFixture.java @@ -17,9 +17,9 @@ package com.intellij.testFramework.fixtures.impl; import com.intellij.openapi.Disposable; import com.intellij.openapi.util.Disposer; +import com.intellij.testFramework.EdtTestUtil; import com.intellij.testFramework.UsefulTestCase; import com.intellij.testFramework.fixtures.IdeaTestFixture; -import com.intellij.util.ui.UIUtil; import org.junit.Assert; /** @@ -41,7 +41,7 @@ public class BaseFixture implements IdeaTestFixture { public void tearDown() throws Exception { Assert.assertTrue("setUp() has not been called", myInitialized); Assert.assertFalse("tearDown() already has been called", myDisposed); - UIUtil.invokeAndWaitIfNeeded(new Runnable() { + EdtTestUtil.runInEdtAndWait(new Runnable() { @Override public void run() { Disposer.dispose(myTestRootDisposable); diff --git a/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java b/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java index 02ffd6732a85..57006b629b31 100644 --- a/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java +++ b/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java @@ -1399,32 +1399,37 @@ public class CodeInsightTestFixtureImpl extends BaseFixture implements CodeInsig @Override public void tearDown() throws Exception { - UIUtil.invokeAndWaitIfNeeded(new Runnable() { - @Override - public void run() { - DaemonCodeAnalyzerSettings.getInstance().setImportHintEnabled(true); // return default value to avoid unnecessary save - FileEditorManager editorManager = FileEditorManager.getInstance(getProject()); - PsiDocumentManager.getInstance(getProject()).commitAllDocuments(); - VirtualFile[] openFiles = editorManager.getOpenFiles(); - for (VirtualFile openFile : openFiles) { - editorManager.closeFile(openFile); - } + try { + EdtTestUtil.runInEdtAndWait(new ThrowableRunnable() { + @Override + public void run() throws Throwable { + try { + DaemonCodeAnalyzerSettings.getInstance().setImportHintEnabled(true); // return default value to avoid unnecessary save + FileEditorManager editorManager = FileEditorManager.getInstance(getProject()); + PsiDocumentManager.getInstance(getProject()).commitAllDocuments(); + VirtualFile[] openFiles = editorManager.getOpenFiles(); + for (VirtualFile openFile : openFiles) { + editorManager.closeFile(openFile); + } + } + finally { + myEditor = null; + myFile = null; + myPsiManager = null; - myEditor = null; - myFile = null; - myPsiManager = null; - - try { - myProjectFixture.tearDown(); - myTempDirFixture.tearDown(); + try { + myProjectFixture.tearDown(); + } + finally { + myTempDirFixture.tearDown(); + } + } } - catch (Exception e) { - throw new RuntimeException(e); - } - } - }); - - super.tearDown(); + }); + } + finally { + super.tearDown(); + } } @NotNull diff --git a/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/HeavyIdeaTestFixtureImpl.java b/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/HeavyIdeaTestFixtureImpl.java index b728b74b0383..cfd56708a0d3 100644 --- a/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/HeavyIdeaTestFixtureImpl.java +++ b/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/HeavyIdeaTestFixtureImpl.java @@ -36,7 +36,6 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ex.ProjectManagerEx; import com.intellij.openapi.roots.ProjectRootManager; import com.intellij.openapi.util.Computable; -import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.LocalFileSystem; @@ -45,14 +44,13 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.encoding.EncodingManager; import com.intellij.psi.*; import com.intellij.psi.impl.source.tree.injected.InjectedLanguageManagerImpl; -import com.intellij.testFramework.EditorListenerTracker; -import com.intellij.testFramework.LightPlatformTestCase; -import com.intellij.testFramework.PlatformTestCase; -import com.intellij.testFramework.ThreadTracker; +import com.intellij.testFramework.*; import com.intellij.testFramework.builders.ModuleFixtureBuilder; import com.intellij.testFramework.fixtures.HeavyIdeaTestFixture; import com.intellij.util.PathUtil; -import com.intellij.util.ui.UIUtil; +import com.intellij.util.SmartList; +import com.intellij.util.ThrowableRunnable; +import com.intellij.util.lang.CompoundRuntimeException; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -64,16 +62,15 @@ import java.io.IOException; import java.io.PrintStream; import java.util.HashSet; import java.util.LinkedHashSet; +import java.util.List; import java.util.Set; /** * Creates new project for each test. * @author mike */ +@SuppressWarnings("TestOnlyProblems") class HeavyIdeaTestFixtureImpl extends BaseFixture implements HeavyIdeaTestFixture { - - @NonNls private static final String PROJECT_FILE_SUFFIX = ProjectFileType.DOT_DEFAULT_EXTENSION; - private Project myProject; private final Set myFilesToDelete = new HashSet(); private IdeaTestApplication myApplication; @@ -105,73 +102,79 @@ class HeavyIdeaTestFixtureImpl extends BaseFixture implements HeavyIdeaTestFixtu @Override public void tearDown() throws Exception { - Project project = getProject(); - LightPlatformTestCase.doTearDown(project, myApplication, false); + final Project project = getProject(); + final List exceptions = new SmartList(); + try { + LightPlatformTestCase.doTearDown(project, myApplication, false, exceptions); - for (ModuleFixtureBuilder moduleFixtureBuilder : myModuleFixtureBuilders) { - moduleFixtureBuilder.getFixture().tearDown(); - } - - UIUtil.invokeAndWaitIfNeeded(new Runnable() { - @Override - public void run() { - ApplicationManager.getApplication().runWriteAction(new Runnable() { - @Override - public void run() { - Disposer.dispose(myProject); - myProject = null; - } - }); + for (ModuleFixtureBuilder moduleFixtureBuilder : myModuleFixtureBuilders) { + moduleFixtureBuilder.getFixture().tearDown(); } - }); - for (final File fileToDelete : myFilesToDelete) { - boolean deleted = FileUtil.delete(fileToDelete); - Assert.assertTrue("Can't delete " + fileToDelete, deleted); + EdtTestUtil.runInEdtAndWait(new ThrowableRunnable() { + @Override + public void run() throws Throwable { + PlatformTestCase.closeAndDisposeProjectAndCheckThatNoOpenProjects(project, exceptions); + } + }); + myProject = null; + + for (File fileToDelete : myFilesToDelete) { + if (!FileUtil.delete(fileToDelete)) { + exceptions.add(new IOException("Can't delete " + fileToDelete)); + } + } + } + catch (Throwable e) { + exceptions.add(e); } - super.tearDown(); + try { + super.tearDown(); + } + catch (Throwable e) { + exceptions.add(e); + } - myEditorListenerTracker.checkListenersLeak(); - myThreadTracker.checkLeak(); - LightPlatformTestCase.checkEditorsReleased(); - PlatformTestCase.cleanupApplicationCaches(project); - InjectedLanguageManagerImpl.checkInjectorsAreDisposed(project); + try { + myEditorListenerTracker.checkListenersLeak(); + myThreadTracker.checkLeak(); + LightPlatformTestCase.checkEditorsReleased(exceptions); + PlatformTestCase.cleanupApplicationCaches(project); + InjectedLanguageManagerImpl.checkInjectorsAreDisposed(project); + } + finally { + CompoundRuntimeException.throwIfNotEmpty(exceptions); + } } + private void setUpProject() throws IOException { + File tempDirectory = FileUtil.createTempDirectory(myName, ""); + PlatformTestCase.synchronizeTempDirVfs(LocalFileSystem.getInstance().refreshAndFindFileByIoFile(tempDirectory)); + myFilesToDelete.add(tempDirectory); - private void setUpProject() throws Exception { - UIUtil.invokeAndWaitIfNeeded(new Runnable() { + String projectPath = FileUtil.toSystemIndependentName(tempDirectory.getPath()) + "/" + myName + ProjectFileType.DOT_DEFAULT_EXTENSION; + ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + new Throwable(projectPath).printStackTrace(new PrintStream(buffer)); + myProject = PlatformTestCase.createProject(projectPath, buffer.toString()); + + EdtTestUtil.runInEdtAndWait(new ThrowableRunnable() { + @SuppressWarnings("TestOnlyProblems") @Override - public void run() { - try { - File tempDirectory = FileUtil.createTempDirectory(myName, ""); - PlatformTestCase.synchronizeTempDirVfs(LocalFileSystem.getInstance().refreshAndFindFileByIoFile(tempDirectory)); - myFilesToDelete.add(tempDirectory); + public void run() throws Throwable { + ProjectManagerEx.getInstanceEx().openTestProject(myProject); - File projectFile = new File(tempDirectory, myName + PROJECT_FILE_SUFFIX); - - LocalFileSystem.getInstance().refreshAndFindFileByIoFile(projectFile); - ByteArrayOutputStream buffer = new ByteArrayOutputStream(); - new Throwable(projectFile.getPath()).printStackTrace(new PrintStream(buffer)); - myProject = PlatformTestCase.createProject(projectFile, buffer.toString()); - ProjectManagerEx.getInstanceEx().openTestProject(myProject); - - for (ModuleFixtureBuilder moduleFixtureBuilder: myModuleFixtureBuilders) { - moduleFixtureBuilder.getFixture().setUp(); - } - - LightPlatformTestCase.clearUncommittedDocuments(myProject); - ((FileTypeManagerImpl)FileTypeManager.getInstance()).drainReDetectQueue(); - } - catch (Exception e) { - throw new RuntimeException(e); + for (ModuleFixtureBuilder moduleFixtureBuilder : myModuleFixtureBuilders) { + moduleFixtureBuilder.getFixture().setUp(); } + + LightPlatformTestCase.clearUncommittedDocuments(myProject); + ((FileTypeManagerImpl)FileTypeManager.getInstance()).drainReDetectQueue(); } }); } - private void initApplication() throws Exception { + private void initApplication() { myApplication = IdeaTestApplication.getInstance(); myApplication.setDataProvider(new MyDataProvider()); } diff --git a/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/LightIdeaTestFixtureImpl.java b/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/LightIdeaTestFixtureImpl.java index 97c9c590d488..99ff8d2cb5b8 100644 --- a/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/LightIdeaTestFixtureImpl.java +++ b/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/LightIdeaTestFixtureImpl.java @@ -28,6 +28,7 @@ import com.intellij.psi.codeStyle.CodeStyleSettingsManager; import com.intellij.psi.impl.source.tree.injected.InjectedLanguageManagerImpl; import com.intellij.testFramework.*; import com.intellij.testFramework.fixtures.LightIdeaTestFixture; +import com.intellij.util.SmartList; import com.intellij.util.lang.CompoundRuntimeException; import java.util.List; @@ -64,15 +65,19 @@ public class LightIdeaTestFixtureImpl extends BaseFixture implements LightIdeaTe CodeStyleSettingsManager.getInstance(project).dropTemporarySettings(); CodeStyleSettings oldCodeStyleSettings = myOldCodeStyleSettings; myOldCodeStyleSettings = null; - @SuppressWarnings("ThrowableResultOfMethodCallIgnored") - List errors = UsefulTestCase.doCheckForSettingsDamage(oldCodeStyleSettings, getCurrentCodeStyleSettings()); + List exceptions = new SmartList(); + try { + UsefulTestCase.doCheckForSettingsDamage(oldCodeStyleSettings, getCurrentCodeStyleSettings(), exceptions); - LightPlatformTestCase.doTearDown(project, LightPlatformTestCase.getApplication(), true); - super.tearDown(); - InjectedLanguageManagerImpl.checkInjectorsAreDisposed(project); - PersistentFS.getInstance().clearIdCache(); - PlatformTestCase.cleanupApplicationCaches(project); - CompoundRuntimeException.doThrow(errors); + LightPlatformTestCase.doTearDown(project, LightPlatformTestCase.getApplication(), true, exceptions); + super.tearDown(); + InjectedLanguageManagerImpl.checkInjectorsAreDisposed(project); + PersistentFS.getInstance().clearIdCache(); + PlatformTestCase.cleanupApplicationCaches(project); + } + finally { + CompoundRuntimeException.throwIfNotEmpty(exceptions); + } } @Override diff --git a/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/ModuleFixtureImpl.java b/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/ModuleFixtureImpl.java index 2bba6b208517..4b1e15ac780d 100644 --- a/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/ModuleFixtureImpl.java +++ b/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/ModuleFixtureImpl.java @@ -13,35 +13,28 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.intellij.testFramework.fixtures.impl; -import com.intellij.openapi.command.WriteCommandAction; import com.intellij.openapi.module.Module; import com.intellij.testFramework.fixtures.ModuleFixture; +import org.jetbrains.annotations.NotNull; /** * @author mike */ public class ModuleFixtureImpl extends BaseFixture implements ModuleFixture { - private Module myModule; protected final ModuleFixtureBuilderImpl myBuilder; - public ModuleFixtureImpl(final ModuleFixtureBuilderImpl builder) { + public ModuleFixtureImpl(@NotNull ModuleFixtureBuilderImpl builder) { myBuilder = builder; } @Override public Module getModule() { - if (myModule != null) return myModule; - new WriteCommandAction.Simple(null) { - @Override - protected void run() throws Throwable { - myModule = myBuilder.buildModule(); - } - }.execute().throwException(); - + if (myModule == null) { + myModule = myBuilder.buildModule(); + } return myModule; } diff --git a/platform/testFramework/testSrc/com/intellij/testFramework/FixtureRule.kt b/platform/testFramework/testSrc/com/intellij/testFramework/FixtureRule.kt index e8852af9b643..bb8ddc710b74 100644 --- a/platform/testFramework/testSrc/com/intellij/testFramework/FixtureRule.kt +++ b/platform/testFramework/testSrc/com/intellij/testFramework/FixtureRule.kt @@ -19,15 +19,17 @@ import com.intellij.ide.highlighter.ProjectFileType import com.intellij.idea.IdeaTestApplication import com.intellij.openapi.Disposable import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.components.impl.stores.IProjectStore +import com.intellij.openapi.components.stateStore import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.module.Module import com.intellij.openapi.module.ModuleManager +import com.intellij.openapi.project.Project import com.intellij.openapi.project.ProjectManager import com.intellij.openapi.project.ex.ProjectEx import com.intellij.openapi.project.ex.ProjectManagerEx import com.intellij.openapi.project.impl.ProjectManagerImpl import com.intellij.openapi.util.Disposer -import com.intellij.openapi.util.io.FileUtil import com.intellij.openapi.vfs.VirtualFile import com.intellij.openapi.vfs.impl.VirtualFilePointerManagerImpl import com.intellij.openapi.vfs.newvfs.persistent.PersistentFS @@ -45,6 +47,7 @@ import java.lang.annotation.ElementType import java.lang.annotation.Retention import java.lang.annotation.RetentionPolicy import java.lang.annotation.Target +import java.nio.file.Files import java.util.concurrent.atomic.AtomicBoolean /** @@ -53,7 +56,7 @@ import java.util.concurrent.atomic.AtomicBoolean public class ProjectRule() : ExternalResource() { companion object { init { - Logger.setFactory(javaClass()) + Logger.setFactory(TestLoggerFactory::class.java) } private var sharedProject: ProjectEx? = null @@ -63,18 +66,19 @@ public class ProjectRule() : ExternalResource() { private fun createLightProject(): ProjectEx { (PersistentFS.getInstance() as PersistentFSImpl).cleanPersistedContents() - val projectFile = generateTemporaryPath("light_temp_shared_project${ProjectFileType.DOT_DEFAULT_EXTENSION}").toFile() + val projectFile = generateTemporaryPath("light_temp_shared_project${ProjectFileType.DOT_DEFAULT_EXTENSION}") + val projectPath = projectFile.systemIndependentPath val buffer = ByteArrayOutputStream() - java.lang.Throwable(projectFile.path).printStackTrace(PrintStream(buffer)) + java.lang.Throwable(projectPath).printStackTrace(PrintStream(buffer)) - val project = PlatformTestCase.createProject(projectFile, "Light project: $buffer") as ProjectEx + val project = PlatformTestCase.createProject(projectPath, "Light project: $buffer") as ProjectEx Disposer.register(ApplicationManager.getApplication(), Disposable { try { disposeProject() } finally { - FileUtil.delete(projectFile) + Files.deleteIfExists(projectFile) } }) @@ -164,7 +168,7 @@ public class RuleChain(vararg val rules: TestRule) : TestRule { } } - CompoundRuntimeException.doThrow(errors) + CompoundRuntimeException.throwIfNotEmpty(errors) return statement } } @@ -177,7 +181,7 @@ annotation public class RunsInEdt public class EdtRule : TestRule { override fun apply(base: Statement, description: Description): Statement { - return if (description.getOwnOrClassAnnotation(javaClass()) == null) { + return if (description.getOwnOrClassAnnotation(RunsInEdt::class.java) == null) { base } else { @@ -192,7 +196,7 @@ public class EdtRule : TestRule { /** * Do not optimise test load speed. - * @see ProjectEx.setOptimiseTestLoadSpeed + * @see IProjectStore.setOptimiseTestLoadSpeed */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD, ElementType.TYPE) @@ -200,31 +204,39 @@ annotation public class RunsInActiveStoreMode public class ActiveStoreRule(private val projectRule: ProjectRule) : TestRule { override fun apply(base: Statement, description: Description): Statement { - return if (description.getOwnOrClassAnnotation(javaClass()) == null) { + return if (description.getOwnOrClassAnnotation(RunsInActiveStoreMode::class.java) == null) { base } else { object : Statement() { override fun evaluate() { - val project = projectRule.project - val isModeDisabled = project.isOptimiseTestLoadSpeed() - if (isModeDisabled) { - project.setOptimiseTestLoadSpeed(false) - } - try { - base.evaluate() - } - finally { - if (isModeDisabled) { - project.setOptimiseTestLoadSpeed(true) - } - } + projectRule.project.runInLoadComponentStateMode { base.evaluate() } } } } } } +/** + * In test mode component state is not loaded. Project or module store will load component state if project/module file exists. + * So must be a strong reason to explicitly use this method. + */ +public inline fun Project.runInLoadComponentStateMode(task: () -> T): T { + val store = stateStore as IProjectStore + val isModeDisabled = store.isOptimiseTestLoadSpeed() + if (isModeDisabled) { + store.setOptimiseTestLoadSpeed(false) + } + try { + return task() + } + finally { + if (isModeDisabled) { + store.setOptimiseTestLoadSpeed(true) + } + } +} + public class DisposeModulesRule(private val projectRule: ProjectRule) : ExternalResource() { override fun after() { projectRule.projectIfOpened?.let { @@ -247,7 +259,7 @@ public class DisposeModulesRule(private val projectRule: ProjectRule) : External } } } - CompoundRuntimeException.doThrow(errors) + CompoundRuntimeException.throwIfNotEmpty(errors) } } } \ No newline at end of file diff --git a/platform/testRunner/src/com/intellij/execution/testframework/autotest/AutoTestManager.java b/platform/testRunner/src/com/intellij/execution/testframework/autotest/AutoTestManager.java index bcd0388cb4bd..e21f36f4d913 100644 --- a/platform/testRunner/src/com/intellij/execution/testframework/autotest/AutoTestManager.java +++ b/platform/testRunner/src/com/intellij/execution/testframework/autotest/AutoTestManager.java @@ -26,6 +26,7 @@ import com.intellij.execution.runners.ExecutionUtil; import com.intellij.execution.ui.RunContentDescriptor; import com.intellij.execution.ui.RunContentManager; import com.intellij.ide.DataManager; +import com.intellij.ide.scratch.ScratchFileService; import com.intellij.ide.util.PropertiesComponent; import com.intellij.openapi.actionSystem.LangDataKeys; import com.intellij.openapi.application.ApplicationManager; @@ -79,6 +80,9 @@ public class AutoTestManager { }, new Condition() { @Override public boolean value(VirtualFile file) { + if (ScratchFileService.getInstance().getRootType(file) != null) { + return false; + } // Vladimir.Krivosheev - I don't know, why AutoTestManager checks it, but old behavior is preserved return FileEditorManager.getInstance(myProject).isFileOpen(file); } diff --git a/platform/util-rt/src/com/intellij/openapi/util/io/FileUtilRt.java b/platform/util-rt/src/com/intellij/openapi/util/io/FileUtilRt.java index 8a48ba176218..fe7fdf648c90 100644 --- a/platform/util-rt/src/com/intellij/openapi/util/io/FileUtilRt.java +++ b/platform/util-rt/src/com/intellij/openapi/util/io/FileUtilRt.java @@ -385,12 +385,14 @@ public class FileUtilRt { if (suffix == null) { suffix = ".tmp"; } + // normalize and use only the file name from the prefix + prefix = new File(prefix).getName(); int exceptionsCount = 0; + int i = 0; while (true) { try { - // If there was an IOException, there's no reason to do sequential search - fallback to random - final File temp = createTemp(prefix, suffix, dir, isDirectory, exceptionsCount > 0); + final File temp = callCreate(dir, prefix, suffix, isDirectory, i); return normalizeFile(temp); } catch (IOException e) { // Win32 createFileExclusively access denied @@ -398,41 +400,28 @@ public class FileUtilRt { throw e; } } + i++; // for some reason the file1 can't be created (previous file1 was deleted but got locked by anti-virus?). try file2. + if (i > 2) { + i = 2 + (int)(System.nanoTime() % 998); // generate random suffix if too many failures + } } } @NotNull - private static File createTemp(@NotNull String prefix, + private static File callCreate(@NotNull File directory, + @NotNull String prefix, @NotNull String suffix, - @NotNull File directory, boolean isDirectory, - boolean randomName) throws IOException { - // Fallback to the original File.createTempFile - if (randomName) { - @SuppressWarnings("SSBasedInspection") - File res = File.createTempFile(prefix, suffix, directory); - if (isDirectory) { - if (!res.delete() || !res.mkdir()) { - throw new IOException("Cannot create directory: " + res); - } - } - return res; + int i) throws IOException { + prefix += i == 0 ? "" : i; + if (prefix.endsWith(".") && suffix.startsWith(".")) { + prefix = prefix.substring(0, prefix.length() - 1); } - - // normalize and use only the file name from the prefix - prefix = new File(prefix).getName(); - - File f; - int i = 0; - do { - String name = prefix + i + suffix; - f = new File(directory, name); - if (!name.equals(f.getName())) { - throw new IOException("Unable to create temporary file " + f + " for name " + name); - } - i++; + String name = prefix + suffix; + File f = new File(directory, name); + if (!name.equals(f.getName())) { + throw new IOException("Unable to create temporary file " + f + " for name " + name); } - while (f.exists()); boolean success = isDirectory ? f.mkdir() : f.createNewFile(); if (!success) { diff --git a/platform/util/src/com/intellij/util/EnvironmentUtil.java b/platform/util/src/com/intellij/util/EnvironmentUtil.java index 7cb0a5216335..09de8487165b 100644 --- a/platform/util/src/com/intellij/util/EnvironmentUtil.java +++ b/platform/util/src/com/intellij/util/EnvironmentUtil.java @@ -24,6 +24,7 @@ import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.vfs.CharsetToolkit; import com.intellij.util.concurrency.FixedFuture; import com.intellij.util.text.CaseInsensitiveStringHashingStrategy; import gnu.trove.THashMap; @@ -32,6 +33,7 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.TestOnly; import java.io.File; +import java.nio.charset.Charset; import java.util.*; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; @@ -43,6 +45,10 @@ public class EnvironmentUtil { private static final int SHELL_ENV_READING_TIMEOUT = 20000; + private static final String LANG = "LANG"; + private static final String LC_ALL = "LC_ALL"; + private static final String LC_CTYPE = "LC_CTYPE"; + private static final Future> ourEnvGetter; static { if (SystemInfo.isMac && "unlocked".equals(System.getProperty("__idea.mac.env.lock")) && Registry.is("idea.fix.mac.env")) { @@ -50,7 +56,7 @@ public class EnvironmentUtil { ourEnvGetter = executor.submit(new Callable>() { @Override public Map call() throws Exception { - return getShellEnv(); + return Collections.unmodifiableMap(setCharsetVar(getShellEnv())); } }); executor.shutdown(); @@ -97,9 +103,13 @@ public class EnvironmentUtil { * On Mac OS X things are complicated.
* An app launched by a GUI launcher (Finder, Dock, Spotlight etc.) receives a pretty empty and useless environment, * since standard Unix ways of setting variables via e.g. ~/.profile do not work. What's more important, there are no - * sane alternatives. This causes a lot of user complains about tools working in a terminal not working when launched + * sane alternatives. This causes a lot of user complaints about tools working in a terminal not working when launched * from the IDE. To ease their pain, the IDE loads a shell environment (see {@link #getShellEnv()} for gory details) - * and returns it as the result. + * and returns it as the result.
+ * And one more thing (c): locale variables on OS X are usually set by a terminal app - meaning they are missing + * even from a shell environment above. This again causes user complaints about tools being unable to output anything + * outside ASCII range when launched from the IDE. Resolved by adding LC_CTYPE variable to the map if it doesn't contain + * explicitly set locale variables (LANG/LC_ALL/LC_CTYPE). See {@link #setCharsetVar(Map)} for details. * * @return unmodifiable map of the process environment. */ @@ -193,7 +203,7 @@ public class EnvironmentUtil { } LOG.info("shell environment loaded (" + newEnv.size() + " vars)"); - return Collections.unmodifiableMap(newEnv); + return newEnv; } private static int waitAndTerminateAfter(@NotNull Process process, int timeoutMillis) { @@ -230,6 +240,22 @@ public class EnvironmentUtil { return null; } + private static Map setCharsetVar(@NotNull Map env) { + if (!isCharsetVarDefined(env)) { + Locale locale = Locale.getDefault(); + Charset charset = CharsetToolkit.getDefaultSystemCharset(); + String language = locale.getLanguage(); + String country = locale.getCountry(); + String value = (language.isEmpty() || country.isEmpty() ? "en_US" : language + '_' + country) + '.' + charset.name(); + env.put(LC_CTYPE, value); + } + return env; + } + + private static boolean isCharsetVarDefined(@NotNull Map env) { + return !env.isEmpty() && (env.containsKey(LANG) || env.containsKey(LC_ALL) || env.containsKey(LC_CTYPE)); + } + public static void inlineParentOccurrences(@NotNull Map envs) { Map parentParams = new HashMap(System.getenv()); for (Map.Entry entry : envs.entrySet()) { diff --git a/platform/util/src/com/intellij/util/Restarter.java b/platform/util/src/com/intellij/util/Restarter.java index ab4a5ce7bfec..c0e3968df4b2 100644 --- a/platform/util/src/com/intellij/util/Restarter.java +++ b/platform/util/src/com/intellij/util/Restarter.java @@ -18,7 +18,6 @@ package com.intellij.util; import com.intellij.openapi.application.PathManager; import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.io.FileUtilRt; -import com.intellij.openapi.util.io.StreamUtil; import com.intellij.openapi.util.text.StringUtil; import com.sun.jna.Native; import com.sun.jna.Pointer; @@ -27,12 +26,10 @@ import com.sun.jna.ptr.IntByReference; import com.sun.jna.win32.StdCallLibrary; import org.jetbrains.annotations.NotNull; +import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; -import java.io.BufferedWriter; import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -89,16 +86,26 @@ public class Restarter { if (beforeRestart.length == 0) return; File restartDir = new File(System.getProperty("user.home") + "/." + System.getProperty("idea.paths.selector") + "/restart"); - if (! FileUtilRt.createDirectory(restartDir)) throw new IOException("Cannot create dir: " + restartDir); - File restarter = new File(restartDir.getPath() + "/restarter.sh"); + if (!FileUtilRt.createDirectory(restartDir)) { + throw new IOException("Cannot create dir: " + restartDir); + } + + File restarter = new File(restartDir, "restarter.sh"); BufferedWriter output = new BufferedWriter(new FileWriter(restarter)); - output.write("#!/bin/sh\n"); - for (String command : beforeRestart ){ - output.write(command); - output.write(" "); + try { + output.write("#!/bin/sh\n"); + for (int i = 0; i < beforeRestart.length; i++) { + output.write(beforeRestart[i]); + output.write(i == beforeRestart.length - 1 ? '\n' : ' '); + } + } + finally { + output.close(); + } + + if (!restarter.setExecutable(true, true)) { + throw new IOException("Cannot make file executable: " + restarter); } - output.close(); - if (! restarter.setExecutable(true, true)) throw new IOException("Cannot make file executable: " + restarter); } private static void restartOnWindows(@NotNull final String... beforeRestart) throws IOException { @@ -175,22 +182,4 @@ public class Restarter { private interface Shell32 extends StdCallLibrary { Pointer CommandLineToArgvW(WString command_line, IntByReference argc); } - - private static class StreamRedirector implements Runnable { - private final InputStream myIn; - private final OutputStream myOut; - - private StreamRedirector(InputStream in, OutputStream out) { - myIn = in; - myOut = out; - } - - @Override - public void run() { - try { - StreamUtil.copyStreamContent(myIn, myOut); - } - catch (IOException ignore) { } - } - } } \ No newline at end of file diff --git a/platform/util/src/com/intellij/util/lang/CompoundRuntimeException.java b/platform/util/src/com/intellij/util/lang/CompoundRuntimeException.java index 28ccf8d25eea..c7ee6325fa41 100644 --- a/platform/util/src/com/intellij/util/lang/CompoundRuntimeException.java +++ b/platform/util/src/com/intellij/util/lang/CompoundRuntimeException.java @@ -15,6 +15,9 @@ */ package com.intellij.util.lang; +import com.intellij.util.Consumer; +import com.intellij.util.EmptyConsumer; +import com.intellij.util.Function; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -27,31 +30,111 @@ import java.util.List; * @author mike */ public class CompoundRuntimeException extends RuntimeException { - private final List myThrowables; + private final List myExceptions; public CompoundRuntimeException(@NotNull List throwables) { - //noinspection HardCodedStringLiteral - super("Several Exceptions occurred", throwables.get(0)); - - myThrowables = throwables; + myExceptions = throwables; } @Override - public void printStackTrace(PrintStream s) { - for (Throwable throwable : myThrowables) { - throwable.printStackTrace(s); - } + public String getMessage() { + return processAll(new Function() { + @Override + public String fun(Throwable throwable) { + return throwable.getMessage(); + } + }, EmptyConsumer.getInstance()); } - @Override - public void printStackTrace(PrintWriter s) { - for (Throwable throwable : myThrowables) { - throwable.printStackTrace(s); - } + public String getLocalizedMessage() { + return processAll(new Function() { + @Override + public String fun(Throwable throwable) { + return throwable.getLocalizedMessage(); + } + }, EmptyConsumer.getInstance()); } - public static void doThrow(@Nullable List throwables) { + @Override + public String toString() { + return processAll(new Function() { + @Override + public String fun(Throwable throwable) { + return throwable.toString(); + } + }, EmptyConsumer.getInstance()); + } + + @Override + public void printStackTrace(final PrintStream s) { + processAll(new Function() { + @Override + public String fun(Throwable throwable) { + throwable.printStackTrace(s); + return ""; + } + }, new Consumer() { + @Override + public void consume(String str) { + s.print(str); + } + }); + } + + @Override + public void printStackTrace(final PrintWriter s) { + processAll(new Function() { + @Override + public String fun(Throwable throwable) { + throwable.printStackTrace(s); + return ""; + } + }, new Consumer() { + @Override + public void consume(String str) { + s.print(str); + } + }); + } + + private String processAll(@NotNull Function exceptionProcessor, @NotNull Consumer stringProcessor) { + if (myExceptions.size() == 1) { + Throwable throwable = myExceptions.get(0); + String s = exceptionProcessor.fun(throwable); + stringProcessor.consume(s); + return s; + } + + StringBuilder sb = new StringBuilder(); + String line = "CompositeException (" + myExceptions.size() + " nested):\n------------------------------\n"; + stringProcessor.consume(line); + sb.append(line); + + for (int i = 0; i < myExceptions.size(); i++) { + Throwable exception = myExceptions.get(i); + + line = "[" + i + "]: "; + stringProcessor.consume(line); + sb.append(line); + + line = exceptionProcessor.fun(exception); + if (line == null) { + line = "null\n"; + } + else if (!line.endsWith("\n")) line += '\n'; + stringProcessor.consume(line); + sb.append(line); + } + + line = "------------------------------\n"; + stringProcessor.consume(line); + sb.append(line); + + return sb.toString(); + } + + public static void throwIfNotEmpty(@Nullable List throwables) { if (ContainerUtil.isEmpty(throwables)) { return; } diff --git a/platform/util/src/com/intellij/util/ui/ThreeStateCheckBox.java b/platform/util/src/com/intellij/util/ui/ThreeStateCheckBox.java index 123021663a4e..0d9e6b58bf2e 100644 --- a/platform/util/src/com/intellij/util/ui/ThreeStateCheckBox.java +++ b/platform/util/src/com/intellij/util/ui/ThreeStateCheckBox.java @@ -15,6 +15,8 @@ */ package com.intellij.util.ui; +import com.intellij.openapi.util.SystemInfo; + import javax.swing.*; import java.awt.*; import java.awt.event.ItemEvent; @@ -116,7 +118,7 @@ public class ThreeStateCheckBox extends JCheckBox { @Override protected void paintComponent(Graphics g) { super.paintComponent(g); - if (UIUtil.isUnderAquaLookAndFeel()) { + if (UIUtil.isUnderAquaLookAndFeel() || (SystemInfo.isMac && UIUtil.isUnderIntelliJLaF())) { return; } diff --git a/platform/util/testSrc/com/intellij/util/Assertion.java b/platform/util/testSrc/com/intellij/util/Assertion.java index c1ea62275d73..92769218229c 100644 --- a/platform/util/testSrc/com/intellij/util/Assertion.java +++ b/platform/util/testSrc/com/intellij/util/Assertion.java @@ -18,8 +18,8 @@ package com.intellij.util; import com.intellij.openapi.util.Comparing; import gnu.trove.Equality; -import junit.framework.Assert; import junit.framework.AssertionFailedError; +import org.junit.Assert; import java.io.BufferedReader; import java.io.IOException; diff --git a/platform/util/testSrc/com/intellij/util/containers/FilteringIteratorTest.java b/platform/util/testSrc/com/intellij/util/containers/FilteringIteratorTest.java index 792274d493ee..3e77ceb7ac08 100644 --- a/platform/util/testSrc/com/intellij/util/containers/FilteringIteratorTest.java +++ b/platform/util/testSrc/com/intellij/util/containers/FilteringIteratorTest.java @@ -18,7 +18,6 @@ package com.intellij.util.containers; import com.intellij.openapi.util.Condition; import com.intellij.util.Assertion; -import junit.framework.Assert; import junit.framework.TestCase; import java.util.ArrayList; @@ -65,28 +64,28 @@ public class FilteringIteratorTest extends TestCase { MockIterator mockIterator = new MockIterator(list.iterator()); MockCondition mockCondition = new MockCondition(STRINGS_ONLY); Iterator iterator = FilteringIterator.create(mockIterator, mockCondition); - Assert.assertTrue(iterator.hasNext()); - Assert.assertTrue(iterator.hasNext()); - Assert.assertEquals(2, mockIterator.myHasNextCalls); - Assert.assertEquals(2, mockCondition.myValueCalls); - Assert.assertEquals("a", iterator.next()); - Assert.assertEquals(2, mockIterator.myHasNextCalls); - Assert.assertEquals(2, mockCondition.myValueCalls); + assertTrue(iterator.hasNext()); + assertTrue(iterator.hasNext()); + assertEquals(2, mockIterator.myHasNextCalls); + assertEquals(2, mockCondition.myValueCalls); + assertEquals("a", iterator.next()); + assertEquals(2, mockIterator.myHasNextCalls); + assertEquals(2, mockCondition.myValueCalls); iterator.remove(); - Assert.assertEquals(2, mockIterator.myHasNextCalls); - Assert.assertEquals(2, mockCondition.myValueCalls); - Assert.assertTrue(iterator.hasNext()); - Assert.assertTrue(iterator.hasNext()); - Assert.assertEquals(4, mockIterator.myHasNextCalls); - Assert.assertEquals(4, mockCondition.myValueCalls); - Assert.assertEquals("b", iterator.next()); - Assert.assertEquals(4, mockIterator.myHasNextCalls); - Assert.assertEquals(4, mockCondition.myValueCalls); + assertEquals(2, mockIterator.myHasNextCalls); + assertEquals(2, mockCondition.myValueCalls); + assertTrue(iterator.hasNext()); + assertTrue(iterator.hasNext()); + assertEquals(4, mockIterator.myHasNextCalls); + assertEquals(4, mockCondition.myValueCalls); + assertEquals("b", iterator.next()); + assertEquals(4, mockIterator.myHasNextCalls); + assertEquals(4, mockCondition.myValueCalls); - Assert.assertEquals(3, list.size()); + assertEquals(3, list.size()); } - private void checkRemove(Object[] expected, ArrayList collection) { + private static void checkRemove(Object[] expected, ArrayList collection) { Iterator iterator = FilteringIterator.create(collection.iterator(), STRINGS_ONLY); while (iterator.hasNext()) { if (iterator.next().equals("x")) iterator.remove(); diff --git a/platform/util/testSrc/com/intellij/util/xmlb/XmlSerializerTest.kt b/platform/util/testSrc/com/intellij/util/xmlb/XmlSerializerTest.kt index 20d4c9574ebd..d199f7778e95 100644 --- a/platform/util/testSrc/com/intellij/util/xmlb/XmlSerializerTest.kt +++ b/platform/util/testSrc/com/intellij/util/xmlb/XmlSerializerTest.kt @@ -22,19 +22,15 @@ import com.intellij.openapi.util.io.BufferExposingByteArrayOutputStream import com.intellij.openapi.util.text.StringUtil import com.intellij.util.SmartList import com.intellij.util.xmlb.annotations.* +import com.intellij.util.xmlb.annotations.AbstractCollection import gnu.trove.THashMap import junit.framework.AssertionFailedError import junit.framework.TestCase import org.assertj.core.api.Assertions.assertThat import org.intellij.lang.annotations.Language import org.jdom.Element -import org.jdom.JDOMException import org.junit.Test -import java.io.IOException -import java.util.ArrayList -import java.util.Arrays -import java.util.LinkedHashMap -import java.util.LinkedHashSet +import java.util.* import java.util.concurrent.atomic.AtomicReference public class XmlSerializerTest { @@ -198,8 +194,8 @@ public class XmlSerializerTest { public class BeanWithMapWithAnnotations { - Property(surroundWithTag = false) - MapAnnotation(surroundWithTag = false, entryTagName = "option", keyAttributeName = "name", valueAttributeName = "value") + @Property(surroundWithTag = false) + @MapAnnotation(surroundWithTag = false, entryTagName = "option", keyAttributeName = "name", valueAttributeName = "value") public var VALUES: MutableMap = LinkedHashMap() init { @@ -237,7 +233,7 @@ public class XmlSerializerTest { public class BeanWithMapWithBeanValue2 { - MapAnnotation(surroundWithTag = false, surroundKeyWithTag = false, surroundValueWithTag = false) + @MapAnnotation(surroundWithTag = false, surroundKeyWithTag = false, surroundValueWithTag = false) public var values: Map = THashMap() } @@ -284,13 +280,13 @@ public class XmlSerializerTest { } class BeanWithFieldWithTagAnnotation { - Tag("name") + @Tag("name") public var STRING_V: String = "hello" } @Test fun ParallelDeserialization() { val e = Element("root").addContent(Element("name").setText("x")) - XmlSerializer.deserialize(e, javaClass())//to initialize XmlSerializerImpl.ourBindings + XmlSerializer.deserialize(e, BeanWithArray::class.java)//to initialize XmlSerializerImpl.ourBindings val exc = AtomicReference() val threads = Array(5) { Thread(Runnable { @@ -383,7 +379,7 @@ public class XmlSerializerTest { } public class BeanWithArrayWithoutTagName { - AbstractCollection(surroundWithTag = false) + @AbstractCollection(surroundWithTag = false) public var V: Array = arrayOf("a") } @@ -620,7 +616,7 @@ public class XmlSerializerTest { class BeanWithPropertyFilter { - Property(filter = PropertyFilterTest::class) + @Property(filter = PropertyFilterTest::class) public var STRING_V: String = "hello" } @@ -646,7 +642,7 @@ public class XmlSerializerTest { class BeanWithJDOMElement { public var STRING_V: String = "hello" - Tag("actions") + @Tag("actions") public var actions: org.jdom.Element? = null } @@ -660,12 +656,8 @@ public class XmlSerializerTest { assertSerializer(element, "\n" + " ", null) } - throws(Exception::class) @Test fun DeserializeJDOMElementField() { - - - val bean = XmlSerializer.deserialize(JDOMUtil.loadDocument("").getRootElement(), javaClass())!! - + val bean = XmlSerializer.deserialize(JDOMUtil.loadDocument("").getRootElement(), BeanWithJDOMElement::class.java)!! TestCase.assertEquals("bye", bean.STRING_V) TestCase.assertNotNull(bean.actions) @@ -674,13 +666,13 @@ public class XmlSerializerTest { class BeanWithJDOMElementArray { public var STRING_V: String = "hello" - Tag("actions") + @Tag("actions") public var actions: Array? = null } @Test fun JDOMElementArrayField() { val text = "\n" + " " - val bean = XmlSerializer.deserialize(JDOMUtil.loadDocument(text).getRootElement(), javaClass())!! + val bean = XmlSerializer.deserialize(JDOMUtil.loadDocument(text).getRootElement(), BeanWithJDOMElementArray::class.java)!! TestCase.assertEquals("bye", bean.STRING_V) @@ -701,7 +693,7 @@ public class XmlSerializerTest { class BeanWithTextAnnotation { public var INT_V: Int = 1 - Text + @Text public var STRING_V: String = "hello" public constructor(INT_V: Int, STRING_V: String) { @@ -757,7 +749,7 @@ public class XmlSerializerTest { val bb = doSerializerTest("\n" + " \n" + "", bean) for (collection in bb.myMap.keySet()) { - assertThat(collection).isInstanceOf(javaClass>()) + assertThat(collection).isInstanceOf(Set::class.java) } } @@ -875,12 +867,12 @@ public class XmlSerializerTest { } private class BeanWithDefaultAttributeName { - Attribute + @Attribute public fun getFoo(): String { return "foo" } - public fun setFoo(value: String) { + public fun setFoo(@Suppress("UNUSED_PARAMETER") value: String) { } } @@ -890,17 +882,16 @@ public class XmlSerializerTest { } class Bean2 { - Attribute + @Attribute var ab: String? = null - Attribute + @Attribute var module: String? = null - Attribute + @Attribute var ac: String? = null } - throws(IOException::class, JDOMException::class) @Test fun Ordered() { val bean = Bean2() bean.module = "module" @@ -916,11 +907,11 @@ public class XmlSerializerTest { @Tag("b") class Bean3 { - @suppress("DEPRECATED_SYMBOL_WITH_MESSAGE") + @Suppress("DEPRECATED_SYMBOL_WITH_MESSAGE") public var list: JDOMExternalizableStringList = JDOMExternalizableStringList() } - Tag("b") + @Tag("b") class Bean4 { @CollectionBean val list = SmartList() @@ -943,7 +934,7 @@ public class XmlSerializerTest { } @Test fun CollectionBeanReadJDOMExternalizableStringList() { - @suppress("DEPRECATED_SYMBOL_WITH_MESSAGE") + @Suppress("DEPRECATED_SYMBOL_WITH_MESSAGE") val list = JDOMExternalizableStringList() list.add("one") list.add("two") @@ -951,7 +942,7 @@ public class XmlSerializerTest { val value = Element("value") list.writeExternal(value) - val o = XmlSerializer.deserialize(Element("state").addContent(Element("option").setAttribute("name", "myList").addContent(value)), javaClass())!! + val o = XmlSerializer.deserialize(Element("state").addContent(Element("option").setAttribute("name", "myList").addContent(value)), Bean4::class.java)!! assertSerializer(o, "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + "", SkipDefaultsSerializationFilter()) } @@ -972,7 +963,7 @@ public class XmlSerializerTest { @Test fun cdataAfterNewLine() { @Tag("bean") - @data class Bean(@Tag var description: String? = null) + data class Bean(@Tag var description: String? = null) var bean = XmlSerializer.deserialize(JDOMUtil.load(""" @@ -980,10 +971,10 @@ public class XmlSerializerTest {

Node.js integration

]]>
-
""".reader), javaClass())!! +""".reader), Bean::class.java)!! assertThat(bean.description).isEqualToIgnoringWhitespace("

Node.js integration

") - bean = XmlSerializer.deserialize(JDOMUtil.load("""Node.js integration]]>""".reader), javaClass())!! + bean = XmlSerializer.deserialize(JDOMUtil.load("""Node.js integration]]>""".reader), Bean::class.java)!! assertThat(bean.description).isEqualTo("

Node.js integration

") } @@ -998,7 +989,7 @@ public class XmlSerializerTest { TestCase.assertEquals(serialized, JDOMUtil.writeElement(serializedState)) } - private fun doSerializerTest(Language("XML") expectedText: String, bean: T, filter: SerializationFilter? = null): T { + private fun doSerializerTest(@Language("XML") expectedText: String, bean: T, filter: SerializationFilter? = null): T { val element = assertSerializer(bean, expectedText, filter) //test deserializer @@ -1020,11 +1011,11 @@ public class XmlSerializerTest { } } -public fun T.serialize(filter: SerializationFilter? = SkipDefaultValuesSerializationFilters()): Element = XmlSerializer.serialize(this, filter) +fun T.serialize(filter: SerializationFilter? = SkipDefaultValuesSerializationFilters()): Element = XmlSerializer.serialize(this, filter) -public inline fun Element.deserialize(): T = XmlSerializer.deserialize(this, javaClass())!! +inline fun Element.deserialize(): T = XmlSerializer.deserialize(this, T::class.java)!! -public fun Element.toByteArray(): ByteArray { +fun Element.toByteArray(): ByteArray { val out = BufferExposingByteArrayOutputStream(512) JDOMUtil.writeParent(this, out, "\n") return out.toByteArray() diff --git a/platform/vcs-api/src/com/intellij/vcsUtil/UIVcsUtil.java b/platform/vcs-api/src/com/intellij/vcsUtil/UIVcsUtil.java index 6ab106673a8f..bb36b35e7f82 100644 --- a/platform/vcs-api/src/com/intellij/vcsUtil/UIVcsUtil.java +++ b/platform/vcs-api/src/com/intellij/vcsUtil/UIVcsUtil.java @@ -17,18 +17,23 @@ package com.intellij.vcsUtil; import com.intellij.openapi.util.text.StringUtil; import com.intellij.ui.SimpleTextAttributes; +import com.intellij.util.FontUtil; import com.intellij.util.ui.UIUtil; import com.intellij.xml.util.XmlStringUtil; +import org.jetbrains.annotations.NotNull; import javax.swing.*; import java.awt.*; public class UIVcsUtil { - public static final String SPACE_AND_THIN_SPACE = " \u2009"; - private UIVcsUtil() { } + @NotNull + public static String spaceAndThinSpace() { + return " " + FontUtil.canDisplay(UIUtil.getLabelFont(), '\u2009', ""); + } + public static JPanel errorPanel(final String text, boolean isError) { final JLabel label = new JLabel(XmlStringUtil.wrapInHtml(escapeXmlAndAddBr(text))); label.setForeground(isError ? SimpleTextAttributes.ERROR_ATTRIBUTES.getFgColor() : UIUtil.getInactiveTextColor()); diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/ChangeListRemoveConfirmation.kt b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/ChangeListRemoveConfirmation.kt index 8d15b4af8fe4..a3a2ad105945 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/ChangeListRemoveConfirmation.kt +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/ChangeListRemoveConfirmation.kt @@ -21,14 +21,13 @@ import com.intellij.openapi.vcs.changes.ChangeListManager import com.intellij.openapi.vcs.changes.LocalChangeList import com.intellij.util.ThreeState import com.intellij.util.containers.ContainerUtil -import kotlin.platform.platformStatic abstract class ChangeListRemoveConfirmation() { abstract fun askIfShouldRemoveChangeLists(ask: List): Boolean companion object { - platformStatic + JvmStatic fun processLists(project: Project, explicitly: Boolean, allLists: Collection, ask: ChangeListRemoveConfirmation) { val confirmationAsked = ContainerUtil.newIdentityTroveSet() val doNotRemove = ContainerUtil.newIdentityTroveSet() diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/PatchNameChecker.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/PatchNameChecker.java index 935747ecfe84..1ec5dbba450f 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/PatchNameChecker.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/PatchNameChecker.java @@ -19,6 +19,7 @@ import java.io.File; public class PatchNameChecker { public final static int MAX = 100; + private final static int MAX_PATH = 255; // Windows path len restrictions private final String myName; private boolean myPreventsOk; private String myError; @@ -35,8 +36,8 @@ public class PatchNameChecker { myError = "File name cannot be empty"; myPreventsOk = true; return false; - } else if (myName.length() > MAX) { - myError = "File name length cannot exceed " + MAX + " characters"; + } else if (myPath.length() > MAX_PATH) { + myError = "File path should not be too long."; myPreventsOk = true; return false; } else if (new File(myPath).exists()) { diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/shelf/ShelvedChangesViewManager.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/shelf/ShelvedChangesViewManager.java index 155783b97000..59f725885afa 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/shelf/ShelvedChangesViewManager.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/shelf/ShelvedChangesViewManager.java @@ -40,6 +40,7 @@ import com.intellij.openapi.fileTypes.StdFileTypes; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.Couple; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vcs.*; import com.intellij.openapi.vcs.changes.Change; import com.intellij.openapi.vcs.changes.CommitContext; @@ -79,7 +80,7 @@ import java.io.IOException; import java.util.*; import java.util.List; -import static com.intellij.vcsUtil.UIVcsUtil.SPACE_AND_THIN_SPACE; +import static com.intellij.vcsUtil.UIVcsUtil.spaceAndThinSpace; public class ShelvedChangesViewManager implements ProjectComponent { private final ChangesViewContentManager myContentManager; @@ -463,7 +464,7 @@ public class ShelvedChangesViewManager implements ProjectComponent { myIssueLinkRenderer.appendTextWithLinks(changeListData.DESCRIPTION); } int count = node.getChildCount(); - String numFilesText = SPACE_AND_THIN_SPACE + count + ((count == 1) ? " file" : " files") + ","; + String numFilesText = spaceAndThinSpace() + count + " " + StringUtil.pluralize("file", 1) + ","; append(numFilesText, SimpleTextAttributes.GRAYED_ATTRIBUTES); String date = DateFormatUtil.formatPrettyDateTime(changeListData.DATE); @@ -503,7 +504,7 @@ public class ShelvedChangesViewManager implements ProjectComponent { if (movedMessage != null) { append(movedMessage, SimpleTextAttributes.REGULAR_ATTRIBUTES); } - append(SPACE_AND_THIN_SPACE + directory, SimpleTextAttributes.GRAYED_ATTRIBUTES); + append(spaceAndThinSpace() + directory, SimpleTextAttributes.GRAYED_ATTRIBUTES); setIcon(FileTypeManager.getInstance().getFileTypeByFileName(fileName).getIcon()); } } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesBrowserChangeListNode.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesBrowserChangeListNode.java index 9cfe1af4032a..c13227df13a1 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesBrowserChangeListNode.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesBrowserChangeListNode.java @@ -26,7 +26,7 @@ import com.intellij.ui.SimpleTextAttributes; import java.util.ArrayList; import java.util.List; -import static com.intellij.vcsUtil.UIVcsUtil.SPACE_AND_THIN_SPACE; +import static com.intellij.vcsUtil.UIVcsUtil.spaceAndThinSpace; /** * @author yole @@ -55,12 +55,12 @@ public class ChangesBrowserChangeListNode extends ChangesBrowserNode } final String freezed = myClManager.isFreezed(); if (freezed != null) { - renderer.append(SPACE_AND_THIN_SPACE + freezed, SimpleTextAttributes.GRAYED_ATTRIBUTES); + renderer.append(spaceAndThinSpace() + freezed, SimpleTextAttributes.GRAYED_ATTRIBUTES); } else if (myClManager.isInUpdate()) { - renderer.append(SPACE_AND_THIN_SPACE + VcsBundle.message("changes.nodetitle.updating"), SimpleTextAttributes.GRAYED_ATTRIBUTES); + renderer.append(", " + VcsBundle.message("changes.nodetitle.updating"), SimpleTextAttributes.GRAYED_ATTRIBUTES); } if (! myChangeListRemoteState.getState()) { - renderer.append(SPACE_AND_THIN_SPACE); + renderer.append(spaceAndThinSpace()); renderer.append(VcsBundle.message("changes.nodetitle.have.outdated.files"), SimpleTextAttributes.ERROR_ATTRIBUTES); } } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesBrowserChangeNode.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesBrowserChangeNode.java index bea00b0470cd..7a50151ad687 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesBrowserChangeNode.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesBrowserChangeNode.java @@ -32,7 +32,7 @@ import javax.swing.*; import java.awt.*; import java.io.File; -import static com.intellij.vcsUtil.UIVcsUtil.SPACE_AND_THIN_SPACE; +import static com.intellij.vcsUtil.UIVcsUtil.spaceAndThinSpace; /** * @author yole @@ -71,13 +71,13 @@ public class ChangesBrowserChangeNode extends ChangesBrowserNode impleme final String originText = change.getOriginText(myProject); if (originText != null) { - renderer.append(SPACE_AND_THIN_SPACE + originText, SimpleTextAttributes.REGULAR_ATTRIBUTES); + renderer.append(spaceAndThinSpace() + originText, SimpleTextAttributes.REGULAR_ATTRIBUTES); } if (renderer.isShowFlatten()) { final File parentFile = filePath.getIOFile().getParentFile(); if (parentFile != null) { - renderer.append(SPACE_AND_THIN_SPACE + FileUtil.getLocationRelativeToUserHome(parentFile.getPath()), SimpleTextAttributes.GRAYED_ATTRIBUTES); + renderer.append(spaceAndThinSpace() + FileUtil.getLocationRelativeToUserHome(parentFile.getPath()), SimpleTextAttributes.GRAYED_ATTRIBUTES); } appendSwitched(renderer); } @@ -111,7 +111,7 @@ public class ChangesBrowserChangeNode extends ChangesBrowserNode impleme if (virtualFile != null && ! myProject.isDefault()) { String branch = ChangeListManager.getInstance(myProject).getSwitchedBranch(virtualFile); if (branch != null) { - renderer.append(SPACE_AND_THIN_SPACE + "[switched to " + branch + "]", SimpleTextAttributes.REGULAR_ATTRIBUTES); + renderer.append(spaceAndThinSpace() + "[switched to " + branch + "]", SimpleTextAttributes.REGULAR_ATTRIBUTES); } } } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesBrowserFileNode.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesBrowserFileNode.java index eb7ef8cb77e2..f5a584e75c2a 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesBrowserFileNode.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesBrowserFileNode.java @@ -27,7 +27,7 @@ import com.intellij.ui.SimpleTextAttributes; import com.intellij.util.PlatformIcons; import org.jetbrains.annotations.NotNull; -import static com.intellij.vcsUtil.UIVcsUtil.SPACE_AND_THIN_SPACE; +import static com.intellij.vcsUtil.UIVcsUtil.spaceAndThinSpace; /** * @author yole @@ -62,7 +62,7 @@ public class ChangesBrowserFileNode extends ChangesBrowserNode impl if (renderer.isShowFlatten() && file.isValid()) { final VirtualFile parentFile = file.getParent(); assert parentFile != null; - renderer.append(SPACE_AND_THIN_SPACE + FileUtil.getLocationRelativeToUserHome(parentFile.getPresentableUrl()), SimpleTextAttributes.GRAYED_ATTRIBUTES); + renderer.append(spaceAndThinSpace() + FileUtil.getLocationRelativeToUserHome(parentFile.getPresentableUrl()), SimpleTextAttributes.GRAYED_ATTRIBUTES); } else if (getCount() != 1 || getDirectoryCount() != 0) { appendCount(renderer); diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesBrowserFilePathNode.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesBrowserFilePathNode.java index d582f039e134..f53f94f24537 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesBrowserFilePathNode.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesBrowserFilePathNode.java @@ -25,7 +25,7 @@ import com.intellij.util.PlatformIcons; import java.io.File; -import static com.intellij.vcsUtil.UIVcsUtil.SPACE_AND_THIN_SPACE; +import static com.intellij.vcsUtil.UIVcsUtil.spaceAndThinSpace; /** * @author yole @@ -58,7 +58,7 @@ public class ChangesBrowserFilePathNode extends ChangesBrowserNode { if (renderer.isShowFlatten()) { renderer.append(path.getName(), SimpleTextAttributes.REGULAR_ATTRIBUTES); FilePath parentPath = path.getParentPath(); - renderer.append(SPACE_AND_THIN_SPACE + FileUtil.getLocationRelativeToUserHome(parentPath.getPresentableUrl()), SimpleTextAttributes.GRAYED_ATTRIBUTES); + renderer.append(spaceAndThinSpace() + FileUtil.getLocationRelativeToUserHome(parentPath.getPresentableUrl()), SimpleTextAttributes.GRAYED_ATTRIBUTES); } else { renderer.append(getRelativePath(safeCastToFilePath(((ChangesBrowserNode)getParent()).getUserObject()), path), diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesBrowserLocallyDeletedNode.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesBrowserLocallyDeletedNode.java index 5d72c0a8da78..8113558678f0 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesBrowserLocallyDeletedNode.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesBrowserLocallyDeletedNode.java @@ -28,7 +28,7 @@ import javax.swing.*; import java.awt.*; import java.io.File; -import static com.intellij.vcsUtil.UIVcsUtil.SPACE_AND_THIN_SPACE; +import static com.intellij.vcsUtil.UIVcsUtil.spaceAndThinSpace; public class ChangesBrowserLocallyDeletedNode extends ChangesBrowserNode implements TreeLinkMouseListener.HaveTooltip { public ChangesBrowserLocallyDeletedNode(LocallyDeletedChange userObject) { @@ -66,7 +66,7 @@ public class ChangesBrowserLocallyDeletedNode extends ChangesBrowserNode impleme if (renderer.isShowFlatten()) { final File parentFile = filePath.getIOFile().getParentFile(); if (parentFile != null) { - renderer.append(SPACE_AND_THIN_SPACE + parentFile.getPath(), SimpleTextAttributes.GRAYED_ATTRIBUTES); + renderer.append(spaceAndThinSpace() + parentFile.getPath(), SimpleTextAttributes.GRAYED_ATTRIBUTES); } } else if (getCount() != 1 || getDirectoryCount() != 0) { diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesBrowserLockedFoldersNode.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesBrowserLockedFoldersNode.java index d0592e8d377b..9ff2969b0b43 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesBrowserLockedFoldersNode.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesBrowserLockedFoldersNode.java @@ -31,7 +31,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import static com.intellij.vcsUtil.UIVcsUtil.SPACE_AND_THIN_SPACE; +import static com.intellij.vcsUtil.UIVcsUtil.spaceAndThinSpace; public class ChangesBrowserLockedFoldersNode extends ChangesBrowserNode implements TreeLinkMouseListener.HaveTooltip { private final Project myProject; @@ -55,7 +55,7 @@ public class ChangesBrowserLockedFoldersNode extends ChangesBrowserNode implemen public void render(final ChangesBrowserNodeRenderer renderer, final boolean selected, final boolean expanded, final boolean hasFocus) { renderer.append(userObject.toString(), SimpleTextAttributes.REGULAR_ATTRIBUTES); renderer.append(getCountText(), SimpleTextAttributes.GRAY_ITALIC_ATTRIBUTES); - renderer.append(SPACE_AND_THIN_SPACE, SimpleTextAttributes.REGULAR_ATTRIBUTES); + renderer.append(spaceAndThinSpace(), SimpleTextAttributes.REGULAR_ATTRIBUTES); final CleanupStarter starter = new CleanupStarter(myProject, this); renderer.append("do cleanup...", new SimpleTextAttributes(SimpleTextAttributes.STYLE_UNDERLINE, JBColor.RED), starter); } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesBrowserLogicallyLockedFile.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesBrowserLogicallyLockedFile.java index 7458203e4858..669f35303253 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesBrowserLogicallyLockedFile.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesBrowserLogicallyLockedFile.java @@ -20,7 +20,7 @@ import com.intellij.openapi.vcs.changes.LogicalLock; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.ui.SimpleTextAttributes; -import static com.intellij.vcsUtil.UIVcsUtil.SPACE_AND_THIN_SPACE; +import static com.intellij.vcsUtil.UIVcsUtil.spaceAndThinSpace; public class ChangesBrowserLogicallyLockedFile extends ChangesBrowserFileNode { private final LogicalLock myLogicalLock; @@ -33,7 +33,7 @@ public class ChangesBrowserLogicallyLockedFile extends ChangesBrowserFileNode { @Override public void render(ChangesBrowserNodeRenderer renderer, boolean selected, boolean expanded, boolean hasFocus) { super.render(renderer, selected, expanded, hasFocus); - renderer.append(SPACE_AND_THIN_SPACE + "locked by ", SimpleTextAttributes.REGULAR_ATTRIBUTES); + renderer.append(spaceAndThinSpace() + "locked by ", SimpleTextAttributes.REGULAR_ATTRIBUTES); renderer.append(myLogicalLock.getOwner(), SimpleTextAttributes.REGULAR_ATTRIBUTES); } } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesBrowserNode.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesBrowserNode.java index c3f8c5662adf..c004a5f2308a 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesBrowserNode.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesBrowserNode.java @@ -24,7 +24,6 @@ import com.intellij.openapi.vcs.changes.LocallyDeletedChange; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.ui.ColoredTreeCellRenderer; import com.intellij.ui.SimpleTextAttributes; -import com.intellij.vcsUtil.UIVcsUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -34,6 +33,8 @@ import java.util.ArrayList; import java.util.Enumeration; import java.util.List; +import static com.intellij.vcsUtil.UIVcsUtil.spaceAndThinSpace; + /** * @author max */ @@ -213,13 +214,13 @@ public class ChangesBrowserNode extends DefaultMutableTreeNode { int count = getCount(); int dirCount = getDirectoryCount(); if (dirCount == 0) { - return UIVcsUtil.SPACE_AND_THIN_SPACE + VcsBundle.message("changes.nodetitle.changecount", count); + return spaceAndThinSpace() + VcsBundle.message("changes.nodetitle.changecount", count); } else if (count == 0 && dirCount > 0) { - return UIVcsUtil.SPACE_AND_THIN_SPACE + VcsBundle.message("changes.nodetitle.directory.changecount", dirCount); + return spaceAndThinSpace() + VcsBundle.message("changes.nodetitle.directory.changecount", dirCount); } else { - return UIVcsUtil.SPACE_AND_THIN_SPACE + VcsBundle.message("changes.nodetitle.directory.file.changecount", dirCount, count); + return spaceAndThinSpace() + VcsBundle.message("changes.nodetitle.directory.file.changecount", dirCount, count); } } diff --git a/platform/vcs-impl/testSrc/com/intellij/openapi/vcs/Executor.java b/platform/vcs-impl/testSrc/com/intellij/openapi/vcs/Executor.java index cdc052faec89..7acc62e9ae5d 100644 --- a/platform/vcs-impl/testSrc/com/intellij/openapi/vcs/Executor.java +++ b/platform/vcs-impl/testSrc/com/intellij/openapi/vcs/Executor.java @@ -26,6 +26,7 @@ import com.intellij.openapi.vfs.CharsetToolkit; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.io.File; import java.io.IOException; @@ -62,12 +63,12 @@ public class Executor { private static String ourCurrentDir; - private static void cdAbs(String absolutePath) { + private static void cdAbs(@NotNull String absolutePath) { ourCurrentDir = absolutePath; debug("# cd " + shortenPath(absolutePath)); } - private static void cdRel(String relativePath) { + private static void cdRel(@NotNull String relativePath) { cdAbs(ourCurrentDir + "/" + relativePath); } @@ -75,7 +76,7 @@ public class Executor { cdAbs(dir.getAbsolutePath()); } - public static void cd(String relativeOrAbsolutePath) { + public static void cd(@NotNull String relativeOrAbsolutePath) { if (relativeOrAbsolutePath.startsWith("/") || relativeOrAbsolutePath.charAt(1) == ':') { cdAbs(relativeOrAbsolutePath); } @@ -84,7 +85,7 @@ public class Executor { } } - public static void cd(VirtualFile dir) { + public static void cd(@NotNull VirtualFile dir) { cd(dir.getPath()); } @@ -110,13 +111,13 @@ public class Executor { } @NotNull - public static File touch(String fileName, String content) { + public static File touch(@NotNull String fileName, @NotNull String content) { File filePath = touch(fileName); echo(fileName, content); return filePath; } - public static void echo(String fileName, String content) { + public static void echo(@NotNull String fileName, @NotNull String content) { try { FileUtil.writeToFile(child(fileName), content.getBytes(), true); } @@ -152,7 +153,8 @@ public class Executor { return file; } - public static String cat(String fileName) { + @NotNull + public static String cat(@NotNull String fileName) { try { String content = FileUtil.loadFile(child(fileName)); debug("# cat " + fileName); @@ -163,7 +165,7 @@ public class Executor { } } - public static void cp(String fileName, File destinationDir) { + public static void cp(@NotNull String fileName, @NotNull File destinationDir) { try { FileUtil.copy(child(fileName), new File(destinationDir, fileName)); } @@ -172,8 +174,10 @@ public class Executor { } } - protected static String run(@NotNull File workingDir, @NotNull List params, - boolean ignoreNonZeroExitCode) throws ExecutionException { + @NotNull + protected static String run(@NotNull File workingDir, @NotNull List params, boolean ignoreNonZeroExitCode) + throws ExecutionException + { final ProcessBuilder builder = new ProcessBuilder().command(params); builder.directory(workingDir); builder.redirectErrorStream(true); @@ -207,7 +211,8 @@ public class Executor { return stdout; } - public static List splitCommandInParameters(String command) { + @NotNull + public static List splitCommandInParameters(@NotNull String command) { List split = new ArrayList(); boolean insideParam = false; @@ -248,7 +253,11 @@ public class Executor { return split; } - protected static String findExecutable(String programName, String unixExec, String winExec, Collection envs) { + @NotNull + protected static String findExecutable(@NotNull String programName, + @NotNull String unixExec, + @NotNull String winExec, + @NotNull Collection envs) { String exec = findEnvValue(programName, envs); if (exec != null) { return exec; @@ -265,7 +274,8 @@ public class Executor { " executable." : "")); } - public static String findEnvValue(String programNameForLog, Collection envs) { + @Nullable + public static String findEnvValue(@NotNull String programNameForLog, @NotNull Collection envs) { for (String env : envs) { String val = System.getenv(env); if (val != null && new File(val).canExecute()) { @@ -276,13 +286,14 @@ public class Executor { return null; } - public static void debug(String msg) { + public static void debug(@NotNull String msg) { if (!StringUtil.isEmptyOrSpaces(msg)) { LOG.info(msg); } } - private static String shortenPath(String path) { + @NotNull + private static String shortenPath(@NotNull String path) { String[] split = path.split("/"); if (split.length > 3) { // split[0] is empty, because the path starts from / @@ -291,7 +302,8 @@ public class Executor { return path; } - private static File child(String fileName) { + @NotNull + protected static File child(@NotNull String fileName) { assert ourCurrentDir != null : "Current dir hasn't been initialized yet. Call cd at least once before any other command."; return new File(ourCurrentDir, fileName); } diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/TestUtils.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/TestUtils.java index e2de10c72bac..1020bb1f9ef4 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/TestUtils.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/TestUtils.java @@ -39,14 +39,8 @@ public class TestUtils { return false; } final PsiFile file = element.getContainingFile(); - final VirtualFile virtualFile = file.getVirtualFile(); - if (virtualFile == null) { - return true; - } - final Project project = element.getProject(); - final ProjectRootManager rootManager = ProjectRootManager.getInstance(project); - final ProjectFileIndex fileIndex = rootManager.getFileIndex(); - return fileIndex.isInTestSourceContent(virtualFile); + final VirtualFile virtualFile = file == null ? null : file.getVirtualFile(); + return virtualFile != null && ProjectRootManager.getInstance(file.getProject()).getFileIndex().isInTestSourceContent(virtualFile); } public static boolean isPartOfJUnitTestMethod(@NotNull PsiElement element) { diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/exceptions/SplitTryWithMultipleResourcesIntention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/exceptions/SplitTryWithMultipleResourcesIntention.java index 2977d6b00f05..2f6003e476ac 100644 --- a/plugins/IntentionPowerPak/src/com/siyeh/ipp/exceptions/SplitTryWithMultipleResourcesIntention.java +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/exceptions/SplitTryWithMultipleResourcesIntention.java @@ -61,6 +61,10 @@ public class SplitTryWithMultipleResourcesIntention extends Intention { for (PsiCatchSection catchSection : catchSections) { newTryStatementText.append(catchSection.getText()); } + final PsiCodeBlock finallyBlock = tryStatement.getFinallyBlock(); + if (finallyBlock != null) { + newTryStatementText.append("finally").append(finallyBlock.getText()); + } PsiReplacementUtil.replaceStatement(tryStatement, newTryStatementText.toString()); } } diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/exceptions/TryWithMultipleResourcesPredicate.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/exceptions/TryWithMultipleResourcesPredicate.java index 6e2b34ea0a5f..6643f47cf285 100644 --- a/plugins/IntentionPowerPak/src/com/siyeh/ipp/exceptions/TryWithMultipleResourcesPredicate.java +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/exceptions/TryWithMultipleResourcesPredicate.java @@ -42,10 +42,6 @@ class TryWithMultipleResourcesPredicate implements PsiElementPredicate { return false; } final PsiTryStatement tryStatement = (PsiTryStatement)parent; - final PsiCodeBlock finallyBlock = tryStatement.getFinallyBlock(); - if (finallyBlock != null) { - return false; - } final PsiResourceList resourceList = tryStatement.getResourceList(); if (resourceList == null) { return false; diff --git a/plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/exceptions/SplitTryWithMultipleResourcesIntentionTest.java b/plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/exceptions/SplitTryWithMultipleResourcesIntentionTest.java index 8507e8666f9b..505c0c5f4a62 100644 --- a/plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/exceptions/SplitTryWithMultipleResourcesIntentionTest.java +++ b/plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/exceptions/SplitTryWithMultipleResourcesIntentionTest.java @@ -73,6 +73,33 @@ public class SplitTryWithMultipleResourcesIntentionTest extends IPPTestCase { "}"); } + public void testWithFinally() { + doTest( + "import java.io.*;\n" + + "class C {\n" + + " void foo(File file1, File file2) throws IOException {\n" + + " /*_Split 'try' statement with multiple resources*/try (FileInputStream in = new FileInputStream(file1); FileOutputStream out = new FileOutputStream(file2)) {\n" + + " System.out.println(in + \", \" + out);\n" + + " } finally {\n" + + " System.out.println();\n" + + " }\n" + + " }\n" + + "}", + + "import java.io.*;\n" + + "class C {\n" + + " void foo(File file1, File file2) throws IOException {\n" + + " try (FileInputStream in = new FileInputStream(file1)) {\n" + + " try (FileOutputStream out = new FileOutputStream(file2)) {\n" + + " System.out.println(in + \", \" + out);\n" + + " }\n" + + " } finally {\n" + + " System.out.println();\n" + + " }\n" + + " }\n" + + "}"); + } + public void testMixedResources() { doTest( "import java.io.*;\n" + diff --git a/plugins/devkit/devkit-tests.iml b/plugins/devkit/devkit-tests.iml new file mode 100644 index 000000000000..cf89675ebc14 --- /dev/null +++ b/plugins/devkit/devkit-tests.iml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/plugins/devkit/devkit.iml b/plugins/devkit/devkit.iml index 62aa16567062..385c3b6b6f82 100644 --- a/plugins/devkit/devkit.iml +++ b/plugins/devkit/devkit.iml @@ -4,7 +4,6 @@ - @@ -47,5 +46,4 @@ - - + \ No newline at end of file diff --git a/plugins/devkit/src/build/PluginBuildConfiguration.java b/plugins/devkit/src/build/PluginBuildConfiguration.java index 5adffafc5d41..a7f27c92b923 100644 --- a/plugins/devkit/src/build/PluginBuildConfiguration.java +++ b/plugins/devkit/src/build/PluginBuildConfiguration.java @@ -68,7 +68,7 @@ public class PluginBuildConfiguration implements PersistentStateComponent errorMessages = new ArrayList(); - PrepareToDeployAction.doPrepare(module, errorMessages, new ArrayList()); - assertTrue("Building plugin zip finished with errors: " + errorMessages, errorMessages.isEmpty()); - } - - private Module setupSimplePluginProject() { - copyToProject("plugins/devkit/testData/build/simple"); - Module module = loadModule(getProjectBasePath() + "/pluginProject.iml"); - readJdomExternalizables(module); - return module; - } - - private Module setupPluginProjectWithJpsModule() { - copyToProject("plugins/devkit/testData/build/withJpsModule"); - Module module = loadModule(getProjectBasePath() + "/pluginProject.iml"); - readJdomExternalizables(module); - loadModuleComponentState(module, PluginBuildConfiguration.getInstance(module)); - Module jpsModule = loadModule(getProjectBasePath() + "/jps-plugin/jps-plugin.iml"); - readJdomExternalizables(jpsModule); - ModuleRootModificationUtil.setModuleSdk(jpsModule, getTestProjectJdk()); - return module; - } -} diff --git a/plugins/devkit/testSources/build/PluginModuleCompilationTest.kt b/plugins/devkit/testSources/build/PluginModuleCompilationTest.kt new file mode 100644 index 000000000000..b8d060d4822b --- /dev/null +++ b/plugins/devkit/testSources/build/PluginModuleCompilationTest.kt @@ -0,0 +1,150 @@ +/* + * 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 org.jetbrains.idea.devkit.build + +import com.intellij.compiler.BaseCompilerTestCase +import com.intellij.openapi.application.PathManager +import com.intellij.openapi.application.runWriteAction +import com.intellij.openapi.module.Module +import com.intellij.openapi.module.ModuleType +import com.intellij.openapi.projectRoots.ProjectJdkTable +import com.intellij.openapi.projectRoots.Sdk +import com.intellij.openapi.projectRoots.SdkType +import com.intellij.openapi.roots.ModuleRootModificationUtil +import com.intellij.openapi.roots.OrderRootType +import com.intellij.openapi.util.io.FileUtil +import com.intellij.openapi.util.io.FileUtilRt +import com.intellij.openapi.vfs.LocalFileSystem +import com.intellij.util.SmartList +import com.intellij.util.io.TestFileSystemBuilder.fs +import org.assertj.core.api.Assertions.assertThat +import org.jetbrains.idea.devkit.module.PluginModuleType +import org.jetbrains.idea.devkit.projectRoots.IdeaJdk +import org.jetbrains.idea.devkit.projectRoots.Sandbox +import java.io.File +import java.util.* + +/** + * @author nik + */ +public class PluginModuleCompilationTest : BaseCompilerTestCase() { + private var pluginSdk: Sdk? = null + + override fun setUpJdk() { + super.setUpJdk() + runWriteAction { + val table = ProjectJdkTable.getInstance() + pluginSdk = table.createSdk("IDEA plugin SDK", SdkType.findInstance(IdeaJdk::class.java)) + val modificator = pluginSdk!!.sdkModificator + modificator.sdkAdditionalData = Sandbox(getSandboxPath(), testProjectJdk, pluginSdk) + val rootPath = FileUtil.toSystemIndependentName(PathManager.getJarPathForClass(FileUtilRt::class.java)!!) + modificator.addRoot(LocalFileSystem.getInstance().refreshAndFindFileByPath(rootPath), OrderRootType.CLASSES) + modificator.commitChanges() + table.addJdk(pluginSdk) + } + } + + private fun getSandboxPath() = "$projectBasePath/sandbox" + + override fun tearDown() { + try { + if (pluginSdk != null) { + runWriteAction { ProjectJdkTable.getInstance().removeJdk(pluginSdk) } + } + } + finally { + super.tearDown() + } + } + + public fun testMakeSimpleModule() { + val module = setupSimplePluginProject() + make(module) + BaseCompilerTestCase.assertOutput(module, fs().dir("xxx").file("MyAction.class")) + + val sandbox = File(getSandboxPath()) + assertThat(sandbox).isDirectory() + fs() + .dir("plugins") + .dir("pluginProject") + .dir("META-INF").file("plugin.xml").end() + .dir("classes") + .dir("xxx").file("MyAction.class") + .build().assertDirectoryEqual(sandbox) + } + + public fun testRebuildSimpleProject() { + setupSimplePluginProject() + val log = rebuild() + assertThat(log.warnings).`as`("Rebuild finished with warnings: ${Arrays.toString(log.warnings)}").isEmpty() + } + + public fun testPrepareSimpleProjectForDeployment() { + val module = setupSimplePluginProject() + rebuild() + prepareForDeployment(module) + + val outputFile = File("$projectBasePath/pluginProject.jar") + assertThat(outputFile).isFile() + fs() + .archive("pluginProject.jar") + .dir("META-INF").file("plugin.xml").file("MANIFEST.MF").end() + .dir("xxx").file("MyAction.class") + .build().assertFileEqual(outputFile) + } + + public fun testBuildProjectWithJpsModule() { + val module = setupPluginProjectWithJpsModule() + rebuild() + prepareForDeployment(module) + + val outputFile = File("$projectBasePath/pluginProject.zip") + assertThat(outputFile).isFile() + fs() + .archive("pluginProject.zip") + .dir("pluginProject") + .dir("lib") + .archive("pluginProject.jar") + .dir("META-INF").file("plugin.xml").file("MANIFEST.MF").end() + .dir("xxx").file("MyAction.class").end() + .end() + .dir("jps") + .archive("jps-plugin.jar").file("Builder.class") + .build().assertFileEqual(outputFile) + } + + private fun prepareForDeployment(module: Module) { + val errorMessages = SmartList() + PrepareToDeployAction.doPrepare(module, errorMessages, SmartList()) + assertThat(errorMessages).`as`("Building plugin zip finished with errors: $errorMessages").isEmpty() + } + + private fun setupSimplePluginProject() = copyAndCreateModule("plugins/devkit/testData/build/simple") + + private fun copyAndCreateModule(relativePath: String): Module { + copyToProject(relativePath) + val module = loadModule("$projectBasePath/pluginProject.iml") + assertThat(ModuleType.get(module)).isEqualTo(PluginModuleType.getInstance()) + return module + } + + private fun setupPluginProjectWithJpsModule(): Module { + val module = copyAndCreateModule("plugins/devkit/testData/build/withJpsModule") + val jpsModule = loadModule("$projectBasePath/jps-plugin/jps-plugin.iml") + ModuleRootModificationUtil.setModuleSdk(jpsModule, testProjectJdk) + return module + } +} diff --git a/plugins/git4idea/src/git4idea/GitUtil.java b/plugins/git4idea/src/git4idea/GitUtil.java index 0a52c63299e7..141d3c95fd4f 100644 --- a/plugins/git4idea/src/git4idea/GitUtil.java +++ b/plugins/git4idea/src/git4idea/GitUtil.java @@ -66,6 +66,8 @@ import java.io.IOException; import java.io.UnsupportedEncodingException; import java.util.*; +import static com.intellij.dvcs.DvcsUtil.getShortRepositoryName; + /** * Git utility/helper methods */ @@ -993,4 +995,9 @@ public class GitUtil { } }, "
"); } + + @NotNull + public static String mention(@NotNull GitRepository repository) { + return getRepositoryManager(repository.getProject()).moreThanOneRoot() ? " in " + getShortRepositoryName(repository) : ""; + } } diff --git a/plugins/git4idea/src/git4idea/branch/GitBranchWorker.java b/plugins/git4idea/src/git4idea/branch/GitBranchWorker.java index 67e8d2e5f8cc..88a6c8088204 100644 --- a/plugins/git4idea/src/git4idea/branch/GitBranchWorker.java +++ b/plugins/git4idea/src/git4idea/branch/GitBranchWorker.java @@ -17,6 +17,7 @@ package git4idea.branch; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.Condition; @@ -32,6 +33,7 @@ import git4idea.GitPlatformFacade; import git4idea.changes.GitChangeUtils; import git4idea.commands.Git; import git4idea.history.GitHistoryUtils; +import git4idea.rebase.GitRebaseUtils; import git4idea.repo.GitRepository; import git4idea.ui.branch.GitCompareBranchesDialog; import git4idea.util.GitCommitCompareInfo; @@ -121,6 +123,12 @@ public final class GitBranchWorker { new GitMergeOperation(myProject, myFacade, myGit, myUiHandler, repositories, branchName, deleteOnMerge, revisions).execute(); } + public void rebase(@NotNull List repositories, @NotNull String branchName) { + updateInfo(repositories); + GitRebaseUtils.rebase(myProject, repositories, new GitRebaseParams(branchName), + ProgressManager.getInstance().getProgressIndicator()); + } + public void compare(@NotNull final String branchName, @NotNull final List repositories, @NotNull final GitRepository selectedRepository) { final GitCommitCompareInfo myCompareInfo = loadCommitsToCompare(repositories, branchName); diff --git a/plugins/git4idea/src/git4idea/branch/GitBrancher.java b/plugins/git4idea/src/git4idea/branch/GitBrancher.java index 80cea7e3ee89..4a18e10f8332 100644 --- a/plugins/git4idea/src/git4idea/branch/GitBrancher.java +++ b/plugins/git4idea/src/git4idea/branch/GitBrancher.java @@ -129,6 +129,11 @@ public interface GitBrancher { */ void merge(@NotNull String branchName, @NotNull DeleteOnMergeOption deleteOnMerge, @NotNull List repositories); + /** + * Call {@code git rebase } for each of the given repositories. + */ + void rebase(@NotNull List repositories, @NotNull String branchName); + /** * What should be done after successful merging a branch: delete the merged branch, propose to delete or do nothing. */ diff --git a/plugins/git4idea/src/git4idea/branch/GitBrancherImpl.java b/plugins/git4idea/src/git4idea/branch/GitBrancherImpl.java index a1be7b8fea0f..51a072273f79 100644 --- a/plugins/git4idea/src/git4idea/branch/GitBrancherImpl.java +++ b/plugins/git4idea/src/git4idea/branch/GitBrancherImpl.java @@ -131,6 +131,16 @@ class GitBrancherImpl implements GitBrancher { }.runInBackground(); } + @Override + public void rebase(@NotNull final List repositories, @NotNull final String branchName) { + new CommonBackgroundTask(myProject, "Rebasing " + branchName, null) { + @Override + void execute(@NotNull ProgressIndicator indicator) { + newWorker(indicator).rebase(repositories, branchName); + } + }.runInBackground(); + } + /** * Executes common operations before/after executing the actual branch operation. */ diff --git a/plugins/git4idea/src/git4idea/branch/GitRebaseParams.java b/plugins/git4idea/src/git4idea/branch/GitRebaseParams.java new file mode 100644 index 000000000000..c6a836cba78a --- /dev/null +++ b/plugins/git4idea/src/git4idea/branch/GitRebaseParams.java @@ -0,0 +1,84 @@ +/* + * 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 git4idea.branch; + +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +import static java.util.Collections.singletonList; + +public class GitRebaseParams { + + public enum Mode { + STANDARD, + CONTINUE, + SKIP, + ABORT; + + @NotNull + @SuppressWarnings("StringToUpperCaseOrToLowerCaseWithoutLocale") + String asArgument() { + if (this == STANDARD) return ""; + return "--" + this.name().toLowerCase(); + } + } + + @Nullable private final String myBase; + @NotNull private final Mode myMode; + + @NotNull + public static GitRebaseParams abort() { + return new GitRebaseParams(null, Mode.ABORT); + } + + public GitRebaseParams(@NotNull String base) { + this(base, Mode.STANDARD); + } + + private GitRebaseParams(@Nullable String base, @NotNull Mode mode) { + myBase = base; + myMode = mode; + } + + @NotNull + public GitRebaseParams withMode(@NotNull Mode mode) { + return mode == myMode ? this : new GitRebaseParams(myBase, mode); + } + + @NotNull + public String getBase() { + return StringUtil.notNullize(myBase); + } + + @NotNull + public Mode getMode() { + return myMode; + } + + @NotNull + public List getCommandLineArguments() { + if (myMode != Mode.STANDARD) { + return singletonList(myMode.asArgument()); + } + List args = ContainerUtil.newArrayList(); + args.add(myBase); + return args; + } +} diff --git a/plugins/git4idea/src/git4idea/commands/Git.java b/plugins/git4idea/src/git4idea/commands/Git.java index e23541338af8..011f70a4fbc0 100644 --- a/plugins/git4idea/src/git4idea/commands/Git.java +++ b/plugins/git4idea/src/git4idea/commands/Git.java @@ -20,6 +20,7 @@ import com.intellij.openapi.util.Computable; import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vfs.VirtualFile; import git4idea.GitCommit; +import git4idea.branch.GitRebaseParams; import git4idea.repo.GitRemote; import git4idea.repo.GitRepository; import git4idea.reset.GitResetMode; @@ -168,4 +169,7 @@ public interface Git { @NotNull GitCommandResult remotePrune(@NotNull GitRepository repository, @NotNull GitRemote remote); + + @NotNull + GitCommandResult rebase(@NotNull GitRepository repository, @NotNull GitRebaseParams params, @NotNull GitLineHandlerListener... listeners); } diff --git a/plugins/git4idea/src/git4idea/commands/GitImpl.java b/plugins/git4idea/src/git4idea/commands/GitImpl.java index 3b1d1bbc6ebd..ff3a48f4c0d3 100644 --- a/plugins/git4idea/src/git4idea/commands/GitImpl.java +++ b/plugins/git4idea/src/git4idea/commands/GitImpl.java @@ -31,6 +31,7 @@ import com.intellij.vcsUtil.VcsFileUtil; import git4idea.GitCommit; import git4idea.GitExecutionException; import git4idea.GitVcs; +import git4idea.branch.GitRebaseParams; import git4idea.config.GitVersionSpecialty; import git4idea.history.GitHistoryUtils; import git4idea.repo.GitRemote; @@ -137,7 +138,7 @@ public class GitImpl implements Git { return untrackedFiles; } - + @Override @NotNull public GitCommandResult clone(@NotNull final Project project, @NotNull final File parentDirectory, @NotNull final String url, @@ -268,7 +269,7 @@ public class GitImpl implements Git { } if (newBranch == null) { // simply checkout h.addParameters(detach ? reference + "^0" : reference); // we could use `--detach` here, but it is supported only since 1.7.5. - } + } else { // checkout reference as new branch h.addParameters("-b", newBranch, reference); } @@ -557,6 +558,17 @@ public class GitImpl implements Git { }); } + @NotNull + @Override + public GitCommandResult rebase(@NotNull GitRepository repository, + @NotNull GitRebaseParams params, + @NotNull GitLineHandlerListener... listeners) { + GitLineHandler handler = new GitLineHandler(repository.getProject(), repository.getRoot(), GitCommand.REBASE); + handler.addParameters(params.getCommandLineArguments()); + addListeners(handler, listeners); + return run(handler); + } + @NotNull private static GitCommandResult doLsRemote(@NotNull final Project project, @NotNull final File workingDir, diff --git a/plugins/git4idea/src/git4idea/merge/GitConflictResolver.java b/plugins/git4idea/src/git4idea/merge/GitConflictResolver.java index 99cd3eb0c386..9abae4f49fcc 100644 --- a/plugins/git4idea/src/git4idea/merge/GitConflictResolver.java +++ b/plugins/git4idea/src/git4idea/merge/GitConflictResolver.java @@ -39,6 +39,7 @@ import git4idea.commands.GitCommandResult; import git4idea.repo.GitRepository; import git4idea.repo.GitRepositoryManager; import git4idea.util.StringScanner; +import org.jetbrains.annotations.CalledInBackground; import org.jetbrains.annotations.NotNull; import javax.swing.event.HyperlinkEvent; @@ -153,6 +154,7 @@ public class GitConflictResolver { * In the basic implementation no action is performed, {@code true} is returned. * @return Return value is returned from {@link #merge()} */ + @CalledInBackground protected boolean proceedAfterAllMerged() throws VcsException { return true; } diff --git a/plugins/git4idea/src/git4idea/rebase/GitAbortRebaseProcess.java b/plugins/git4idea/src/git4idea/rebase/GitAbortRebaseProcess.java new file mode 100644 index 000000000000..a8abc3591ed3 --- /dev/null +++ b/plugins/git4idea/src/git4idea/rebase/GitAbortRebaseProcess.java @@ -0,0 +1,226 @@ +/* + * 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 git4idea.rebase; + +import com.intellij.dvcs.DvcsUtil; +import com.intellij.openapi.application.AccessToken; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ModalityState; +import com.intellij.openapi.components.ServiceManager; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.Messages; +import com.intellij.openapi.util.Ref; +import com.intellij.openapi.vcs.VcsNotifier; +import com.intellij.util.Function; +import com.intellij.util.containers.ContainerUtil; +import git4idea.DialogManager; +import git4idea.GitPlatformFacade; +import git4idea.GitUtil; +import git4idea.branch.GitRebaseParams; +import git4idea.commands.Git; +import git4idea.commands.GitCommandResult; +import git4idea.repo.GitRepository; +import git4idea.reset.GitResetMode; +import git4idea.stash.GitChangesSaver; +import git4idea.util.GitFreezingProcess; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; +import java.util.List; +import java.util.Map; + +import static com.intellij.CommonBundle.getCancelButtonText; +import static com.intellij.dvcs.DvcsUtil.getShortRepositoryName; +import static com.intellij.openapi.ui.Messages.getQuestionIcon; +import static com.intellij.openapi.vfs.VfsUtil.markDirtyAndRefresh; +import static com.intellij.openapi.vfs.VfsUtilCore.toVirtualFileArray; +import static git4idea.GitUtil.getRootsFromRepositories; +import static git4idea.rebase.GitRebaseUtils.mentionLocalChangesRemainingInStash; + +class GitAbortRebaseProcess { + private static final Logger LOG = Logger.getInstance(GitAbortRebaseProcess.class); + + @NotNull private final Project myProject; + @NotNull private final Git myGit; + @NotNull private final VcsNotifier myNotifier; + + @Nullable private final GitRepository myRepositoryToAbort; + @NotNull private final Map myRepositoriesToRollback; + @NotNull private final ProgressIndicator myIndicator; + @Nullable private final GitChangesSaver mySaver; + + GitAbortRebaseProcess(@NotNull Project project, + @Nullable GitRepository repositoryToAbort, + @NotNull Map repositoriesToRollback, + @NotNull ProgressIndicator progressIndicator, + @Nullable GitChangesSaver changesSaver) { + myProject = project; + myRepositoryToAbort = repositoryToAbort; + myRepositoriesToRollback = repositoriesToRollback; + myIndicator = progressIndicator; + mySaver = changesSaver; + + myGit = ServiceManager.getService(Git.class); + myNotifier = VcsNotifier.getInstance(myProject); + } + + void abortWithConfirmation() { + LOG.debug("Abort rebase. " + (myRepositoryToAbort == null ? "Nothing to abort" : getShortRepositoryName(myRepositoryToAbort)) + + ". Roots to rollback: " + mention(myRepositoriesToRollback.keySet())); + final Ref ref = Ref.create(); + ApplicationManager.getApplication().invokeAndWait(new Runnable() { + @Override + public void run() { + ref.set(confirmAbort()); + } + }, ModalityState.defaultModalityState()); + + LOG.debug("User choice: " + ref.get()); + if (ref.get() == AbortChoice.ROLLBACK_AND_ABORT) { + doAbort(true); + } + else if (ref.get() == AbortChoice.ABORT) { + doAbort(false); + } + } + + @NotNull + private AbortChoice confirmAbort() { + String title = "Abort Rebase"; + if (myRepositoryToAbort != null) { + if (myRepositoriesToRollback.isEmpty()) { + String message = "Are you sure you want to abort rebase" + GitUtil.mention(myRepositoryToAbort) + "?"; + int choice = DialogManager.showOkCancelDialog(myProject, message, title, "Abort", getCancelButtonText(), getQuestionIcon()); + if (choice == Messages.OK) { + return AbortChoice.ABORT; + } + } + else { + String message = "Do you want just to abort rebase" + GitUtil.mention(myRepositoryToAbort) + ",\n" + + "or also rollback the successful rebase in " + mention(myRepositoriesToRollback.keySet()) + "?"; + int choice = DialogManager.showYesNoCancelDialog(myProject, message, title, "Abort & Rollback", "Abort", + getCancelButtonText(), getQuestionIcon()); + if (choice == Messages.YES) { + return AbortChoice.ROLLBACK_AND_ABORT; + } + else if (choice == Messages.NO) { + return AbortChoice.ABORT; + } + } + } + else { + if (myRepositoriesToRollback.isEmpty()) { + LOG.error(new Throwable()); + } + else { + String description = "Do you want rollback the successful rebase in " + mention(myRepositoriesToRollback.keySet()) + "?"; + int choice = DialogManager.showOkCancelDialog(myProject, description, title, "Rollback", getCancelButtonText(), getQuestionIcon()); + if (choice == Messages.YES) { + return AbortChoice.ROLLBACK_AND_ABORT; + } + } + } + return AbortChoice.CANCEL; + } + + enum AbortChoice { + ABORT, + ROLLBACK_AND_ABORT, + CANCEL + } + + private void doAbort(final boolean rollback) { + new GitFreezingProcess(myProject, ServiceManager.getService(GitPlatformFacade.class), "rebase", new Runnable() { + public void run() { + AccessToken token = DvcsUtil.workingTreeChangeStarted(myProject); + List repositoriesToRefresh = ContainerUtil.newArrayList(); + try { + if (myRepositoryToAbort != null) { + myIndicator.setText2("git rebase --abort" + GitUtil.mention(myRepositoryToAbort)); + GitCommandResult result = myGit.rebase(myRepositoryToAbort, GitRebaseParams.abort()); + repositoriesToRefresh.add(myRepositoryToAbort); + if (!result.success()) { + myNotifier.notifyError("Rebase Abort Failed", + result.getErrorOutputAsHtmlString() + mentionLocalChangesRemainingInStash(mySaver)); + return; + } + } + + if (rollback) { + for (GitRepository repo : myRepositoriesToRollback.keySet()) { + myIndicator.setText2("git reset --keep" + GitUtil.mention(repo)); + GitCommandResult res = myGit.reset(repo, GitResetMode.KEEP, myRepositoriesToRollback.get(repo)); + repositoriesToRefresh.add(repo); + if (!res.success()) { + String description = myRepositoryToAbort != null ? + "Rebase abort was successful" + GitUtil.mention(myRepositoryToAbort) + ", but rollback failed": + "Rollback failed"; + description += GitUtil.mention(repo) + ":" + res.getErrorOutputAsHtmlString() + + mentionLocalChangesRemainingInStash(mySaver); + myNotifier.notifyImportantWarning("Rebase Rollback Failed", description); + return; + } + } + } + + if (mySaver != null) { + mySaver.load(); + } + myNotifier.notifySuccess("Rebase abort succeeded"); + } + finally { + refresh(repositoriesToRefresh); + DvcsUtil.workingTreeChangeFinished(myProject, token); + } + } + }).execute(); + } + + private static void refresh(@NotNull List toRefresh) { + for (GitRepository repository : toRefresh) { + repository.update(); + } + markDirtyAndRefresh(false, true, false, toVirtualFileArray(getRootsFromRepositories(toRefresh))); + } + + @NotNull + private static String mention(@NotNull Collection repositories) { + return joinWithAnd(ContainerUtil.map(repositories, new Function() { + @Override + public String fun(@NotNull GitRepository repository) { + return getShortRepositoryName(repository); + } + })); + } + + @NotNull + private static String joinWithAnd(@NotNull List strings) { + int size = strings.size(); + if (size == 0) return ""; + if (size == 1) return strings.get(0); + if (size == 2) return strings.get(0) + " and " + strings.get(1); + + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < size - 2; i++) { + sb.append(strings.get(i)).append(", "); + } + sb.append(strings.get(size - 2)).append(" and ").append(strings.get(size - 1)); + return sb.toString(); + } +} diff --git a/plugins/git4idea/src/git4idea/rebase/GitRebaseProcess.java b/plugins/git4idea/src/git4idea/rebase/GitRebaseProcess.java new file mode 100644 index 000000000000..d63ff9a13b44 --- /dev/null +++ b/plugins/git4idea/src/git4idea/rebase/GitRebaseProcess.java @@ -0,0 +1,548 @@ +/* + * 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 git4idea.rebase; + +import com.google.common.annotations.VisibleForTesting; +import com.intellij.dvcs.DvcsUtil; +import com.intellij.notification.Notification; +import com.intellij.notification.NotificationListener; +import com.intellij.openapi.application.AccessToken; +import com.intellij.openapi.components.ServiceManager; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.progress.Task; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Condition; +import com.intellij.openapi.util.Pair; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.vcs.VcsException; +import com.intellij.openapi.vcs.VcsNotifier; +import com.intellij.openapi.vcs.changes.ChangeListManager; +import com.intellij.openapi.vfs.VfsUtil; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.util.Function; +import com.intellij.util.ThreeState; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.containers.MultiMap; +import git4idea.GitPlatformFacade; +import git4idea.GitUtil; +import git4idea.branch.GitRebaseParams; +import git4idea.commands.Git; +import git4idea.commands.GitCommandResult; +import git4idea.commands.GitUntrackedFilesOverwrittenByOperationDetector; +import git4idea.merge.GitConflictResolver; +import git4idea.repo.GitRepository; +import git4idea.stash.GitChangesSaver; +import git4idea.stash.GitStashChangesSaver; +import git4idea.util.GitFreezingProcess; +import git4idea.util.GitUntrackedFilesHelper; +import org.jetbrains.annotations.CalledInBackground; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.event.HyperlinkEvent; +import java.util.*; + +import static com.intellij.dvcs.DvcsUtil.getShortRepositoryName; +import static com.intellij.openapi.vfs.VfsUtilCore.toVirtualFileArray; +import static git4idea.GitUtil.getRootsFromRepositories; +import static git4idea.GitUtil.mention; +import static java.util.Collections.singleton; + +public class GitRebaseProcess { + + private static final Logger LOG = Logger.getInstance(GitRebaseProcess.class); + + @NotNull private final Project myProject; + @NotNull private final Git myGit; + @NotNull private final ChangeListManager myChangeListManager; + @NotNull private final VcsNotifier myNotifier; + @NotNull private final GitPlatformFacade myFacade; + + @NotNull private final List myAllRepositories; + @NotNull private final GitRebaseParams myParams; + @NotNull private final GitChangesSaver mySaver; + @NotNull private final Map mySuccessfulRepositories; + @NotNull private final Map myInitialHeadPositions; + + @NotNull private final MultiMap mySkippedCommits; + + protected GitRebaseProcess(@NotNull Project project, + @NotNull List repositories, + @NotNull GitRebaseParams params, + @NotNull ProgressIndicator indicator) { + this(project, repositories, params, newSaver(project, indicator), + MultiMap.create(), Collections.emptyMap()); + } + + private GitRebaseProcess(@NotNull Project project, + @NotNull List allRepositories, + @NotNull GitRebaseParams params, + @NotNull GitChangesSaver saver, + @NotNull MultiMap skippedCommits, + @NotNull Map successfulRepositories) { + myProject = project; + myAllRepositories = allRepositories; + myParams = params; + mySaver = saver; + mySuccessfulRepositories = successfulRepositories; + + myGit = ServiceManager.getService(Git.class); + myChangeListManager = ChangeListManager.getInstance(myProject); + myNotifier = VcsNotifier.getInstance(myProject); + myFacade = ServiceManager.getService(GitPlatformFacade.class); + + myInitialHeadPositions = readInitialHeadPositions(myAllRepositories); + mySkippedCommits = skippedCommits; + } + + void rebase() { + new GitFreezingProcess(myProject, myFacade, "rebase", new Runnable() { + public void run() { + doRebase(); + } + }).execute(); + } + + void abort(@Nullable GitRepository repositoryToAbort, + @NotNull final Collection successfulRepositories, + @NotNull ProgressIndicator indicator) { + new GitAbortRebaseProcess(myProject, repositoryToAbort, ContainerUtil.filter(myInitialHeadPositions, new Condition() { + @Override + public boolean value(GitRepository repository) { + return successfulRepositories.contains(repository); + } + }), indicator, mySaver).abortWithConfirmation(); + } + + void retry(final boolean continueRebase) { + new GitFreezingProcess(myProject, myFacade, "rebase", new Runnable() { + public void run() { + GitRebaseParams params = continueRebase ? myParams.withMode(GitRebaseParams.Mode.CONTINUE) : myParams; + new GitRebaseProcess(myProject, myAllRepositories, params, mySaver, mySkippedCommits, mySuccessfulRepositories).doRebase(); + } + }).execute(); + } + + private void doRebase() { + LOG.debug("Started rebase."); + Map successfulWithTypes = ContainerUtil.newLinkedHashMap(mySuccessfulRepositories); + List repositories = ContainerUtil.newArrayList(myAllRepositories); + repositories.removeAll(successfulWithTypes.keySet()); + ListIterator iterator = repositories.listIterator(); + + AccessToken token = DvcsUtil.workingTreeChangeStarted(myProject); + try { + if (!saveDirtyRootsInitially(repositories)) return; + + GitRepository facedDirtyError = null; + Map customModes = ContainerUtil.newLinkedHashMap(); + while (iterator.hasNext()) { + GitRepository repository = iterator.next(); + VirtualFile root = repository.getRoot(); + String repoName = getShortRepositoryName(repository); + LOG.debug("Rebase iteration. Root: " + repoName); + Collection successful = successfulWithTypes.keySet(); + + GitRebaseProblemDetector rebaseDetector = new GitRebaseProblemDetector(); + GitUntrackedFilesOverwrittenByOperationDetector untrackedDetector = new GitUntrackedFilesOverwrittenByOperationDetector(root); + GitRebaseLineListener progressListener = new GitRebaseLineListener(); + + GitRebaseParams.Mode customMode = customModes.get(repository); + GitRebaseParams rebaseParams = customMode != null ? myParams.withMode(customMode) : myParams; + GitCommandResult result = myGit.rebase(repository, rebaseParams, rebaseDetector, untrackedDetector, progressListener); + boolean nonStandardMode = rebaseParams.getMode() != GitRebaseParams.Mode.STANDARD; + boolean somethingRebased = nonStandardMode || progressListener.getResult().current > 1; + + if (result.success()) { + LOG.debug("Successfully rebased " + repoName); + successfulWithTypes.put(repository, SuccessType.fromOutput(result.getOutput())); + } + else if (rebaseDetector.isDirtyTree() && !nonStandardMode && repository != facedDirtyError) { + // if the initial dirty tree check doesn't find all local changes, we are still ready to stash-on-demand, + // but only once per repository (if the error happens again, that means that the previous stash attempt failed for some reason), + // and not in the case of --continue (where all local changes are expected to be committed) or --skip. + + LOG.debug("Dirty tree detected in " + repoName); + String saveError = saveLocalChanges(singleton(repository.getRoot())); + if (saveError == null) { + iterator.previous(); // try same repository again + facedDirtyError = repository; + } + else { + LOG.warn("Couldn't " + mySaver.getOperationName() + " root " + repository.getRoot() + ": " + saveError); + showFatalError(saveError, repository, somethingRebased, successful); + return; + } + } + else if (rebaseDetector.isMergeConflict()) { + LOG.debug("Merge conflict in " + repoName); + boolean allResolved = showConflictResolver(repository, false); + if (allResolved) { + iterator.previous(); // continue with the same repository + customModes.put(repository, GitRebaseParams.Mode.CONTINUE); + } + else { + notifyNotAllConflictsResolved(repository, successful); + return; + } + } + else if (rebaseDetector.isNoChangeError()) { + LOG.info("'No changes' situation detected in " + repoName); + mySkippedCommits.putValue(repository, GitRebaseUtils.getCurrentRebaseCommit(root)); + iterator.previous(); + customModes.put(repository, GitRebaseParams.Mode.SKIP); + } + else if (untrackedDetector.wasMessageDetected()) { + LOG.debug("Untracked files detected in " + repoName); + showUntrackedFilesError(untrackedDetector.getRelativeFilePaths(), repository, somethingRebased, successful); + return; + } + else { + LOG.info("Error rebasing root " + repoName + ": " + result.getErrorOutputAsJoinedString()); + showFatalError(result.getErrorOutputAsHtmlString(), repository, somethingRebased, successful); + return; + } + } // while + + LOG.debug("Rebase completed successfully."); + mySaver.load(); + } + finally { + refresh(getRepositoriesToRefresh(successfulWithTypes, iterator.previous())); + DvcsUtil.workingTreeChangeFinished(myProject, token); + } + notifySuccess(successfulWithTypes); // refresh _before_ showing the notification + } + + @VisibleForTesting + @NotNull + protected Collection getDirtyRoots(@NotNull Collection repositories) { + return findRootsWithLocalChanges(repositories); + } + + @NotNull + private static Map readInitialHeadPositions(@NotNull Collection repositories) { + updateRepositoriesInfo(repositories); + return ContainerUtil.map2Map(repositories, new Function>() { + @Override + public Pair fun(@NotNull GitRepository repository) { + String currentRevision = repository.getCurrentRevision(); + LOG.debug("Current revision in [" + repository.getRoot().getName() + "] is [" + currentRevision + "]"); + return Pair.create(repository, currentRevision); + } + }); + } + + @NotNull + private static Collection getRepositoriesToRefresh(@NotNull final Map successfulWithTypes, + @NotNull GitRepository latestProcessed) { + Collection toRefresh = ContainerUtil.newHashSet(ContainerUtil.filter(successfulWithTypes.keySet(), + new Condition() { + @Override + public boolean value(GitRepository repository) { + return successfulWithTypes.get(repository) != SuccessType.UP_TO_DATE; + } + })); + toRefresh.add(latestProcessed); + return toRefresh; + } + + private static void refresh(@NotNull Collection repositories) { + updateRepositoriesInfo(repositories); + VfsUtil.markDirtyAndRefresh(false, true, false, toVirtualFileArray(getRootsFromRepositories(repositories))); + } + + private static void updateRepositoriesInfo(@NotNull Collection repositories) { + for (GitRepository repository : repositories) { + repository.update(); + } + } + + @NotNull + private static GitStashChangesSaver newSaver(@NotNull Project project, @NotNull ProgressIndicator indicator) { + Git git = ServiceManager.getService(Git.class); + GitPlatformFacade facade = ServiceManager.getService(GitPlatformFacade.class); + return new GitStashChangesSaver(project, facade, git, indicator, "Uncommitted changes before rebase"); + } + + private boolean saveDirtyRootsInitially(@NotNull List repositories) { + if (myParams.getMode() != GitRebaseParams.Mode.STANDARD) { + LOG.debug("No need to pre-save dirty roots in the " + myParams.getMode() + " mode"); + return true; + } + Collection rootsToSave = getRootsFromRepositories(getDirtyRoots(repositories)); + String error = saveLocalChanges(rootsToSave); + if (error != null) { + myNotifier.notifyError("Rebase not Started", error); + return false; + } + return true; + } + + @Nullable + private String saveLocalChanges(@NotNull Collection rootsToSave) { + try { + mySaver.saveLocalChanges(rootsToSave); + return null; + } + catch (VcsException e) { + LOG.warn(e); + return "Couldn't " + mySaver.getSaverName() + " local uncommitted changes:
" + e.getMessage(); + } + } + + private Collection findRootsWithLocalChanges(@NotNull Collection repositories) { + return ContainerUtil.filter(repositories, new Condition() { + @Override + public boolean value(GitRepository repository) { + return myChangeListManager.haveChangesUnder(repository.getRoot()) != ThreeState.NO; + } + }); + } + + private void notifySuccess(@NotNull Map successful) { + String rebasedBranch = getCommonCurrentBranchNameIfAllTheSame(myAllRepositories); + SuccessType commonType = getItemIfAllTheSame(successful.values(), SuccessType.REBASED); + String message = commonType.formatMessage(rebasedBranch, myParams.getBase()); + message += mentionSkippedCommits(); + myNotifier.notifyMinorInfo("Rebase Successful", message, new NotificationListener.Adapter() { + @Override + protected void hyperlinkActivated(@NotNull Notification notification, @NotNull HyperlinkEvent e) { + handlePossibleCommitLinks(e.getDescription()); + } + }); + } + + @Nullable + private static String getCommonCurrentBranchNameIfAllTheSame(@NotNull Collection repositories) { + return getItemIfAllTheSame(ContainerUtil.map(repositories, new Function() { + @Override + public String fun(@NotNull GitRepository repository) { + return repository.getCurrentBranchName(); + } + }), null); + } + + @Contract("_, !null -> !null") + private static T getItemIfAllTheSame(@NotNull Collection collection, @Nullable T defaultItem) { + return ContainerUtil.newHashSet(collection).size() == 1 ? ContainerUtil.getFirstItem(collection) : defaultItem; + } + + private void notifyNotAllConflictsResolved(@NotNull GitRepository conflictingRepository, @NotNull Collection successful) { + String description = "You have to resolve the conflicts and continue rebase.
" + + "If you want to start from the beginning, you can abort rebase."; + description += GitRebaseUtils.mentionLocalChangesRemainingInStash(mySaver); + myNotifier.notifyImportantWarning("Rebase Suspended", description, + new RebaseNotificationListener(conflictingRepository, true, successful)); + } + + private boolean showConflictResolver(@NotNull GitRepository conflicting, boolean calledFromNotification) { + GitConflictResolver.Params params = new GitConflictResolver.Params().setReverse(true); + RebaseConflictResolver conflictResolver = new RebaseConflictResolver(myProject, myGit, myFacade, conflicting, params, + calledFromNotification); + return conflictResolver.merge(); + } + + private void showFatalError(@NotNull final String error, + @NotNull final GitRepository currentRepository, + boolean somethingWasRebased, + @NotNull final Collection successful) { + String description = "Rebase failed with error" + mention(currentRepository) + ": " + error + "
" + + mentionRetryAndAbort(somethingWasRebased, successful) + + mentionSkippedCommits() + + GitRebaseUtils.mentionLocalChangesRemainingInStash(mySaver); + myNotifier.notifyError("Rebase Failed", description, + new RebaseNotificationListener(currentRepository, somethingWasRebased, successful)); + } + + private void showUntrackedFilesError(@NotNull Set untrackedPaths, + @NotNull GitRepository currentRepository, + boolean somethingWasRebased, + @NotNull Collection successful) { + String message = GitUntrackedFilesHelper.createUntrackedFilesOverwrittenDescription("rebase", true) + + mentionRetryAndAbort(somethingWasRebased, successful) + + mentionSkippedCommits() + + GitRebaseUtils.mentionLocalChangesRemainingInStash(mySaver); + GitUntrackedFilesHelper.notifyUntrackedFilesOverwrittenBy(myProject, currentRepository.getRoot(), untrackedPaths, "rebase", message); + } + + @NotNull + private static String mentionRetryAndAbort(boolean somethingWasRebased, @NotNull Collection successful) { + return somethingWasRebased || !successful.isEmpty() + ? "You can retry or abort rebase." + : "Retry."; + } + + @NotNull + private String mentionSkippedCommits() { + if (mySkippedCommits.isEmpty()) return ""; + String message = "
"; + if (mySkippedCommits.size() == 1) { + message += "The following commit was skipped during rebase:
"; + } + else { + message += "The following commits were skipped during rebase:
"; + } + message += StringUtil.join(mySkippedCommits.values(), new Function() { + @Override + public String fun(@NotNull GitRebaseUtils.CommitInfo commitInfo) { + String commitMessage = StringUtil.shortenPathWithEllipsis(commitInfo.subject, 72, true); + String hash = commitInfo.revision.asString(); + String shortHash = DvcsUtil.getShortHash(commitInfo.revision.asString()); + return String.format("%s %s", hash, shortHash, commitMessage); + } + }, "
"); + return message; + } + + private enum SuccessType { + REBASED { + @NotNull + @Override + public String formatMessage(@Nullable String currentBranch, @NotNull String baseBranch) { + return "Rebased" + notNullize(currentBranch) + " on " + baseBranch; + } + }, + UP_TO_DATE { + @NotNull + @Override + public String formatMessage(@Nullable String currentBranch, @NotNull String baseBranch) { + return currentBranch != null ? currentBranch + " is up-to-date with " + baseBranch : "Up-to-date with " + baseBranch; + } + }, + FAST_FORWARDED { + @NotNull + @Override + public String formatMessage(@Nullable String currentBranch, @NotNull String baseBranch) { + return "Fast-forwarded" + notNullize(currentBranch) + " to " + baseBranch; + } + }; + + @NotNull + private static String notNullize(@Nullable String currentBranch) { + return currentBranch != null ? " " + currentBranch : ""; + } + + @NotNull + abstract String formatMessage(@Nullable String currentBranch, @NotNull String baseBranch); + + @NotNull + static SuccessType fromOutput(@NotNull List output) { + for (String line : output) { + if (StringUtil.containsIgnoreCase(line, "Fast-forwarded")) { + return FAST_FORWARDED; + } + if (StringUtil.containsIgnoreCase(line, "is up to date")) { + return UP_TO_DATE; + } + } + return REBASED; + } + } + + private class RebaseConflictResolver extends GitConflictResolver { + private final boolean myCalledFromNotification; + + RebaseConflictResolver(@NotNull Project project, + @NotNull Git git, + @NotNull GitPlatformFacade platformFacade, + @NotNull GitRepository repository, + @NotNull Params params, boolean calledFromNotification) { + super(project, git, platformFacade, singleton(repository.getRoot()), params); + myCalledFromNotification = calledFromNotification; + } + + @Override + protected void notifyUnresolvedRemain() { + // will be handled in the common notification + } + + @CalledInBackground + @Override + protected boolean proceedAfterAllMerged() throws VcsException { + if (myCalledFromNotification) retry(true); + return true; + } + } + + private class RebaseNotificationListener extends NotificationListener.Adapter { + @NotNull private final GitRepository myCurrentRepository; + private final boolean mySomethingWasRebased; + @NotNull private final Collection mySuccessful; + + RebaseNotificationListener(@NotNull GitRepository currentRepository, + boolean somethingWasRebased, + @NotNull Collection successful) { + myCurrentRepository = currentRepository; + mySomethingWasRebased = somethingWasRebased; + mySuccessful = successful; + } + + @Override + protected void hyperlinkActivated(@NotNull Notification notification, @NotNull final HyperlinkEvent e) { + final String href = e.getDescription(); + if ("abort".equals(href)) { + new Task.Backgroundable(myProject, "Aborting Rebase...") { + @Override + public void run(@NotNull ProgressIndicator indicator) { + abort(mySomethingWasRebased ? myCurrentRepository : null, mySuccessful, indicator); + } + }.queue(); + } + else if ("retry".equals(href) || "continue".equals(href)) { + new Task.Backgroundable(myProject, "Rebasing...") { + @Override + public void run(@NotNull ProgressIndicator indicator) { + retry(mySomethingWasRebased); + } + }.queue(); + } + else if ("resolve".equals(href)) { + showConflictResolver(myCurrentRepository, true); + } + else if ("stash".equals(href)) { + mySaver.showSavedChanges(); + } + else { + handlePossibleCommitLinks(href); + } + } + } + + private void handlePossibleCommitLinks(@NotNull String href) { + GitRepository repository = findRootBySkippedCommit(href); + if (repository != null) { + GitUtil.showSubmittedFiles(myProject, href, repository.getRoot(), true, false); + } + } + + @Nullable + private GitRepository findRootBySkippedCommit(@NotNull final String hash) { + return ContainerUtil.find(mySkippedCommits.keySet(), new Condition() { + @Override + public boolean value(GitRepository repository) { + return ContainerUtil.exists(mySkippedCommits.get(repository), new Condition() { + @Override + public boolean value(GitRebaseUtils.CommitInfo info) { + return info.revision.asString().equals(hash); + } + }); + } + }); + } +} diff --git a/plugins/git4idea/src/git4idea/rebase/GitRebaseUtils.java b/plugins/git4idea/src/git4idea/rebase/GitRebaseUtils.java index 798472f162ef..04edbd7db2ed 100644 --- a/plugins/git4idea/src/git4idea/rebase/GitRebaseUtils.java +++ b/plugins/git4idea/src/git4idea/rebase/GitRebaseUtils.java @@ -15,20 +15,31 @@ */ package git4idea.rebase; +import com.intellij.dvcs.repo.Repository; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.project.Project; import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.vcs.VcsNotifier; import com.intellij.openapi.vfs.CharsetToolkit; import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; import git4idea.GitRevisionNumber; import git4idea.GitUtil; +import git4idea.branch.GitRebaseParams; +import git4idea.repo.GitRepository; import git4idea.repo.GitRepositoryFiles; +import git4idea.stash.GitChangesSaver; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.InputStreamReader; +import java.util.Collection; +import java.util.List; +import java.util.Map; /** * The utilities related to rebase functionality @@ -45,6 +56,66 @@ public class GitRebaseUtils { private GitRebaseUtils() { } + public static void rebase(@NotNull final Project project, + @NotNull final List repositories, + @NotNull final GitRebaseParams params, + @NotNull final ProgressIndicator indicator) { + if (!isRebaseAllowed(project, repositories)) return; // TODO maybe move to the outside + new GitRebaseProcess(project, repositories, params, indicator).rebase(); + } + + /** + * Abort the ongoing rebase process in the {@code repositoryToAbort}, + * and optionally rollback rebase which has already successfully completed in some other repositories. + * + * @param repositoryToAbort Repository to perform {@code git rebase --abort}. + * @param repositoriesToRollback Repositories to rollback the successful rebase, together with commit hashes which were HEAD revisions + * before that successful rebase started - these are the revisions which the method will rollback to + * via {@code git reset --keep}. + */ + public static void abort(@NotNull final Project project, + @Nullable final GitRepository repositoryToAbort, + @NotNull final Map repositoriesToRollback, + @NotNull ProgressIndicator progressIndicator) { + new GitAbortRebaseProcess(project, repositoryToAbort, repositoriesToRollback, progressIndicator, null).abortWithConfirmation(); + } + + private static boolean isRebaseAllowed(@NotNull Project project, @NotNull Collection repositories) { + // TODO links to 'rebase', 'resolve conflicts', etc. + for (GitRepository repository : repositories) { + Repository.State state = repository.getState(); + String in = GitUtil.mention(repository); + String message = null; + switch (state) { + case NORMAL: + if (repository.isFresh()) { + message = "Repository" + in + " is empty."; + } + break; + case MERGING: + message = "There is an unfinished merge process" + in + ".
You should complete the merge before starting a rebase"; + break; + case REBASING: + message = "There is an unfinished rebase process" + in + ".
You should complete it before starting another rebase"; + break; + case GRAFTING: + message = "There is an unfinished cherry-pick process" + in + ".
You should finish it before starting a rebase."; + break; + case DETACHED: + message = "You are in the detached HEAD state" + in + ".
Rebase is not possible."; + break; + default: + LOG.error("Unknown state [" + state.name() + "]"); + message = "Rebase is not possible" + in; + } + if (message != null) { + VcsNotifier.getInstance(project).notifyError("Rebase not Allowed", message); + return false; + } + } + return true; + } + /** * Checks if the rebase is in the progress for the specified git root * @@ -140,6 +211,18 @@ public class GitRebaseUtils { return new CommitInfo(new GitRevisionNumber(hash), subject); } + @NotNull + static String mentionLocalChangesRemainingInStash(@Nullable GitChangesSaver saver) { + return saver != null && saver.wereChangesSaved() ? + "
Note that some local changes were " + toPast(saver.getOperationName()) + " before rebase." : + ""; + } + + @NotNull + private static String toPast(@NotNull String word) { + return word.endsWith("e") ? word + "d" : word + "ed"; + } + /** * Short commit info */ diff --git a/plugins/git4idea/src/git4idea/stash/GitStashChangesSaver.java b/plugins/git4idea/src/git4idea/stash/GitStashChangesSaver.java index fd0967976660..38db08222aea 100644 --- a/plugins/git4idea/src/git4idea/stash/GitStashChangesSaver.java +++ b/plugins/git4idea/src/git4idea/stash/GitStashChangesSaver.java @@ -20,6 +20,7 @@ import com.intellij.notification.NotificationListener; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vcs.VcsNotifier; import com.intellij.openapi.vcs.history.VcsRevisionNumber; @@ -48,6 +49,7 @@ import java.util.Set; public class GitStashChangesSaver extends GitChangesSaver { private static final Logger LOG = Logger.getInstance(GitStashChangesSaver.class); + private static final String NO_LOCAL_CHANGES_TO_SAVE = "No local changes to save"; @NotNull private final GitRepositoryManager myRepositoryManager; @NotNull private final Set myStashedRoots = ContainerUtil.newHashSet(); // save stashed roots to unstash only them @@ -76,7 +78,7 @@ public class GitStashChangesSaver extends GitChangesSaver { } else { GitCommandResult result = myGit.stashSave(repository, myStashMessage); - if (result.success() && !result.getErrorOutputAsJoinedString().contains("No local changes to save")) { + if (result.success() && somethingWasStashed(result)) { myStashedRoots.add(root); } else { @@ -93,6 +95,11 @@ public class GitStashChangesSaver extends GitChangesSaver { } } + private static boolean somethingWasStashed(@NotNull GitCommandResult result) { + return !StringUtil.containsIgnoreCase(result.getErrorOutputAsJoinedString(), NO_LOCAL_CHANGES_TO_SAVE) && + !StringUtil.containsIgnoreCase(result.getOutputAsJoinedString(), NO_LOCAL_CHANGES_TO_SAVE); + } + @Override public void load() { for (VirtualFile root : myStashedRoots) { diff --git a/plugins/git4idea/src/git4idea/ui/branch/GitBranchPopupActions.java b/plugins/git4idea/src/git4idea/ui/branch/GitBranchPopupActions.java index ac591d1f39ef..d253f82de947 100644 --- a/plugins/git4idea/src/git4idea/ui/branch/GitBranchPopupActions.java +++ b/plugins/git4idea/src/git4idea/ui/branch/GitBranchPopupActions.java @@ -172,6 +172,7 @@ class GitBranchPopupActions { new CheckoutAction(myProject, myRepositories, myBranchName), new CheckoutAsNewBranch(myProject, myRepositories, myBranchName), new CompareAction(myProject, myRepositories, myBranchName, mySelectedRepository), + new RebaseAction(myProject, myRepositories, myBranchName), new MergeAction(myProject, myRepositories, myBranchName, true), new DeleteAction(myProject, myRepositories, myBranchName) }; @@ -268,6 +269,7 @@ class GitBranchPopupActions { return new AnAction[] { new CheckoutRemoteBranchAction(myProject, myRepositories, myBranchName), new CompareAction(myProject, myRepositories, myBranchName, mySelectedRepository), + new RebaseAction(myProject, myRepositories, myBranchName), new MergeAction(myProject, myRepositories, myBranchName, false), new RemoteDeleteAction(myProject, myRepositories, myBranchName) }; @@ -378,4 +380,24 @@ class GitBranchPopupActions { return GitBrancher.DeleteOnMergeOption.NOTHING; } } + + private static class RebaseAction extends DumbAwareAction { + + private final Project myProject; + private final List myRepositories; + private final String myBranchName; + + public RebaseAction(@NotNull Project project, @NotNull List repositories, @NotNull String branchName) { + super("Rebase"); + myProject = project; + myRepositories = repositories; + myBranchName = branchName; + } + + @Override + public void actionPerformed(AnActionEvent e) { + GitBrancher brancher = ServiceManager.getService(myProject, GitBrancher.class); + brancher.rebase(myRepositories, myBranchName); + } + } } diff --git a/plugins/git4idea/tests/git4idea/log/GitLogProviderTest.java b/plugins/git4idea/tests/git4idea/log/GitLogProviderTest.java index d36b9081132c..9501ddc03ce6 100644 --- a/plugins/git4idea/tests/git4idea/log/GitLogProviderTest.java +++ b/plugins/git4idea/tests/git4idea/log/GitLogProviderTest.java @@ -39,7 +39,6 @@ import java.util.Collections; import java.util.List; import java.util.Set; -import static com.intellij.openapi.vcs.Executor.touch; import static git4idea.test.GitExecutor.*; import static git4idea.test.GitTestUtil.setupUsername; import static java.util.Collections.singleton; @@ -229,11 +228,6 @@ public class GitLogProviderTest extends GitSingleRepoTest { tac("b.txt"); } - private static String tac(@NotNull String file) { - touch(file, "content" + Math.random()); - return addCommit("touched " + file); - } - private static void createTaggedBranch() { String hash = last(); tac("c.txt"); diff --git a/plugins/git4idea/tests/git4idea/push/GitPushResultNotificationTest.java b/plugins/git4idea/tests/git4idea/push/GitPushResultNotificationTest.java index 46f84b8a3daf..6f568c4e5a9e 100644 --- a/plugins/git4idea/tests/git4idea/push/GitPushResultNotificationTest.java +++ b/plugins/git4idea/tests/git4idea/push/GitPushResultNotificationTest.java @@ -15,7 +15,6 @@ */ package git4idea.push; -import com.intellij.notification.Notification; import com.intellij.notification.NotificationType; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.project.Project; @@ -42,6 +41,7 @@ import java.util.Map; import static git4idea.push.GitPushNativeResult.Type.*; import static git4idea.push.GitPushRepoResult.convertFromNative; +import static git4idea.test.GitTestUtil.assertNotification; import static java.util.Arrays.asList; import static java.util.Collections.singletonList; @@ -124,7 +124,7 @@ public class GitPushResultNotificationTest extends GitPlatformTest { GitPushResultNotification notification = notification(convertFromNative(branchResult, singletonList(tagResult), 1, from("master"), to("origin/master"))); assertNotification(NotificationType.INFORMATION, "Push successful", - "Pushed 1 commit to origin/master, and tag v0.1 to origin", notification); + "Pushed 1 commit to origin/master, and tag v0.1 to origin", notification); } public void test_nothing() { @@ -245,11 +245,4 @@ public class GitPushResultNotificationTest extends GitPlatformTest { }); return new MockGitRepository(ourProject, root); } - - private static void assertNotification(NotificationType type, String title, String content, Notification actual) { - assertEquals(type, actual.getType()); - assertEquals(title, actual.getTitle()); - assertEquals(content, actual.getContent()); - } - } \ No newline at end of file diff --git a/plugins/git4idea/tests/git4idea/rebase/GitMultiRepoRebaseTest.kt b/plugins/git4idea/tests/git4idea/rebase/GitMultiRepoRebaseTest.kt new file mode 100644 index 000000000000..5836da0958ad --- /dev/null +++ b/plugins/git4idea/tests/git4idea/rebase/GitMultiRepoRebaseTest.kt @@ -0,0 +1,210 @@ +/* + * 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 git4idea.rebase + +import com.intellij.openapi.progress.EmptyProgressIndicator +import com.intellij.openapi.ui.Messages +import com.intellij.openapi.vcs.Executor +import com.intellij.openapi.vcs.Executor.mkdir +import com.intellij.openapi.vcs.Executor.touch +import git4idea.branch.GitRebaseParams +import git4idea.rebase.GitRebaseBaseTest.LocalChange +import git4idea.repo.GitRepository +import git4idea.test.GitExecutor.git +import git4idea.test.GitTestUtil.cleanupForAssertion +import git4idea.test.UNKNOWN_ERROR_TEXT +import kotlin.properties.Delegates +import kotlin.test.assertEquals +import kotlin.test.assertFalse +import kotlin.test.assertNotNull +import kotlin.test.assertTrue + +public class GitMultiRepoRebaseTest : GitRebaseBaseTest() { + + private var myUltimate: GitRepository by Delegates.notNull() + private var myCommunity: GitRepository by Delegates.notNull() + private var myContrib: GitRepository by Delegates.notNull() + private var myAllRepositories: List by Delegates.notNull() + + override fun setUp() { + super.setUp() + + Executor.cd(myProjectRoot) + val community = mkdir("community") + val contrib = mkdir("contrib") + + myUltimate = createRepository(myProjectPath) + myCommunity = createRepository(community.path) + myContrib = createRepository(contrib.path) + myAllRepositories = listOf(myUltimate, myCommunity, myContrib) + + Executor.cd(myProjectRoot) + touch(".gitignore", "community\ncontrib") + git("add .gitignore") + git("commit -m gitignore") + } + + public fun `test all successful`() { + myUltimate.`place feature above master`() + myCommunity.`diverge feature and master`() + myContrib.`place feature on master`() + + rebase("master") + + assertSuccessfulNotification("Rebased feature on master") + assertAllRebased() + assertNoRebaseInProgress(myAllRepositories) + } + + public fun `test abort from critical error during rebasing 2nd root, before any commits were applied`() { + val localChange = LocalChange(myUltimate, "new.txt", "Some content") + val rebaseProcess = `fail with critical error while rebasing 2nd root`(localChange) + + assertErrorNotification("Rebase Failed", + """ + Rebase failed with error in community:
+ $UNKNOWN_ERROR_TEXT + You can retry or abort rebase. + $LOCAL_CHANGES_WARNING + """) + + myUltimate.`assert feature rebased on master`() + myCommunity.`assert feature not rebased on master`() + myContrib.`assert feature not rebased on master`() + assertNoRebaseInProgress(myAllRepositories) + myUltimate.assertNoLocalChanges() + + var confirmation: String? = null + myDialogManager.onMessage { + confirmation = it + Messages.YES; + } + + rebaseProcess.abort(null, listOf(myUltimate), EmptyProgressIndicator()) + + assertNotNull(confirmation, "Abort confirmation message was not shown") + assertEquals(cleanupForAssertion("Do you want rollback the successful rebase in project?"), + cleanupForAssertion(confirmation!!), + "Incorrect confirmation message text"); + assertNoRebaseInProgress(myAllRepositories) + myAllRepositories.forEach { it.`assert feature not rebased on master`() } + + localChange.verify() + } + + public fun `test abort from critical error while rebasing 2nd root, after some commits were applied`() { + val localChange = LocalChange(myUltimate, "new.txt", "Some content") + val rebaseProcess = `fail with critical error while rebasing 2nd root after some commits are applied`(localChange) + + myVcsNotifier.lastNotification + + var confirmation: String? = null + myDialogManager.onMessage { + confirmation = it + Messages.YES; + } + + rebaseProcess.abort(myCommunity, listOf(myUltimate), EmptyProgressIndicator()) + + assertNotNull(confirmation, "Abort confirmation message was not shown") + assertEquals(cleanupForAssertion("Do you want just to abort rebase in community, or also rollback the successful rebase in project?"), + cleanupForAssertion(confirmation!!), + "Incorrect confirmation message text"); + assertNoRebaseInProgress(myAllRepositories) + myAllRepositories.forEach { it.`assert feature not rebased on master`() } + + localChange.verify() + } + + public fun `test conflicts in multiple repositories are resolved separately`() { + myUltimate.`prepare simple conflict`() + myCommunity.`prepare simple conflict`() + myContrib.`diverge feature and master`() + + var conflictInUltimate = false + var conflictInCommunity = false + myVcsHelper.onMerge({ + if (!conflictInUltimate) { + myUltimate.assertConflict("c.txt") + assertNoRebaseInProgress(myCommunity) + resolveConflicts(myUltimate) + conflictInUltimate = true + } + else { + assertFalse(conflictInCommunity) + myCommunity.assertConflict("c.txt") + assertNoRebaseInProgress(myUltimate) + resolveConflicts(myCommunity) + conflictInCommunity = true + } + }) + + rebase("master") + + assertTrue(conflictInUltimate) + assertTrue(conflictInCommunity) + myAllRepositories.forEach { + it.`assert feature rebased on master`() + assertNoRebaseInProgress(it) + it.assertNoLocalChanges() + } + } + + public fun `test retry doesn't touch successful repositories`() { + val rebaseProcess = `fail with critical error while rebasing 2nd root`() + + rebaseProcess.retry(false) + + assertSuccessfulNotification("Rebased feature on master") + assertAllRebased() + assertNoRebaseInProgress(myAllRepositories) + } + + private fun `fail with critical error while rebasing 2nd root`(localChange: LocalChange? = null): GitRebaseProcess { + myAllRepositories.forEach { it.`diverge feature and master`() } + localChange?.generate() + + myFailingGit.setShouldFail { it == myCommunity } + val rebaseProcess = rebase("master") + + myFailingGit.setShouldFail { false } + return rebaseProcess + } + + private fun `fail with critical error while rebasing 2nd root after some commits are applied`(localChange: LocalChange? = null): GitRebaseProcess { + myUltimate.`diverge feature and master`() + myCommunity.`make rebase fail on 2nd commit`() + myContrib.`diverge feature and master`() + localChange?.generate() + + val rebaseProcess = rebase("master") + + myFailingGit.setShouldFail { false } + return rebaseProcess + } + + private fun rebase(onto: String): GitRebaseProcess { + val rebaseProcess = GitRebaseProcess(myProject, myAllRepositories, GitRebaseParams(onto), EmptyProgressIndicator()) + rebaseProcess.rebase() + return rebaseProcess + } + + private fun assertAllRebased() { + assertRebased(myUltimate, "feature", "master") + assertRebased(myCommunity, "feature", "master") + assertRebased(myContrib, "feature", "master") + } +} diff --git a/plugins/git4idea/tests/git4idea/rebase/GitRebaseBaseTest.kt b/plugins/git4idea/tests/git4idea/rebase/GitRebaseBaseTest.kt new file mode 100644 index 000000000000..f96e7c876a16 --- /dev/null +++ b/plugins/git4idea/tests/git4idea/rebase/GitRebaseBaseTest.kt @@ -0,0 +1,223 @@ +/* + * 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 git4idea.rebase + +import com.intellij.dvcs.repo.Repository +import com.intellij.notification.Notification +import com.intellij.notification.NotificationType.ERROR +import com.intellij.notification.NotificationType.INFORMATION +import com.intellij.notification.NotificationType.WARNING +import com.intellij.openapi.vcs.AbstractVcsHelper +import com.intellij.openapi.vcs.Executor +import git4idea.GitUtil +import git4idea.commands.Git +import git4idea.repo.GitRepository +import git4idea.test.* +import git4idea.test.GitExecutor.cd +import git4idea.test.GitExecutor.git +import git4idea.test.GitTestUtil.assertNotification +import kotlin.test.assertEquals +import kotlin.test.assertFalse + +public abstract class GitRebaseBaseTest : GitPlatformTest() { + + protected val LOCAL_CHANGES_WARNING : String = "Note that some local changes were stashed before rebase." + + lateinit protected var myVcsHelper: MockVcsHelper + lateinit protected var myFailingGit: TestGitImpl + + override fun setUp() { + super.setUp() + + myVcsHelper = GitTestUtil.overrideService(myProject, AbstractVcsHelper::class.java, MockVcsHelper::class.java) + myFailingGit = GitTestUtil.overrideService(Git::class.java, TestGitImpl::class.java) + } + + override fun tearDown() { + try { + myFailingGit.setShouldFail { false } // to do check for null + } + finally { + super.tearDown() + } + } + + override fun createRepository(path: String) = GitTestUtil.createRepository(myProject, path, false) + + override fun getDebugLogCategories() = listOf("#" + GitRebaseProcess::class.java.name) + + protected fun GitRepository.`diverge feature and master`() { + build(this) { + master { + 0() + 1() + } + feature(0) { + 2() + } + } + } + + protected fun GitRepository.`place feature above master`() { + build(this) { + master { + 0() + 1() + } + feature { + 2() + } + } + } + + protected fun GitRepository.`place feature below master`() { + build(this) { + master { + 0() + 1() + } + feature(0) { + } + } + } + + protected fun GitRepository.`place feature on master`() { + build(this) { + master { + 0() + 1() + } + feature {} + } + } + + protected fun GitRepository.`prepare simple conflict`() { + build(this) { + master { + 0("c.txt") + 1("c.txt") + } + feature(0) { + 2("c.txt") + } + } + } + + protected fun assertSuccessfulNotification(message: String) { + assertNotification(INFORMATION, "Rebase Successful", message, myVcsNotifier.lastNotification) + } + + protected fun assertWarningNotification(title: String, message: String) { + assertNotification(WARNING, title, message, myVcsNotifier.lastNotification) + } + + protected fun assertErrorNotification(title: String, message: String) : Notification { + val notification = myVcsNotifier.lastNotification + assertNotification(ERROR, title, message, notification) + return notification + } + + protected fun GitRepository.`make rebase fail on 2nd commit`() { + build(this) { + master { + 0() + 1("m.txt") + } + feature(0) { + 2() + 3("m.txt") + } + } + `make rebase fail after resolving conflicts`() + } + + protected fun GitRepository.`make rebase fail after resolving conflicts`() { + myVcsHelper.onMerge { + resolveConflicts(this) + myFailingGit.setShouldFail { true } + } + } + + protected fun resolveConflicts(repository: GitRepository) { + cd(repository) + git("add -u .") + } + + protected fun GitRepository.`assert feature rebased on master`() { + assertRebased(this, "feature", "master") + } + + protected fun GitRepository.`assert feature not rebased on master`() { + assertNotRebased("feature", "master", this) + } + + protected fun assertRebased(repository: GitRepository, feature: String, master: String) { + cd(repository) + assertEquals(git("rev-parse " + master), git("merge-base $feature $master")) + } + + protected fun assertNotRebased(feature: String, master: String, repository: GitRepository) { + cd(repository) + assertFalse(git("rev-parse " + master) == git("merge-base $feature $master"), + "$feature is unexpectedly rebased on $master" + GitUtil.mention(repository)) + } + + protected fun assertNoRebaseInProgress(repository: GitRepository) { + assertEquals(Repository.State.NORMAL, repository.state) + } + + protected fun assertNoRebaseInProgress(repositories: Collection) { + for (repository in repositories) { + assertNoRebaseInProgress(repository) + } + } + + protected fun GitRepository.assertRebaseInProgress() { + assertEquals(Repository.State.REBASING, this.state) + } + + protected fun GitRepository.assertNoLocalChanges() { + assertEquals("", gitStatus(), "There should be no local changes!") + } + + protected fun GitRepository.isDirty(): Boolean { + return !gitStatus().isEmpty(); + } + + private fun GitRepository.gitStatus() = git(this, "status --porcelain").trim() + + protected fun GitRepository.assertConflict(file: String) { + assertEquals("UU " + file, git(this, "status --porcelain")) + } + + public class LocalChange(val repository: GitRepository, val filePath: String, val content: String = "Some content") { + fun generate() : LocalChange { + cd(repository) + GitExecutor.file(filePath).create(content).add() + return this + } + + fun verify() { + assertNewFile(repository, filePath, content) + } + + public fun assertNewFile(repository: GitRepository, file: String, content: String) { + cd(repository) + assertEquals("A " + file, git("status --porcelain"), "Incorrect git status output") + assertEquals(content, Executor.cat(file), "Incorrect content of the file [$file]") + } + } +} diff --git a/plugins/git4idea/tests/git4idea/rebase/GitSingleRepoRebaseTest.kt b/plugins/git4idea/tests/git4idea/rebase/GitSingleRepoRebaseTest.kt new file mode 100644 index 000000000000..d232f98bdef2 --- /dev/null +++ b/plugins/git4idea/tests/git4idea/rebase/GitSingleRepoRebaseTest.kt @@ -0,0 +1,405 @@ +/* + * 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 git4idea.rebase + +import com.intellij.dvcs.DvcsUtil +import com.intellij.openapi.progress.EmptyProgressIndicator +import com.intellij.openapi.ui.Messages +import git4idea.branch.GitRebaseParams +import git4idea.rebase.GitRebaseBaseTest.LocalChange +import git4idea.repo.GitRepository +import git4idea.test.GitExecutor.file +import git4idea.test.GitExecutor.git +import git4idea.test.RepoBuilder +import git4idea.test.UNKNOWN_ERROR_TEXT +import git4idea.test.build +import kotlin.properties.Delegates +import kotlin.test.assertEquals +import kotlin.test.assertFalse +import kotlin.test.assertTrue + +public class GitSingleRepoRebaseTest : GitRebaseBaseTest() { + + protected var myRepo: GitRepository by Delegates.notNull() + + override fun setUp() { + super.setUp() + myRepo = createRepository(myProjectPath) + } + + fun `test simple case`() { + myRepo.`diverge feature and master`() + + rebaseOnMaster() + + assertSuccessfulNotification("Rebased feature on master") + myRepo.`assert feature rebased on master`() + assertNoRebaseInProgress(myRepo) + } + + fun `test up-to-date`() { + myRepo.`place feature above master`() + + rebaseOnMaster() + + assertSuccessfulNotification("feature is up-to-date with master") + myRepo.`assert feature rebased on master`() + assertNoRebaseInProgress(myRepo) + } + + fun test_ff() { + myRepo.`place feature below master`() + + rebaseOnMaster() + + assertSuccessfulNotification("Fast-forwarded feature to master") + myRepo.`assert feature rebased on master`() + assertNoRebaseInProgress(myRepo) + } + + fun `test conflict resolver is shown`() { + myRepo.`prepare simple conflict`() + `do nothing on merge`() + + rebaseOnMaster() + + assertTrue(myVcsHelper.mergeDialogWasShown()) + } + + fun `test fail on 2nd commit should show notification with proposal to abort`() { + myRepo.`make rebase fail on 2nd commit`() + + rebaseOnMaster() + + `assert unknown error notification with link to abort`() + } + + fun `test multiple conflicts`() { + build { + master { + 0("c.txt") + 1("c.txt") + } + feature(0) { + 2("c.txt") + 3("c.txt") + } + } + + var conflicts = 0 + myVcsHelper.onMerge { + conflicts++ + myRepo.assertConflict("c.txt") + resolveConflicts(myRepo) + } + + rebaseOnMaster() + + assertEquals(2, conflicts, "Incorrect number of conflicting patches") + myRepo.`assert feature rebased on master`() + assertSuccessfulNotification("Rebased feature on master") + } + + fun `test continue rebase after resolving all conflicts`() { + myRepo.`prepare simple conflict`() + + myVcsHelper.onMerge { + resolveConflicts(myRepo) + } + + rebaseOnMaster() + assertSuccessfulNotification("Rebased feature on master") + myRepo.`assert feature rebased on master`() + assertNoRebaseInProgress(myRepo) + } + + fun `test warning notification if conflicts were not resolved`() { + myRepo.`prepare simple conflict`() + `do nothing on merge`() + + rebaseOnMaster() + `assert conflict not resolved notification`() + myRepo.assertRebaseInProgress() + } + + fun `test rebase failed for unknown reason`() { + myRepo.`diverge feature and master`() + myFailingGit.setShouldFail { true } + rebaseOnMaster() + `assert unknown error notification`() + } + + fun `test propose to abort when rebase failed after continue`() { + myRepo.`prepare simple conflict`() + `do nothing on merge`() + + rebaseOnMaster() + + myRepo.`assert feature not rebased on master`() + myRepo.assertRebaseInProgress() + resolveConflicts(myRepo) + + myFailingGit.setShouldFail { true } + val continueRebase = GitRebaseParams("master").withMode(GitRebaseParams.Mode.CONTINUE) + GitTestingRebaseProcess(continueRebase).rebase() + + `assert unknown error notification with link to abort`() + myRepo.`assert feature not rebased on master`() + myRepo.assertRebaseInProgress() + } + + fun `test local changes auto-saved`() { + myRepo.`diverge feature and master`() + val localChange = LocalChange(myRepo, "new.txt").generate() + + rebaseOnMaster() + + assertSuccessfulNotification("Rebased feature on master") + assertRebased(myRepo, "feature", "master") + assertNoRebaseInProgress(myRepo) + localChange.verify() + } + + fun `test local changes are saved even if not detected initially`() { + myRepo.`diverge feature and master`() + val localChange = LocalChange(myRepo, "new.txt").generate() + + object : GitTestingRebaseProcess(GitRebaseParams("master")) { + override fun getDirtyRoots(repositories: Collection): Collection { + return emptyList() + } + }.rebase() + + assertSuccessfulNotification("Rebased feature on master") + assertRebased(myRepo, "feature", "master") + assertNoRebaseInProgress(myRepo) + localChange.verify() + } + + fun `test local changes are not restored in case of error even if nothing was rebased`() { + myRepo.`diverge feature and master`() + LocalChange(myRepo, "new.txt", "content").generate() + + myFailingGit.setShouldFail { true } + + rebaseOnMaster() + + assertErrorNotification("Rebase Failed", + """ + Rebase failed with error: $UNKNOWN_ERROR_TEXT
+ Retry.
+ Note that some local changes were stashed before rebase. + """) + assertNoRebaseInProgress(myRepo) + myRepo.assertNoLocalChanges() + assertFalse(file("new.txt").exists()) + } + + fun `test critical error should show notification and not restore local changes`() { + myRepo.`diverge feature and master`() + LocalChange(myRepo, "new.txt", "content").generate() + myFailingGit.setShouldFail { true } + + rebaseOnMaster() + + `assert unknown error notification with link to stash`() + myRepo.assertNoLocalChanges() + } + + fun `test successful retry from notification on critical error restores local changes`() { + myRepo.`diverge feature and master`() + val localChange = LocalChange(myRepo, "new.txt", "content").generate() + + var attempt = 0 + myFailingGit.setShouldFail { attempt == 0 } + + val rebaseProcess = rebaseOnMaster() + + attempt++ + myVcsNotifier.lastNotification + + rebaseProcess.retry(false) + + assertNoRebaseInProgress(myRepo) + myRepo.`assert feature rebased on master`() + localChange.verify() + } + + fun `test local changes are restored after successful abort`() { + myRepo.`prepare simple conflict`() + val localChange = LocalChange(myRepo, "new.txt", "content").generate() + myVcsHelper.onMerge {} + myDialogManager.onMessage { Messages.YES } + + val rebaseProcess = rebaseOnMaster() + + `assert conflict not resolved notification with link to stash`() + + rebaseProcess.abort(myRepo, emptyList(), EmptyProgressIndicator()) + + assertNoRebaseInProgress(myRepo) + myRepo.`assert feature not rebased on master`() + localChange.verify() + } + + fun `test local changes are not restored after failed abort`() { + myRepo.`prepare simple conflict`() + LocalChange(myRepo, "new.txt", "content").generate() + myVcsHelper.onMerge {} + myDialogManager.onMessage { Messages.YES } + + val rebaseProcess = rebaseOnMaster() + + `assert conflict not resolved notification with link to stash`() + + myFailingGit.setShouldFail { true } + rebaseProcess.abort(myRepo, emptyList(), EmptyProgressIndicator()) + + myRepo.assertRebaseInProgress() + myRepo.`assert feature not rebased on master`() + myRepo.assertConflict("c.txt") + assertErrorNotification("Rebase Abort Failed", + """ + unknown error
+ $LOCAL_CHANGES_WARNING + """) + } + + // git rebase --continue should be either called from a commit dialog, either from the GitRebaseProcess. + // both should prepare the working tree themselves by adding all necessary changes to the index. + fun `test local changes should not be saved when continue rebase`() { + myRepo.`prepare simple conflict`() + `do nothing on merge`() + + rebaseOnMaster() + myRepo.assertConflict("c.txt") + + //manually resolve conflicts + resolveConflicts(myRepo) + file("c.txt").append("more changes after resolving") + // forget to git add afterwards + + val continueRebase = GitRebaseParams("master").withMode(GitRebaseParams.Mode.CONTINUE) + GitTestingRebaseProcess(continueRebase).rebase() + + assertErrorNotification("Rebase Failed", + """ + Rebase failed with error: c.txt: needs update + You must edit all merge conflicts + and then mark them as resolved using git add + You can retry or abort rebase. + """) + + myRepo.`assert feature not rebased on master`() + myRepo.assertRebaseInProgress() + } + + fun `test skipped commit`() { + build { + master { + 0("c.txt", "base") + 1("c.txt", "\nmaster") + } + feature(0) { + 2("c.txt", "feature", "commit to be skipped") + 3() + } + } + + val hash2skip = DvcsUtil.getShortHash(git("log -2 --pretty=%H").lines().get(1)) + + myVcsHelper.onMerge { + file("c.txt").write("base\nmaster") + resolveConflicts(myRepo) + } + + rebaseOnMaster() + + assertRebased(myRepo, "feature", "master") + assertNoRebaseInProgress(myRepo) + + assertSuccessfulNotification( + """ + Rebased feature on master
+ The following commit was skipped during rebase:
+ $hash2skip commit to be skipped + """) + } + + private fun build(f: RepoBuilder.() -> Unit) { + build(myRepo, f) + } + + private fun `do nothing on merge`() { + myVcsHelper.onMerge{} + } + + private open inner class GitTestingRebaseProcess(params: GitRebaseParams) : + GitRebaseProcess(myProject, listOf(myRepo), params, EmptyProgressIndicator()) { + override fun getDirtyRoots(repositories: Collection): Collection { + return if (myRepo.isDirty()) listOf(myRepo) else emptyList() + } + } + + private fun rebaseOnMaster() : GitRebaseProcess { + val rebaseProcess = GitTestingRebaseProcess(GitRebaseParams("master")) + rebaseProcess.rebase() + return rebaseProcess + } + + private fun `assert conflict not resolved notification`() { + assertWarningNotification("Rebase Suspended", + """ + You have to resolve the conflicts and continue rebase.
+ If you want to start from the beginning, you can abort rebase. + """) + } + + private fun `assert conflict not resolved notification with link to stash`() { + assertWarningNotification("Rebase Suspended", + """ + You have to resolve the conflicts and continue rebase.
+ If you want to start from the beginning, you can abort rebase.
+ $LOCAL_CHANGES_WARNING + """) + } + + private fun `assert unknown error notification`() { + assertErrorNotification("Rebase Failed", + """ + Rebase failed with error: $UNKNOWN_ERROR_TEXT
+ Retry. + """) + } + + private fun `assert unknown error notification with link to abort`() { + assertErrorNotification("Rebase Failed", + """ + Rebase failed with error: $UNKNOWN_ERROR_TEXT
+ You can retry or abort rebase. + """) + } + + private fun `assert unknown error notification with link to stash`() { + assertErrorNotification("Rebase Failed", + """ + Rebase failed with error: $UNKNOWN_ERROR_TEXT
+ Retry.
+ $LOCAL_CHANGES_WARNING + """) + } +} + diff --git a/plugins/git4idea/tests/git4idea/repo/GitRepositoryReaderTest.java b/plugins/git4idea/tests/git4idea/repo/GitRepositoryReaderTest.java index cefbdb7a6192..599bbd9b1001 100644 --- a/plugins/git4idea/tests/git4idea/repo/GitRepositoryReaderTest.java +++ b/plugins/git4idea/tests/git4idea/repo/GitRepositoryReaderTest.java @@ -1,3 +1,18 @@ +/* + * 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 git4idea.repo; import com.intellij.openapi.application.PluginPathManager; @@ -5,6 +20,7 @@ import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.io.FileUtilRt; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vcs.VcsTestUtil; +import com.intellij.testFramework.EdtTestUtil; import com.intellij.util.Function; import com.intellij.util.ThrowableRunnable; import com.intellij.util.containers.ContainerUtil; @@ -57,7 +73,7 @@ public class GitRepositoryReaderTest extends GitPlatformTest { @Override @Before public void setUp() throws Exception { - edt(new ThrowableRunnable() { + EdtTestUtil.runInEdtAndWait(new ThrowableRunnable() { @Override public void run() throws Exception { GitRepositoryReaderTest.super.setUp(); @@ -76,12 +92,12 @@ public class GitRepositoryReaderTest extends GitPlatformTest { } } finally { - edt(new ThrowableRunnable() { - @Override - public void run() throws Throwable { - GitRepositoryReaderTest.super.tearDown(); - } - }); + EdtTestUtil.runInEdtAndWait(new ThrowableRunnable() { + @Override + public void run() throws Throwable { + GitRepositoryReaderTest.super.tearDown(); + } + }); } } diff --git a/plugins/git4idea/tests/git4idea/test/GitExecutor.java b/plugins/git4idea/tests/git4idea/test/GitExecutor.java index bde7ca388677..3a952a0281a6 100644 --- a/plugins/git4idea/tests/git4idea/test/GitExecutor.java +++ b/plugins/git4idea/tests/git4idea/test/GitExecutor.java @@ -15,15 +15,19 @@ */ package git4idea.test; +import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vcs.Executor; import git4idea.repo.GitRepository; import org.jetbrains.annotations.NotNull; import java.io.File; +import java.io.IOException; import java.util.Arrays; import java.util.List; +import static org.junit.Assert.assertFalse; + /** * * @author Kirill Likhodedov @@ -116,6 +120,12 @@ public class GitExecutor extends Executor { return last(); } + @NotNull + public static String tac(@NotNull String file) { + touch(file, "content" + Math.random()); + return addCommit("touched " + file); + } + @NotNull public static String last() { return git("log -1 --pretty=%H"); @@ -141,4 +151,56 @@ public class GitExecutor extends Executor { } } + @NotNull + public static TestFile file(@NotNull String fileName) { + File f = child(fileName); + return new TestFile(f); + } + + public static class TestFile { + @NotNull private final File myFile; + + private TestFile(@NotNull File file) { + myFile = file; + } + + public TestFile append(@NotNull String content) throws IOException { + FileUtil.writeToFile(myFile, content.getBytes(), true); + return this; + } + + public TestFile write(@NotNull String content) throws IOException { + FileUtil.writeToFile(myFile, content.getBytes(), false); + return this; + } + + public TestFile create(@NotNull String content) throws IOException { + assertNotExists(); + FileUtil.writeToFile(myFile, content.getBytes(), false); + return this; + } + + public TestFile assertNotExists() { + assertFalse(myFile.exists()); + return this; + } + + public TestFile add() { + GitExecutor.add(myFile.getPath()); + return this; + } + + public TestFile commit() { + return commit("Some message"); + } + + public TestFile commit(String message) { + GitExecutor.commit(message); + return this; + } + + public boolean exists() { + return myFile.exists(); + } + } } diff --git a/plugins/git4idea/tests/git4idea/test/GitPlatformTest.java b/plugins/git4idea/tests/git4idea/test/GitPlatformTest.java index 83b448032a94..422220375c7d 100644 --- a/plugins/git4idea/tests/git4idea/test/GitPlatformTest.java +++ b/plugins/git4idea/tests/git4idea/test/GitPlatformTest.java @@ -25,6 +25,7 @@ import com.intellij.openapi.vcs.changes.ChangeListManager; import com.intellij.openapi.vcs.changes.VcsDirtyScopeManager; import com.intellij.openapi.vfs.VfsUtil; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.testFramework.EdtTestUtil; import com.intellij.testFramework.PlatformTestCase; import com.intellij.testFramework.TestLoggerFactory; import com.intellij.testFramework.vcs.AbstractVcsTestCase; @@ -72,7 +73,7 @@ public abstract class GitPlatformTest extends PlatformTestCase { checkTestRootIsEmpty(myTestRoot); - edt(new ThrowableRunnable() { + EdtTestUtil.runInEdtAndWait(new ThrowableRunnable() { @Override public void run() throws Exception { GitPlatformTest.super.setUp(); @@ -151,7 +152,7 @@ public abstract class GitPlatformTest extends PlatformTestCase { } finally { try { - edt(new ThrowableRunnable() { + EdtTestUtil.runInEdtAndWait(new ThrowableRunnable() { @Override public void run() throws Exception { GitPlatformTest.super.tearDown(); diff --git a/plugins/git4idea/tests/git4idea/test/GitTestUtil.java b/plugins/git4idea/tests/git4idea/test/GitTestUtil.java index 257cff8d4dc5..4244d9410e86 100644 --- a/plugins/git4idea/tests/git4idea/test/GitTestUtil.java +++ b/plugins/git4idea/tests/git4idea/test/GitTestUtil.java @@ -15,6 +15,8 @@ */ package git4idea.test; +import com.intellij.notification.Notification; +import com.intellij.notification.NotificationType; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.project.Project; @@ -43,6 +45,7 @@ import static com.intellij.openapi.vcs.Executor.mkdir; import static com.intellij.openapi.vcs.Executor.touch; import static git4idea.test.GitExecutor.*; import static junit.framework.Assert.assertNotNull; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assume.assumeTrue; @@ -125,6 +128,7 @@ public class GitTestUtil { } @SuppressWarnings("unchecked") + @NotNull public static T overrideService(@NotNull Project project, Class serviceInterface, Class serviceImplementation) { String key = serviceInterface.getName(); MutablePicoContainer picoContainer = (MutablePicoContainer) project.getPicoContainer(); @@ -134,6 +138,7 @@ public class GitTestUtil { } @SuppressWarnings("unchecked") + @NotNull public static T overrideService(Class serviceInterface, Class serviceImplementation) { String key = serviceInterface.getName(); MutablePicoContainer picoContainer = (MutablePicoContainer) ApplicationManager.getApplication().getPicoContainer(); @@ -158,4 +163,23 @@ public class GitTestUtil { addCommit("some message"); return last(); } + + public static void assertNotification(@NotNull NotificationType type, + @NotNull String title, + @NotNull String content, + @NotNull Notification actual) { + assertEquals("Incorrect type of notification: " + tos(actual), type, actual.getType()); + assertEquals(title, actual.getTitle()); + assertEquals(cleanupForAssertion(content), cleanupForAssertion(actual.getContent())); + } + + @NotNull + public static String cleanupForAssertion(@NotNull String content) { + return content.replace("
", "\n").replace("\n", " ").replaceAll("[ ]{2,}", " ").replaceAll(" href='[^']*'", "").trim(); + } + + @NotNull + private static String tos(@NotNull Notification notification) { + return notification.getTitle() + "|" + notification.getContent(); + } } diff --git a/plugins/git4idea/tests/git4idea/test/MockVcsHelper.java b/plugins/git4idea/tests/git4idea/test/MockVcsHelper.java deleted file mode 100644 index 15bc061c7d29..000000000000 --- a/plugins/git4idea/tests/git4idea/test/MockVcsHelper.java +++ /dev/null @@ -1,239 +0,0 @@ -/* - * Copyright 2000-2014 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 git4idea.test; - -import com.intellij.ide.errorTreeView.HotfixData; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.vcs.*; -import com.intellij.openapi.vcs.annotate.AnnotationProvider; -import com.intellij.openapi.vcs.annotate.FileAnnotation; -import com.intellij.openapi.vcs.changes.Change; -import com.intellij.openapi.vcs.changes.CommitResultHandler; -import com.intellij.openapi.vcs.changes.LocalChangeList; -import com.intellij.openapi.vcs.history.VcsFileRevision; -import com.intellij.openapi.vcs.history.VcsHistoryProvider; -import com.intellij.openapi.vcs.history.VcsRevisionNumber; -import com.intellij.openapi.vcs.merge.MergeDialogCustomizer; -import com.intellij.openapi.vcs.merge.MergeProvider; -import com.intellij.openapi.vcs.versionBrowser.ChangeBrowserSettings; -import com.intellij.openapi.vcs.versionBrowser.CommittedChangeList; -import com.intellij.openapi.vfs.VirtualFile; -import org.jetbrains.annotations.Nls; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.awt.*; -import java.io.File; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Map; - -public class MockVcsHelper extends AbstractVcsHelper { - private volatile boolean myCommitDialogShown; - private volatile boolean myMergeDialogShown; - - private CommitHandler myCommitHandler; - private MergeHandler myMergeHandler; - - public MockVcsHelper(@NotNull Project project) { - super(project); - } - - @Override - public void showErrors(List abstractVcsExceptions, @NotNull String tabDisplayName) { - throw new UnsupportedOperationException(); - } - - @Override - public void showErrors(Map> exceptionGroups, @NotNull String tabDisplayName) { - throw new UnsupportedOperationException(); - } - - @Override - public List runTransactionRunnable(AbstractVcs vcs, TransactionRunnable runnable, Object vcsParameters) { - throw new UnsupportedOperationException(); - } - - @Override - public void showAnnotation(FileAnnotation annotation, VirtualFile file, AbstractVcs vcs, int line) { - throw new UnsupportedOperationException(); - } - - @Override - public void showAnnotation(FileAnnotation annotation, VirtualFile file, AbstractVcs vcs) { - throw new UnsupportedOperationException(); - } - - @Override - public void showDifferences(VcsFileRevision cvsVersionOn, VcsFileRevision cvsVersionOn1, File file) { - throw new UnsupportedOperationException(); - } - - @Override - public void showChangesListBrowser(CommittedChangeList changelist, @Nls String title) { - throw new UnsupportedOperationException(); - } - - @Override - public void showChangesBrowser(List changelists) { - throw new UnsupportedOperationException(); - } - - @Override - public void showChangesBrowser(List changelists, @Nls String title) { - throw new UnsupportedOperationException(); - } - - @Override - public void showChangesBrowser(CommittedChangesProvider provider, - RepositoryLocation location, - @Nls String title, - @Nullable Component parent) { - throw new UnsupportedOperationException(); - } - - @Override - public void showWhatDiffersBrowser(@Nullable Component parent, Collection changes, @Nls String title) { - throw new UnsupportedOperationException(); - } - - @Override - public T chooseCommittedChangeList(@NotNull CommittedChangesProvider provider, - RepositoryLocation location) { - throw new UnsupportedOperationException(); - } - - @Override - public void openCommittedChangesTab(AbstractVcs vcs, VirtualFile root, ChangeBrowserSettings settings, int maxCount, String title) { - throw new UnsupportedOperationException(); - } - - @Override - public void openCommittedChangesTab(CommittedChangesProvider provider, - RepositoryLocation location, - ChangeBrowserSettings settings, - int maxCount, - String title) { - throw new UnsupportedOperationException(); - } - - @NotNull - @Override - public List showMergeDialog(List files, - MergeProvider provider, - @NotNull MergeDialogCustomizer mergeDialogCustomizer) { - myMergeDialogShown = true; - if (myMergeHandler != null) { - myMergeHandler.showMergeDialog(); - } - return Collections.emptyList(); - } - - public boolean mergeDialogWasShown() { - return myMergeDialogShown; - } - - @Override - public void showFileHistory(@NotNull VcsHistoryProvider historyProvider, @NotNull FilePath path, @NotNull AbstractVcs vcs, String repositoryPath) { - throw new UnsupportedOperationException(); - } - - @Override - public void showFileHistory(@NotNull VcsHistoryProvider historyProvider, - AnnotationProvider annotationProvider, - @NotNull FilePath path, - String repositoryPath, - @NotNull AbstractVcs vcs) { - throw new UnsupportedOperationException(); - } - - @Override - public void showRollbackChangesDialog(List changes) { - throw new UnsupportedOperationException(); - } - - @Override - public Collection selectFilesToProcess(List files, - String title, - @Nullable String prompt, - String singleFileTitle, - String singleFilePromptTemplate, - VcsShowConfirmationOption confirmationOption) { - throw new UnsupportedOperationException(); - } - - @Override - public Collection selectFilePathsToProcess(List files, - String title, - @Nullable String prompt, - String singleFileTitle, - String singleFilePromptTemplate, - VcsShowConfirmationOption confirmationOption) { - throw new UnsupportedOperationException(); - } - - @Override - public boolean commitChanges(@NotNull Collection changes, @NotNull LocalChangeList initialChangeList, - @NotNull String commitMessage, @Nullable CommitResultHandler customResultHandler) { - myCommitDialogShown = true; - if (myCommitHandler != null) { - boolean success = myCommitHandler.commit(commitMessage); - if (customResultHandler != null) { - if (success) { - customResultHandler.onSuccess(commitMessage); - } - else { - customResultHandler.onFailure(); - } - } - return success; - } - if (customResultHandler != null) { - customResultHandler.onFailure(); - } - return false; - } - - public void registerHandler(CommitHandler handler) { - myCommitHandler = handler; - } - - public void registerHandler(MergeHandler handler) { - myMergeHandler = handler; - } - - public boolean commitDialogWasShown() { - return myCommitDialogShown; - } - - public interface CommitHandler { - boolean commit(String commitMessage); - } - - public interface MergeHandler { - void showMergeDialog(); - } - - @Override - public void loadAndShowCommittedChangesDetails(@NotNull Project project, - @NotNull VcsRevisionNumber revision, - @NotNull VirtualFile file, - @NotNull VcsKey key, - @Nullable RepositoryLocation location, - boolean local) { - } -} diff --git a/plugins/git4idea/tests/git4idea/test/MockVcsHelper.kt b/plugins/git4idea/tests/git4idea/test/MockVcsHelper.kt new file mode 100644 index 000000000000..9d559f9d354f --- /dev/null +++ b/plugins/git4idea/tests/git4idea/test/MockVcsHelper.kt @@ -0,0 +1,180 @@ +/* + * Copyright 2000-2014 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 git4idea.test + +import com.intellij.ide.errorTreeView.HotfixData +import com.intellij.openapi.project.Project +import com.intellij.openapi.vcs.* +import com.intellij.openapi.vcs.annotate.AnnotationProvider +import com.intellij.openapi.vcs.annotate.FileAnnotation +import com.intellij.openapi.vcs.changes.Change +import com.intellij.openapi.vcs.changes.CommitResultHandler +import com.intellij.openapi.vcs.changes.LocalChangeList +import com.intellij.openapi.vcs.history.VcsFileRevision +import com.intellij.openapi.vcs.history.VcsHistoryProvider +import com.intellij.openapi.vcs.history.VcsRevisionNumber +import com.intellij.openapi.vcs.merge.MergeDialogCustomizer +import com.intellij.openapi.vcs.merge.MergeProvider +import com.intellij.openapi.vcs.versionBrowser.ChangeBrowserSettings +import com.intellij.openapi.vcs.versionBrowser.CommittedChangeList +import com.intellij.openapi.vfs.VirtualFile +import java.awt.Component +import java.io.File + +public class MockVcsHelper(project: Project) : AbstractVcsHelper(project) { + @Volatile private var myCommitDialogShown: Boolean = false + @Volatile private var myMergeDialogShown: Boolean = false + @Volatile private var myMergeDelegate: () -> Unit = { throw IllegalStateException() } + @Volatile private var myCommitDelegate: (String) -> Boolean = { throw IllegalStateException() } + + override fun runTransactionRunnable(vcs: AbstractVcs<*>?, runnable: TransactionRunnable?, vcsParameters: Any?): MutableList? { + throw UnsupportedOperationException() + } + + override fun showAnnotation(annotation: FileAnnotation?, file: VirtualFile?, vcs: AbstractVcs<*>?) { + throw UnsupportedOperationException() + } + + override fun showAnnotation(annotation: FileAnnotation?, file: VirtualFile?, vcs: AbstractVcs<*>?, line: Int) { + throw UnsupportedOperationException() + } + + override fun showChangesBrowser(provider: CommittedChangesProvider<*, *>?, location: RepositoryLocation?, title: String?, parent: Component?) { + throw UnsupportedOperationException() + } + + override fun openCommittedChangesTab(vcs: AbstractVcs<*>?, root: VirtualFile?, settings: ChangeBrowserSettings?, maxCount: Int, title: String?) { + throw UnsupportedOperationException() + } + + override fun openCommittedChangesTab(provider: CommittedChangesProvider<*, *>?, location: RepositoryLocation?, settings: ChangeBrowserSettings?, maxCount: Int, title: String?) { + throw UnsupportedOperationException() + } + + override fun showFileHistory(historyProvider: VcsHistoryProvider, path: FilePath, vcs: AbstractVcs<*>, repositoryPath: String?) { + throw UnsupportedOperationException() + } + + override fun showFileHistory(historyProvider: VcsHistoryProvider, annotationProvider: AnnotationProvider?, path: FilePath, repositoryPath: String?, vcs: AbstractVcs<*>) { + throw UnsupportedOperationException() + } + + override fun showErrors(abstractVcsExceptions: List, tabDisplayName: String) { + throw UnsupportedOperationException() + } + + override fun showErrors(exceptionGroups: Map>, tabDisplayName: String) { + throw UnsupportedOperationException() + } + + override fun showDifferences(cvsVersionOn: VcsFileRevision, cvsVersionOn1: VcsFileRevision, file: File) { + throw UnsupportedOperationException() + } + + override fun showChangesListBrowser(changelist: CommittedChangeList, title: String) { + throw UnsupportedOperationException() + } + + override fun showChangesBrowser(changelists: List) { + throw UnsupportedOperationException() + } + + override fun showChangesBrowser(changelists: List, title: String) { + throw UnsupportedOperationException() + } + + override fun showWhatDiffersBrowser(parent: Component?, changes: Collection, title: String) { + throw UnsupportedOperationException() + } + + override fun chooseCommittedChangeList(provider: CommittedChangesProvider, location: RepositoryLocation): T? { + throw UnsupportedOperationException() + } + + override fun showRollbackChangesDialog(changes: List) { + throw UnsupportedOperationException() + } + + override fun selectFilesToProcess(files: List, title: String, prompt: String?, singleFileTitle: String, singleFilePromptTemplate: String, confirmationOption: VcsShowConfirmationOption): Collection? { + throw UnsupportedOperationException() + } + + override fun selectFilePathsToProcess(files: List, title: String, prompt: String?, singleFileTitle: String, singleFilePromptTemplate: String, confirmationOption: VcsShowConfirmationOption): Collection? { + throw UnsupportedOperationException() + } + + override fun loadAndShowCommittedChangesDetails(project: Project, revision: VcsRevisionNumber, file: VirtualFile, key: VcsKey, location: RepositoryLocation?, local: Boolean) { + throw UnsupportedOperationException() + } + + override fun showMergeDialog(files: List, provider: MergeProvider, mergeDialogCustomizer: MergeDialogCustomizer): List { + myMergeDialogShown = true + myMergeDelegate() + return emptyList() + } + + override fun commitChanges(changes: Collection, initialChangeList: LocalChangeList, commitMessage: String, customResultHandler: CommitResultHandler?): Boolean { + myCommitDialogShown = true + + val success = myCommitDelegate(commitMessage) + if (customResultHandler != null) { + if (success) { + customResultHandler.onSuccess(commitMessage) + } + else { + customResultHandler.onFailure() + } + } + return success + } + + public fun mergeDialogWasShown(): Boolean { + return myMergeDialogShown + } + + public fun commitDialogWasShown(): Boolean { + return myCommitDialogShown + } + + public fun onMerge(delegate : () -> Unit) { + myMergeDelegate = delegate + } + + public fun onCommit(delegate : (String) -> Boolean) { + myCommitDelegate = delegate + } + + @Deprecated("use onCommit") + public fun registerHandler(handler: CommitHandler) { + myCommitDelegate = { handler.commit(it) } + } + + @Deprecated("use onMerge") + public fun registerHandler(handler: MergeHandler) { + myMergeDelegate = { handler.showMergeDialog() } + } + + @Deprecated("use onCommit") + public interface CommitHandler { + public fun commit(commitMessage: String): Boolean + } + + @Deprecated("use onMerge") + public interface MergeHandler { + public fun showMergeDialog() + } + +} diff --git a/plugins/git4idea/tests/git4idea/test/RepoBuilder.kt b/plugins/git4idea/tests/git4idea/test/RepoBuilder.kt new file mode 100644 index 000000000000..9114d5642b74 --- /dev/null +++ b/plugins/git4idea/tests/git4idea/test/RepoBuilder.kt @@ -0,0 +1,98 @@ +/* + * 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 git4idea.test + +import com.intellij.openapi.vcs.Executor.append +import com.intellij.openapi.vcs.Executor.touch +import git4idea.repo.GitRepository +import git4idea.test.GitExecutor.addCommit +import git4idea.test.GitExecutor.cd +import git4idea.test.GitExecutor.git +import java.io.File +import java.util.* + +public fun build(repo: GitRepository, f: RepoBuilder.() -> Unit) { + val builder = RepoBuilder(repo) + builder.f() + builder.build() +} + +public class RepoBuilder(val repo: GitRepository) { + init { + cd(repo) + } + + public val master: String = "master" + public val feature: String = "feature" + + private val myCommitIndices = HashMap() + private var myCurrentBranch : String = master + + fun String.invoke(commands: RepoBuilder.() -> Unit) { // switch branch + createOrCheckout(this) + myCurrentBranch = this + commands() + } + + private fun createOrCheckout(branch: String) { + if (isFresh()) { + if (branch != "master") { + git("checkout -b $branch") + } + } + else { + if (git("branch").splitBy("\n").map({ it.replace("*", "") }).contains(branch)) { + git("checkout $branch") + } + else { + git("checkout -b $branch") + } + } + } + + private fun isFresh(): Boolean = myCommitIndices.isEmpty() + + fun String.invoke(fromCommit: Int, commands: RepoBuilder.() -> Unit) { + git("checkout -b $this ${myCommitIndices[fromCommit]}") + myCurrentBranch = this + commands() + } + + fun Int.invoke(file: String = this.toString() + ".txt", + content: String = "More content in $myCurrentBranch: ${randomHash()}", + commitMessage: String = if (File(repo.getRoot().getPath(), file).exists()) "Created $file" else "Modified $file") { + modifyAndCommit(this, file, content, commitMessage) + } + + fun build() { + repo.update() + } + + private fun modifyAndCommit(id: Int, file: String, content: String, commitMessage: String) { + val hash: String + if (File(repo.getRoot().getPath(), file).exists()) { + append(file, content) + } + else { + touch(file, content) + } + hash = addCommit(commitMessage) + assert(!myCommitIndices.containsKey(id)) { "commit $id is already in the map!" } + myCommitIndices.put(id, hash) + } +} + +fun randomHash() = Integer.toHexString(Random().nextInt()) diff --git a/plugins/git4idea/tests/git4idea/test/TestGit.kt b/plugins/git4idea/tests/git4idea/test/TestGit.kt new file mode 100644 index 000000000000..d50186d39efe --- /dev/null +++ b/plugins/git4idea/tests/git4idea/test/TestGit.kt @@ -0,0 +1,45 @@ +/* + * 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 git4idea.test + +import git4idea.branch.GitRebaseParams +import git4idea.commands.GitCommandResult +import git4idea.commands.GitImpl +import git4idea.commands.GitLineHandlerListener +import git4idea.repo.GitRepository + +/** + * Any unknown error that could be returned by Git. + */ +public val UNKNOWN_ERROR_TEXT: String = "unknown error" + +public class TestGitImpl : GitImpl() { + + private var myShouldFail: (GitRepository) -> Boolean = { false } + + override fun rebase(repository: GitRepository, params: GitRebaseParams, vararg listeners: GitLineHandlerListener): GitCommandResult { + return if (myShouldFail(repository)) + GitCommandResult(false, 128, listOf("fatal: error: $UNKNOWN_ERROR_TEXT"), emptyList(), null) + else + super.rebase(repository, params, *listeners) + } + + public fun setShouldFail(shouldFail: (GitRepository) -> Boolean) { + myShouldFail = shouldFail + } +} + + diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/dgm/DGMMemberContributor.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/dgm/DGMMemberContributor.java index e265644d9191..53e05009bcfc 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/dgm/DGMMemberContributor.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/dgm/DGMMemberContributor.java @@ -17,17 +17,19 @@ package org.jetbrains.plugins.groovy.dgm; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Couple; -import com.intellij.psi.PsiClass; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiType; -import com.intellij.psi.ResolveState; +import com.intellij.psi.*; import com.intellij.psi.scope.PsiScopeProcessor; import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.psi.util.CachedValueProvider; +import com.intellij.psi.util.CachedValuesManager; +import com.intellij.psi.util.PsiModificationTracker; +import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; -import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyPsiManager; +import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.lang.resolve.NonCodeMembersContributor; import java.util.List; +import java.util.concurrent.ConcurrentMap; /** * Provides members from extension classes referenced in {@code META-INF/services/org.codehaus.groovy.runtime.ExtensionModule}. @@ -40,34 +42,49 @@ public class DGMMemberContributor extends NonCodeMembersContributor { @NotNull PsiScopeProcessor processor, @NotNull PsiElement place, @NotNull ResolveState state) { - Project project = place.getProject(); - GlobalSearchScope resolveScope = place.getResolveScope(); - GroovyPsiManager groovyPsiManager = GroovyPsiManager.getInstance(project); + final Project project = place.getProject(); - Couple> extensions = GroovyExtensionProvider.getInstance(project).collectExtensions(resolveScope); - - List instanceCategories = extensions.getFirst(); - List staticCategories = extensions.getSecond(); - - if (!processCategories(qualifierType, processor, state, project, resolveScope, groovyPsiManager, instanceCategories, false)) return; - if (!processCategories(qualifierType, processor, state, project, resolveScope, groovyPsiManager, staticCategories, true)) return; - } - - private static boolean processCategories(PsiType qualifierType, - PsiScopeProcessor processor, - @NotNull ResolveState state, - Project project, - GlobalSearchScope resolveScope, - GroovyPsiManager groovyPsiManager, List instanceCategories, - boolean isStatic) { - for (String category : instanceCategories) { - PsiClass clazz = groovyPsiManager.findClassWithCache(category, resolveScope); - if (clazz != null) { - if (!GdkMethodHolder.getHolderForClass(clazz, isStatic, resolveScope).processMethods(processor, state, qualifierType, project)) { - return false; + ConcurrentMap> map = CachedValuesManager.getManager(project).getCachedValue( + project, new CachedValueProvider>>() { + @Nullable + @Override + public Result>> compute() { + ConcurrentMap> value = ContainerUtil.createConcurrentSoftValueMap(); + return Result.create(value, PsiModificationTracker.MODIFICATION_COUNT); } + }); + + GlobalSearchScope scope = place.getResolveScope(); + List gdkMethods = map.get(scope); + if (gdkMethods == null) { + map.put(scope, gdkMethods = calcGdkMethods(project, scope)); + } + + for (GdkMethodHolder holder : gdkMethods) { + if (!holder.processMethods(processor, state, qualifierType, project)) { + return; } } - return true; + } + + @NotNull + private static List calcGdkMethods(Project project, GlobalSearchScope resolveScope) { + List gdkMethods = ContainerUtil.newArrayList(); + + JavaPsiFacade facade = JavaPsiFacade.getInstance(project); + Couple> extensions = GroovyExtensionProvider.getInstance(project).collectExtensions(resolveScope); + for (String category : extensions.getFirst()) { + PsiClass clazz = facade.findClass(category, resolveScope); + if (clazz != null) { + gdkMethods.add(GdkMethodHolder.getHolderForClass(clazz, false, resolveScope)); + } + } + for (String category : extensions.getSecond()) { + PsiClass clazz = facade.findClass(category, resolveScope); + if (clazz != null) { + gdkMethods.add(GdkMethodHolder.getHolderForClass(clazz, true, resolveScope)); + } + } + return gdkMethods; } } diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyPsiManager.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyPsiManager.java index d0fd0c22c8fe..a2b367459739 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyPsiManager.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyPsiManager.java @@ -61,7 +61,7 @@ public class GroovyPsiManager { private final Map myArrayClass = new HashMap(); private final ConcurrentMap myCalculatedTypes = ContainerUtil.createConcurrentWeakMap(); - private final ConcurrentMap myCompileStatic = ContainerUtil.newConcurrentMap(); + private final ConcurrentMap myCompileStatic = ContainerUtil.createConcurrentWeakMap(); private static final RecursionGuard ourGuard = RecursionManager.createGuard("groovyPsiManager"); diff --git a/plugins/java-i18n/src/com/intellij/codeInspection/duplicateStringLiteral/DuplicateStringLiteralInspection.java b/plugins/java-i18n/src/com/intellij/codeInspection/duplicateStringLiteral/DuplicateStringLiteralInspection.java index 3c6a35737812..b696de3aa241 100644 --- a/plugins/java-i18n/src/com/intellij/codeInspection/duplicateStringLiteral/DuplicateStringLiteralInspection.java +++ b/plugins/java-i18n/src/com/intellij/codeInspection/duplicateStringLiteral/DuplicateStringLiteralInspection.java @@ -21,7 +21,6 @@ import com.intellij.codeInspection.*; import com.intellij.codeInspection.ex.BaseLocalInspectionTool; import com.intellij.codeInspection.i18n.JavaI18nUtil; import com.intellij.lang.java.JavaLanguage; -import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; @@ -59,7 +58,6 @@ import java.awt.event.ActionListener; import java.util.*; public class DuplicateStringLiteralInspection extends BaseLocalInspectionTool { - private static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.DuplicateStringLiteralInspection"); @SuppressWarnings({"WeakerAccess"}) public int MIN_STRING_LENGTH = 5; @SuppressWarnings({"WeakerAccess"}) public boolean IGNORE_PROPERTY_KEYS = false; @NonNls private static final String BR = "
"; @@ -101,8 +99,7 @@ public class DuplicateStringLiteralInspection extends BaseLocalInspectionTool { final boolean isOnTheFly) { Object value = originalExpression.getValue(); if (!(value instanceof String)) return; - final Project project = holder.getProject(); - if (!shouldCheck(project, originalExpression)) return; + if (!shouldCheck(originalExpression)) return; final String stringToFind = (String)value; if (stringToFind.length() == 0) return; final GlobalSearchScope scope = GlobalSearchScope.projectScope(originalExpression.getProject()); @@ -152,7 +149,7 @@ public class DuplicateStringLiteralInspection extends BaseLocalInspectionTool { PsiElement element = file.findElementAt(offset); if (element == null || !(element.getParent() instanceof PsiLiteralExpression)) return true; PsiLiteralExpression expression = (PsiLiteralExpression)element.getParent(); - if (expression != originalExpression && Comparing.equal(stringToFind, expression.getValue()) && shouldCheck(project, expression)) { + if (expression != originalExpression && Comparing.equal(stringToFind, expression.getValue()) && shouldCheck(expression)) { foundExpr.add(expression); } return true; @@ -215,8 +212,8 @@ public class DuplicateStringLiteralInspection extends BaseLocalInspectionTool { holder.registerProblem(originalExpression, msg, ProblemHighlightType.GENERIC_ERROR_OR_WARNING, array); } - private boolean shouldCheck(@NotNull Project project, @NotNull PsiLiteralExpression expression) { - if (IGNORE_PROPERTY_KEYS && JavaI18nUtil.mustBePropertyKey(project, expression, new THashMap())) return false; + private boolean shouldCheck(@NotNull PsiLiteralExpression expression) { + if (IGNORE_PROPERTY_KEYS && JavaI18nUtil.mustBePropertyKey(expression, new THashMap())) return false; return !SuppressManager.isSuppressedInspectionName(expression); } diff --git a/plugins/java-i18n/src/com/intellij/codeInspection/i18n/I18nInspection.java b/plugins/java-i18n/src/com/intellij/codeInspection/i18n/I18nInspection.java index c39f607ec845..986e49d272dd 100644 --- a/plugins/java-i18n/src/com/intellij/codeInspection/i18n/I18nInspection.java +++ b/plugins/java-i18n/src/com/intellij/codeInspection/i18n/I18nInspection.java @@ -568,11 +568,11 @@ public class I18nInspection extends BaseLocalInspectionTool { return false; } - if (JavaI18nUtil.isPassedToAnnotatedParam(project, expression, AnnotationUtil.NON_NLS, new HashMap(), nonNlsTargets)) { + if (JavaI18nUtil.isPassedToAnnotatedParam(expression, AnnotationUtil.NON_NLS, new HashMap(), nonNlsTargets)) { return false; } - if (isInNonNlsCall(project, expression, nonNlsTargets)) { + if (isInNonNlsCall(expression, nonNlsTargets)) { return false; } @@ -580,11 +580,11 @@ public class I18nInspection extends BaseLocalInspectionTool { return false; } - if (isPassedToNonNlsVariable(project, expression, nonNlsTargets)) { + if (isPassedToNonNlsVariable(expression, nonNlsTargets)) { return false; } - if (JavaI18nUtil.mustBePropertyKey(project, expression, new HashMap())) { + if (JavaI18nUtil.mustBePropertyKey(expression, new HashMap())) { return false; } @@ -678,10 +678,9 @@ public class I18nInspection extends BaseLocalInspectionTool { || isPackageNonNls(psiPackage.getParentPackage()); } - private boolean isPassedToNonNlsVariable(@NotNull Project project, - @NotNull PsiLiteralExpression expression, + private boolean isPassedToNonNlsVariable(@NotNull PsiLiteralExpression expression, final Set nonNlsTargets) { - PsiExpression toplevel = JavaI18nUtil.getToplevelExpression(project, expression); + PsiExpression toplevel = JavaI18nUtil.getTopLevelExpression(expression); PsiVariable var = null; if (toplevel instanceof PsiAssignmentExpression) { PsiExpression lExpression = ((PsiAssignmentExpression)toplevel).getLExpression(); @@ -785,8 +784,9 @@ public class I18nInspection extends BaseLocalInspectionTool { return false; } - private static boolean isInNonNlsCall(@NotNull Project project, @NotNull PsiExpression expression, final Set nonNlsTargets) { - expression = JavaI18nUtil.getToplevelExpression(project, expression); + private static boolean isInNonNlsCall(@NotNull PsiExpression expression, + final Set nonNlsTargets) { + expression = JavaI18nUtil.getTopLevelExpression(expression); final PsiElement parent = expression.getParent(); if (parent instanceof PsiExpressionList) { final PsiElement grParent = parent.getParent(); diff --git a/plugins/java-i18n/src/com/intellij/codeInspection/i18n/InvalidPropertyKeyInspection.java b/plugins/java-i18n/src/com/intellij/codeInspection/i18n/InvalidPropertyKeyInspection.java index 9017e6bc3765..0e2e5d0a6485 100644 --- a/plugins/java-i18n/src/com/intellij/codeInspection/i18n/InvalidPropertyKeyInspection.java +++ b/plugins/java-i18n/src/com/intellij/codeInspection/i18n/InvalidPropertyKeyInspection.java @@ -219,7 +219,7 @@ public class InvalidPropertyKeyInspection extends BaseJavaLocalInspectionTool { else if (expression.getParent() instanceof PsiExpressionList && expression.getParent().getParent() instanceof PsiMethodCallExpression) { final Map annotationParams = new HashMap(); annotationParams.put(AnnotationUtil.PROPERTY_KEY_RESOURCE_BUNDLE_PARAMETER, null); - if (!JavaI18nUtil.mustBePropertyKey(myManager.getProject(), expression, annotationParams)) return; + if (!JavaI18nUtil.mustBePropertyKey(expression, annotationParams)) return; final SortedSet paramsCount = JavaI18nUtil.getPropertyValueParamsCount(expression, resourceBundleName.get()); if (paramsCount.isEmpty() || (paramsCount.size() != 1 && resourceBundleName.get() == null)) { diff --git a/plugins/java-i18n/src/com/intellij/codeInspection/i18n/JavaI18nUtil.java b/plugins/java-i18n/src/com/intellij/codeInspection/i18n/JavaI18nUtil.java index 8d3e16047586..3fd56f225c41 100644 --- a/plugins/java-i18n/src/com/intellij/codeInspection/i18n/JavaI18nUtil.java +++ b/plugins/java-i18n/src/com/intellij/codeInspection/i18n/JavaI18nUtil.java @@ -25,7 +25,6 @@ import com.intellij.lang.properties.references.I18nUtil; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Key; -import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.TextRange; import com.intellij.psi.*; @@ -68,8 +67,7 @@ public class JavaI18nUtil extends I18nUtil { return psiElement.getTextRange(); } - public static boolean mustBePropertyKey(@NotNull Project project, - @NotNull PsiExpression expression, + public static boolean mustBePropertyKey(@NotNull PsiExpression expression, @NotNull Map annotationAttributeValues) { final PsiElement parent = expression.getParent(); if (parent instanceof PsiVariable) { @@ -78,15 +76,14 @@ public class JavaI18nUtil extends I18nUtil { return processAnnotationAttributes(annotationAttributeValues, annotation); } } - return isPassedToAnnotatedParam(project, expression, AnnotationUtil.PROPERTY_KEY, annotationAttributeValues, null); + return isPassedToAnnotatedParam(expression, AnnotationUtil.PROPERTY_KEY, annotationAttributeValues, null); } - static boolean isPassedToAnnotatedParam(@NotNull Project project, - @NotNull PsiExpression expression, + static boolean isPassedToAnnotatedParam(@NotNull PsiExpression expression, final String annFqn, @Nullable Map annotationAttributeValues, @Nullable final Set nonNlsTargets) { - expression = getToplevelExpression(project, expression); + expression = getTopLevelExpression(expression); final PsiElement parent = expression.getParent(); if (!(parent instanceof PsiExpressionList)) return false; @@ -117,49 +114,47 @@ public class JavaI18nUtil extends I18nUtil { return false; } - private static final Key>> TOP_LEVEL_EXPRESSION = Key.create("TOP_LEVEL_EXPRESSION"); - private static final ParameterizedCachedValueProvider> TOP_LEVEL_PROVIDER = - new ParameterizedCachedValueProvider>() { - @Override - public CachedValueProvider.Result compute(Pair pair) { - PsiExpression param = pair.second; - Project project = pair.first; - PsiExpression topLevel = getTopLevel(project, param); - ParameterizedCachedValue> cachedValue = param.getUserData(TOP_LEVEL_EXPRESSION); - assert cachedValue != null; - int i = 0; - for (PsiElement element = param; element != topLevel; element = element.getParent(), i++) { - if (i % 10 == 0) { // optimization: store up link to the top level expression in each 10nth element - element.putUserData(TOP_LEVEL_EXPRESSION, cachedValue); - } - } - return CachedValueProvider.Result.create(topLevel, PsiManager.getInstance(project).getModificationTracker()); - } - }; + private static final Key> TOP_LEVEL_EXPRESSION = Key.create("TOP_LEVEL_EXPRESSION"); @NotNull - static PsiExpression getToplevelExpression(@NotNull final Project project, @NotNull final PsiExpression expression) { + static PsiExpression getTopLevelExpression(@NotNull final PsiExpression expression) { if (expression instanceof PsiBinaryExpression || expression.getParent() instanceof PsiBinaryExpression) { //can be large, cache - return CachedValuesManager.getManager(project).getParameterizedCachedValue(expression, TOP_LEVEL_EXPRESSION, TOP_LEVEL_PROVIDER, true, - Pair.create(project, expression)); + CachedValue cachedValue = expression.getUserData(TOP_LEVEL_EXPRESSION); + if (cachedValue == null) { + expression.putUserData(TOP_LEVEL_EXPRESSION, cachedValue = CachedValuesManager.getManager(expression.getProject()).createCachedValue(new CachedValueProvider() { + @Nullable + @Override + public Result compute() { + PsiExpression topLevel = getTopLevel(expression); + CachedValue cachedValue = expression.getUserData(TOP_LEVEL_EXPRESSION); + assert cachedValue != null; + int i = 0; + for (PsiElement element = expression; element != topLevel; element = element.getParent(), i++) { + if (i % 10 == 0) { // optimization: store up link to the top level expression in each 10nth element + element.putUserData(TOP_LEVEL_EXPRESSION, cachedValue); + } + } + return Result.create(topLevel, expression, PsiModificationTracker.MODIFICATION_COUNT); + } + }, false)); + } + return cachedValue.getValue(); } - return getTopLevel(project, expression); + return getTopLevel(expression); } @NotNull - private static PsiExpression getTopLevel(Project project, @NotNull PsiExpression expression) { - int i = 0; + private static PsiExpression getTopLevel(@NotNull PsiExpression expression) { while (expression.getParent() instanceof PsiExpression) { - i++; final PsiExpression parent = (PsiExpression)expression.getParent(); if (parent instanceof PsiConditionalExpression && ((PsiConditionalExpression)parent).getCondition() == expression) break; expression = parent; if (expression instanceof PsiAssignmentExpression) break; - if (i > 10 && expression instanceof PsiBinaryExpression) { - ParameterizedCachedValue> value = expression.getUserData(TOP_LEVEL_EXPRESSION); - if (value != null && value.hasUpToDateValue()) { - return getToplevelExpression(project, expression); // optimization: use caching for big hierarchies + if (expression instanceof PsiBinaryExpression) { + CachedValue value = expression.getUserData(TOP_LEVEL_EXPRESSION); + if (value != null) { + return value.getValue(); // optimization: use caching for big hierarchies } } } @@ -233,7 +228,7 @@ public class JavaI18nUtil extends I18nUtil { @NotNull Ref outResourceBundle) { final HashMap annotationAttributeValues = new HashMap(); annotationAttributeValues.put(AnnotationUtil.PROPERTY_KEY_RESOURCE_BUNDLE_PARAMETER, null); - if (mustBePropertyKey(project, expression, annotationAttributeValues)) { + if (mustBePropertyKey(expression, annotationAttributeValues)) { final Object resourceBundleName = annotationAttributeValues.get(AnnotationUtil.PROPERTY_KEY_RESOURCE_BUNDLE_PARAMETER); if (!(resourceBundleName instanceof PsiExpression)) { return false; diff --git a/plugins/java-i18n/src/com/intellij/codeInspection/i18n/folding/I18nMessageGotoDeclarationHandler.java b/plugins/java-i18n/src/com/intellij/codeInspection/i18n/folding/I18nMessageGotoDeclarationHandler.java index 155d83767f8b..ac7897a85a23 100644 --- a/plugins/java-i18n/src/com/intellij/codeInspection/i18n/folding/I18nMessageGotoDeclarationHandler.java +++ b/plugins/java-i18n/src/com/intellij/codeInspection/i18n/folding/I18nMessageGotoDeclarationHandler.java @@ -67,7 +67,7 @@ public class I18nMessageGotoDeclarationHandler extends GotoDeclarationHandlerBas if (foldRegion == null || foldRegion.isExpanded()) return null; for (PsiExpression expression : methodCall.getArgumentList().getExpressions()) { - if (expression instanceof PsiLiteralExpression && PropertyFoldingBuilder.isI18nProperty(expression.getProject(), (PsiLiteralExpression)expression)) { + if (expression instanceof PsiLiteralExpression && PropertyFoldingBuilder.isI18nProperty((PsiLiteralExpression)expression)) { return resolve(expression); } } diff --git a/plugins/java-i18n/src/com/intellij/codeInspection/i18n/folding/PropertyFoldingBuilder.java b/plugins/java-i18n/src/com/intellij/codeInspection/i18n/folding/PropertyFoldingBuilder.java index fe9940dc1eb9..e7435c0640e7 100644 --- a/plugins/java-i18n/src/com/intellij/codeInspection/i18n/folding/PropertyFoldingBuilder.java +++ b/plugins/java-i18n/src/com/intellij/codeInspection/i18n/folding/PropertyFoldingBuilder.java @@ -28,12 +28,10 @@ import com.intellij.lang.properties.psi.Property; import com.intellij.lang.properties.psi.impl.PropertyImpl; import com.intellij.lang.properties.psi.impl.PropertyStubImpl; import com.intellij.openapi.editor.Document; -import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Key; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; import com.intellij.psi.impl.JavaConstantExpressionEvaluator; -import com.intellij.psi.impl.source.SourceTreeToPsiMap; import com.intellij.psi.util.PsiModificationTracker; import com.intellij.util.ObjectUtils; import com.intellij.util.containers.ContainerUtil; @@ -57,19 +55,18 @@ public class PropertyFoldingBuilder extends FoldingBuilderEx { return FoldingDescriptor.EMPTY; } final PsiJavaFile file = (PsiJavaFile) element; - final Project project = file.getProject(); final List result = new ArrayList(); boolean hasJsp = ContainerUtil.intersects(Arrays.asList(StdLanguages.JSP, StdLanguages.JSPX), file.getViewProvider().getLanguages()); //hack here because JspFile PSI elements are not threaded correctly via nextSibling/prevSibling file.accept(hasJsp ? new JavaRecursiveElementVisitor() { @Override public void visitLiteralExpression(PsiLiteralExpression expression) { - checkLiteral(project, expression, result); + checkLiteral(expression, result); } } : new JavaRecursiveElementWalkingVisitor() { @Override public void visitLiteralExpression(PsiLiteralExpression expression) { - checkLiteral(project, expression, result); + checkLiteral(expression, result); } }); @@ -80,9 +77,9 @@ public class PropertyFoldingBuilder extends FoldingBuilderEx { return JavaCodeFoldingSettings.getInstance().isCollapseI18nMessages(); } - private static void checkLiteral(Project project, PsiLiteralExpression expression, List result) { - if (isI18nProperty(project, expression)) { - final IProperty property = getI18nProperty(project, expression); + private static void checkLiteral(PsiLiteralExpression expression, List result) { + if (isI18nProperty(expression)) { + final IProperty property = getI18nProperty(expression); final HashSet set = new HashSet(); set.add(property != null ? property : PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT); final String msg = formatI18nProperty(expression, property); @@ -119,24 +116,24 @@ public class PropertyFoldingBuilder extends FoldingBuilderEx { @Override public String getPlaceholderText(@NotNull ASTNode node) { - final PsiElement element = SourceTreeToPsiMap.treeElementToPsi(node); + final PsiElement element = node.getPsi(); if (element instanceof PsiLiteralExpression) { - return getI18nMessage(element.getProject(), (PsiLiteralExpression)element); + return getI18nMessage((PsiLiteralExpression)element); } else if (element instanceof PsiMethodCallExpression) { - return formatMethodCallExpression(element.getProject(), (PsiMethodCallExpression)element); + return formatMethodCallExpression((PsiMethodCallExpression)element); } return element.getText(); } - private static String formatMethodCallExpression(Project project, PsiMethodCallExpression methodCallExpression) { + private static String formatMethodCallExpression(PsiMethodCallExpression methodCallExpression) { final PsiExpression[] args = methodCallExpression.getArgumentList().getExpressions(); if (args.length > 0 && args[0] instanceof PsiLiteralExpression && args[0].isValid() - && isI18nProperty(project, (PsiLiteralExpression)args[0])) { - final int count = JavaI18nUtil.getPropertyValueParamsMaxCount((PsiLiteralExpression)args[0]); + && isI18nProperty((PsiLiteralExpression)args[0])) { + final int count = JavaI18nUtil.getPropertyValueParamsMaxCount(args[0]); if (args.length == 1 + count) { - String text = getI18nMessage(project, (PsiLiteralExpression)args[0]); + String text = getI18nMessage((PsiLiteralExpression)args[0]); for (int i = 1; i < count + 1; i++) { Object value = JavaConstantExpressionEvaluator.computeConstantExpression(args[i], false); if (value == null) { @@ -162,17 +159,17 @@ public class PropertyFoldingBuilder extends FoldingBuilderEx { return methodCallExpression.getText(); } - private static String getI18nMessage(@NotNull Project project, PsiLiteralExpression literal) { - final IProperty property = getI18nProperty(project, literal); + private static String getI18nMessage(PsiLiteralExpression literal) { + final IProperty property = getI18nProperty(literal); return property == null ? literal.getText() : formatI18nProperty(literal, property); } @Nullable - private static IProperty getI18nProperty(Project project, PsiLiteralExpression literal) { + private static IProperty getI18nProperty(PsiLiteralExpression literal) { final Property property = (Property)literal.getUserData(CACHE); if (property == NULL) return null; if (property != null && isValid(property, literal)) return property; - if (isI18nProperty(project, literal)) { + if (isI18nProperty(literal)) { final PsiReference[] references = literal.getReferences(); for (PsiReference reference : references) { if (reference instanceof PsiPolyVariantReference) { @@ -214,7 +211,7 @@ public class PropertyFoldingBuilder extends FoldingBuilderEx { } - public static boolean isI18nProperty(@NotNull Project project, @NotNull PsiLiteralExpression expr) { + public static boolean isI18nProperty(@NotNull PsiLiteralExpression expr) { if (! isStringLiteral(expr)) return false; final IProperty property = expr.getUserData(CACHE); if (property == NULL) return false; @@ -222,7 +219,7 @@ public class PropertyFoldingBuilder extends FoldingBuilderEx { final Map annotationParams = new HashMap(); annotationParams.put(AnnotationUtil.PROPERTY_KEY_RESOURCE_BUNDLE_PARAMETER, null); - final boolean isI18n = JavaI18nUtil.mustBePropertyKey(project, expr, annotationParams); + final boolean isI18n = JavaI18nUtil.mustBePropertyKey(expr, annotationParams); if (!isI18n) { expr.putUserData(CACHE, NULL); } diff --git a/plugins/java-i18n/src/com/intellij/lang/properties/PropertiesReferenceProvider.java b/plugins/java-i18n/src/com/intellij/lang/properties/PropertiesReferenceProvider.java index 6d0f611d605e..5c7fbe65c07f 100644 --- a/plugins/java-i18n/src/com/intellij/lang/properties/PropertiesReferenceProvider.java +++ b/plugins/java-i18n/src/com/intellij/lang/properties/PropertiesReferenceProvider.java @@ -40,6 +40,7 @@ public class PropertiesReferenceProvider extends PsiReferenceProvider { private final boolean myDefaultSoft; + @SuppressWarnings("unused") // invoked by reflection public PropertiesReferenceProvider() { this(false); } @@ -66,7 +67,7 @@ public class PropertiesReferenceProvider extends PsiReferenceProvider { final Map annotationParams = new HashMap(); annotationParams.put(AnnotationUtil.PROPERTY_KEY_RESOURCE_BUNDLE_PARAMETER, null); - if (JavaI18nUtil.mustBePropertyKey(element.getProject(), literalExpression, annotationParams)) { + if (JavaI18nUtil.mustBePropertyKey(literalExpression, annotationParams)) { soft = false; final Object resourceBundleName = annotationParams.get(AnnotationUtil.PROPERTY_KEY_RESOURCE_BUNDLE_PARAMETER); if (resourceBundleName instanceof PsiExpression) { @@ -93,7 +94,7 @@ public class PropertiesReferenceProvider extends PsiReferenceProvider { if (value instanceof String) { String text = (String)value; PsiReference reference = propertyRefWithPrefix ? - new PrefixBasedPropertyReference(text, element, bundleName, soft): + new PrefixBasedPropertyReference(text, element, null, soft) : new PropertyReference(text, element, bundleName, soft); return new PsiReference[]{reference}; } diff --git a/plugins/java-i18n/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/JavaReferenceContributor.java b/plugins/java-i18n/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/JavaReferenceContributor.java index bff0504509e6..994eb01cf241 100644 --- a/plugins/java-i18n/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/JavaReferenceContributor.java +++ b/plugins/java-i18n/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/JavaReferenceContributor.java @@ -47,7 +47,7 @@ public class JavaReferenceContributor extends PsiReferenceContributor{ PsiLiteralExpression literalExpression = (PsiLiteralExpression) context; final Map annotationParams = new HashMap(); annotationParams.put(AnnotationUtil.PROPERTY_KEY_RESOURCE_BUNDLE_PARAMETER, null); - return !JavaI18nUtil.mustBePropertyKey(context.getProject(), literalExpression, annotationParams); + return !JavaI18nUtil.mustBePropertyKey(literalExpression, annotationParams); } public boolean isClassAcceptable(Class hintClass) { diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/dom/MavenDomUtil.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/dom/MavenDomUtil.java index 179127db648d..ab88c1f963dc 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/dom/MavenDomUtil.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/dom/MavenDomUtil.java @@ -353,10 +353,11 @@ public class MavenDomUtil { } public static boolean isFilteredResourceFile(PsiElement element) { - VirtualFile file = getVirtualFile(element); + PsiFile psiFile = element.getContainingFile(); + VirtualFile file = getVirtualFile(psiFile); if (file == null) return false; - MavenProjectsManager manager = MavenProjectsManager.getInstance(element.getProject()); + MavenProjectsManager manager = MavenProjectsManager.getInstance(psiFile.getProject()); MavenProject mavenProject = manager.findContainingProject(file); if (mavenProject == null) return false; diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/navigator/MavenProjectsNavigator.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/navigator/MavenProjectsNavigator.java index a66c6d841dcb..0e6c494a0296 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/navigator/MavenProjectsNavigator.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/navigator/MavenProjectsNavigator.java @@ -372,7 +372,9 @@ public class MavenProjectsNavigator extends MavenSimpleProjectComponent implemen private void scheduleStructureRequest(final Runnable r) { if (isUnitTestMode()) { - r.run(); + if (myStructure != null) { + r.run(); + } return; } diff --git a/plugins/settings-repository/src/IcsBundle.kt b/plugins/settings-repository/src/IcsBundle.kt index 045afff450cf..1793542b3646 100644 --- a/plugins/settings-repository/src/IcsBundle.kt +++ b/plugins/settings-repository/src/IcsBundle.kt @@ -1,11 +1,25 @@ +/* + * 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 org.jetbrains.settingsRepository import com.intellij.CommonBundle import org.jetbrains.annotations.PropertyKey import java.lang.ref.Reference import java.lang.ref.SoftReference -import java.util.ResourceBundle -import kotlin.platform.platformStatic +import java.util.* class IcsBundle { companion object { @@ -13,7 +27,7 @@ class IcsBundle { val BUNDLE: String = "messages.IcsBundle" - platformStatic + JvmStatic fun message(PropertyKey(resourceBundle = BUNDLE) key: String, vararg params: Any?): String { return CommonBundle.message(getBundle(), key, *params) } diff --git a/plugins/settings-repository/src/IcsManager.kt b/plugins/settings-repository/src/IcsManager.kt index a0d1aa62b99d..f68ef032730e 100644 --- a/plugins/settings-repository/src/IcsManager.kt +++ b/plugins/settings-repository/src/IcsManager.kt @@ -46,10 +46,10 @@ import kotlin.properties.Delegates val PLUGIN_NAME: String = "Settings Repository" -val LOG: Logger = Logger.getInstance(javaClass()) +val LOG: Logger = Logger.getInstance(IcsManager::class.java) val icsManager by Delegates.lazy { - ApplicationLoadListener.EP_NAME.findExtension(javaClass()).icsManager + ApplicationLoadListener.EP_NAME.findExtension(IcsApplicationLoadListener::class.java).icsManager } class IcsManager(dir: File) { @@ -91,7 +91,7 @@ class IcsManager(dir: File) { ProgressManager.getInstance().run(object : Task.Backgroundable(null, IcsBundle.message("task.commit.title")) { override fun run(indicator: ProgressIndicator) { try { - repositoryManager.commit(indicator) + repositoryManager.commit(indicator, fixStateIfCannotCommit = false) } catch (e: Throwable) { LOG.error(e) diff --git a/plugins/settings-repository/src/RepositoryManager.kt b/plugins/settings-repository/src/RepositoryManager.kt index 6fa3f4410f10..16dcdab057d7 100644 --- a/plugins/settings-repository/src/RepositoryManager.kt +++ b/plugins/settings-repository/src/RepositoryManager.kt @@ -54,8 +54,10 @@ public interface RepositoryManager { * Not all implementations support progress indicator (will not be updated on progress). * * syncType will be passed if called before sync. + * + * If fixStateIfCannotCommit, repository state will be fixed before commit. */ - public fun commit(indicator: ProgressIndicator? = null, syncType: SyncType? = null): Boolean + public fun commit(indicator: ProgressIndicator? = null, syncType: SyncType? = null, fixStateIfCannotCommit: Boolean = true): Boolean public fun getAheadCommitsCount(): Int diff --git a/plugins/settings-repository/src/actions/CommitToIcsAction.kt b/plugins/settings-repository/src/actions/CommitToIcsAction.kt index 304251949164..4d7542d4b0a8 100644 --- a/plugins/settings-repository/src/actions/CommitToIcsAction.kt +++ b/plugins/settings-repository/src/actions/CommitToIcsAction.kt @@ -1,3 +1,18 @@ +/* + * 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 org.jetbrains.settingsRepository.actions import com.intellij.openapi.components.ServiceManager @@ -28,7 +43,7 @@ import org.jetbrains.settingsRepository.CommitToIcsDialog import org.jetbrains.settingsRepository.IcsBundle import org.jetbrains.settingsRepository.ProjectId import org.jetbrains.settingsRepository.icsManager -import java.util.UUID +import java.util.* class CommitToIcsAction : CommonCheckinFilesAction() { class IcsBeforeCommitDialogHandler : CheckinHandlerFactory() { @@ -103,7 +118,7 @@ private class ProjectChangeCollectConsumer(private val project: Project) { } private fun getProjectId(project: Project): String? { - val projectId = ServiceManager.getService(project, javaClass())!! + val projectId = ServiceManager.getService(project, ProjectId::class.java)!! if (projectId.uid == null) { if (MessageDialogBuilder.yesNo("Settings Server Project Mapping", "Project is not mapped on Settings Server. Would you like to map?").project(project).doNotAsk(object : DialogWrapper.PropertyDoNotAskOption("") { override fun setToBeShown(value: Boolean, exitCode: Int) { diff --git a/plugins/settings-repository/src/actions/SyncAction.kt b/plugins/settings-repository/src/actions/SyncAction.kt index e7f653ecfb05..0b6517b6f81a 100644 --- a/plugins/settings-repository/src/actions/SyncAction.kt +++ b/plugins/settings-repository/src/actions/SyncAction.kt @@ -26,7 +26,8 @@ val NOTIFICATION_GROUP = NotificationGroup.balloonGroup(PLUGIN_NAME) abstract class SyncAction(private val syncType: SyncType) : DumbAwareAction() { override fun update(e: AnActionEvent) { - e.getPresentation().setEnabledAndVisible(icsManager.repositoryManager.hasUpstream()) + val repositoryManager = icsManager.repositoryManager + e.getPresentation().setEnabledAndVisible(repositoryManager.isRepositoryExists() && repositoryManager.hasUpstream()) } override fun actionPerformed(event: AnActionEvent) { @@ -39,15 +40,14 @@ fun syncAndNotify(syncType: SyncType, project: Project?, notifyIfUpToDate: Boole if (icsManager.sync(syncType, project) == null && !notifyIfUpToDate) { return } + NOTIFICATION_GROUP.createNotification(IcsBundle.message("sync.done.message"), NotificationType.INFORMATION).notify(project) } catch (e: Exception) { LOG.warn(e) NOTIFICATION_GROUP.createNotification(IcsBundle.message("sync.rejected.title"), e.getMessage() ?: "Internal error", NotificationType.ERROR, null).notify(project) } - NOTIFICATION_GROUP.createNotification(IcsBundle.message("sync.done.message"), NotificationType.INFORMATION).notify(project) } -// we don't class MergeAction : SyncAction(SyncType.MERGE) class ResetToTheirsAction : SyncAction(SyncType.OVERWRITE_LOCAL) class ResetToMyAction : SyncAction(SyncType.OVERWRITE_REMOTE) diff --git a/plugins/settings-repository/src/copyAppSettingsToRepository.kt b/plugins/settings-repository/src/copyAppSettingsToRepository.kt index e42c1e8ab607..be631497f57f 100644 --- a/plugins/settings-repository/src/copyAppSettingsToRepository.kt +++ b/plugins/settings-repository/src/copyAppSettingsToRepository.kt @@ -72,7 +72,7 @@ private fun getRoamingType(components: Collection): Roaming return component.getRoamingType() } else if (component is PersistentStateComponent<*>) { - val stateAnnotation = component.javaClass.getAnnotation(javaClass()) + val stateAnnotation = component.javaClass.getAnnotation(State::class.java) if (stateAnnotation != null) { val storages = stateAnnotation.storages if (!storages.isEmpty()) { diff --git a/plugins/settings-repository/src/git/GitEx.kt b/plugins/settings-repository/src/git/GitEx.kt index 5997a40eab20..1428ad659c17 100644 --- a/plugins/settings-repository/src/git/GitEx.kt +++ b/plugins/settings-repository/src/git/GitEx.kt @@ -1,3 +1,18 @@ +/* + * 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 org.jetbrains.settingsRepository.git import com.intellij.openapi.progress.ProcessCanceledException @@ -29,7 +44,7 @@ import java.io.File import java.io.InputStream fun wrapIfNeedAndReThrow(e: TransportException) { - if (e.getStatus() == TransportException.Status.CANNOT_RESOLVE_REPO) { + if (e is org.eclipse.jgit.errors.NoRemoteRepositoryException || e.getStatus() == TransportException.Status.CANNOT_RESOLVE_REPO) { throw org.jetbrains.settingsRepository.NoRemoteRepositoryException(e) } @@ -47,10 +62,15 @@ fun wrapIfNeedAndReThrow(e: TransportException) { } fun Repository.fetch(remoteConfig: RemoteConfig, credentialsProvider: CredentialsProvider? = null, progressMonitor: ProgressMonitor? = null): FetchResult? { - val transport = Transport.open(this, remoteConfig) try { - transport.setCredentialsProvider(credentialsProvider) - return transport.fetch(progressMonitor ?: NullProgressMonitor.INSTANCE, null) + val transport = Transport.open(this, remoteConfig) + try { + transport.setCredentialsProvider(credentialsProvider) + return transport.fetch(progressMonitor ?: NullProgressMonitor.INSTANCE, null) + } + finally { + transport.close() + } } catch (e: TransportException) { val message = e.getMessage()!! @@ -63,9 +83,6 @@ fun Repository.fetch(remoteConfig: RemoteConfig, credentialsProvider: Credential wrapIfNeedAndReThrow(e) return null } - finally { - transport.close() - } } fun Repository.disableAutoCrLf(): Repository { diff --git a/plugins/settings-repository/src/git/GitRepositoryManager.kt b/plugins/settings-repository/src/git/GitRepositoryManager.kt index e63ca32c2e9a..363798b65246 100644 --- a/plugins/settings-repository/src/git/GitRepositoryManager.kt +++ b/plugins/settings-repository/src/git/GitRepositoryManager.kt @@ -52,6 +52,9 @@ class GitRepositoryManager(private val credentialsStore: NotNullLazyValue): Boolean { - val addCommand = AddCommand(repository) + var addCommand: AddCommand? = null val toDelete = SmartList() - var added = false for ((oldPath, newPath) in pairs) { val old = File(dir, oldPath) if (!old.exists()) { @@ -252,8 +252,10 @@ class GitRepositoryManager(private val credentialsStore: NotNullLazyValue()) +val LOG: Logger = Logger.getInstance(CredentialsStore::class.java) public data class Credentials(id: String?, token: String?) { public val id: String? = if (id.isNullOrEmpty()) null else id diff --git a/plugins/settings-repository/src/keychain/OSXKeychainLibrary.kt b/plugins/settings-repository/src/keychain/OSXKeychainLibrary.kt index 4367ab7ba5f8..650174e0658e 100644 --- a/plugins/settings-repository/src/keychain/OSXKeychainLibrary.kt +++ b/plugins/settings-repository/src/keychain/OSXKeychainLibrary.kt @@ -1,3 +1,18 @@ +/* + * 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 org.jetbrains.keychain import com.intellij.openapi.util.SystemInfo @@ -12,7 +27,7 @@ val isOSXCredentialsStoreSupported: Boolean // It is very, very important to use CFRelease/SecKeychainItemFreeContent You must do it, otherwise you can get "An invalid record was encountered." public interface OSXKeychainLibrary : com.sun.jna.Library { companion object { - private val LIBRARY = com.sun.jna.Native.loadLibrary("Security", javaClass()) as OSXKeychainLibrary + private val LIBRARY = com.sun.jna.Native.loadLibrary("Security", OSXKeychainLibrary::class.java) as OSXKeychainLibrary fun saveGenericPassword(serviceName: ByteArray, accountName: String, password: CharArray) { saveGenericPassword(serviceName, accountName, Charsets.UTF_8.encode(CharBuffer.wrap(password))) diff --git a/plugins/settings-repository/src/settings/IcsSettings.kt b/plugins/settings-repository/src/settings/IcsSettings.kt index 0b2886649858..c1e944221d70 100644 --- a/plugins/settings-repository/src/settings/IcsSettings.kt +++ b/plugins/settings-repository/src/settings/IcsSettings.kt @@ -74,7 +74,7 @@ fun loadSettings(settingsFile: File): IcsSettings { return IcsSettings() } - val settings = ObjectMapper().readValue(settingsFile, javaClass()) + val settings = ObjectMapper().readValue(settingsFile, IcsSettings::class.java) if (settings.commitDelay <= 0) { settings.commitDelay = DEFAULT_COMMIT_DELAY } diff --git a/plugins/settings-repository/src/settings/readOnlySourcesEditor.kt b/plugins/settings-repository/src/settings/readOnlySourcesEditor.kt index b2f15ea01e71..adeebbe95ea2 100644 --- a/plugins/settings-repository/src/settings/readOnlySourcesEditor.kt +++ b/plugins/settings-repository/src/settings/readOnlySourcesEditor.kt @@ -38,7 +38,7 @@ import javax.swing.JTextField import javax.swing.event.DocumentEvent private val COLUMNS = arrayOf(object : TableModelEditor.EditableColumnInfo() { - override fun getColumnClass() = javaClass() + override fun getColumnClass() = Boolean::class.java override fun valueOf(item: ReadonlySource) = item.active @@ -58,7 +58,7 @@ private fun createReadOnlySourcesEditor(): ConfigurableUi { val itemEditor = object : TableModelEditor.DialogItemEditor() { override fun clone(item: ReadonlySource, forInPlaceEditing: Boolean) = ReadonlySource(item.url, item.active) - override fun getItemClass() = javaClass() + override fun getItemClass() = ReadonlySource::class.java override fun edit(item: ReadonlySource, mutator: Function, isAdd: Boolean) { val dialogBuilder = DialogBuilder() diff --git a/plugins/svn4idea/testSource/org/jetbrains/idea/svn/SvnAuthenticationTest.java b/plugins/svn4idea/testSource/org/jetbrains/idea/svn/SvnAuthenticationTest.java index bf0c9eebb1bb..24aea3a633fa 100644 --- a/plugins/svn4idea/testSource/org/jetbrains/idea/svn/SvnAuthenticationTest.java +++ b/plugins/svn4idea/testSource/org/jetbrains/idea/svn/SvnAuthenticationTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * 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. @@ -20,7 +20,9 @@ import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.Trinity; import com.intellij.openapi.util.io.FileUtil; +import com.intellij.testFramework.EdtTestUtil; import com.intellij.testFramework.PlatformTestCase; +import com.intellij.util.ThrowableRunnable; import com.intellij.util.concurrency.Semaphore; import com.intellij.util.ui.UIUtil; import junit.framework.Assert; @@ -46,21 +48,18 @@ public class SvnAuthenticationTest extends PlatformTestCase { private SvnConfiguration myConfiguration; @Override - protected void runBareRunnable(Runnable runnable) throws Throwable { + protected void runBareRunnable(ThrowableRunnable runnable) throws Throwable { runnable.run(); } @Override protected void setUp() throws Exception { - UIUtil.invokeAndWaitIfNeeded(new Runnable() { - @Override - public void run() { - try { - SvnAuthenticationTest.super.setUp(); - } - catch (Exception e) { - throw new RuntimeException(e); - } + EdtTestUtil.runInEdtAndWait((Runnable)() -> { + try { + SvnAuthenticationTest.super.setUp(); + } + catch (Exception e) { + throw new RuntimeException(e); } }); diff --git a/plugins/svn4idea/testSource/org/jetbrains/idea/svn16/SvnAuthenticationTest.java b/plugins/svn4idea/testSource/org/jetbrains/idea/svn16/SvnAuthenticationTest.java index e8068989374b..3842e0ae125e 100644 --- a/plugins/svn4idea/testSource/org/jetbrains/idea/svn16/SvnAuthenticationTest.java +++ b/plugins/svn4idea/testSource/org/jetbrains/idea/svn16/SvnAuthenticationTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * 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. @@ -20,18 +20,15 @@ import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.Trinity; import com.intellij.openapi.util.io.FileUtil; +import com.intellij.testFramework.EdtTestUtil; import com.intellij.testFramework.PlatformTestCase; +import com.intellij.util.ThrowableRunnable; import com.intellij.util.concurrency.Semaphore; import com.intellij.util.ui.UIUtil; import junit.framework.Assert; -import org.jetbrains.idea.svn.auth.SvnAuthenticationManager; -import org.jetbrains.idea.svn.auth.SvnAuthenticationNotifier; import org.jetbrains.idea.svn.SvnConfiguration; import org.jetbrains.idea.svn.SvnVcs; -import org.jetbrains.idea.svn.auth.ProviderType; -import org.jetbrains.idea.svn.auth.SvnAuthenticationInteraction; -import org.jetbrains.idea.svn.auth.SvnAuthenticationListener; -import org.jetbrains.idea.svn.auth.SvnAuthenticationProvider; +import org.jetbrains.idea.svn.auth.*; import org.tmatesoft.svn.core.SVNErrorMessage; import org.tmatesoft.svn.core.SVNException; import org.tmatesoft.svn.core.SVNURL; @@ -53,21 +50,18 @@ public class SvnAuthenticationTest extends PlatformTestCase { private SvnConfiguration myConfiguration; @Override - protected void runBareRunnable(Runnable runnable) throws Throwable { + protected void runBareRunnable(ThrowableRunnable runnable) throws Throwable { runnable.run(); } @Override protected void setUp() throws Exception { - UIUtil.invokeAndWaitIfNeeded(new Runnable() { - @Override - public void run() { - try { - SvnAuthenticationTest.super.setUp(); - } - catch (Exception e) { - throw new RuntimeException(e); - } + EdtTestUtil.runInEdtAndWait((Runnable)() -> { + try { + SvnAuthenticationTest.super.setUp(); + } + catch (Exception e) { + throw new RuntimeException(e); } }); @@ -95,15 +89,12 @@ public class SvnAuthenticationTest extends PlatformTestCase { @Override protected void tearDown() throws Exception { - UIUtil.invokeAndWaitIfNeeded(new Runnable() { - @Override - public void run() { - try { - SvnAuthenticationTest.super.tearDown(); - } - catch (Exception e) { - throw new RuntimeException(e); - } + EdtTestUtil.runInEdtAndWait((Runnable)() -> { + try { + SvnAuthenticationTest.super.tearDown(); + } + catch (Exception e) { + throw new RuntimeException(e); } }); @@ -120,42 +111,39 @@ public class SvnAuthenticationTest extends PlatformTestCase { final SVNException[] exception = new SVNException[1]; final boolean[] result = {false}; - synchronousBackground(new Runnable() { - @Override - public void run() { - try { + synchronousBackground(() -> { + try { - listener.addStep(new Trinity(ProviderType.persistent, url, Type.request)); - listener.addStep(new Trinity(ProviderType.interactive, url, Type.request)); - if (SystemInfo.isWindows) { - listener.addStep(new Trinity(ProviderType.persistent, url, Type.save)); - } else { - listener.addStep(new Trinity(ProviderType.persistent, url, Type.without_pasword_save)); - } - - commonScheme(url, false, null); - Assert.assertEquals(3, listener.getCnt()); - //long start = System.currentTimeMillis(); - //waitListenerStep(start, listener, 3); - - listener.reset(); - if (!SystemInfo.isWindows) savedOnceListener.reset(); - SvnConfiguration.RUNTIME_AUTH_CACHE.clear(); - listener.addStep(new Trinity(ProviderType.persistent, url, Type.request)); - if (! SystemInfo.isWindows) { - listener.addStep(new Trinity(ProviderType.interactive, url, Type.request)); - listener.addStep(new Trinity(ProviderType.persistent, url, Type.without_pasword_save)); - } - commonScheme(url, false, null); - //start = System.currentTimeMillis(); - //waitListenerStep(start, listener, 4); - Assert.assertEquals(SystemInfo.isWindows ? 1 : 3, listener.getCnt()); + listener.addStep(new Trinity<>(ProviderType.persistent, url, Type.request)); + listener.addStep(new Trinity<>(ProviderType.interactive, url, Type.request)); + if (SystemInfo.isWindows) { + listener.addStep(new Trinity<>(ProviderType.persistent, url, Type.save)); + } else { + listener.addStep(new Trinity<>(ProviderType.persistent, url, Type.without_pasword_save)); } - catch (SVNException e) { - exception[0] = e; + + commonScheme(url, false, null); + Assert.assertEquals(3, listener.getCnt()); + //long start = System.currentTimeMillis(); + //waitListenerStep(start, listener, 3); + + listener.reset(); + if (!SystemInfo.isWindows) savedOnceListener.reset(); + SvnConfiguration.RUNTIME_AUTH_CACHE.clear(); + listener.addStep(new Trinity<>(ProviderType.persistent, url, Type.request)); + if (! SystemInfo.isWindows) { + listener.addStep(new Trinity<>(ProviderType.interactive, url, Type.request)); + listener.addStep(new Trinity<>(ProviderType.persistent, url, Type.without_pasword_save)); } - result[0] = true; + commonScheme(url, false, null); + //start = System.currentTimeMillis(); + //waitListenerStep(start, listener, 4); + Assert.assertEquals(SystemInfo.isWindows ? 1 : 3, listener.getCnt()); } + catch (SVNException e) { + exception[0] = e; + } + result[0] = true; }); Assert.assertTrue(result[0]); @@ -194,31 +182,28 @@ public class SvnAuthenticationTest extends PlatformTestCase { try { FileUtil.appendToFile(servers, "\nstore-plaintext-passwords=yes\n"); - synchronousBackground(new Runnable() { - @Override - public void run() { - try { - listener.addStep(new Trinity(ProviderType.persistent, url, Type.request)); - listener.addStep(new Trinity(ProviderType.interactive, url, Type.request)); - listener.addStep(new Trinity(ProviderType.persistent, url, Type.save)); + synchronousBackground(() -> { + try { + listener.addStep(new Trinity<>(ProviderType.persistent, url, Type.request)); + listener.addStep(new Trinity<>(ProviderType.interactive, url, Type.request)); + listener.addStep(new Trinity<>(ProviderType.persistent, url, Type.save)); - commonScheme(url, false, null); - Assert.assertEquals(3, listener.getCnt()); - //long start = System.currentTimeMillis(); - //waitListenerStep(start, listener, 3); + commonScheme(url, false, null); + Assert.assertEquals(3, listener.getCnt()); + //long start = System.currentTimeMillis(); + //waitListenerStep(start, listener, 3); - SvnConfiguration.RUNTIME_AUTH_CACHE.clear(); - listener.addStep(new Trinity(ProviderType.persistent, url, Type.request)); - commonScheme(url, false, null); - //start = System.currentTimeMillis(); - //waitListenerStep(start, listener, 4); - Assert.assertEquals(4, listener.getCnt()); - } - catch (SVNException e) { - exception[0] = e; - } - result[0] = true; + SvnConfiguration.RUNTIME_AUTH_CACHE.clear(); + listener.addStep(new Trinity<>(ProviderType.persistent, url, Type.request)); + commonScheme(url, false, null); + //start = System.currentTimeMillis(); + //waitListenerStep(start, listener, 4); + Assert.assertEquals(4, listener.getCnt()); } + catch (SVNException e) { + exception[0] = e; + } + result[0] = true; }); } finally { FileUtil.delete(servers); @@ -264,35 +249,32 @@ public class SvnAuthenticationTest extends PlatformTestCase { final SVNException[] exception = new SVNException[1]; final Boolean[] result = new Boolean[1]; - synchronousBackground(new Runnable() { - @Override - public void run() { - try { - listener.addStep(new Trinity(ProviderType.persistent, url, Type.request)); - listener.addStep(new Trinity(ProviderType.interactive, url, Type.request)); + synchronousBackground(() -> { + try { + listener.addStep(new Trinity<>(ProviderType.persistent, url, Type.request)); + listener.addStep(new Trinity<>(ProviderType.interactive, url, Type.request)); - commonScheme(url, false, null); - //long start = System.currentTimeMillis(); - //waitListenerStep(start, listener, 2); - Assert.assertEquals(2, listener.getCnt()); + commonScheme(url, false, null); + //long start = System.currentTimeMillis(); + //waitListenerStep(start, listener, 2); + Assert.assertEquals(2, listener.getCnt()); - savedOnceListener.assertNotSaved(url, ISVNAuthenticationManager.PASSWORD); - // cause is not cleared though - savedOnceListener.reset(); + savedOnceListener.assertNotSaved(url, ISVNAuthenticationManager.PASSWORD); + // cause is not cleared though + savedOnceListener.reset(); - SvnConfiguration.RUNTIME_AUTH_CACHE.clear(); - listener.addStep(new Trinity(ProviderType.persistent, url, Type.request)); - listener.addStep(new Trinity(ProviderType.interactive, url, Type.request)); - commonScheme(url, false, null); - Assert.assertEquals(4, listener.getCnt()); - //start = System.currentTimeMillis(); - //waitListenerStep(start, listener, 4); - } - catch (SVNException e) { - exception[0] = e; - } - result[0] = true; + SvnConfiguration.RUNTIME_AUTH_CACHE.clear(); + listener.addStep(new Trinity<>(ProviderType.persistent, url, Type.request)); + listener.addStep(new Trinity<>(ProviderType.interactive, url, Type.request)); + commonScheme(url, false, null); + Assert.assertEquals(4, listener.getCnt()); + //start = System.currentTimeMillis(); + //waitListenerStep(start, listener, 4); } + catch (SVNException e) { + exception[0] = e; + } + result[0] = true; }); Assert.assertTrue(result[0]); @@ -330,32 +312,29 @@ public class SvnAuthenticationTest extends PlatformTestCase { final SVNException[] exception = new SVNException[1]; final Boolean[] result = new Boolean[1]; - synchronousBackground(new Runnable() { - @Override - public void run() { - try { - listener.addStep(new Trinity(ProviderType.persistent, url, Type.request)); - listener.addStep(new Trinity(ProviderType.interactive, url, Type.request)); + synchronousBackground(() -> { + try { + listener.addStep(new Trinity<>(ProviderType.persistent, url, Type.request)); + listener.addStep(new Trinity<>(ProviderType.interactive, url, Type.request)); - commonScheme(url, false, null); - Assert.assertEquals(2, listener.getCnt()); - Assert.assertEquals(1, myTestInteraction.getNumAuthWarn()); - myTestInteraction.reset(); - savedOnceListener.assertForAwt(); - savedOnceListener.reset(); + commonScheme(url, false, null); + Assert.assertEquals(2, listener.getCnt()); + Assert.assertEquals(1, myTestInteraction.getNumAuthWarn()); + myTestInteraction.reset(); + savedOnceListener.assertForAwt(); + savedOnceListener.reset(); - SvnConfiguration.RUNTIME_AUTH_CACHE.clear(); - listener.addStep(new Trinity(ProviderType.persistent, url, Type.request)); - listener.addStep(new Trinity(ProviderType.interactive, url, Type.request)); - commonScheme(url, false, null); - Assert.assertEquals(4, listener.getCnt()); - Assert.assertEquals(1, myTestInteraction.getNumAuthWarn()); - } - catch (SVNException e) { - exception[0] = e; - } - result[0] = true; + SvnConfiguration.RUNTIME_AUTH_CACHE.clear(); + listener.addStep(new Trinity<>(ProviderType.persistent, url, Type.request)); + listener.addStep(new Trinity<>(ProviderType.interactive, url, Type.request)); + commonScheme(url, false, null); + Assert.assertEquals(4, listener.getCnt()); + Assert.assertEquals(1, myTestInteraction.getNumAuthWarn()); } + catch (SVNException e) { + exception[0] = e; + } + result[0] = true; }); Assert.assertTrue(result[0]); @@ -391,32 +370,29 @@ public class SvnAuthenticationTest extends PlatformTestCase { final SVNException[] exception = new SVNException[1]; final Boolean[] result = new Boolean[1]; - synchronousBackground(new Runnable() { - @Override - public void run() { - try { - listener.addStep(new Trinity(ProviderType.persistent, url, Type.request)); - listener.addStep(new Trinity(ProviderType.interactive, url, Type.request)); + synchronousBackground(() -> { + try { + listener.addStep(new Trinity<>(ProviderType.persistent, url, Type.request)); + listener.addStep(new Trinity<>(ProviderType.interactive, url, Type.request)); - commonScheme(url, false, null); - Assert.assertEquals(2, listener.getCnt()); - Assert.assertEquals(1, myTestInteraction.getNumAuthWarn()); - myTestInteraction.reset(); - savedOnceListener.assertForAwt(); - savedOnceListener.reset(); + commonScheme(url, false, null); + Assert.assertEquals(2, listener.getCnt()); + Assert.assertEquals(1, myTestInteraction.getNumAuthWarn()); + myTestInteraction.reset(); + savedOnceListener.assertForAwt(); + savedOnceListener.reset(); - SvnConfiguration.RUNTIME_AUTH_CACHE.clear(); - listener.addStep(new Trinity(ProviderType.persistent, url, Type.request)); - listener.addStep(new Trinity(ProviderType.interactive, url, Type.request)); - commonScheme(url, false, null); - Assert.assertEquals(4, listener.getCnt()); - Assert.assertEquals(1, myTestInteraction.getNumAuthWarn()); - } - catch (SVNException e) { - exception[0] = e; - } - result[0] = true; + SvnConfiguration.RUNTIME_AUTH_CACHE.clear(); + listener.addStep(new Trinity<>(ProviderType.persistent, url, Type.request)); + listener.addStep(new Trinity<>(ProviderType.interactive, url, Type.request)); + commonScheme(url, false, null); + Assert.assertEquals(4, listener.getCnt()); + Assert.assertEquals(1, myTestInteraction.getNumAuthWarn()); } + catch (SVNException e) { + exception[0] = e; + } + result[0] = true; }); Assert.assertTrue(result[0]); @@ -458,34 +434,31 @@ public class SvnAuthenticationTest extends PlatformTestCase { final SVNException[] exception = new SVNException[1]; final Boolean[] result = new Boolean[1]; - synchronousBackground(new Runnable() { - @Override - public void run() { - try { - listener.addStep(new Trinity(ProviderType.persistent, url, Type.request)); - listener.addStep(new Trinity(ProviderType.interactive, url, Type.request)); - listener.addStep(new Trinity(ProviderType.persistent, url, Type.without_pasword_save)); + synchronousBackground(() -> { + try { + listener.addStep(new Trinity<>(ProviderType.persistent, url, Type.request)); + listener.addStep(new Trinity<>(ProviderType.interactive, url, Type.request)); + listener.addStep(new Trinity<>(ProviderType.persistent, url, Type.without_pasword_save)); - commonScheme(url, false, null); - Assert.assertEquals(3, listener.getCnt()); - Assert.assertEquals(1, myTestInteraction.getNumPasswordsWarn()); - myTestInteraction.reset(); - savedOnceListener.assertForAwt(); - savedOnceListener.reset(); + commonScheme(url, false, null); + Assert.assertEquals(3, listener.getCnt()); + Assert.assertEquals(1, myTestInteraction.getNumPasswordsWarn()); + myTestInteraction.reset(); + savedOnceListener.assertForAwt(); + savedOnceListener.reset(); - SvnConfiguration.RUNTIME_AUTH_CACHE.clear(); - listener.addStep(new Trinity(ProviderType.persistent, url, Type.request)); - listener.addStep(new Trinity(ProviderType.interactive, url, Type.request)); - listener.addStep(new Trinity(ProviderType.persistent, url, Type.without_pasword_save)); - commonScheme(url, false, null); - Assert.assertEquals(6, listener.getCnt()); - Assert.assertEquals(1, myTestInteraction.getNumPasswordsWarn()); - } - catch (SVNException e) { - exception[0] = e; - } - result[0] = true; + SvnConfiguration.RUNTIME_AUTH_CACHE.clear(); + listener.addStep(new Trinity<>(ProviderType.persistent, url, Type.request)); + listener.addStep(new Trinity<>(ProviderType.interactive, url, Type.request)); + listener.addStep(new Trinity<>(ProviderType.persistent, url, Type.without_pasword_save)); + commonScheme(url, false, null); + Assert.assertEquals(6, listener.getCnt()); + Assert.assertEquals(1, myTestInteraction.getNumPasswordsWarn()); } + catch (SVNException e) { + exception[0] = e; + } + result[0] = true; }); Assert.assertTrue(result[0]); @@ -521,34 +494,31 @@ public class SvnAuthenticationTest extends PlatformTestCase { final SVNException[] exception = new SVNException[1]; final Boolean[] result = new Boolean[1]; - synchronousBackground(new Runnable() { - @Override - public void run() { - try { - listener.addStep(new Trinity(ProviderType.persistent, url, Type.request)); - listener.addStep(new Trinity(ProviderType.interactive, url, Type.request)); - listener.addStep(new Trinity(ProviderType.persistent, url, Type.without_pasword_save)); + synchronousBackground(() -> { + try { + listener.addStep(new Trinity<>(ProviderType.persistent, url, Type.request)); + listener.addStep(new Trinity<>(ProviderType.interactive, url, Type.request)); + listener.addStep(new Trinity<>(ProviderType.persistent, url, Type.without_pasword_save)); - commonScheme(url, false, null); - Assert.assertEquals(3, listener.getCnt()); - Assert.assertEquals(1, myTestInteraction.getNumPasswordsWarn()); - myTestInteraction.reset(); - savedOnceListener.assertForAwt(); - savedOnceListener.reset(); + commonScheme(url, false, null); + Assert.assertEquals(3, listener.getCnt()); + Assert.assertEquals(1, myTestInteraction.getNumPasswordsWarn()); + myTestInteraction.reset(); + savedOnceListener.assertForAwt(); + savedOnceListener.reset(); - SvnConfiguration.RUNTIME_AUTH_CACHE.clear(); - listener.addStep(new Trinity(ProviderType.persistent, url, Type.request)); - listener.addStep(new Trinity(ProviderType.interactive, url, Type.request)); - listener.addStep(new Trinity(ProviderType.persistent, url, Type.without_pasword_save)); - commonScheme(url, false, null); - Assert.assertEquals(6, listener.getCnt()); - Assert.assertEquals(1, myTestInteraction.getNumPasswordsWarn()); - } - catch (SVNException e) { - exception[0] = e; - } - result[0] = true; + SvnConfiguration.RUNTIME_AUTH_CACHE.clear(); + listener.addStep(new Trinity<>(ProviderType.persistent, url, Type.request)); + listener.addStep(new Trinity<>(ProviderType.interactive, url, Type.request)); + listener.addStep(new Trinity<>(ProviderType.persistent, url, Type.without_pasword_save)); + commonScheme(url, false, null); + Assert.assertEquals(6, listener.getCnt()); + Assert.assertEquals(1, myTestInteraction.getNumPasswordsWarn()); } + catch (SVNException e) { + exception[0] = e; + } + result[0] = true; }); Assert.assertTrue(result[0]); @@ -591,34 +561,31 @@ public class SvnAuthenticationTest extends PlatformTestCase { final SVNException[] exception = new SVNException[1]; final Boolean[] result = new Boolean[1]; - synchronousBackground(new Runnable() { - @Override - public void run() { - try { - listener.addStep(new Trinity(ProviderType.persistent, url, Type.request)); - listener.addStep(new Trinity(ProviderType.interactive, url, Type.request)); - listener.addStep(new Trinity(ProviderType.persistent, url, Type.without_pasword_save)); + synchronousBackground(() -> { + try { + listener.addStep(new Trinity<>(ProviderType.persistent, url, Type.request)); + listener.addStep(new Trinity<>(ProviderType.interactive, url, Type.request)); + listener.addStep(new Trinity<>(ProviderType.persistent, url, Type.without_pasword_save)); - commonScheme(url, false, null); - Assert.assertEquals(3, listener.getCnt()); - Assert.assertEquals(1, myTestInteraction.getNumPasswordsWarn()); - myTestInteraction.reset(); - savedOnceListener.assertForAwt(); - savedOnceListener.reset(); + commonScheme(url, false, null); + Assert.assertEquals(3, listener.getCnt()); + Assert.assertEquals(1, myTestInteraction.getNumPasswordsWarn()); + myTestInteraction.reset(); + savedOnceListener.assertForAwt(); + savedOnceListener.reset(); - SvnConfiguration.RUNTIME_AUTH_CACHE.clear(); - listener.addStep(new Trinity(ProviderType.persistent, url, Type.request)); - listener.addStep(new Trinity(ProviderType.interactive, url, Type.request)); - listener.addStep(new Trinity(ProviderType.persistent, url, Type.without_pasword_save)); - commonScheme(url, false, null); - Assert.assertEquals(6, listener.getCnt()); - Assert.assertEquals(1, myTestInteraction.getNumPasswordsWarn()); - } - catch (SVNException e) { - exception[0] = e; - } - result[0] = true; + SvnConfiguration.RUNTIME_AUTH_CACHE.clear(); + listener.addStep(new Trinity<>(ProviderType.persistent, url, Type.request)); + listener.addStep(new Trinity<>(ProviderType.interactive, url, Type.request)); + listener.addStep(new Trinity<>(ProviderType.persistent, url, Type.without_pasword_save)); + commonScheme(url, false, null); + Assert.assertEquals(6, listener.getCnt()); + Assert.assertEquals(1, myTestInteraction.getNumPasswordsWarn()); } + catch (SVNException e) { + exception[0] = e; + } + result[0] = true; }); Assert.assertTrue(result[0]); @@ -654,34 +621,31 @@ public class SvnAuthenticationTest extends PlatformTestCase { final SVNException[] exception = new SVNException[1]; final Boolean[] result = new Boolean[1]; - synchronousBackground(new Runnable() { - @Override - public void run() { - try { - listener.addStep(new Trinity(ProviderType.persistent, url, Type.request)); - listener.addStep(new Trinity(ProviderType.interactive, url, Type.request)); - listener.addStep(new Trinity(ProviderType.persistent, url, Type.without_pasword_save)); + synchronousBackground(() -> { + try { + listener.addStep(new Trinity<>(ProviderType.persistent, url, Type.request)); + listener.addStep(new Trinity<>(ProviderType.interactive, url, Type.request)); + listener.addStep(new Trinity<>(ProviderType.persistent, url, Type.without_pasword_save)); - commonScheme(url, false, null); - Assert.assertEquals(3, listener.getCnt()); - Assert.assertEquals(1, myTestInteraction.getNumSSLWarn()); - myTestInteraction.reset(); - savedOnceListener.assertForAwt(); - savedOnceListener.reset(); + commonScheme(url, false, null); + Assert.assertEquals(3, listener.getCnt()); + Assert.assertEquals(1, myTestInteraction.getNumSSLWarn()); + myTestInteraction.reset(); + savedOnceListener.assertForAwt(); + savedOnceListener.reset(); - SvnConfiguration.RUNTIME_AUTH_CACHE.clear(); - listener.addStep(new Trinity(ProviderType.persistent, url, Type.request)); - listener.addStep(new Trinity(ProviderType.interactive, url, Type.request)); - listener.addStep(new Trinity(ProviderType.persistent, url, Type.without_pasword_save)); - commonScheme(url, false, null); - Assert.assertEquals(6, listener.getCnt()); - Assert.assertEquals(1, myTestInteraction.getNumSSLWarn()); - } - catch (SVNException e) { - exception[0] = e; - } - result[0] = true; + SvnConfiguration.RUNTIME_AUTH_CACHE.clear(); + listener.addStep(new Trinity<>(ProviderType.persistent, url, Type.request)); + listener.addStep(new Trinity<>(ProviderType.interactive, url, Type.request)); + listener.addStep(new Trinity<>(ProviderType.persistent, url, Type.without_pasword_save)); + commonScheme(url, false, null); + Assert.assertEquals(6, listener.getCnt()); + Assert.assertEquals(1, myTestInteraction.getNumSSLWarn()); } + catch (SVNException e) { + exception[0] = e; + } + result[0] = true; }); Assert.assertTrue(result[0]); @@ -714,61 +678,55 @@ public class SvnAuthenticationTest extends PlatformTestCase { final SVNException[] exception = new SVNException[1]; final Boolean[] result = new Boolean[1]; - synchronousBackground(new Runnable() { - @Override - public void run() { - try { - listener.addStep(new Trinity(ProviderType.persistent, url, Type.request)); - listener.addStep(new Trinity(ProviderType.interactive, url, Type.request)); - listener.addStep(new Trinity(ProviderType.persistent, url, Type.save)); + synchronousBackground(() -> { + try { + listener.addStep(new Trinity<>(ProviderType.persistent, url, Type.request)); + listener.addStep(new Trinity<>(ProviderType.interactive, url, Type.request)); + listener.addStep(new Trinity<>(ProviderType.persistent, url, Type.save)); - commonScheme(url, false, null); - long start = System.currentTimeMillis(); - waitListenerStep(start, listener, 3); - Assert.assertEquals(1, myTestInteraction.getNumPlaintextPrompt()); - savedOnceListener.assertSaved(url, ISVNAuthenticationManager.PASSWORD); - savedOnceListener.reset(); - myTestInteraction.reset(); + commonScheme(url, false, null); + long start = System.currentTimeMillis(); + waitListenerStep(start, listener, 3); + Assert.assertEquals(1, myTestInteraction.getNumPlaintextPrompt()); + savedOnceListener.assertSaved(url, ISVNAuthenticationManager.PASSWORD); + savedOnceListener.reset(); + myTestInteraction.reset(); - UIUtil.invokeAndWaitIfNeeded(new Runnable() { - @Override - public void run() { - try { - clearAuthCache(); - } - catch (Exception e) { - throw new RuntimeException(e); - } - } - }); + UIUtil.invokeAndWaitIfNeeded((Runnable)() -> { + try { + clearAuthCache(); + } + catch (Exception e) { + throw new RuntimeException(e); + } + }); - myTestInteraction.setPlaintextAnswer(false); - SvnConfiguration.RUNTIME_AUTH_CACHE.clear(); + myTestInteraction.setPlaintextAnswer(false); + SvnConfiguration.RUNTIME_AUTH_CACHE.clear(); - listener.addStep(new Trinity(ProviderType.persistent, url, Type.request)); - listener.addStep(new Trinity(ProviderType.interactive, url, Type.request)); - listener.addStep(new Trinity(ProviderType.persistent, url, Type.without_pasword_save)); - commonScheme(url, false, null); - start = System.currentTimeMillis(); - waitListenerStep(start, listener, 6); - Assert.assertEquals(1, myTestInteraction.getNumPlaintextPrompt()); + listener.addStep(new Trinity<>(ProviderType.persistent, url, Type.request)); + listener.addStep(new Trinity<>(ProviderType.interactive, url, Type.request)); + listener.addStep(new Trinity<>(ProviderType.persistent, url, Type.without_pasword_save)); + commonScheme(url, false, null); + start = System.currentTimeMillis(); + waitListenerStep(start, listener, 6); + Assert.assertEquals(1, myTestInteraction.getNumPlaintextPrompt()); - savedOnceListener.reset(); - myTestInteraction.reset(); - SvnConfiguration.RUNTIME_AUTH_CACHE.clear(); - listener.addStep(new Trinity(ProviderType.persistent, url, Type.request)); - listener.addStep(new Trinity(ProviderType.interactive, url, Type.request)); - listener.addStep(new Trinity(ProviderType.persistent, url, Type.without_pasword_save)); - commonScheme(url, false, null); - start = System.currentTimeMillis(); - waitListenerStep(start, listener, 9); - Assert.assertEquals(1, myTestInteraction.getNumPlaintextPrompt()); - } - catch (SVNException e) { - exception[0] = e; - } - result[0] = true; + savedOnceListener.reset(); + myTestInteraction.reset(); + SvnConfiguration.RUNTIME_AUTH_CACHE.clear(); + listener.addStep(new Trinity<>(ProviderType.persistent, url, Type.request)); + listener.addStep(new Trinity<>(ProviderType.interactive, url, Type.request)); + listener.addStep(new Trinity<>(ProviderType.persistent, url, Type.without_pasword_save)); + commonScheme(url, false, null); + start = System.currentTimeMillis(); + waitListenerStep(start, listener, 9); + Assert.assertEquals(1, myTestInteraction.getNumPlaintextPrompt()); } + catch (SVNException e) { + exception[0] = e; + } + result[0] = true; }); Assert.assertTrue(result[0]); @@ -803,36 +761,33 @@ public class SvnAuthenticationTest extends PlatformTestCase { final SVNException[] exception = new SVNException[1]; final Boolean[] result = new Boolean[1]; - synchronousBackground(new Runnable() { - @Override - public void run() { - try { - listener.addStep(new Trinity(ProviderType.persistent, url, Type.request)); - listener.addStep(new Trinity(ProviderType.interactive, url, Type.request)); - listener.addStep(new Trinity(ProviderType.persistent, url, Type.without_pasword_save)); + synchronousBackground(() -> { + try { + listener.addStep(new Trinity<>(ProviderType.persistent, url, Type.request)); + listener.addStep(new Trinity<>(ProviderType.interactive, url, Type.request)); + listener.addStep(new Trinity<>(ProviderType.persistent, url, Type.without_pasword_save)); - commonScheme(url, false, null); - long start = System.currentTimeMillis(); - waitListenerStep(start, listener, 3); - Assert.assertEquals(1, myTestInteraction.getNumPlaintextPrompt()); - // actually password not saved, but save was called - savedOnceListener.assertSaved(url, ISVNAuthenticationManager.PASSWORD); - savedOnceListener.reset(); - myTestInteraction.reset(); + commonScheme(url, false, null); + long start = System.currentTimeMillis(); + waitListenerStep(start, listener, 3); + Assert.assertEquals(1, myTestInteraction.getNumPlaintextPrompt()); + // actually password not saved, but save was called + savedOnceListener.assertSaved(url, ISVNAuthenticationManager.PASSWORD); + savedOnceListener.reset(); + myTestInteraction.reset(); - listener.addStep(new Trinity(ProviderType.persistent, url2, Type.request)); - listener.addStep(new Trinity(ProviderType.interactive, url2, Type.request)); - listener.addStep(new Trinity(ProviderType.persistent, url2, Type.without_pasword_save)); - commonScheme(url2, false, "anotherRealm"); - start = System.currentTimeMillis(); - waitListenerStep(start, listener, 6); - Assert.assertEquals(1, myTestInteraction.getNumPlaintextPrompt()); - } - catch (SVNException e) { - exception[0] = e; - } - result[0] = true; + listener.addStep(new Trinity<>(ProviderType.persistent, url2, Type.request)); + listener.addStep(new Trinity<>(ProviderType.interactive, url2, Type.request)); + listener.addStep(new Trinity<>(ProviderType.persistent, url2, Type.without_pasword_save)); + commonScheme(url2, false, "anotherRealm"); + start = System.currentTimeMillis(); + waitListenerStep(start, listener, 6); + Assert.assertEquals(1, myTestInteraction.getNumPlaintextPrompt()); } + catch (SVNException e) { + exception[0] = e; + } + result[0] = true; }); Assert.assertTrue(result[0]); @@ -863,62 +818,56 @@ public class SvnAuthenticationTest extends PlatformTestCase { final SVNException[] exception = new SVNException[1]; final Boolean[] result = new Boolean[1]; - synchronousBackground(new Runnable() { - @Override - public void run() { - try { - listener.addStep(new Trinity(ProviderType.persistent, url, Type.request)); - listener.addStep(new Trinity(ProviderType.interactive, url, Type.request)); - listener.addStep(new Trinity(ProviderType.persistent, url, Type.save)); + synchronousBackground(() -> { + try { + listener.addStep(new Trinity<>(ProviderType.persistent, url, Type.request)); + listener.addStep(new Trinity<>(ProviderType.interactive, url, Type.request)); + listener.addStep(new Trinity<>(ProviderType.persistent, url, Type.save)); - commonScheme(url, false, null); - long start = System.currentTimeMillis(); - waitListenerStep(start, listener, 3); - Assert.assertEquals(1, myTestInteraction.getNumSSLPlaintextPrompt()); - savedOnceListener.assertSaved(url, ISVNAuthenticationManager.SSL); - savedOnceListener.reset(); - myTestInteraction.reset(); + commonScheme(url, false, null); + long start = System.currentTimeMillis(); + waitListenerStep(start, listener, 3); + Assert.assertEquals(1, myTestInteraction.getNumSSLPlaintextPrompt()); + savedOnceListener.assertSaved(url, ISVNAuthenticationManager.SSL); + savedOnceListener.reset(); + myTestInteraction.reset(); - UIUtil.invokeAndWaitIfNeeded(new Runnable() { - @Override - public void run() { - try { - clearAuthCache(); - } - catch (Exception e) { - throw new RuntimeException(e); - } - } - }); + UIUtil.invokeAndWaitIfNeeded((Runnable)() -> { + try { + clearAuthCache(); + } + catch (Exception e) { + throw new RuntimeException(e); + } + }); - myTestInteraction.setSSLPlaintextAnswer(false); - SvnConfiguration.RUNTIME_AUTH_CACHE.clear(); + myTestInteraction.setSSLPlaintextAnswer(false); + SvnConfiguration.RUNTIME_AUTH_CACHE.clear(); - listener.addStep(new Trinity(ProviderType.persistent, url, Type.request)); - listener.addStep(new Trinity(ProviderType.interactive, url, Type.request)); - listener.addStep(new Trinity(ProviderType.persistent, url, Type.without_pasword_save)); - commonScheme(url, false, null); - start = System.currentTimeMillis(); - waitListenerStep(start, listener, 6); - Assert.assertEquals(1, myTestInteraction.getNumSSLPlaintextPrompt()); + listener.addStep(new Trinity<>(ProviderType.persistent, url, Type.request)); + listener.addStep(new Trinity<>(ProviderType.interactive, url, Type.request)); + listener.addStep(new Trinity<>(ProviderType.persistent, url, Type.without_pasword_save)); + commonScheme(url, false, null); + start = System.currentTimeMillis(); + waitListenerStep(start, listener, 6); + Assert.assertEquals(1, myTestInteraction.getNumSSLPlaintextPrompt()); - SvnConfiguration.RUNTIME_AUTH_CACHE.clear(); - myTestInteraction.reset(); - savedOnceListener.reset(); + SvnConfiguration.RUNTIME_AUTH_CACHE.clear(); + myTestInteraction.reset(); + savedOnceListener.reset(); - listener.addStep(new Trinity(ProviderType.persistent, url, Type.request)); - listener.addStep(new Trinity(ProviderType.interactive, url, Type.request)); - listener.addStep(new Trinity(ProviderType.persistent, url, Type.without_pasword_save)); - commonScheme(url, false, null); - start = System.currentTimeMillis(); - waitListenerStep(start, listener, 9); - Assert.assertEquals(1, myTestInteraction.getNumSSLPlaintextPrompt()); - } - catch (SVNException e) { - exception[0] = e; - } - result[0] = true; + listener.addStep(new Trinity<>(ProviderType.persistent, url, Type.request)); + listener.addStep(new Trinity<>(ProviderType.interactive, url, Type.request)); + listener.addStep(new Trinity<>(ProviderType.persistent, url, Type.without_pasword_save)); + commonScheme(url, false, null); + start = System.currentTimeMillis(); + waitListenerStep(start, listener, 9); + Assert.assertEquals(1, myTestInteraction.getNumSSLPlaintextPrompt()); } + catch (SVNException e) { + exception[0] = e; + } + result[0] = true; }); Assert.assertTrue(result[0]); @@ -937,14 +886,11 @@ public class SvnAuthenticationTest extends PlatformTestCase { private static void synchronousBackground(final Runnable runnable) throws InterruptedException { final Semaphore semaphore = new Semaphore(); semaphore.down(); - ApplicationManager.getApplication().executeOnPooledThread(new Runnable() { - @Override - public void run() { - try { - runnable.run(); - } finally { - semaphore.up(); - } + ApplicationManager.getApplication().executeOnPooledThread((Runnable)() -> { + try { + runnable.run(); + } finally { + semaphore.up(); } }); semaphore.waitFor(); @@ -1049,7 +995,7 @@ public class SvnAuthenticationTest extends PlatformTestCase { private TestListener(final Object synchObject) { mySynchObject = synchObject; - myExpectedSequence = new ArrayList>(); + myExpectedSequence = new ArrayList<>(); myCnt = 0; mySuccess = true; } @@ -1087,7 +1033,7 @@ public class SvnAuthenticationTest extends PlatformTestCase { } private void saveRegistration(ProviderType type, SVNURL url, boolean withCredentials) { - mySuccess = myExpectedSequence.get(myCnt).equals(new Trinity(type, url, withCredentials ? Type.save : Type.without_pasword_save)); + mySuccess = myExpectedSequence.get(myCnt).equals(new Trinity<>(type, url, withCredentials ? Type.save : Type.without_pasword_save)); if (mySuccess) { ++ myCnt; } @@ -1106,7 +1052,7 @@ public class SvnAuthenticationTest extends PlatformTestCase { public void requested(ProviderType type, SVNURL url, String realm, String kind, boolean canceled) { if (! mySuccess) return; - mySuccess = myExpectedSequence.get(myCnt).equals(new Trinity(type, url, Type.request)); + mySuccess = myExpectedSequence.get(myCnt).equals(new Trinity<>(type, url, Type.request)); if (mySuccess) { ++ myCnt; } @@ -1127,8 +1073,8 @@ public class SvnAuthenticationTest extends PlatformTestCase { private boolean mySaveCalled; private SavedOnceListener() { - myClientRequested = new HashSet>(); - mySaved = new HashSet>(); + myClientRequested = new HashSet<>(); + mySaved = new HashSet<>(); } @Override @@ -1159,7 +1105,7 @@ public class SvnAuthenticationTest extends PlatformTestCase { } private void saveRegistration(SVNURL url, String kind) { - final Pair pair = new Pair(url, kind); + final Pair pair = new Pair<>(url, kind); if (mySaved.contains(pair)) { myCause = "saved twice"; } @@ -1167,13 +1113,13 @@ public class SvnAuthenticationTest extends PlatformTestCase { } public boolean isSaved(final SVNURL url, final String kind) { - return mySaved.contains(new Pair(url, kind)); + return mySaved.contains(new Pair<>(url, kind)); } @Override public void requested(ProviderType type, SVNURL url, String realm, String kind, boolean canceled) { if (ProviderType.interactive.equals(type)) { - final Pair pair = new Pair(url, kind); + final Pair pair = new Pair<>(url, kind); if (myClientRequested.contains(pair)) { myCause = "client requested twice"; } @@ -1186,11 +1132,11 @@ public class SvnAuthenticationTest extends PlatformTestCase { } public void assertSaved(final SVNURL url, final String kind) { - Assert.assertTrue("not saved", mySaved.contains(new Pair(url, kind))); + Assert.assertTrue("not saved", mySaved.contains(new Pair<>(url, kind))); } public void assertNotSaved(final SVNURL url, final String kind) { - Assert.assertTrue("saved", ! mySaved.contains(new Pair(url, kind))); + Assert.assertTrue("saved", ! mySaved.contains(new Pair<>(url, kind))); } } diff --git a/plugins/ui-designer/src/com/intellij/uiDesigner/Properties.java b/plugins/ui-designer/src/com/intellij/uiDesigner/Properties.java index 0c0c84dfd175..15e0064770b8 100644 --- a/plugins/ui-designer/src/com/intellij/uiDesigner/Properties.java +++ b/plugins/ui-designer/src/com/intellij/uiDesigner/Properties.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * 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. @@ -15,11 +15,10 @@ */ package com.intellij.uiDesigner; -import com.intellij.openapi.components.NamedComponent; +import com.intellij.openapi.components.PersistentStateComponent; import com.intellij.openapi.components.ServiceManager; +import com.intellij.openapi.components.State; import com.intellij.openapi.module.Module; -import com.intellij.openapi.util.JDOMExternalizable; -import com.intellij.openapi.util.WriteExternalException; import com.intellij.psi.JavaPsiFacade; import com.intellij.psi.PsiClass; import com.intellij.psi.PsiMethod; @@ -27,7 +26,6 @@ import com.intellij.psi.util.PropertyUtil; import com.intellij.uiDesigner.lw.LwXmlReader; import com.intellij.uiDesigner.propertyInspector.editors.IntEnumEditor; import org.jdom.Element; -import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -37,7 +35,8 @@ import java.util.*; * @author Anton Katilin * @author Vladimir Kondratyev */ -public final class Properties implements NamedComponent, JDOMExternalizable{ +@State(name = "gui-designer-properties", defaultStateAsResource = true, storages = {}) +public final class Properties implements PersistentStateComponent { private final HashMap myClass2InplaceProperty; private final HashMap> myClass2ExpertProperties; private final Map> myClass2EnumProperties; @@ -113,22 +112,17 @@ public final class Properties implements NamedComponent, JDOMExternalizable{ return null; } - @SuppressWarnings({"HardCodedStringLiteral"}) - public void readExternal(final Element element) { - for (final Object classObject : element.getChildren("class")) { - final Element classElement = (Element)classObject; - + @Override + public void loadState(Element state) { + for (Element classElement : state.getChildren("class")) { final String className = LwXmlReader.getRequiredString(classElement, "name"); // Read "expert" properties final Element expertPropertiesElement = classElement.getChild("expert-properties"); if (expertPropertiesElement != null) { - final HashSet expertProperties = new HashSet(); - - for (final Object o : expertPropertiesElement.getChildren("property")) { - final Element e = (Element)o; - final String name = LwXmlReader.getRequiredString(e, "name"); - expertProperties.add(name); + HashSet expertProperties = new HashSet(); + for (Element e : expertPropertiesElement.getChildren("property")) { + expertProperties.add(LwXmlReader.getRequiredString(e, "name")); } myClass2ExpertProperties.put(className, expertProperties); @@ -171,12 +165,9 @@ public final class Properties implements NamedComponent, JDOMExternalizable{ } } - public void writeExternal(final Element element) throws WriteExternalException{ - throw new WriteExternalException(); - } - - @NonNls @NotNull - public String getComponentName() { - return "gui-designer-properties"; + @Nullable + @Override + public Element getState() { + return null; } } diff --git a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/quickfix/DownloadManager.java b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/quickfix/DownloadManager.java index d448c4f4562d..6ca2bdd84a6e 100644 --- a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/quickfix/DownloadManager.java +++ b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/quickfix/DownloadManager.java @@ -18,8 +18,6 @@ package org.intellij.lang.xpath.xslt.quickfix; import com.intellij.javaee.ExternalResourceManager; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.PathManager; -import com.intellij.openapi.application.Result; -import com.intellij.openapi.application.WriteAction; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.project.Project; @@ -73,31 +71,24 @@ public abstract class DownloadManager { }); try { - final File _file = file; //noinspection unchecked final Set[] resourceDependencies = new Set[1]; - new WriteAction() { - @Override - protected void run(@NotNull Result result) throws Throwable { - final VirtualFile vf = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(_file); - if (vf != null) { - final PsiFile psiFile = PsiManager.getInstance(myProject).findFile(vf); - if (psiFile != null && isAccepted(psiFile)) { - resourceDependencies[0] = getResourceDependencies(psiFile); - resourceManager.addResource(location, _file.getAbsolutePath()); - } - else { - ApplicationManager.getApplication().invokeLater( - new Runnable() { - @Override - public void run() { - Messages.showErrorDialog(myProject, "Not a valid file: " + vf.getPresentableUrl(), "Download Problem"); - } - }, myProject.getDisposed()); - } - } + final VirtualFile vf = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(file); + if (vf != null) { + PsiFile psiFile = PsiManager.getInstance(myProject).findFile(vf); + if (psiFile != null && isAccepted(psiFile)) { + resourceDependencies[0] = getResourceDependencies(psiFile); + resourceManager.addResource(location, file.getAbsolutePath()); } - }.execute(); + else { + ApplicationManager.getApplication().invokeLater(new Runnable() { + @Override + public void run() { + Messages.showErrorDialog(myProject, "Not a valid file: " + vf.getPresentableUrl(), "Download Problem"); + } + }, myProject.getDisposed()); + } + } if (resourceDependencies[0] != null) { for (String s : resourceDependencies[0]) { diff --git a/resources-en/src/messages/DebuggerBundle.properties b/resources-en/src/messages/DebuggerBundle.properties index 0ccde1aa3a48..1107191084fe 100644 --- a/resources-en/src/messages/DebuggerBundle.properties +++ b/resources-en/src/messages/DebuggerBundle.properties @@ -28,9 +28,10 @@ title.evaluating=Evaluating... error.modification.watchpoints.not.supported=Target VM does not support modification watchpoints error.native.method.exception=None of the frames through and including frame may be native error.executing.finally=Error while executing finally blocks: {0} +error.early.return=Error while doing early return: {0} warning.finally.block.detected=Non-empty finally blocks detected: -button.drop.anyway=Drop frame anyway -button.execute.finally=Execute finally blocks and drop frame +button.drop.anyway=Do not execute +button.execute.finally=Execute finally blocks drop.frame.error.no.information=Information about the frame is not available action.remove.watch.text={0,choice, 1#Remove Watch|2#Remove Watches} progress.evaluating=Evaluating {0} @@ -233,7 +234,7 @@ label.debugger.general.configurable.skip.constructors=Skip &constructors label.debugger.general.configurable.skip.classLoaders=Skip class l&oaders label.debugger.general.configurable.skip.simple.getters=Skip simple &getters label.debugger.general.configurable.step.filters.list.header=Do not step &into the classes -label.debugger.general.configurable.evaluate.finally.on.pop=Evaluate finally blocks on pop frame: +label.debugger.general.configurable.evaluate.finally.on.pop=Evaluate finally blocks on pop frame and early return: label.debugger.general.configurable.evaluate.finally.always=&Always label.debugger.general.configurable.evaluate.finally.never=N&ever label.debugger.general.configurable.evaluate.finally.ask=As&k @@ -335,7 +336,7 @@ method.breakpoints.tab.title=Java Method Breakpoints title.error.evaluating.breakpoint.condition=Breakpoint Condition Error title.error.evaluating.breakpoint.action=Breakpoint Action Error error.evaluating.breakpoint.condition.or.action=Problem processing VM event:\nBreakpoint: ''{0}''\nError: {1}\nWould you like to stop at the breakpoint? -error.unable.to.evaluate.expression=unable to evaluate the expression +error.unable.to.evaluate.expression=Unable to evaluate the expression breakpoint.properties.panel.option.pass.count=&Pass count: breakpoint.properties.panel.option.class.filters=C&lass filters: breakpoint.properties.panel.option.instance.filters=&Instance filters: diff --git a/resources/src/META-INF/IdeaPlugin.xml b/resources/src/META-INF/IdeaPlugin.xml index dc491169370d..f4ee697a1045 100644 --- a/resources/src/META-INF/IdeaPlugin.xml +++ b/resources/src/META-INF/IdeaPlugin.xml @@ -1548,6 +1548,7 @@ + diff --git a/resources/src/idea/JavaActions.xml b/resources/src/idea/JavaActions.xml index 2f511f16f876..6f675109b883 100644 --- a/resources/src/idea/JavaActions.xml +++ b/resources/src/idea/JavaActions.xml @@ -110,6 +110,10 @@ + + + + diff --git a/xml/impl/src/com/intellij/codeInsight/template/emmet/ZenCodingTemplate.java b/xml/impl/src/com/intellij/codeInsight/template/emmet/ZenCodingTemplate.java index 2540fec6de44..978dec974a63 100644 --- a/xml/impl/src/com/intellij/codeInsight/template/emmet/ZenCodingTemplate.java +++ b/xml/impl/src/com/intellij/codeInsight/template/emmet/ZenCodingTemplate.java @@ -66,6 +66,9 @@ public class ZenCodingTemplate extends CustomLiveTemplateBase { @Nullable public static ZenCodingGenerator findApplicableDefaultGenerator(@NotNull PsiElement context, boolean wrapping) { + if (!context.isValid()) { + return null; + } for (ZenCodingGenerator generator : ZenCodingGenerator.getInstances()) { if (generator.isMyContext(context, wrapping) && generator.isAppliedByDefault(context)) { return generator;