From 668e1f52e2ac27d0625afc255a14abb7a7c0afce Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Mon, 16 Jun 2014 11:25:23 +0400 Subject: [PATCH 01/20] redundant assignment in arg list fixed (IDEA-126190) --- .../intellij/codeInspection/RemoveAssignmentFix.java | 2 +- .../unusedAssignment/afterCallAsArgument.java | 11 +++++++++++ .../unusedAssignment/beforeCallAsArgument.java | 11 +++++++++++ 3 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unusedAssignment/afterCallAsArgument.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unusedAssignment/beforeCallAsArgument.java diff --git a/java/java-impl/src/com/intellij/codeInspection/RemoveAssignmentFix.java b/java/java-impl/src/com/intellij/codeInspection/RemoveAssignmentFix.java index b80e3a07121d..9db065ad321f 100644 --- a/java/java-impl/src/com/intellij/codeInspection/RemoveAssignmentFix.java +++ b/java/java-impl/src/com/intellij/codeInspection/RemoveAssignmentFix.java @@ -40,7 +40,7 @@ public class RemoveAssignmentFix extends RemoveInitializerFix { if (!(parent instanceof PsiAssignmentExpression)) return; final PsiExpression rExpression = ((PsiAssignmentExpression)parent).getRExpression(); final PsiElement gParent = parent.getParent(); - if (gParent instanceof PsiExpression && rExpression != null) { + if ((gParent instanceof PsiExpression || gParent instanceof PsiExpressionList) && rExpression != null) { if (!FileModificationService.getInstance().prepareFileForWrite(gParent.getContainingFile())) return; if (gParent instanceof PsiParenthesizedExpression) { gParent.replace(rExpression); diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unusedAssignment/afterCallAsArgument.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unusedAssignment/afterCallAsArgument.java new file mode 100644 index 000000000000..6ef1870458fb --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unusedAssignment/afterCallAsArgument.java @@ -0,0 +1,11 @@ +// "Remove redundant assignment" "true" +class Test { + void foo() { + String var; + this.bar("someString"); + } + + void bar(String arg) { + + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unusedAssignment/beforeCallAsArgument.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unusedAssignment/beforeCallAsArgument.java new file mode 100644 index 000000000000..116cc94e30f4 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unusedAssignment/beforeCallAsArgument.java @@ -0,0 +1,11 @@ +// "Remove redundant assignment" "true" +class Test { + void foo() { + String var; + this.bar(var = "someString"); + } + + void bar(String arg) { + + } +} From 8cbfea6b51cf68ed1b6da709a0ad022a7a095c2a Mon Sep 17 00:00:00 2001 From: nik Date: Mon, 16 Jun 2014 11:26:37 +0400 Subject: [PATCH 02/20] fixed 'change library level' action: keep position in classpath, 'exported' and 'scope' values (IDEA-100632) --- .../roots/ui/configuration/ModuleEditor.java | 2 +- .../ChangeLibraryLevelActionBase.java | 2 +- .../ChangeLibraryLevelInClasspathAction.java | 10 ++-- .../openapi/roots/impl/OrderEntryUtil.java | 49 ++++++++++++++----- 4 files changed, 46 insertions(+), 17 deletions(-) diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ModuleEditor.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ModuleEditor.java index 47e901512ed5..14c5fba1ded9 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ModuleEditor.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ModuleEditor.java @@ -332,7 +332,7 @@ public abstract class ModuleEditor implements Place.Navigator, Disposable { private final ModifiableRootModel myDelegateModel; @NonNls private final Set myCheckedNames = new HashSet( Arrays.asList("addOrderEntry", "addLibraryEntry", "addInvalidLibrary", "addModuleOrderEntry", "addInvalidModuleEntry", - "removeOrderEntry", "setSdk", "inheritSdk", "inheritCompilerOutputPath", "setExcludeOutput", "replaceEntryOfType")); + "removeOrderEntry", "setSdk", "inheritSdk", "inheritCompilerOutputPath", "setExcludeOutput", "replaceEntryOfType", "rearrangeOrderEntries")); ModifiableRootModelInvocationHandler(ModifiableRootModel model) { myDelegateModel = model; diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/classpath/ChangeLibraryLevelActionBase.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/classpath/ChangeLibraryLevelActionBase.java index 046157ef3bc7..0a162f49bb90 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/classpath/ChangeLibraryLevelActionBase.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/classpath/ChangeLibraryLevelActionBase.java @@ -103,7 +103,7 @@ public abstract class ChangeLibraryLevelActionBase extends AnAction { } } - final Library copied = ((LibraryTableBase.ModifiableModelEx)provider.getModifiableModel()).createLibrary(dialog.getLibraryName(), library.getKind()); + final Library copied = ((LibraryTableBase.ModifiableModelEx)provider.getModifiableModel()).createLibrary(StringUtil.nullize(dialog.getLibraryName()), library.getKind()); final LibraryEx.ModifiableModelEx model = (LibraryEx.ModifiableModelEx)copied.getModifiableModel(); LibraryEditingUtil.copyLibrary(library, copiedFiles, model); diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/classpath/ChangeLibraryLevelInClasspathAction.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/classpath/ChangeLibraryLevelInClasspathAction.java index 2b42fd3158e4..9a670be8f458 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/classpath/ChangeLibraryLevelInClasspathAction.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/classpath/ChangeLibraryLevelInClasspathAction.java @@ -18,6 +18,7 @@ package com.intellij.openapi.roots.ui.configuration.classpath; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.roots.LibraryOrderEntry; import com.intellij.openapi.roots.OrderEntry; +import com.intellij.openapi.roots.impl.OrderEntryUtil; import com.intellij.openapi.roots.impl.libraries.LibraryEx; import com.intellij.openapi.roots.impl.libraries.LibraryTableImplUtil; import com.intellij.openapi.roots.libraries.Library; @@ -43,15 +44,18 @@ class ChangeLibraryLevelInClasspathAction extends ChangeLibraryLevelActionBase { public void actionPerformed(AnActionEvent event) { final OrderEntry entry = myPanel.getSelectedEntry(); if (!(entry instanceof LibraryOrderEntry)) return; - final LibraryEx library = (LibraryEx)((LibraryOrderEntry)entry).getLibrary(); + LibraryOrderEntry libraryEntry = (LibraryOrderEntry)entry; + final LibraryEx library = (LibraryEx)libraryEntry.getLibrary(); if (library == null) return; final Library copied = doCopy(library); if (copied == null) return; - myPanel.getRootModel().removeOrderEntry(entry); if (!isConvertingToModuleLibrary()) { - myPanel.getRootModel().addLibraryEntry(copied); + OrderEntryUtil.replaceLibrary(myPanel.getRootModel(), library, copied); + } + else { + OrderEntryUtil.replaceLibraryEntryByAdded(myPanel.getRootModel(), libraryEntry); } } diff --git a/platform/lang-impl/src/com/intellij/openapi/roots/impl/OrderEntryUtil.java b/platform/lang-impl/src/com/intellij/openapi/roots/impl/OrderEntryUtil.java index 1b58b05357a6..100eb1bcd284 100644 --- a/platform/lang-impl/src/com/intellij/openapi/roots/impl/OrderEntryUtil.java +++ b/platform/lang-impl/src/com/intellij/openapi/roots/impl/OrderEntryUtil.java @@ -26,6 +26,7 @@ import com.intellij.openapi.roots.libraries.Library; import com.intellij.openapi.roots.libraries.LibraryTable; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.util.ArrayUtil; import com.intellij.util.Processor; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -152,21 +153,45 @@ public class OrderEntryUtil { rootModel.commit(); } - public static void replaceLibrary(@NotNull ModifiableRootModel model, @NotNull Library oldLibrary, @NotNull Library newLibrary) { - OrderEntry[] entries = model.getOrderEntries(); + private static int findLibraryOrderEntry(@NotNull OrderEntry[] entries, @NotNull Library library) { for (int i = 0; i < entries.length; i++) { - OrderEntry orderEntry = entries[i]; - if (orderEntry instanceof LibraryOrderEntry && oldLibrary.equals(((LibraryOrderEntry)orderEntry).getLibrary())) { - model.removeOrderEntry(orderEntry); - final LibraryOrderEntry newEntry = model.addLibraryEntry(newLibrary); - final OrderEntry[] newEntries = new OrderEntry[entries.length]; - System.arraycopy(entries, 0, newEntries, 0, i); - newEntries[i] = newEntry; - System.arraycopy(entries, i, newEntries, i+1, entries.length - i - 1); - model.rearrangeOrderEntries(newEntries); - return; + OrderEntry entry = entries[i]; + if (entry instanceof LibraryOrderEntry && library.equals(((LibraryOrderEntry)entry).getLibrary())) { + return i; } } + return -1; + } + + public static void replaceLibrary(@NotNull ModifiableRootModel model, @NotNull Library oldLibrary, @NotNull Library newLibrary) { + int i = findLibraryOrderEntry(model.getOrderEntries(), oldLibrary); + if (i == -1) return; + + model.addLibraryEntry(newLibrary); + replaceLibraryByAdded(model, i); + } + + public static void replaceLibraryEntryByAdded(@NotNull ModifiableRootModel model, @NotNull LibraryOrderEntry entry) { + int i = ArrayUtil.indexOf(model.getOrderEntries(), entry); + if (i == -1) return; + + replaceLibraryByAdded(model, i); + } + + private static void replaceLibraryByAdded(ModifiableRootModel model, int toReplace) { + OrderEntry[] entries = model.getOrderEntries(); + LibraryOrderEntry newEntry = (LibraryOrderEntry)entries[entries.length - 1]; + LibraryOrderEntry libraryEntry = (LibraryOrderEntry)entries[toReplace]; + boolean exported = libraryEntry.isExported(); + DependencyScope scope = libraryEntry.getScope(); + model.removeOrderEntry(libraryEntry); + newEntry.setExported(exported); + newEntry.setScope(scope); + final OrderEntry[] newEntries = new OrderEntry[entries.length-1]; + System.arraycopy(entries, 0, newEntries, 0, toReplace); + newEntries[toReplace] = newEntry; + System.arraycopy(entries, toReplace + 1, newEntries, toReplace + 1, entries.length - toReplace - 2); + model.rearrangeOrderEntries(newEntries); } public static void processOrderEntries(@NotNull Module module, From c61a7a7a16ac9fa69f874d89501d1f1ff0110307 Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Mon, 16 Jun 2014 11:49:25 +0400 Subject: [PATCH 03/20] diff: fix NPE this should not happen normally, but can be caused by other exceptions --- .../src/com/intellij/openapi/vcs/ex/LineStatusTracker.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTracker.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTracker.java index 548cc514b300..59a63a591a07 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTracker.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTracker.java @@ -452,7 +452,9 @@ public class LineStatusTracker { private void replaceRanges(List rangesInChange, List newRangesInChange) { for (Range range : rangesInChange) { - range.getHighlighter().dispose(); + if (range.getHighlighter() != null) { + range.getHighlighter().dispose(); + } range.setHighlighter(null); } for (Range range : newRangesInChange) { From 803f4a6918937d2015928fd3fcf11e71af80e16b Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Mon, 16 Jun 2014 11:49:28 +0400 Subject: [PATCH 04/20] IDEA-95430 IDEA-103824 diff: fix changed range calculation bug case: modification right before previously deleted block vcs version: A B C Before: A B After: X B --- .../openapi/vcs/ex/LineStatusTracker.java | 139 +++++++----------- .../com/intellij/openapi/vcs/ex/Range.java | 18 --- 2 files changed, 54 insertions(+), 103 deletions(-) diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTracker.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTracker.java index 59a63a591a07..a0fcbd1770e9 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTracker.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTracker.java @@ -38,6 +38,7 @@ import com.intellij.openapi.vcs.changes.VcsDirtyScopeManager; import com.intellij.openapi.vcs.history.VcsRevisionNumber; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.ui.EditorNotificationPanel; +import com.intellij.util.containers.ContainerUtil; import com.intellij.util.diff.FilesTooBigForDiffException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -156,7 +157,7 @@ public class LineStatusTracker { } private void removeAnathema() { - if (! myAnathemaThrown) return; + if (!myAnathemaThrown) return; myAnathemaThrown = false; final FileEditor[] editors = myFileEditorManager.getEditors(myVirtualFile); for (FileEditor editor : editors) { @@ -286,8 +287,6 @@ public class LineStatusTracker { private class MyDocumentListener extends DocumentAdapter { private int myFirstChangedLine; - private int myUpToDateFirstLine; - private int myUpToDateLastLine; private int myLastChangedLine; private int myLinesBeforeChange; private final VcsDirtyScopeManager myVcsDirtyScopeManager = VcsDirtyScopeManager.getInstance(myProject); @@ -302,50 +301,14 @@ public class LineStatusTracker { try { myFirstChangedLine = myDocument.getLineNumber(e.getOffset()); myLastChangedLine = myDocument.getLineNumber(e.getOffset() + e.getOldLength()); + myLinesBeforeChange = myLastChangedLine - myFirstChangedLine; if (StringUtil.endsWithChar(e.getOldFragment(), '\n')) myLastChangedLine++; - - myLinesBeforeChange = myDocument.getLineNumber(e.getOffset() + e.getOldLength()) - myDocument.getLineNumber(e.getOffset()); - - Range firstChangedRange = getLastRangeBeforeLine(myFirstChangedLine); - - if (firstChangedRange == null) { - myUpToDateFirstLine = myFirstChangedLine; - } - else if (firstChangedRange.containsLine(myFirstChangedLine)) { - myFirstChangedLine = firstChangedRange.getOffset1(); - myUpToDateFirstLine = firstChangedRange.getUOffset1(); - } - else { - myUpToDateFirstLine = firstChangedRange.getUOffset2() + myFirstChangedLine - firstChangedRange.getOffset2(); - } - - Range myLastChangedRange = getLastRangeBeforeLine(myLastChangedLine); - - if (myLastChangedRange == null) { - myUpToDateLastLine = myLastChangedLine; - } - else if (myLastChangedRange.containsLine(myLastChangedLine)) { - myUpToDateLastLine = myLastChangedRange.getUOffset2(); - myLastChangedLine = myLastChangedRange.getOffset2(); - } - else { - myUpToDateLastLine = myLastChangedRange.getUOffset2() + myLastChangedLine - myLastChangedRange.getOffset2(); - } - } catch (ProcessCanceledException ignore) { + } + catch (ProcessCanceledException ignore) { } } } - @Nullable - private Range getLastRangeBeforeLine(int line) { - Range result = null; - for (Range range : myRanges) { - if (range.isAfter(line)) return result; - result = range; - } - return result; - } - @Override public void documentChanged(final DocumentEvent e) { myApplication.assertWriteAccessAllowed(); @@ -354,27 +317,40 @@ public class LineStatusTracker { if (myReleased) return; if (myBulkUpdate || myAnathemaThrown || BaseLoadState.LOADED != myBaseLoaded) return; try { + int upToDateFirstLine; + int upToDateLastLine; - int line = myDocument.getLineNumber(e.getOffset() + e.getNewLength()); - int linesAfterChange = line - myDocument.getLineNumber(e.getOffset()); + int linesAfterChange = myDocument.getLineNumber(e.getOffset() + e.getNewLength()) - myDocument.getLineNumber(e.getOffset()); int linesShift = linesAfterChange - myLinesBeforeChange; - List rangesAfterChange = getRangesAfter(myRanges, myLastChangedLine); - List rangesBeforeChange = getRangesBefore(myRanges, myFirstChangedLine); + List rangesBeforeChange = new ArrayList(); + List rangesAfterChange = new ArrayList(); + List changedRanges = new ArrayList(); + sortRanges(myRanges, myFirstChangedLine, myLastChangedLine, rangesBeforeChange, changedRanges, rangesAfterChange); - List changedRanges = getChangedRanges(myFirstChangedLine, myLastChangedLine); + Range firstChangedRange = ContainerUtil.getFirstItem(changedRanges); + Range lastChangedRange = ContainerUtil.getLastItem(changedRanges); + Range lastRangeBefore = ContainerUtil.getLastItem(rangesBeforeChange); - int newSize = rangesBeforeChange.size() + changedRanges.size() + rangesAfterChange.size(); - if (myRanges.size() != newSize) { - LOG.info("Ranges: " + myRanges + "; first changed line: " + myFirstChangedLine + "; last changed line: " + myLastChangedLine); - LOG.assertTrue(false); + if (firstChangedRange != null && firstChangedRange.getOffset1() < myFirstChangedLine) { + myFirstChangedLine = firstChangedRange.getOffset1(); + } + if (lastChangedRange != null && lastChangedRange.getOffset2() > myLastChangedLine) { + myLastChangedLine = lastChangedRange.getOffset2(); } + upToDateFirstLine = getUpToDateLine(lastRangeBefore, myFirstChangedLine); + + if (lastChangedRange == null) { + upToDateLastLine = getUpToDateLine(lastRangeBefore, myLastChangedLine); + } + else { + upToDateLastLine = getUpToDateLine(lastChangedRange, myLastChangedLine); + } myLastChangedLine += linesShift; - - List newChangedRanges = getNewChangedRanges(); + List newChangedRanges = getNewChangedRanges(upToDateFirstLine, upToDateLastLine); shiftRanges(rangesAfterChange, linesShift); @@ -418,11 +394,14 @@ public class LineStatusTracker { } } - private List getNewChangedRanges() throws FilesTooBigForDiffException { + private int getUpToDateLine(@Nullable Range range, int line) { + return range == null ? line : line + range.getUOffset2() - range.getOffset2(); + } + + private List getNewChangedRanges(int upToDateFirstLine, int upToDateLastLine) throws FilesTooBigForDiffException { List lines = new DocumentWrapper(myDocument).getLines(myFirstChangedLine, myLastChangedLine); - List uLines = new DocumentWrapper(myUpToDateDocument) - .getLines(myUpToDateFirstLine, myUpToDateLastLine); - return new RangesBuilder(lines, uLines, myFirstChangedLine, myUpToDateFirstLine).getRanges(); + List uLines = new DocumentWrapper(myUpToDateDocument).getLines(upToDateFirstLine, upToDateLastLine); + return new RangesBuilder(lines, uLines, myFirstChangedLine, upToDateFirstLine).getRanges(); } private List mergeRanges(List ranges) { @@ -467,20 +446,28 @@ public class LineStatusTracker { aRangesAfterChange.shift(shift); } } - } - private List getChangedRanges(int from, int to) { - return getChangedRanges(myRanges, from, to); - } - - public static List getChangedRanges(List ranges, int from, int to) { - ArrayList result = new ArrayList(); + public static void sortRanges(@NotNull List ranges, + int firstChangedLine, + int lastChangedLine, + @NotNull List rangesBeforeChange, + @NotNull List changedRanges, + @NotNull List rangesAfterChange) { for (Range range : ranges) { - if (range.getOffset1() <= to && range.getOffset2() >= from) result.add(range); -// if (range.getOffset1() > to) break; + int offset1 = range.getType() == Range.DELETED ? range.getOffset1() - 1 : range.getOffset1(); + int offset2 = range.getOffset2(); + + if (offset2 < firstChangedLine) { + rangesBeforeChange.add(range); + } + else if (offset1 > lastChangedLine) { + rangesAfterChange.add(range); + } + else { + changedRanges.add(range); + } } - return result; } @Nullable @@ -538,24 +525,6 @@ public class LineStatusTracker { } } - public static List getRangesBefore(List ranges, int line) { - ArrayList result = new ArrayList(); - - for (Range range : ranges) { - if (range.getOffset2() < line) result.add(range); - //if (range.getOffset2() > line) break; - } - return result; - } - - public static List getRangesAfter(List ranges, int line) { - ArrayList result = new ArrayList(); - for (Range range : ranges) { - if (range.getOffset1() > line) result.add(range); - } - return result; - } - @Nullable public Range getRangeForLine(final int line) { synchronized (myLock) { diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/Range.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/Range.java index 6900d46c9f10..03338a4510f9 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/Range.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/Range.java @@ -154,22 +154,4 @@ public class Range { public RangeHighlighter getHighlighter() { return myRangeHighlighter; } - - public boolean contains(int offset1, int offset2) { - return getOffset1() <= offset1 && getOffset2() >= offset2; - } - - public boolean containsLine(int line) { - if (myType == DELETED) return (myOffset1 - 1) <= line - && (myOffset2) >= line; - return myOffset1 <= line && myOffset2 >= line; - } - - public boolean isAfter(int line) { - if (myType == DELETED) - return (getOffset1() - 1) > line; - else - return getOffset1() > line; - } - } From 9c2daf694d246c11b20dbe2584eb85e192172658 Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Mon, 16 Jun 2014 11:49:31 +0400 Subject: [PATCH 05/20] diff: fix IDEA-97563 and related issues --- .../openapi/vcs/ex/LineStatusTracker.java | 55 ++++++++++++------- .../vcs/ex/ShowLineStatusRangeDiffAction.java | 4 +- 2 files changed, 38 insertions(+), 21 deletions(-) diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTracker.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTracker.java index a0fcbd1770e9..d8fd155c366b 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTracker.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTracker.java @@ -544,25 +544,34 @@ public class LineStatusTracker { myApplication.assertWriteAccessAllowed(); synchronized (myLock) { - TextRange currentTextRange = getCurrentTextRange(range); + TextRange currentTextRange = getCurrentTextRangeWithMagic(range); if (range.getType() == Range.INSERTED) { myDocument .replaceString(currentTextRange.getStartOffset(), Math.min(currentTextRange.getEndOffset() + 1, myDocument.getTextLength()), ""); } else if (range.getType() == Range.DELETED) { - String upToDateContent = getUpToDateContent(range); + String upToDateContent = getUpToDateContentWithMagic(range); myDocument.insertString(currentTextRange.getStartOffset(), upToDateContent); } else { - String upToDateContent = getUpToDateContent(range); + String upToDateContent = getUpToDateContentWithMagic(range); myDocument.replaceString(currentTextRange.getStartOffset(), Math.min(currentTextRange.getEndOffset() + 1, myDocument.getTextLength()), upToDateContent); } } } + public String getUpToDateContentWithMagic(Range range) { + synchronized (myLock) { + TextRange textRange = getUpToDateRangeWithMagic(range); + final int startOffset = textRange.getStartOffset(); + final int endOffset = Math.min(textRange.getEndOffset() + 1, myUpToDateDocument.getTextLength()); + return myUpToDateDocument.getCharsSequence().subSequence(startOffset, endOffset).toString(); + } + } + public String getUpToDateContent(Range range) { synchronized (myLock) { TextRange textRange = getUpToDateRange(range); @@ -576,25 +585,23 @@ public class LineStatusTracker { return myProject; } + TextRange getCurrentTextRangeWithMagic(Range range) { + return getRangeWithMagic(range.getType(), range.getOffset1(), range.getOffset2(), Range.DELETED, myDocument); + } + + TextRange getUpToDateRangeWithMagic(Range range) { + return getRangeWithMagic(range.getType(), range.getUOffset1(), range.getUOffset2(), Range.INSERTED, myUpToDateDocument); + } + TextRange getCurrentTextRange(Range range) { - return getRange(range.getType(), range.getOffset1(), range.getOffset2(), Range.DELETED, myDocument, false); + return getRange(range.getType(), range.getOffset1(), range.getOffset2(), Range.DELETED, myDocument); } TextRange getUpToDateRange(Range range) { - return getRange(range.getType(), range.getUOffset1(), range.getUOffset2(), Range.INSERTED, myUpToDateDocument, false); + return getRange(range.getType(), range.getUOffset1(), range.getUOffset2(), Range.INSERTED, myUpToDateDocument); } - TextRange getCurrentTextRangeWithEndSymbol(Range range) { - return getRange(range.getType(), range.getOffset1(), range.getOffset2(), Range.DELETED, myDocument, true); - } - - // a hack - TextRange getUpToDateRangeWithEndSymbol(Range range) { - return getRange(range.getType(), range.getUOffset1(), range.getUOffset2(), Range.INSERTED, myUpToDateDocument, true); - } - - private static TextRange getRange(byte rangeType, int offset1, int offset2, byte emptyRangeCondition, Document document, - final boolean keepEnd) { + private static TextRange getRangeWithMagic(byte rangeType, int offset1, int offset2, byte emptyRangeCondition, Document document) { if (rangeType == emptyRangeCondition) { int lineStartOffset; if (offset1 == 0) { @@ -612,14 +619,24 @@ public class LineStatusTracker { int endOffset = document.getLineEndOffset(offset2 - 1); if (startOffset > 0) { -- startOffset; - if (! keepEnd) { - -- endOffset; - } + -- endOffset; } return new TextRange(startOffset, endOffset); } } + private static TextRange getRange(byte rangeType, int offset1, int offset2, byte emptyRangeCondition, Document document) { + if (rangeType == emptyRangeCondition) { + int lineStartOffset = offset1 < document.getLineCount() ? document.getLineStartOffset(offset1) : document.getTextLength(); + return new TextRange(lineStartOffset, lineStartOffset); + } + else { + int startOffset = document.getLineStartOffset(offset1); + int endOffset = document.getLineEndOffset(offset2 - 1); + return new TextRange(startOffset, endOffset); + } + } + public static LineStatusTracker createOn(@Nullable VirtualFile virtualFile, final Document doc, final Project project) { final Document document = new DocumentImpl("",true); return new LineStatusTracker(doc, document, project, virtualFile); diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/ShowLineStatusRangeDiffAction.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/ShowLineStatusRangeDiffAction.java index 50622b27d0ce..c5dba0cab29c 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/ShowLineStatusRangeDiffAction.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/ShowLineStatusRangeDiffAction.java @@ -56,10 +56,10 @@ public class ShowLineStatusRangeDiffAction extends BaseLineStatusRangeAction { public DiffContent[] getContents() { return new DiffContent[]{ createDiffContent(myLineStatusTracker.getUpToDateDocument(), - myLineStatusTracker.getUpToDateRangeWithEndSymbol(myRange), + myLineStatusTracker.getUpToDateRange(myRange), null), createDiffContent(myLineStatusTracker.getDocument(), - myLineStatusTracker.getCurrentTextRangeWithEndSymbol(myRange), + myLineStatusTracker.getCurrentTextRange(myRange), myLineStatusTracker.getVirtualFile())}; } From ffcbeab9c5555fe1935902a6a2791073762593e2 Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Mon, 16 Jun 2014 11:49:34 +0400 Subject: [PATCH 06/20] diff: cleanup --- .../openapi/vcs/ex/LineStatusTracker.java | 63 +++++++++++-------- 1 file changed, 36 insertions(+), 27 deletions(-) diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTracker.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTracker.java index d8fd155c366b..39585fe8678b 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTracker.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTracker.java @@ -51,14 +51,14 @@ import java.util.ListIterator; /** * @author irengrig - * author: lesya + * author: lesya */ public class LineStatusTracker { private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.vcs.ex.LineStatusTracker"); - private static final Key PANEL_KEY = new Key("LineStatusTracker.CanNotCalculateDiffPanel"); + private static final Key PANEL_KEY = + new Key("LineStatusTracker.CanNotCalculateDiffPanel"); private final Object myLock = new Object(); - // true -> have contents private BaseLoadState myBaseLoaded; private final Document myDocument; @@ -72,15 +72,17 @@ public class LineStatusTracker { private boolean myBulkUpdate; private final Application myApplication; - @Nullable - private RevisionPack myBaseRevisionNumber; + @Nullable private RevisionPack myBaseRevisionNumber; private String myPreviousBaseRevision; private boolean myAnathemaThrown; private FileEditorManager myFileEditorManager; private final VirtualFile myVirtualFile; private boolean myReleased = false; - private LineStatusTracker(final Document document, final Document upToDateDocument, final Project project, final VirtualFile virtualFile) { + private LineStatusTracker(@NotNull final Document document, + @NotNull final Document upToDateDocument, + final Project project, + @Nullable final VirtualFile virtualFile) { myVirtualFile = virtualFile; myApplication = ApplicationManager.getApplication(); myDocument = document; @@ -386,8 +388,10 @@ public class LineStatusTracker { }); } } - } catch (ProcessCanceledException ignore) { - } catch (FilesTooBigForDiffException e1) { + } + catch (ProcessCanceledException ignore) { + } + catch (FilesTooBigForDiffException e1) { installAnathema(); removeHighlightersFromMarkupModel(); } @@ -404,7 +408,8 @@ public class LineStatusTracker { return new RangesBuilder(lines, uLines, myFirstChangedLine, upToDateFirstLine).getRanges(); } - private List mergeRanges(List ranges) { + @NotNull + private List mergeRanges(@NotNull List ranges) { ArrayList result = new ArrayList(); Iterator iterator = ranges.iterator(); if (!iterator.hasNext()) return result; @@ -429,7 +434,7 @@ public class LineStatusTracker { return result; } - private void replaceRanges(List rangesInChange, List newRangesInChange) { + private void replaceRanges(@NotNull List rangesInChange, @NotNull List newRangesInChange) { for (Range range : rangesInChange) { if (range.getHighlighter() != null) { range.getHighlighter().dispose(); @@ -441,7 +446,7 @@ public class LineStatusTracker { } } - private void shiftRanges(List rangesAfterChange, int shift) { + private void shiftRanges(@NotNull List rangesAfterChange, int shift) { for (final Range aRangesAfterChange : rangesAfterChange) { aRangesAfterChange.shift(shift); } @@ -514,7 +519,7 @@ public class LineStatusTracker { return getPrevRange(currentRange); } - for (ListIterator iterator = myRanges.listIterator(myRanges.size()); iterator.hasPrevious();) { + for (ListIterator iterator = myRanges.listIterator(myRanges.size()); iterator.hasPrevious(); ) { final Range range = iterator.previous(); if (range.getOffset1() > line) { continue; @@ -546,19 +551,18 @@ public class LineStatusTracker { synchronized (myLock) { TextRange currentTextRange = getCurrentTextRangeWithMagic(range); + int offset1 = currentTextRange.getStartOffset(); + int offset2 = Math.min(currentTextRange.getEndOffset() + 1, myDocument.getTextLength()); if (range.getType() == Range.INSERTED) { - myDocument - .replaceString(currentTextRange.getStartOffset(), Math.min(currentTextRange.getEndOffset() + 1, myDocument.getTextLength()), ""); + myDocument.replaceString(offset1, offset2, ""); } else if (range.getType() == Range.DELETED) { String upToDateContent = getUpToDateContentWithMagic(range); - myDocument.insertString(currentTextRange.getStartOffset(), upToDateContent); + myDocument.insertString(offset1, upToDateContent); } else { - String upToDateContent = getUpToDateContentWithMagic(range); - myDocument.replaceString(currentTextRange.getStartOffset(), Math.min(currentTextRange.getEndOffset() + 1, myDocument.getTextLength()), - upToDateContent); + myDocument.replaceString(offset1, offset2, upToDateContent); } } } @@ -585,22 +589,27 @@ public class LineStatusTracker { return myProject; } - TextRange getCurrentTextRangeWithMagic(Range range) { + @NotNull + TextRange getCurrentTextRangeWithMagic(@NotNull Range range) { return getRangeWithMagic(range.getType(), range.getOffset1(), range.getOffset2(), Range.DELETED, myDocument); } - TextRange getUpToDateRangeWithMagic(Range range) { + @NotNull + TextRange getUpToDateRangeWithMagic(@NotNull Range range) { return getRangeWithMagic(range.getType(), range.getUOffset1(), range.getUOffset2(), Range.INSERTED, myUpToDateDocument); } - TextRange getCurrentTextRange(Range range) { + @NotNull + TextRange getCurrentTextRange(@NotNull Range range) { return getRange(range.getType(), range.getOffset1(), range.getOffset2(), Range.DELETED, myDocument); } - TextRange getUpToDateRange(Range range) { + @NotNull + TextRange getUpToDateRange(@NotNull Range range) { return getRange(range.getType(), range.getUOffset1(), range.getUOffset2(), Range.INSERTED, myUpToDateDocument); } + @NotNull private static TextRange getRangeWithMagic(byte rangeType, int offset1, int offset2, byte emptyRangeCondition, Document document) { if (rangeType == emptyRangeCondition) { int lineStartOffset; @@ -612,19 +621,19 @@ public class LineStatusTracker { } //if (lineStartOffset > 0) lineStartOffset--; return new TextRange(lineStartOffset, lineStartOffset); - } else { int startOffset = document.getLineStartOffset(offset1); int endOffset = document.getLineEndOffset(offset2 - 1); if (startOffset > 0) { - -- startOffset; - -- endOffset; + --startOffset; + --endOffset; } return new TextRange(startOffset, endOffset); } } + @NotNull private static TextRange getRange(byte rangeType, int offset1, int offset2, byte emptyRangeCondition, Document document) { if (rangeType == emptyRangeCondition) { int lineStartOffset = offset1 < document.getLineCount() ? document.getLineStartOffset(offset1) : document.getTextLength(); @@ -637,8 +646,8 @@ public class LineStatusTracker { } } - public static LineStatusTracker createOn(@Nullable VirtualFile virtualFile, final Document doc, final Project project) { - final Document document = new DocumentImpl("",true); + public static LineStatusTracker createOn(@Nullable VirtualFile virtualFile, @NotNull final Document doc, final Project project) { + final Document document = new DocumentImpl("", true); return new LineStatusTracker(doc, document, project, virtualFile); } From d809d097f46077012c36f8f4c53ae1bd3bbb9098 Mon Sep 17 00:00:00 2001 From: nik Date: Mon, 16 Jun 2014 13:18:10 +0400 Subject: [PATCH 07/20] added logging for BookmarkManagerTest#testBookmarkLineRemove --- .../openapi/components/impl/ComponentManagerImpl.java | 5 +++++ .../extensions/impl/ExtensionComponentAdapter.java | 5 +++++ .../openapi/components/impl/ServiceManagerImpl.java | 5 +++++ .../com/intellij/ide/bookmarks/BookmarkManagerTest.java | 8 ++++++++ 4 files changed, 23 insertions(+) diff --git a/platform/core-impl/src/com/intellij/openapi/components/impl/ComponentManagerImpl.java b/platform/core-impl/src/com/intellij/openapi/components/impl/ComponentManagerImpl.java index 7a0e77707300..6d280a5e11af 100644 --- a/platform/core-impl/src/com/intellij/openapi/components/impl/ComponentManagerImpl.java +++ b/platform/core-impl/src/com/intellij/openapi/components/impl/ComponentManagerImpl.java @@ -611,5 +611,10 @@ public abstract class ComponentManagerImpl extends UserDataHolderBase implements visitor.visitComponentAdapter(this); myDelegate.accept(visitor); } + + @Override + public String toString() { + return "ComponentConfigAdapter[" + getComponentKey() + "]: implementation=" + getComponentImplementation() + ", plugin=" + myConfig.getPluginId(); + } } } diff --git a/platform/extensions/src/com/intellij/openapi/extensions/impl/ExtensionComponentAdapter.java b/platform/extensions/src/com/intellij/openapi/extensions/impl/ExtensionComponentAdapter.java index d172a30ff285..f992e45bc9fc 100644 --- a/platform/extensions/src/com/intellij/openapi/extensions/impl/ExtensionComponentAdapter.java +++ b/platform/extensions/src/com/intellij/openapi/extensions/impl/ExtensionComponentAdapter.java @@ -191,4 +191,9 @@ public class ExtensionComponentAdapter implements LoadingOrder.Orderable, Assign public void setNotificationSent(boolean notificationSent) { myNotificationSent = notificationSent; } + + @Override + public String toString() { + return "ExtensionComponentAdapter[" + myImplementationClassName + "]: plugin=" + myPluginDescriptor; + } } 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 641208bf4477..0b302d11f9c1 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 @@ -190,5 +190,10 @@ public class ServiceManagerImpl implements BaseComponent { public String getAssignableToClassName() { return myDescriptor.getInterface(); } + + @Override + public String toString() { + return "ServiceComponentAdapter[" + myDescriptor.getInterface() + "]: implementation=" + myDescriptor.getImplementation() + ", plugin=" + myPluginDescriptor; + } } } diff --git a/platform/platform-tests/testSrc/com/intellij/ide/bookmarks/BookmarkManagerTest.java b/platform/platform-tests/testSrc/com/intellij/ide/bookmarks/BookmarkManagerTest.java index 6c0a9f10886b..ed3c995edf48 100644 --- a/platform/platform-tests/testSrc/com/intellij/ide/bookmarks/BookmarkManagerTest.java +++ b/platform/platform-tests/testSrc/com/intellij/ide/bookmarks/BookmarkManagerTest.java @@ -21,10 +21,12 @@ import com.intellij.openapi.editor.LogicalPosition; import com.intellij.openapi.editor.impl.AbstractEditorTest; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.fileEditor.OpenFileDescriptor; +import com.intellij.openapi.vcs.changes.ChangeListManagerImpl; import com.intellij.openapi.vfs.VfsUtil; import com.intellij.testFramework.LeakHunter; import com.intellij.testFramework.TestFileType; import org.jetbrains.annotations.NonNls; +import org.picocontainer.ComponentAdapter; import java.io.IOException; import java.util.ArrayList; @@ -69,6 +71,12 @@ public class BookmarkManagerTest extends AbstractEditorTest { } public void testBookmarkLineRemove() throws IOException { + List adapters = getProject().getPicoContainer().getComponentAdaptersOfType(ChangeListManagerImpl.class); + System.out.println(adapters.size() + " adapters:"); + for (ComponentAdapter adapter : adapters) { + System.out.println(adapter); + } + @NonNls String text = "public class Test {\n" + " public void test() {\n" + From bbc13de04a2382753b99db7df4e68307449688cb Mon Sep 17 00:00:00 2001 From: "Vladislav.Soroka" Date: Mon, 16 Jun 2014 13:27:27 +0400 Subject: [PATCH 08/20] IDEA-126138 Open gradle test report should not be visible for non-gradle projects --- .../OpenGradleTestResultActionProvider.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/execution/test/runner/OpenGradleTestResultActionProvider.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/execution/test/runner/OpenGradleTestResultActionProvider.java index 6ae3a2cfb8b6..522c6057b9eb 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/execution/test/runner/OpenGradleTestResultActionProvider.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/execution/test/runner/OpenGradleTestResultActionProvider.java @@ -15,17 +15,21 @@ */ package org.jetbrains.plugins.gradle.execution.test.runner; +import com.intellij.execution.configurations.RunConfiguration; import com.intellij.execution.testframework.TestConsoleProperties; import com.intellij.execution.testframework.TestFrameworkRunningModel; import com.intellij.execution.testframework.ToggleModelAction; import com.intellij.execution.testframework.ToggleModelActionProvider; import com.intellij.ide.BrowserUtil; import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.externalSystem.model.ProjectSystemId; +import com.intellij.openapi.externalSystem.service.execution.ExternalSystemRunConfiguration; import com.intellij.util.config.AbstractProperty; import com.intellij.util.config.BooleanProperty; import icons.GradleIcons; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.gradle.util.GradleBundle; +import org.jetbrains.plugins.gradle.util.GradleConstants; import java.io.File; @@ -42,6 +46,9 @@ public class OpenGradleTestResultActionProvider implements ToggleModelActionProv } private static class MyToggleModelAction extends ToggleModelAction { + @Nullable + private ProjectSystemId mySystemId; + public MyToggleModelAction(TestConsoleProperties properties) { super(GradleBundle.message("gradle.test.runner.ui.tests.actions.open.gradle.report.text"), GradleBundle.message("gradle.test.runner.ui.tests.actions.open.gradle.report.desc"), @@ -50,6 +57,10 @@ public class OpenGradleTestResultActionProvider implements ToggleModelActionProv @Override public void setModel(TestFrameworkRunningModel model) { + final RunConfiguration runConfiguration = model.getProperties().getConfiguration(); + if(runConfiguration instanceof ExternalSystemRunConfiguration) { + mySystemId = ((ExternalSystemRunConfiguration)runConfiguration).getSettings().getExternalSystemId(); + } } @Override @@ -66,6 +77,11 @@ public class OpenGradleTestResultActionProvider implements ToggleModelActionProv return reportFilePath != null; } + @Override + protected boolean isVisible() { + return GradleConstants.SYSTEM_ID.equals(mySystemId); + } + @Nullable private String getReportFilePath() { final AbstractProperty.AbstractPropertyContainer properties = getProperties(); From acbd82ee9c07851f644f764625da59544c89f7b4 Mon Sep 17 00:00:00 2001 From: Ekaterina Tuzova Date: Mon, 16 Jun 2014 13:31:56 +0400 Subject: [PATCH 09/20] fixed PY-13271 PyCharm 3.4.1 (135.1049) freezes added timeout for PyPI connection --- python/src/com/jetbrains/python/packaging/PyPIPackageUtil.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/python/src/com/jetbrains/python/packaging/PyPIPackageUtil.java b/python/src/com/jetbrains/python/packaging/PyPIPackageUtil.java index c1847940b05e..43bb4a933c50 100644 --- a/python/src/com/jetbrains/python/packaging/PyPIPackageUtil.java +++ b/python/src/com/jetbrains/python/packaging/PyPIPackageUtil.java @@ -239,6 +239,8 @@ public class PyPIPackageUtil { if (connection instanceof HttpsURLConnection) { ((HttpsURLConnection)connection).setSSLSocketFactory(sslContext.getSocketFactory()); } + connection.setConnectTimeout(5000); + connection.setReadTimeout(5000); InputStream is = connection.getInputStream(); Reader reader = new InputStreamReader(is); try{ From 229e7edf8741569bb7ddc499ce6a5e680ecacfa1 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Mon, 16 Jun 2014 13:37:07 +0400 Subject: [PATCH 10/20] EA-52085 (diagnostic performance impact eliminated) --- .../com/intellij/util/messages/impl/MessageBusImpl.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/platform/util/src/com/intellij/util/messages/impl/MessageBusImpl.java b/platform/util/src/com/intellij/util/messages/impl/MessageBusImpl.java index 4f0bca735b14..a8ce8f1cb73b 100644 --- a/platform/util/src/com/intellij/util/messages/impl/MessageBusImpl.java +++ b/platform/util/src/com/intellij/util/messages/impl/MessageBusImpl.java @@ -13,10 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -/* - * @author max - */ package com.intellij.util.messages.impl; import com.intellij.openapi.Disposable; @@ -39,6 +35,9 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ConcurrentMap; +/** + * @author max + */ public class MessageBusImpl implements MessageBus { private static final Logger LOG = Logger.getInstance("#com.intellij.util.messages.impl.MessageBusImpl"); private static final Comparator MESSAGE_BUS_COMPARATOR = new Comparator() { @@ -224,7 +223,7 @@ public class MessageBusImpl implements MessageBus { } private void checkNotDisposed() { - LOG.assertTrue(!myDisposed, "Already disposed: " + myOwner); + if (myDisposed) LOG.error("Already disposed: " + myOwner); } private void calcSubscribers(Topic topic, List result) { From dc678fee8ff0a74e08e05b51b65550eb61d3eeae Mon Sep 17 00:00:00 2001 From: Ekaterina Tuzova Date: Mon, 16 Jun 2014 14:11:23 +0400 Subject: [PATCH 11/20] push python language level only for python modules, flush cached modules in PyTestCase (thanks to Yann) --- .../psi/impl/PythonLanguageLevelPusher.java | 55 ++++++++++++++----- .../jetbrains/python/fixtures/PyTestCase.java | 8 ++- 2 files changed, 46 insertions(+), 17 deletions(-) diff --git a/python/src/com/jetbrains/python/psi/impl/PythonLanguageLevelPusher.java b/python/src/com/jetbrains/python/psi/impl/PythonLanguageLevelPusher.java index c3fd23bc289c..136a7073bb8b 100644 --- a/python/src/com/jetbrains/python/psi/impl/PythonLanguageLevelPusher.java +++ b/python/src/com/jetbrains/python/psi/impl/PythonLanguageLevelPusher.java @@ -15,11 +15,14 @@ */ package com.jetbrains.python.psi.impl; +import com.intellij.facet.Facet; +import com.intellij.facet.FacetManager; import com.intellij.openapi.application.Application; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.fileTypes.FileTypeManager; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleManager; +import com.intellij.openapi.module.ModuleType; import com.intellij.openapi.module.ModuleUtilCore; import com.intellij.openapi.project.Project; import com.intellij.openapi.projectRoots.Sdk; @@ -37,6 +40,8 @@ import com.intellij.util.containers.WeakHashMap; import com.intellij.util.io.DataInputOutputUtil; import com.intellij.util.messages.MessageBus; import com.jetbrains.python.PythonFileType; +import com.jetbrains.python.PythonModuleTypeBase; +import com.jetbrains.python.facet.PythonFacetSettings; import com.jetbrains.python.psi.LanguageLevel; import com.jetbrains.python.sdk.PythonSdkType; import org.jetbrains.annotations.NotNull; @@ -61,11 +66,13 @@ public class PythonLanguageLevelPusher implements FilePropertyPusher usedSdks = new HashSet(); for (Module module : modules) { - final Sdk sdk = PythonSdkType.findPythonSdk(module); - myModuleSdks.put(module, sdk); - if (sdk != null && !usedSdks.contains(sdk)) { - usedSdks.add(sdk); - updateSdkLanguageLevel(project, sdk); + if (isPythonModule(module)) { + final Sdk sdk = PythonSdkType.findPythonSdk(module); + myModuleSdks.put(module, sdk); + if (sdk != null && !usedSdks.contains(sdk)) { + usedSdks.add(sdk); + updateSdkLanguageLevel(project, sdk); + } } } } @@ -167,17 +174,19 @@ public class PythonLanguageLevelPusher implements FilePropertyPusher Date: Mon, 16 Jun 2014 14:14:12 +0400 Subject: [PATCH 12/20] Cleanup (formatting; invariant checks) --- .../ide/actions/ReloadFromDiskAction.java | 85 ++++++++----------- 1 file changed, 37 insertions(+), 48 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/ide/actions/ReloadFromDiskAction.java b/platform/lang-impl/src/com/intellij/ide/actions/ReloadFromDiskAction.java index 01edc2485778..92d43150c6c9 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/ReloadFromDiskAction.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/ReloadFromDiskAction.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * 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. @@ -13,14 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.intellij.ide.actions; import com.intellij.ide.IdeBundle; -import com.intellij.openapi.actionSystem.*; +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.CommonDataKeys; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.command.CommandProcessor; -import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.Project; @@ -32,58 +32,47 @@ import com.intellij.psi.PsiManager; public class ReloadFromDiskAction extends AnAction implements DumbAware { @Override public void actionPerformed(AnActionEvent e) { - DataContext dataContext = e.getDataContext(); - final Project project = CommonDataKeys.PROJECT.getData(dataContext); - final Editor editor = CommonDataKeys.EDITOR.getData(dataContext); - if (editor == null) return; - final PsiFile psiFile = PsiDocumentManager.getInstance(project).getPsiFile(editor.getDocument()); - if (psiFile == null) return; + final Project project = e.getProject(); + final Editor editor = CommonDataKeys.EDITOR.getData(e.getDataContext()); + if (project == null || editor == null) return; + final PsiFile file = PsiDocumentManager.getInstance(project).getPsiFile(editor.getDocument()); + if (file == null) return; - int res = Messages.showOkCancelDialog( - project, - IdeBundle.message("prompt.reload.file.from.disk", psiFile.getVirtualFile().getPresentableUrl()), - IdeBundle.message("title.reload.file"), - Messages.getWarningIcon() - ); + String message = IdeBundle.message("prompt.reload.file.from.disk", file.getVirtualFile().getPresentableUrl()); + int res = Messages.showOkCancelDialog(project, message, IdeBundle.message("title.reload.file"), Messages.getWarningIcon()); if (res != Messages.OK) return; - CommandProcessor.getInstance().executeCommand( - project, new Runnable() { - @Override - public void run() { - ApplicationManager.getApplication().runWriteAction( - new Runnable() { - @Override - public void run() { - PsiManager.getInstance(project).reloadFromDisk(psiFile); + Runnable command = new Runnable() { + @Override + public void run() { + ApplicationManager.getApplication().runWriteAction( + new Runnable() { + @Override + public void run() { + if (!project.isDisposed()) { + PsiManager.getInstance(project).reloadFromDisk(file); } } - ); - } - }, - IdeBundle.message("command.reload.from.disk"), - null - ); + } + ); + } + }; + CommandProcessor.getInstance().executeCommand(project, command, IdeBundle.message("command.reload.from.disk"), null); } @Override - public void update(AnActionEvent event){ - Presentation presentation = event.getPresentation(); - DataContext dataContext = event.getDataContext(); - Project project = CommonDataKeys.PROJECT.getData(dataContext); - if (project == null){ - presentation.setEnabled(false); - return; - } - Editor editor = CommonDataKeys.EDITOR.getData(dataContext); - if (editor == null){ - presentation.setEnabled(false); - return; - } - Document document = editor.getDocument(); - PsiFile psiFile = PsiDocumentManager.getInstance(project).getPsiFile(document); - if (psiFile == null || psiFile.getVirtualFile() == null){ - presentation.setEnabled(false); + public void update(AnActionEvent event) { + boolean enabled = false; + + Project project = event.getProject(); + Editor editor = CommonDataKeys.EDITOR.getData(event.getDataContext()); + if (project != null && editor != null) { + PsiFile file = PsiDocumentManager.getInstance(project).getPsiFile(editor.getDocument()); + if (file != null && file.getVirtualFile() != null) { + enabled = true; + } } + + event.getPresentation().setEnabled(enabled); } } From a39a8c7a3b419ae007eec7a84123e1ca40a4341b Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Mon, 16 Jun 2014 15:07:39 +0400 Subject: [PATCH 13/20] IDEA-126213 (update file notifications on VFS events) --- .../ide/actions/ReloadFromDiskAction.java | 1 + .../ide/FileChangedNotificationProvider.java | 26 +++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/platform/lang-impl/src/com/intellij/ide/actions/ReloadFromDiskAction.java b/platform/lang-impl/src/com/intellij/ide/actions/ReloadFromDiskAction.java index 92d43150c6c9..62be241074b6 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/ReloadFromDiskAction.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/ReloadFromDiskAction.java @@ -50,6 +50,7 @@ public class ReloadFromDiskAction extends AnAction implements DumbAware { @Override public void run() { if (!project.isDisposed()) { + file.getVirtualFile().refresh(false, false); PsiManager.getInstance(project).reloadFromDisk(file); } } diff --git a/platform/platform-impl/src/com/intellij/ide/FileChangedNotificationProvider.java b/platform/platform-impl/src/com/intellij/ide/FileChangedNotificationProvider.java index 2d5d8f5e0480..cce510c0233d 100644 --- a/platform/platform-impl/src/com/intellij/ide/FileChangedNotificationProvider.java +++ b/platform/platform-impl/src/com/intellij/ide/FileChangedNotificationProvider.java @@ -15,6 +15,7 @@ */ package com.intellij.ide; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.LogUtil; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.fileEditor.FileEditor; @@ -24,13 +25,21 @@ import com.intellij.openapi.util.Key; import com.intellij.openapi.util.io.FileAttributes; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.vfs.VirtualFileManager; import com.intellij.openapi.vfs.VirtualFileSystem; +import com.intellij.openapi.vfs.newvfs.BulkFileListener; import com.intellij.openapi.vfs.newvfs.RefreshQueue; +import com.intellij.openapi.vfs.newvfs.events.VFileEvent; import com.intellij.ui.EditorNotificationPanel; import com.intellij.ui.EditorNotifications; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.messages.MessageBusConnection; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.List; +import java.util.Set; + public class FileChangedNotificationProvider extends EditorNotifications.Provider { private static final Logger LOG = Logger.getInstance(FileChangedNotificationProvider.class); private static final Key KEY = Key.create("file.changed.notification.panel"); @@ -51,6 +60,23 @@ public class FileChangedNotificationProvider extends EditorNotifications.Provide } } }, project); + + MessageBusConnection connection = ApplicationManager.getApplication().getMessageBus().connect(myProject); + connection.subscribe(VirtualFileManager.VFS_CHANGES, new BulkFileListener.Adapter() { + @Override + public void after(@NotNull List events) { + if (!myProject.isDisposed() && !GeneralSettings.getInstance().isSyncOnFrameActivation()) { + Set openFiles = ContainerUtil.newHashSet(FileEditorManager.getInstance(myProject).getSelectedFiles()); + EditorNotifications notifications = EditorNotifications.getInstance(myProject); + for (VFileEvent event : events) { + VirtualFile file = event.getFile(); + if (openFiles.contains(file)) { + notifications.updateNotifications(file); + } + } + } + } + }); } @Override From a9caf9569a93d7fef6153c01d2ca929d9f97d318 Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Fri, 13 Jun 2014 17:44:49 +0400 Subject: [PATCH 14/20] getFields --- .../src/com/intellij/util/ReflectionUtil.java | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/platform/util/src/com/intellij/util/ReflectionUtil.java b/platform/util/src/com/intellij/util/ReflectionUtil.java index 1730d6500ba3..b185d0ab8b74 100644 --- a/platform/util/src/com/intellij/util/ReflectionUtil.java +++ b/platform/util/src/com/intellij/util/ReflectionUtil.java @@ -272,6 +272,16 @@ public class ReflectionUtil { return findMethod(getClassDeclaredMethods(aClass, false), name, parameters); } + @Nullable + public static Field getDeclaredField(@NotNull Class aClass, @NonNls @NotNull final String name) { + return processFields(aClass, new Condition() { + @Override + public boolean value(Field field) { + return name.equals(field.getName()); + } + }); + } + public static List getClassPublicMethods(@NotNull Class aClass) { return getClassPublicMethods(aClass, false); } @@ -284,11 +294,17 @@ public class ReflectionUtil { public static List getClassDeclaredMethods(@NotNull Class aClass) { return getClassDeclaredMethods(aClass, false); } - + + @NotNull public static List getClassDeclaredMethods(@NotNull Class aClass, boolean includeSynthetic) { Method[] methods = aClass.getDeclaredMethods(); return includeSynthetic ? Arrays.asList(methods) : filterRealMethods(methods); } + @NotNull + public static List getClassDeclaredFields(@NotNull Class aClass) { + Field[] fields = aClass.getDeclaredFields(); + return Arrays.asList(fields); + } private static List filterRealMethods(Method[] methods) { List result = ContainerUtil.newArrayList(); From 75b461ebc399e015d2f47658c3f741c3c3683827 Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Fri, 13 Jun 2014 18:37:35 +0400 Subject: [PATCH 15/20] adapted reflection hacks to JDK8 --- .../testFramework/UsefulTestCase.java | 61 ++++++++++--------- 1 file changed, 32 insertions(+), 29 deletions(-) diff --git a/platform/testFramework/src/com/intellij/testFramework/UsefulTestCase.java b/platform/testFramework/src/com/intellij/testFramework/UsefulTestCase.java index 898d9d04bd28..5213e2265556 100644 --- a/platform/testFramework/src/com/intellij/testFramework/UsefulTestCase.java +++ b/platform/testFramework/src/com/intellij/testFramework/UsefulTestCase.java @@ -19,13 +19,10 @@ import com.intellij.codeInsight.CodeInsightSettings; import com.intellij.diagnostic.PerformanceWatcher; import com.intellij.mock.MockApplication; import com.intellij.openapi.Disposable; -import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.application.Application; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.PathManager; import com.intellij.openapi.command.impl.StartMarkAction; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.editor.ex.EditorEx; import com.intellij.openapi.editor.impl.DocumentImpl; import com.intellij.openapi.fileTypes.StdFileTypes; import com.intellij.openapi.project.Project; @@ -38,14 +35,10 @@ import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFileVisitor; import com.intellij.psi.PsiDocumentManager; -import com.intellij.psi.PsiFile; import com.intellij.psi.codeStyle.CodeStyleSchemes; import com.intellij.psi.codeStyle.CodeStyleSettings; import com.intellij.psi.codeStyle.CodeStyleSettingsManager; import com.intellij.psi.impl.source.PostprocessReformattingAspect; -import com.intellij.refactoring.rename.PsiElementRenameHandler; -import com.intellij.refactoring.rename.RenameHandler; -import com.intellij.refactoring.rename.RenameHandlerRegistry; import com.intellij.refactoring.rename.inplace.InplaceRefactoring; import com.intellij.rt.execution.junit.FileComparisonFailure; import com.intellij.testFramework.exceptionCases.AbstractExceptionCase; @@ -75,6 +68,7 @@ import java.lang.reflect.Modifier; import java.security.SecureRandom; import java.util.*; import java.util.List; +import java.util.concurrent.DelayQueue; import java.util.regex.Pattern; /** @@ -178,13 +172,14 @@ public abstract class UsefulTestCase extends TestCase { private static final Set DELETE_ON_EXIT_HOOK_DOT_FILES; private static final Class DELETE_ON_EXIT_HOOK_CLASS; static { - Class aClass = null; - Set files = null; + Class aClass; try { aClass = Class.forName("java.io.DeleteOnExitHook"); - files = ReflectionUtil.getField(aClass, null, Set.class, "files"); } - catch (Exception ignored) { } + catch (Exception e) { + throw new RuntimeException(e); + } + Set files = ReflectionUtil.getField(aClass, null, Set.class, "files"); DELETE_ON_EXIT_HOOK_CLASS = aClass; DELETE_ON_EXIT_HOOK_DOT_FILES = files; } @@ -777,26 +772,35 @@ public abstract class UsefulTestCase extends TestCase { } protected static void checkAllTimersAreDisposed() { + Field firstTimerF; + Object timerQueue; + Object timer; try { - Class aClass = Class.forName("javax.swing.TimerQueue"); + Class TimerQueueC = Class.forName("javax.swing.TimerQueue"); + Method sharedInstance = TimerQueueC.getDeclaredMethod("sharedInstance"); + sharedInstance.setAccessible(true); - Method inst = aClass.getDeclaredMethod("sharedInstance"); - inst.setAccessible(true); - Object queue = inst.invoke(null); - Field field = aClass.getDeclaredField("firstTimer"); - field.setAccessible(true); - Object firstTimer = field.get(queue); - if (firstTimer != null) { - try { - fail("Not disposed Timer: " + firstTimer.toString() + "; queue:" + queue); - } - finally { - field.set(queue, null); - } + firstTimerF = ReflectionUtil.getDeclaredField(TimerQueueC, "firstTimer"); + timerQueue = sharedInstance.invoke(null); + if (firstTimerF == null) { + // jdk 8 + DelayQueue delayQueue = ReflectionUtil.getField(TimerQueueC, timerQueue, DelayQueue.class, "queue"); + timer = delayQueue.peek(); + } + else { + // ancient jdk + firstTimerF.setAccessible(true); + timer = firstTimerF.get(timerQueue); } } catch (Throwable e) { - // Ignore + throw new RuntimeException(e); + } + if (timer != null) { + if (firstTimerF != null) { + ReflectionUtil.resetField(timerQueue, firstTimerF); + } + fail("Not disposed Timer: " + timer.toString() + "; queue:" + timerQueue); } } @@ -886,12 +890,11 @@ public abstract class UsefulTestCase extends TestCase { while (aClass != null && aClass != Object.class) { if (aClass.getAnnotation(annotationClass) != null) return true; if (!methodChecked) { - try { - Method method = aClass.getDeclaredMethod(methodName); + Method method = ReflectionUtil.getDeclaredMethod(aClass, methodName); + if (method != null) { if (method.getAnnotation(annotationClass) != null) return true; methodChecked = true; } - catch (NoSuchMethodException ignored) { } } aClass = aClass.getSuperclass(); } From 6a55620877e7bb62399f32c70a41504ca124fb8a Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Mon, 16 Jun 2014 13:44:19 +0400 Subject: [PATCH 16/20] wait until timers from JBCardLayout are fired --- .../projectWizard/ProjectWizardTestCase.java | 3 +++ .../testFramework/UsefulTestCase.java | 21 ++++++++++++++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/java/testFramework/src/com/intellij/ide/projectWizard/ProjectWizardTestCase.java b/java/testFramework/src/com/intellij/ide/projectWizard/ProjectWizardTestCase.java index 3e8e07a5b6bc..7008c185f308 100644 --- a/java/testFramework/src/com/intellij/ide/projectWizard/ProjectWizardTestCase.java +++ b/java/testFramework/src/com/intellij/ide/projectWizard/ProjectWizardTestCase.java @@ -216,6 +216,9 @@ public abstract class ProjectWizardTestCase ext } }); SelectTemplateSettings.getInstance().setLastTemplate(null, null); + UIUtil.dispatchAllInvocationEvents(); + Thread.sleep(2000); //wait for JBCardLayout release timers + UIUtil.dispatchAllInvocationEvents(); super.tearDown(); } diff --git a/platform/testFramework/src/com/intellij/testFramework/UsefulTestCase.java b/platform/testFramework/src/com/intellij/testFramework/UsefulTestCase.java index 5213e2265556..751a3b9e9538 100644 --- a/platform/testFramework/src/com/intellij/testFramework/UsefulTestCase.java +++ b/platform/testFramework/src/com/intellij/testFramework/UsefulTestCase.java @@ -57,6 +57,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.junit.Assert; +import javax.swing.Timer; import java.awt.*; import java.io.File; import java.io.FileNotFoundException; @@ -69,6 +70,8 @@ import java.security.SecureRandom; import java.util.*; import java.util.List; import java.util.concurrent.DelayQueue; +import java.util.concurrent.Delayed; +import java.util.concurrent.TimeUnit; import java.util.regex.Pattern; /** @@ -800,7 +803,23 @@ public abstract class UsefulTestCase extends TestCase { if (firstTimerF != null) { ReflectionUtil.resetField(timerQueue, firstTimerF); } - fail("Not disposed Timer: " + timer.toString() + "; queue:" + timerQueue); + String text = ""; + if (timer instanceof Delayed) { + long delay = ((Delayed)timer).getDelay(TimeUnit.MILLISECONDS); + text = "(delayed for "+delay+"ms)"; + Method getTimer = ReflectionUtil.getDeclaredMethod(timer.getClass(), "getTimer"); + getTimer.setAccessible(true); + try { + timer = getTimer.invoke(timer); + } + catch (Exception e) { + throw new RuntimeException(e); + } + } + Timer t = (Timer)timer; + text = "Timer (listeners: "+Arrays.asList(t.getActionListeners()) + ") "+text; + + fail("Not disposed Timer: " + text + "; queue:" + timerQueue); } } From 10d492a5697063323ca45efc2680a013f2ee64c7 Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Mon, 16 Jun 2014 14:38:18 +0400 Subject: [PATCH 17/20] TraverseUITest fixed --- .../platform-impl/src/com/intellij/idea/IdeaApplication.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/platform-impl/src/com/intellij/idea/IdeaApplication.java b/platform/platform-impl/src/com/intellij/idea/IdeaApplication.java index ce6ef2c946e5..432fcb975812 100644 --- a/platform/platform-impl/src/com/intellij/idea/IdeaApplication.java +++ b/platform/platform-impl/src/com/intellij/idea/IdeaApplication.java @@ -90,7 +90,7 @@ public class IdeaApplication { } if (Main.isCommandLine()) { - new CommandLineApplication(isInternal, false, headless); + new CommandLineApplication(isInternal, isUnitTest, headless); } else { Splash splash = null; From b3073faf171eb748c02e24fca44ad669c9308845 Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Mon, 16 Jun 2014 14:49:27 +0400 Subject: [PATCH 18/20] already disposed --- .../plugins/InstalledPluginsTableModel.java | 152 ++++++++++-------- 1 file changed, 89 insertions(+), 63 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/ide/plugins/InstalledPluginsTableModel.java b/platform/platform-impl/src/com/intellij/ide/plugins/InstalledPluginsTableModel.java index 44d9606bd418..afd2f0a9cd47 100644 --- a/platform/platform-impl/src/com/intellij/ide/plugins/InstalledPluginsTableModel.java +++ b/platform/platform-impl/src/com/intellij/ide/plugins/InstalledPluginsTableModel.java @@ -15,6 +15,7 @@ */ package com.intellij.ide.plugins; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.extensions.PluginId; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; @@ -73,9 +74,9 @@ public class InstalledPluginsTableModel extends PluginTableModel { final MyPluginManagerColumnInfo infoColumn = new MyPluginManagerColumnInfo(); final EnabledPluginInfo enabledColumn = new EnabledPluginInfo(); final Spacer spacer = new Spacer(); - super.columns = SystemInfo.isMac ? new ColumnInfo[]{infoColumn, enabledColumn, spacer} + columns = SystemInfo.isMac ? new ColumnInfo[]{infoColumn, enabledColumn, spacer} :new ColumnInfo[]{infoColumn, enabledColumn}; - view = new ArrayList(Arrays.asList(PluginManager.getPlugins())); + view = new ArrayList(Arrays.asList(PluginManagerCore.getPlugins())); view.addAll(myInstalled); reset(view); @@ -122,11 +123,12 @@ public class InstalledPluginsTableModel extends PluginTableModel { return 1; } + @Override public int getNameColumn() { return 0; } - private void reset(final List list) { + private void reset(@NotNull List list) { for (IdeaPluginDescriptor ideaPluginDescriptor : list) { setEnabled(ideaPluginDescriptor); } @@ -134,13 +136,16 @@ public class InstalledPluginsTableModel extends PluginTableModel { updatePluginDependencies(); final Runnable runnable = new Runnable() { + @Override public void run() { - ProgressManager.getInstance().run(new Task.Backgroundable(null, "Load custom plugin repositories data...") { - @Override - public void run(@NotNull ProgressIndicator indicator) { - updateRepositoryPlugins(); - } - }); + if (!ApplicationManager.getApplication().isDisposed()) { + ProgressManager.getInstance().run(new Task.Backgroundable(null, "Load custom plugin repositories data...") { + @Override + public void run(@NotNull ProgressIndicator indicator) { + updateRepositoryPlugins(); + } + }); + } } }; SwingUtilities.invokeLater(runnable); @@ -168,7 +173,7 @@ public class InstalledPluginsTableModel extends PluginTableModel { private void setEnabled(IdeaPluginDescriptor ideaPluginDescriptor, final boolean enabled) { - final Collection disabledPlugins = PluginManager.getDisabledPlugins(); + final Collection disabledPlugins = PluginManagerCore.getDisabledPlugins(); final PluginId pluginId = ideaPluginDescriptor.getPluginId(); if (!enabled && !disabledPlugins.contains(pluginId.toString())) { myEnabled.put(pluginId, null); @@ -192,37 +197,40 @@ public class InstalledPluginsTableModel extends PluginTableModel { if (descriptor instanceof IdeaPluginDescriptorImpl && ((IdeaPluginDescriptorImpl)descriptor).isDeleted()) continue; final Boolean enabled = myEnabled.get(pluginId); if (enabled == null || enabled.booleanValue()) { - PluginManager.checkDependants(descriptor, new Function() { - @Nullable - public IdeaPluginDescriptor fun(final PluginId pluginId) { - return PluginManager.getPlugin(pluginId); - } - }, new Condition() { - public boolean value(final PluginId dependantPluginId) { - final Boolean enabled = myEnabled.get(dependantPluginId); - if ((enabled == null && !updatedPlugins.contains(dependantPluginId)) || - (enabled != null && !enabled.booleanValue())) { - Set required = myDependentToRequiredListMap.get(pluginId); - if (required == null) { - required = new HashSet(); - myDependentToRequiredListMap.put(pluginId, required); - } + PluginManagerCore.checkDependants(descriptor, new Function() { + @Override + @Nullable + public IdeaPluginDescriptor fun(final PluginId pluginId) { + return PluginManager.getPlugin(pluginId); + } + }, new Condition() { + @Override + public boolean value(final PluginId dependantPluginId) { + final Boolean enabled = myEnabled.get(dependantPluginId); + if ((enabled == null && !updatedPlugins.contains(dependantPluginId)) || + (enabled != null && !enabled.booleanValue())) { + Set required = myDependentToRequiredListMap.get(pluginId); + if (required == null) { + required = new HashSet(); + myDependentToRequiredListMap.put(pluginId, required); + } - required.add(dependantPluginId); - //return false; - } + required.add(dependantPluginId); + //return false; + } - return true; - } - } + return true; + } + } ); - if (enabled == null && !myDependentToRequiredListMap.containsKey(pluginId) && !PluginManager.isIncompatible(descriptor)) { + if (enabled == null && !myDependentToRequiredListMap.containsKey(pluginId) && !PluginManagerCore.isIncompatible(descriptor)) { myEnabled.put(pluginId, true); } } } } + @Override public void updatePluginsList(List list) { // For each downloadable plugin we need to know whether its counterpart // is already installed, and if yes compare the difference in versions: @@ -277,7 +285,7 @@ public class InstalledPluginsTableModel extends PluginTableModel { installedPlugins.add(idString); } final PluginManagerUISettings updateSettings = PluginManagerUISettings.getInstance(); - if (state > 0 && !PluginManager.isIncompatible(descr) && !updatedPlugins.contains(descr.getPluginId())) { + if (state > 0 && !PluginManagerCore.isIncompatible(descr) && !updatedPlugins.contains(descr.getPluginId())) { NewVersions2Plugins.put(pluginId, 1); if (!updateSettings.myOutdatedPlugins.contains(idString)) { updateSettings.myOutdatedPlugins.add(idString); @@ -312,6 +320,7 @@ public class InstalledPluginsTableModel extends PluginTableModel { private void hideNotApplicablePlugins(Boolean value, final IdeaPluginDescriptor... ideaPluginDescriptors) { if (!value && ENABLED.equals(myEnabledFilter) || (value && DISABLED.equals(myEnabledFilter))) { SwingUtilities.invokeLater(new Runnable() { + @Override public void run() { for (IdeaPluginDescriptor ideaPluginDescriptor : ideaPluginDescriptors) { view.remove(ideaPluginDescriptor); @@ -375,10 +384,12 @@ public class InstalledPluginsTableModel extends PluginTableModel { super(""); } + @Override public Object valueOf(IdeaPluginDescriptor ideaPluginDescriptor) { return null; } + @Override public boolean isCellEditable(final IdeaPluginDescriptor ideaPluginDescriptor) { return false; } @@ -389,6 +400,7 @@ public class InstalledPluginsTableModel extends PluginTableModel { return new DefaultTableCellRenderer(); } + @Override public Class getColumnClass() { return Spacer.class; } @@ -400,22 +412,27 @@ public class InstalledPluginsTableModel extends PluginTableModel { super(/*IdeBundle.message("plugin.manager.enable.column.title")*/""); } + @Override public Boolean valueOf(IdeaPluginDescriptor ideaPluginDescriptor) { return myEnabled.get(ideaPluginDescriptor.getPluginId()); } + @Override public boolean isCellEditable(final IdeaPluginDescriptor ideaPluginDescriptor) { return true; } + @Override public Class getColumnClass() { return Boolean.class; } + @Override public TableCellEditor getEditor(final IdeaPluginDescriptor o) { return new BooleanTableCellEditor(); } + @Override public TableCellRenderer getRenderer(final IdeaPluginDescriptor ideaPluginDescriptor) { return new BooleanTableCellRenderer() { @Override @@ -430,6 +447,7 @@ public class InstalledPluginsTableModel extends PluginTableModel { }; } + @Override public void setValue(final IdeaPluginDescriptor ideaPluginDescriptor, Boolean value) { final PluginId currentPluginId = ideaPluginDescriptor.getPluginId(); final Boolean enabled = myEnabled.get(currentPluginId) == null ? Boolean.FALSE : value; @@ -439,8 +457,10 @@ public class InstalledPluginsTableModel extends PluginTableModel { hideNotApplicablePlugins(value, ideaPluginDescriptor); } + @Override public Comparator getComparator() { return new Comparator() { + @Override public int compare(final IdeaPluginDescriptor o1, final IdeaPluginDescriptor o2) { final Boolean enabled1 = myEnabled.get(o1.getPluginId()); final Boolean enabled2 = myEnabled.get(o2.getPluginId()); @@ -486,34 +506,39 @@ public class InstalledPluginsTableModel extends PluginTableModel { } for (final IdeaPluginDescriptor ideaPluginDescriptor : descriptorsToCheckDependencies) { - PluginManager.checkDependants(ideaPluginDescriptor, new Function() { - @Nullable - public IdeaPluginDescriptor fun(final PluginId pluginId) { - return PluginManager.getPlugin(pluginId); - } - }, new Condition() { - public boolean value(final PluginId pluginId) { - Boolean enabled = myEnabled.get(pluginId); - if (enabled == null) { - return false; - } - if (newVal && !enabled.booleanValue()) { - deps.add(pluginId); - } + PluginManagerCore.checkDependants(ideaPluginDescriptor, new Function() { + @Override + @Nullable + public IdeaPluginDescriptor fun(final PluginId pluginId) { + return PluginManager.getPlugin(pluginId); + } + }, new Condition() { + @Override + public boolean value(final PluginId pluginId) { + Boolean enabled = myEnabled.get(pluginId); + if (enabled == null) { + return false; + } + if (newVal && !enabled.booleanValue()) { + deps.add(pluginId); + } - if (!newVal) { - if (ideaPluginDescriptor instanceof IdeaPluginDescriptorImpl && ((IdeaPluginDescriptorImpl)ideaPluginDescriptor).isDeleted()) return true; - final PluginId pluginDescriptorId = ideaPluginDescriptor.getPluginId(); - for (IdeaPluginDescriptor descriptor : ideaPluginDescriptors) { - if (pluginId.equals(descriptor.getPluginId())) { - deps.add(pluginDescriptorId); - break; - } - } - } - return true; - } - } + if (!newVal) { + if (ideaPluginDescriptor instanceof IdeaPluginDescriptorImpl && + ((IdeaPluginDescriptorImpl)ideaPluginDescriptor).isDeleted()) { + return true; + } + final PluginId pluginDescriptorId = ideaPluginDescriptor.getPluginId(); + for (IdeaPluginDescriptor descriptor : ideaPluginDescriptors) { + if (pluginId.equals(descriptor.getPluginId())) { + deps.add(pluginDescriptorId); + break; + } + } + } + return true; + } + } ); } if (!deps.isEmpty()) { @@ -525,6 +550,7 @@ public class InstalledPluginsTableModel extends PluginTableModel { }, ", "); final Set pluginDependencies = new HashSet(); final String listOfDependencies = StringUtil.join(deps, new Function() { + @Override public String fun(final PluginId pluginId) { final IdeaPluginDescriptor pluginDescriptor = PluginManager.getPlugin(pluginId); assert pluginDescriptor != null; @@ -564,13 +590,13 @@ public class InstalledPluginsTableModel extends PluginTableModel { @Override public Comparator getComparator() { - final Comparator comparator = super.getColumnComparator(); + final Comparator comparator = getColumnComparator(); return new Comparator() { @Override public int compare(IdeaPluginDescriptor o1, IdeaPluginDescriptor o2) { if (isSortByStatus()) { - final boolean incompatible1 = PluginManager.isIncompatible(o1); - final boolean incompatible2 = PluginManager.isIncompatible(o2); + final boolean incompatible1 = PluginManagerCore.isIncompatible(o1); + final boolean incompatible2 = PluginManagerCore.isIncompatible(o2); if (incompatible1) { if (incompatible2) return comparator.compare(o1, o2); return -1; From 4021a73190eaee975d389612c39f8a32bc89f039 Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Mon, 16 Jun 2014 15:00:36 +0400 Subject: [PATCH 19/20] reduce contention --- .../application/impl/ApplicationImpl.java | 331 ++++++++++-------- 1 file changed, 186 insertions(+), 145 deletions(-) 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 4ad95ff25870..c6d108c2aa96 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 @@ -19,6 +19,7 @@ import com.intellij.BundleBase; import com.intellij.CommonBundle; import com.intellij.diagnostic.PerformanceWatcher; import com.intellij.diagnostic.PluginException; +import com.intellij.diagnostic.ThreadDumper; import com.intellij.ide.*; import com.intellij.ide.plugins.IdeaPluginDescriptor; import com.intellij.ide.plugins.PluginManagerCore; @@ -80,7 +81,6 @@ import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.locks.ReentrantReadWriteLock; -@SuppressWarnings({"AssignmentToStaticFieldFromInstanceMethod"}) 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; @@ -96,7 +96,7 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App private IApplicationStore myComponentStore; - private boolean myTestModeFlag; + private final boolean myTestModeFlag; private final boolean myHeadlessMode; private final boolean myCommandLineMode; @@ -107,12 +107,12 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App private volatile Runnable myExceptionalThreadWithReadAccessRunnable; - private int myInEditorPaintCounter = 0; - private long myStartTime = 0; + private int myInEditorPaintCounter; // EDT only + private final long myStartTime; @Nullable private final Splash mySplash; private boolean myDoNotSave; - private volatile boolean myDisposeInProgress = false; + private volatile boolean myDisposeInProgress; private final Disposable myLastDisposable = Disposer.newDisposable(); // will be disposed last @@ -171,7 +171,30 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App private Boolean myActive; - private static final ThreadLocal ourEdtSafe = new ThreadLocal(); + 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 final int IS_EXCEPTIONAL_THREAD_FLAG = 1<<28; + private static class Status { + // higher three bits are for IS_* flags + // lower bits are for edtSafe counter + private int flags; + } + + private static final ThreadLocal status = new ThreadLocal(){ + @Override + protected Status initialValue() { + Status status = new Status(); + status.flags = BitUtil.set(status.flags, IS_EDT_FLAG, EventQueue.isDispatchThread()); + return status; + } + }; + 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); + } + @NonNls private static final ModalityState ANY = new ModalityState() { @Override public boolean dominates(@NotNull ModalityState anotherState) { @@ -201,7 +224,7 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App } @Override - public void initializeComponent(Object component, boolean service) { + public void initializeComponent(@NotNull Object component, boolean service) { getStateStore().initComponent(component, service); } @@ -233,7 +256,7 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App myHeadlessMode = isHeadless; myCommandLineMode = isCommandLine; - myDoNotSave = myTestModeFlag || myHeadlessMode; + myDoNotSave = isUnitTestMode || isHeadless; loadApplicationComponents(); @@ -353,7 +376,11 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App @Override public boolean holdsReadLock() { - return myLock.getReadHoldCount() != 0; + return holdsReadLock(getStatus()); + } + + private static boolean holdsReadLock(Status status) { + return BitUtil.isSet(status.flags, IS_READ_LOCK_ACQUIRED_FLAG); } private void loadApplicationComponents() { @@ -367,7 +394,7 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App } @Override - protected synchronized Object createComponent(Class componentInterface) { + protected synchronized Object createComponent(@NotNull Class componentInterface) { Object component = super.createComponent(componentInterface); if (mySplash != null) { mySplash.showProgress("", 0.65f + getPercentageOfComponentsLoaded() * 0.35f); @@ -375,6 +402,7 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App return component; } + @NotNull @Override protected MutablePicoContainer createPicoContainer() { return Extensions.getRootArea().getPicoContainer(); @@ -395,10 +423,6 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App return myTestModeFlag; } - public void setUnitTestMode(boolean testModeFlag) { - myTestModeFlag = testModeFlag; - } - @Override public boolean isHeadlessEnvironment() { return myHeadlessMode; @@ -415,6 +439,9 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App return ourThreadExecutorsService.submit(new Runnable() { @Override public void run() { + if (isReadAccessAllowed()) { + assert false : describe(Thread.currentThread()); + } try { action.run(); } @@ -427,6 +454,9 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App finally { //ReflectionUtil.resetThreadLocals(); Thread.interrupted(); // reset interrupted status + if (isReadAccessAllowed()) { + assert false : describe(Thread.currentThread()); + } } } }); @@ -438,6 +468,9 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App return ourThreadExecutorsService.submit(new Callable() { @Override public T call() { + if (isReadAccessAllowed()) { + assert false : describe(Thread.currentThread()); + } try { return action.call(); } @@ -450,17 +483,22 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App finally { //ReflectionUtil.resetThreadLocals(); Thread.interrupted(); // reset interrupted status + if (isReadAccessAllowed()) { + assert false : describe(Thread.currentThread()); + } } return null; } }); } - private static Thread ourDispatchThread = null; - @Override public boolean isDispatchThread() { - return EventQueue.isDispatchThread(); + return isDispatchThread(getStatus()); + } + + private static boolean isDispatchThread(Status status) { + return BitUtil.isSet(status.flags, IS_EDT_FLAG); } @Override @@ -535,7 +573,7 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App } @Override - protected T getComponentFromContainer(final Class interfaceClass) { + protected T getComponentFromContainer(@NotNull final Class interfaceClass) { if (myIsFiringLoadingEvent) { return null; } @@ -567,13 +605,6 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App Disposer.dispose(myLastDisposable); // dispose it last } - private final Object lock = new Object(); - private void makeChangesVisibleToEDT() { - synchronized (lock) { - lock.hashCode(); - } - } - @Override public boolean runProcessWithProgressSynchronously(@NotNull final Runnable process, @NotNull String progressTitle, @@ -629,7 +660,7 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App @Override public void run() { if (myExceptionalThreadWithReadAccessRunnable != process) { - LOG.error("myExceptionalThreadWithReadAccessRunnable != process, process = " + myExceptionalThreadWithReadAccessRunnable); + LOG.error("myExceptionalThreadWithReadAccessRunnable != process, process = " + myExceptionalThreadWithReadAccessRunnable); } executeOnPooledThread(new Runnable() { @@ -639,9 +670,9 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App LOG.error("myExceptionalThreadWithReadAccessRunnable != process, process = " + myExceptionalThreadWithReadAccessRunnable); } - final boolean old = setExceptionalThreadWithReadAccessFlag(true); - LOG.assertTrue(isReadAccessAllowed()); + setExceptionalThreadWithReadAccessFlag(true); try { + LOG.assertTrue(isReadAccessAllowed()); ProgressManager.getInstance().runProcess(process, progress); } catch (ProcessCanceledException e) { @@ -653,8 +684,7 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App throw e; } finally { - setExceptionalThreadWithReadAccessFlag(old); - makeChangesVisibleToEDT(); + setExceptionalThreadWithReadAccessFlag(false); } } }); @@ -669,7 +699,6 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App } finally { myExceptionalThreadWithReadAccessRunnable = null; - makeChangesVisibleToEDT(); } return !progress.isCanceled(); @@ -677,12 +706,13 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App @Override public void invokeAndWait(@NotNull Runnable runnable, @NotNull ModalityState modalityState) { - if (isDispatchThread()) { + Status status = getStatus(); + if (isDispatchThread(status)) { runnable.run(); return; } - if (!isExceptionalThreadWithReadAccess() && holdsReadLock()) { + if (!isExceptionalThreadWithReadAccess(status) && holdsReadLock(status)) { LOG.error("Calling invokeAndWait from read-action leads to possible deadlock."); } @@ -712,13 +742,11 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App @Override @NotNull public ModalityState getDefaultModalityState() { - if (EventQueue.isDispatchThread()) { + if (isDispatchThread()) { return getCurrentModalityState(); } - else { - ProgressIndicator progress = ProgressManager.getInstance().getProgressIndicator(); - return progress == null ? getNoneModalityState() : progress.getModalityState(); - } + ProgressIndicator progress = ProgressManager.getInstance().getProgressIndicator(); + return progress == null ? getNoneModalityState() : progress.getModalityState(); } @Override @@ -769,7 +797,6 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App private static volatile boolean exiting = false; public void exit(final boolean force, final boolean allowListenersToCancel, final boolean restart) { - if (exiting) return; exiting = true; @@ -788,19 +815,19 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App getMessageBus().syncPublisher(AppLifecycleListener.TOPIC).appClosing(); myDisposeInProgress = true; - if (!doExit(allowListenersToCancel, restart)) { - myDisposeInProgress = false; - } + doExit(allowListenersToCancel, restart); + myDisposeInProgress = false; } }; - if (!isDispatchThread()) { - invokeLater(runnable, ModalityState.NON_MODAL); - } - else { + if (isDispatchThread()) { runnable.run(); } - } finally { + else { + invokeLater(runnable, ModalityState.NON_MODAL); + } + } + finally { exiting = false; } } @@ -857,6 +884,7 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App return false; } + @NotNull @Override public String getDoNotShowMessage() { return "Do not ask me again"; @@ -896,13 +924,15 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App @Override public void runReadAction(@NotNull final Runnable action) { - if (isReadAccessAllowed()) { + Status status = getStatus(); + if (isReadAccessAllowed(status)) { action.run(); } else { - assertReadActionAllowed(); + assertNoPsiLock(); try { myLock.readLock().lockInterruptibly(); + setReadLockAcquired(status, true); } catch (InterruptedException e) { throw new RuntimeInterruptedException(e); @@ -911,70 +941,66 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App action.run(); } finally { + setReadLockAcquired(status, false); myLock.readLock().unlock(); } } } @Override public T runReadAction(@NotNull final Computable computation) { - if (isReadAccessAllowed()) { + Status status = getStatus(); + if (isReadAccessAllowed(status)) { return computation.compute(); } - else { - assertReadActionAllowed(); - try { - myLock.readLock().lockInterruptibly(); - } - catch (InterruptedException e) { - throw new RuntimeInterruptedException(e); - } - try { - return computation.compute(); - } - finally { - myLock.readLock().unlock(); - } + assertNoPsiLock(); + try { + myLock.readLock().lockInterruptibly(); + setReadLockAcquired(status, true); + } + catch (InterruptedException e) { + throw new RuntimeInterruptedException(e); + } + try { + return computation.compute(); + } + finally { + setReadLockAcquired(status, false); + myLock.readLock().unlock(); } } @Override public T runReadAction(@NotNull ThrowableComputable computation) throws E { - if (isReadAccessAllowed()) { + Status status = getStatus(); + if (isReadAccessAllowed(status)) { return computation.compute(); } - else { - assertReadActionAllowed(); - try { - myLock.readLock().lockInterruptibly(); - } - catch (InterruptedException e) { - throw new RuntimeInterruptedException(e); - } - try { - return computation.compute(); - } - finally { - myLock.readLock().unlock(); - } + assertNoPsiLock(); + try { + myLock.readLock().lockInterruptibly(); + setReadLockAcquired(status, true); + } + catch (InterruptedException e) { + throw new RuntimeInterruptedException(e); + } + try { + return computation.compute(); + } + finally { + setReadLockAcquired(status, false); + myLock.readLock().unlock(); } } - private static final ThreadLocal exceptionalThreadWithReadAccessFlag = new ThreadLocal(); - - private static boolean isExceptionalThreadWithReadAccess() { - Boolean flag = exceptionalThreadWithReadAccessFlag.get(); - return flag == Boolean.TRUE; + private static boolean isExceptionalThreadWithReadAccess(Status status) { + return BitUtil.isSet(status.flags, IS_EXCEPTIONAL_THREAD_FLAG); } - public static boolean setExceptionalThreadWithReadAccessFlag(boolean flag) { - boolean old = isExceptionalThreadWithReadAccess(); - if (flag) { - exceptionalThreadWithReadAccessFlag.set(Boolean.TRUE); - } - else { - exceptionalThreadWithReadAccessFlag.remove(); - } - return old; + public static void setExceptionalThreadWithReadAccessFlag(boolean flag) { + Status status = getStatus(); + assert !isDispatchThread(status) : "exceptional thread must not be EDT"; + assert flag != isReadAccessAllowed(status) : "must not start exceptional thread from inside read action"; + status.flags = BitUtil.set(status.flags, IS_EXCEPTIONAL_THREAD_FLAG, flag); } @Override @@ -1012,7 +1038,7 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App @Override public boolean hasWriteAction(@Nullable Class actionClass) { - assertCanRunWriteAction(); + assertCanRunWriteAction(getStatus()); for (int i = myWriteActionsStack.size() - 1; i >= 0; i--) { Class action = myWriteActionsStack.get(i); @@ -1028,7 +1054,7 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App LOG.error( "Read access is allowed from event dispatch thread or inside read-action only" + " (see com.intellij.openapi.application.Application.runReadAction())", - "Current thread: " + describe(Thread.currentThread()), "Our dispatch thread:" + describe(ourDispatchThread), + "Current thread: " + describe(Thread.currentThread()), "; dispatch thread: " + EventQueue.isDispatchThread() +"; isDispatchThread(): "+isDispatchThread(), "SystemEventQueueThread: " + describe(getEventQueueThread())); } } @@ -1039,7 +1065,6 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App return o + " " + System.identityHashCode(o); } - @Nullable private static Thread getEventQueueThread() { EventQueue eventQueue = Toolkit.getDefaultToolkit().getSystemEventQueue(); try { @@ -1047,63 +1072,63 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App method.setAccessible(true); return (Thread)method.invoke(eventQueue); } - catch (Exception e1) { - // ok + catch (Exception e) { + throw new RuntimeException(e); } - return null; } @Override public boolean isReadAccessAllowed() { - Thread currentThread = Thread.currentThread(); - return ourDispatchThread == currentThread || - isExceptionalThreadWithReadAccess() || - holdsReadLock() || - isDispatchThread(); + return isReadAccessAllowed(getStatus()); } - private static void assertCanRunWriteAction() { - assertIsDispatchThread("Write access is allowed from event dispatch thread only"); + private static boolean isReadAccessAllowed(Status status) { + return (status.flags & (IS_EDT_FLAG | IS_EXCEPTIONAL_THREAD_FLAG | IS_READ_LOCK_ACQUIRED_FLAG)) != 0; + } + + private static void assertCanRunWriteAction(Status status) { + assertIsDispatchThread(status, "Write access is allowed from event dispatch thread only"); } @Override public void assertIsDispatchThread() { - if (ShutDownTracker.isShutdownHookRunning()) return; - Integer safeCounter = ourEdtSafe.get(); - if (safeCounter != null && safeCounter > 0) return; - assertIsDispatchThread("Access is allowed from event dispatch thread only."); + assertIsDispatchThread(getStatus()); } - private static void assertIsDispatchThread(@NotNull String message) { - final Thread currentThread = Thread.currentThread(); - if (ourDispatchThread == currentThread) return; - - if (EventQueue.isDispatchThread()) { - ourDispatchThread = currentThread; + private static void assertIsDispatchThread(Status status) { + if (isDispatchThread(status)) return; + if (ShutDownTracker.isShutdownHookRunning()) return; + int safeCounter = getSafeCounter(status); + if (safeCounter == 0) { + assertIsDispatchThread(status, "Access is allowed from event dispatch thread only."); } - if (ourDispatchThread == currentThread) return; + } + private static int getSafeCounter(Status status) { + return status.flags & 0x1fffffff; + } + + private static void assertIsDispatchThread(Status status, @NotNull String message) { + if (isDispatchThread(status)) return; LOG.error(message, + "EventQueue.isDispatchThread()="+EventQueue.isDispatchThread(), + "isDispatchThread()="+isDispatchThread(getStatus()), + "Toolkit.getEventQueue()="+Toolkit.getDefaultToolkit().getSystemEventQueue(), "Current thread: " + describe(Thread.currentThread()), - "Our dispatch thread:" + describe(ourDispatchThread), - "SystemEventQueueThread: " + describe(getEventQueueThread())); + "SystemEventQueueThread: " + describe(getEventQueueThread()) +"\n"+ ThreadDumper.dumpThreadsToString()+"\n-----------"); } @Override public void runEdtSafeAction(@NotNull Runnable runnable) { - Integer value = ourEdtSafe.get(); - if (value == null) { - value = 0; - } - - ourEdtSafe.set(value + 1); + Status status = getStatus(); + LOG.assertTrue(getSafeCounter(status) < 1<<26); + status.flags++; try { runnable.run(); } finally { - int newValue = ourEdtSafe.get() - 1; - ourEdtSafe.set(newValue >= 1 ? newValue : null); + status.flags--; } } @@ -1111,19 +1136,19 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App public void assertIsDispatchThread(@Nullable final JComponent component) { if (component == null) return; - Thread curThread = Thread.currentThread(); - if (ourDispatchThread == curThread) { + Status status = getStatus(); + if (isDispatchThread(status)) { return; } if (Boolean.TRUE.equals(component.getClientProperty(WAS_EVER_SHOWN))) { - assertIsDispatchThread(); + assertIsDispatchThread(status); } else { final JRootPane root = component.getRootPane(); if (root != null) { component.putClientProperty(WAS_EVER_SHOWN, Boolean.TRUE); - assertIsDispatchThread(); + assertIsDispatchThread(status); } } } @@ -1136,14 +1161,16 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App @Override public boolean tryRunReadAction(@NotNull Runnable action) { - //if we are inside read action, do not try to acquire read lock again since it will deadlock if there is a pending writeAction - boolean mustAcquire = !isReadAccessAllowed(); + Status status = getStatus(); + //if we are inside read action, do not try to acquire read lock again since it will deadlock if there is a pending writeAction + boolean mustAcquire = !isReadAccessAllowed(status); if (mustAcquire) { - LOG.assertTrue(myTestModeFlag || !Thread.holdsLock(PsiLock.LOCK), "Thread must not hold PsiLock while performing readAction"); + 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); @@ -1155,6 +1182,7 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App } finally { if (mustAcquire) { + setReadLockAcquired(status, false); myLock.readLock().unlock(); } } @@ -1167,7 +1195,7 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App if (frame instanceof IdeFrame) { final IdeFrame ideFrame = (IdeFrame)frame; if (isActive() != active) { - myActive = Boolean.valueOf(active); + myActive = active; System.setProperty("idea.active", myActive.toString()); ApplicationActivationListener publisher = getMessageBus().syncPublisher(ApplicationActivationListener.TOPIC); if (active) { @@ -1198,10 +1226,11 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App @NotNull @Override public AccessToken acquireReadActionLock() { + Status status = getStatus(); // if we are inside read action, do not try to acquire read lock again since it will deadlock if there is a pending writeAction - if (isReadAccessAllowed()) return AccessToken.EMPTY_ACCESS_TOKEN; + if (isReadAccessAllowed(status)) return AccessToken.EMPTY_ACCESS_TOKEN; - return new ReadAccessToken(); + return new ReadAccessToken(status); } @NotNull @@ -1215,13 +1244,16 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App public WriteAccessToken(Class _clazz) { clazz = _clazz; - assertCanRunWriteAction(); + assertCanRunWriteAction(getStatus()); ActivityTracker.getInstance().inc(); fireBeforeWriteActionStart(_clazz); final AtomicBoolean stopped = new AtomicBoolean(false); - LOG.assertTrue(isWriteAccessAllowed() || !Thread.holdsLock(PsiLock.LOCK), "Thread must not hold PsiLock while performing writeAction"); + if (!isWriteAccessAllowed()) { + assertNoPsiLock(); + } + try { if (!myLock.writeLock().tryLock()) { if (ourDumpThreadsOnLongWriteActionWaiting > 0) { @@ -1304,10 +1336,14 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App } private class ReadAccessToken extends AccessToken { - private ReadAccessToken() { - assertReadActionAllowed(); + private final Status myStatus; + + private ReadAccessToken(Status status) { + myStatus = status; + assertNoPsiLock(); try { myLock.readLock().lockInterruptibly(); + setReadLockAcquired(myStatus, true); acquired(); } catch (InterruptedException e) { @@ -1317,13 +1353,18 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App @Override public void finish() { + setReadLockAcquired(myStatus, false); myLock.readLock().unlock(); released(); } } - private static void assertReadActionAllowed() { - LOG.assertTrue(!Thread.holdsLock(PsiLock.LOCK), "Thread must not hold PsiLock while performing readAction"); + private final boolean myExtraChecks = isUnitTestMode(); + + private void assertNoPsiLock() { + if (myExtraChecks) { + LOG.assertTrue(!Thread.holdsLock(PsiLock.LOCK), "Thread must not hold PsiLock while performing readAction"); + } } @Override @@ -1334,12 +1375,12 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App @Override public boolean isWriteAccessAllowed() { - return myLock.writeLock().isHeldByCurrentThread(); + return myLock.isWriteLockedByCurrentThread(); } @Override public boolean isWriteActionInProgress() { - return myLock.writeLock().getHoldCount() != 0; + return myLock.getWriteHoldCount() != 0; } public void editorPaintStart() { From 43aadff7cab29daa86eb98b312bdf94ea3109ecd Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Mon, 16 Jun 2014 15:42:23 +0400 Subject: [PATCH 20/20] init dialog in EDT --- .../git4idea/src/git4idea/push/GitPusher.java | 29 ++++++++++--------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/plugins/git4idea/src/git4idea/push/GitPusher.java b/plugins/git4idea/src/git4idea/push/GitPusher.java index 31e289dba806..0d3f982c1130 100644 --- a/plugins/git4idea/src/git4idea/push/GitPusher.java +++ b/plugins/git4idea/src/git4idea/push/GitPusher.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2011 JetBrains s.r.o. + * 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. @@ -48,7 +48,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.*; -import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; /** * Collects information to push and performs the push. @@ -478,9 +478,7 @@ public final class GitPusher { // and don't show the dialog again if user has chosen not to ask again updateSettings = readUpdateSettings(); if (!mySettings.autoUpdateIfPushRejected()) { - final GitRejectedPushUpdateDialog dialog = new GitRejectedPushUpdateDialog(myProject, rejectedPushesForCurrentBranch.keySet(), updateSettings); - final int exitCode = showDialogAndGetExitCode(dialog); - updateSettings = new UpdateSettings(dialog.shouldUpdateAll(), getUpdateMethodFromDialogExitCode(exitCode)); + updateSettings = showDialogAndGetExitCode(rejectedPushesForCurrentBranch, updateSettings); saveUpdateSettings(updateSettings); } } @@ -519,20 +517,23 @@ public final class GitPusher { return new UpdateSettings(updateAllRoots, updateMethod); } - private int showDialogAndGetExitCode(@NotNull final GitRejectedPushUpdateDialog dialog) { - final AtomicInteger exitCode = new AtomicInteger(); + private UpdateSettings showDialogAndGetExitCode(final Map rejectedPushesForCurrentBranch, + final UpdateSettings initialSettings) { + final AtomicReference updateSettings = new AtomicReference(); UIUtil.invokeAndWaitIfNeeded(new Runnable() { @Override public void run() { + final GitRejectedPushUpdateDialog dialog = new GitRejectedPushUpdateDialog(myProject, rejectedPushesForCurrentBranch.keySet(), initialSettings); dialog.show(); - exitCode.set(dialog.getExitCode()); - } + final int exitCode = dialog.getExitCode(); + if (exitCode != DialogWrapper.CANCEL_EXIT_CODE) { + mySettings.setAutoUpdateIfPushRejected(dialog.shouldAutoUpdateInFuture()); + } + updateSettings.set(new UpdateSettings(dialog.shouldUpdateAll(), getUpdateMethodFromDialogExitCode(exitCode))); + + } }); - int code = exitCode.get(); - if (code != DialogWrapper.CANCEL_EXIT_CODE) { - mySettings.setAutoUpdateIfPushRejected(dialog.shouldAutoUpdateInFuture()); - } - return code; + return updateSettings.get(); } /**