diff --git a/build/scripts/utils.gant b/build/scripts/utils.gant index 2ac5d37aaa07..ed09424fa0c4 100644 --- a/build/scripts/utils.gant +++ b/build/scripts/utils.gant @@ -333,9 +333,6 @@ binding.setVariable("layoutMacApp", { String path, String ch, Map args -> String fullName = args.fullName != null ? args.fullName : p("component.names.fullname") String vmOptions = "-Dfile.encoding=UTF-8 ${vmOptions()} -Xverify:none" - if (isEap() && !args.mac_no_yjp) { - vmOptions += " ${yjpOptions(args.system_selector)}" - } String minor = p("component.version.minor") String version = isEap() && !minor.contains("RC") && !minor.contains("Beta") ? "EAP $args.buildNumber" : "${p("component.version.major")}.${minor}" @@ -354,7 +351,11 @@ binding.setVariable("layoutMacApp", { String path, String ch, Map args -> } new File("$path/bin/idea.properties").text = effectiveProperties.toString() - new File("$path/bin/idea.vmoptions").text = "$mem64 -XX:+UseCompressedOops".split(" ").join("\n") + String ideaVmOptions = "$mem64 -XX:+UseCompressedOops".split(" ").join("\n") + if (isEap() && !args.mac_no_yjp) { + ideaVmOptions += " ${yjpOptions(args.system_selector)}" + } + new File("$path/bin/idea.vmoptions").text = ideaVmOptions String classPath = classPathLibs.collect {"\$APP_PACKAGE/Contents/lib/${it}" }.join(":") diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessImpl.java b/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessImpl.java index f10491282d0e..a733888f9501 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessImpl.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessImpl.java @@ -1157,7 +1157,12 @@ public abstract class DebugProcessImpl extends UserDataHolderBase implements Deb public ArrayReference newInstance(final ArrayType arrayType, final int dimension) throws EvaluateException { - return arrayType.newInstance(dimension); + try { + return arrayType.newInstance(dimension); + } + catch (Exception e) { + throw EvaluateExceptionUtil.createEvaluateException(e); + } } @Override diff --git a/java/debugger/openapi/src/com/intellij/debugger/engine/DebuggerUtils.java b/java/debugger/openapi/src/com/intellij/debugger/engine/DebuggerUtils.java index 9da05817277c..ed150d588c3c 100644 --- a/java/debugger/openapi/src/com/intellij/debugger/engine/DebuggerUtils.java +++ b/java/debugger/openapi/src/com/intellij/debugger/engine/DebuggerUtils.java @@ -291,30 +291,37 @@ public abstract class DebuggerUtils { } if (subType instanceof ClassType) { - result = getSuperType(((ClassType)subType).superclass(), superType); - if (result != null) { - return result; - } - - List ifaces = ((ClassType)subType).allInterfaces(); - for (Object iface : ifaces) { - InterfaceType interfaceType = (InterfaceType)iface; - if (typeEquals(interfaceType, superType)) { - return interfaceType; + try { + final ClassType clsType = (ClassType)subType; + result = getSuperType(clsType.superclass(), superType); + if (result != null) { + return result; } + + for (InterfaceType iface : clsType.allInterfaces()) { + if (typeEquals(iface, superType)) { + return iface; + } + } + } + catch (ClassNotPreparedException e) { + LOG.info(e); } return null; } if (subType instanceof InterfaceType) { - List ifaces = ((InterfaceType)subType).superinterfaces(); - for (Object iface : ifaces) { - InterfaceType interfaceType = (InterfaceType)iface; - result = getSuperType(interfaceType, superType); - if (result != null) { - return result; + try { + for (InterfaceType iface : ((InterfaceType)subType).superinterfaces()) { + result = getSuperType(iface, superType); + if (result != null) { + return result; + } } } + catch (ClassNotPreparedException e) { + LOG.info(e); + } } else if (subType instanceof ArrayType) { if (superType.endsWith("[]")) { @@ -324,7 +331,7 @@ public abstract class DebuggerUtils { return instanceOf(subTypeItem, superTypeItem) ? subType : null; } catch (ClassNotLoadedException e) { - LOG.debug(e); + LOG.info(e); } } } diff --git a/java/java-psi-api/src/com/intellij/psi/util/RedundantCastUtil.java b/java/java-psi-api/src/com/intellij/psi/util/RedundantCastUtil.java index 0fbfa4a059f9..65c3ce81812d 100644 --- a/java/java-psi-api/src/com/intellij/psi/util/RedundantCastUtil.java +++ b/java/java-psi-api/src/com/intellij/psi/util/RedundantCastUtil.java @@ -504,9 +504,21 @@ public class RedundantCastUtil { return; } if (parent instanceof PsiForeachStatement) { - if (InheritanceUtil.isInheritor(PsiUtil.resolveClassInType(opType), false, CommonClassNames.JAVA_LANG_ITERABLE)) { - addToResults(typeCast); - return; + final PsiClassType.ClassResolveResult castResolveResult = PsiUtil.resolveGenericsClassInType(opType); + final PsiClass psiClass = castResolveResult.getElement(); + if (psiClass != null) { + final PsiClass iterableClass = JavaPsiFacade.getInstance(parent.getProject()).findClass(CommonClassNames.JAVA_LANG_ITERABLE, psiClass.getResolveScope()); + if (iterableClass != null && InheritanceUtil.isInheritorOrSelf(psiClass, iterableClass, true)) { + final PsiTypeParameter[] iterableTypeParameters = iterableClass.getTypeParameters(); + if (iterableTypeParameters.length == 1) { + final PsiType resultedParamType = TypeConversionUtil.getSuperClassSubstitutor(iterableClass, psiClass, castResolveResult.getSubstitutor()).substitute(iterableTypeParameters[0]); + if (resultedParamType != null && + TypeConversionUtil.isAssignable(((PsiForeachStatement)parent).getIterationParameter().getType(), resultedParamType)) { + addToResults(typeCast); + return; + } + } + } } } if (parent instanceof PsiThrowStatement) { diff --git a/java/java-tests/testData/inspection/redundantCast/generics/ForEachValueIDEA126166/expected.xml b/java/java-tests/testData/inspection/redundantCast/generics/ForEachValueIDEA126166/expected.xml new file mode 100644 index 000000000000..4704d91e891d --- /dev/null +++ b/java/java-tests/testData/inspection/redundantCast/generics/ForEachValueIDEA126166/expected.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/java/java-tests/testData/inspection/redundantCast/generics/ForEachValueIDEA126166/src/Test.java b/java/java-tests/testData/inspection/redundantCast/generics/ForEachValueIDEA126166/src/Test.java new file mode 100644 index 000000000000..18bf47f111b5 --- /dev/null +++ b/java/java-tests/testData/inspection/redundantCast/generics/ForEachValueIDEA126166/src/Test.java @@ -0,0 +1,11 @@ +import java.util.ArrayList; +import java.util.List; + +class SomeClass { + public void test() { + List objects = new ArrayList<>(); + for (String value : (Iterable) objects) { + System.out.println(value); + } + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/RedundantCast15Test.java b/java/java-tests/testSrc/com/intellij/codeInspection/RedundantCast15Test.java index 4dd29648e055..a8b27ab21089 100644 --- a/java/java-tests/testSrc/com/intellij/codeInspection/RedundantCast15Test.java +++ b/java/java-tests/testSrc/com/intellij/codeInspection/RedundantCast15Test.java @@ -49,6 +49,7 @@ public class RedundantCast15Test extends InspectionTestCase { public void testGetClassProcessing() throws Exception { doTest();} public void testInstanceOfChecks() throws Exception { doTest();} public void testForEachValue() throws Exception { doTest();} + public void testForEachValueIDEA126166() throws Exception { doTest();} public void testCaseThrowable() throws Exception { doTest();} public void testSafeTempVarName() throws Exception { doTest();} 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/editor-ui-api/src/com/intellij/openapi/editor/colors/EditorColors.java b/platform/editor-ui-api/src/com/intellij/openapi/editor/colors/EditorColors.java index fe3242e47b44..29cb27933d7c 100644 --- a/platform/editor-ui-api/src/com/intellij/openapi/editor/colors/EditorColors.java +++ b/platform/editor-ui-api/src/com/intellij/openapi/editor/colors/EditorColors.java @@ -48,7 +48,7 @@ public interface EditorColors { TextAttributesKey FOLDED_TEXT_ATTRIBUTES = TextAttributesKey.createTextAttributesKey("FOLDED_TEXT_ATTRIBUTES"); TextAttributesKey DELETED_TEXT_ATTRIBUTES = TextAttributesKey.createTextAttributesKey("DELETED_TEXT_ATTRIBUTES"); - ColorKey GUTTER_BACKGROUND = ColorKey.createColorKey("GUTTER_BACKGROUND"); + ColorKey GUTTER_BACKGROUND = ColorKey.createColorKey("GUTTER_BACKGROUND", new JBColor(0xf0f0f0, 0x313335)); @Deprecated ColorKey LEFT_GUTTER_BACKGROUND = GUTTER_BACKGROUND; ColorKey NOTIFICATION_BACKGROUND = ColorKey.createColorKey("NOTIFICATION_BACKGROUND"); diff --git a/platform/lang-impl/src/com/intellij/execution/impl/SingleConfigurationConfigurable.java b/platform/lang-impl/src/com/intellij/execution/impl/SingleConfigurationConfigurable.java index 930fc2868359..4c58ab7029b3 100644 --- a/platform/lang-impl/src/com/intellij/execution/impl/SingleConfigurationConfigurable.java +++ b/platform/lang-impl/src/com/intellij/execution/impl/SingleConfigurationConfigurable.java @@ -109,7 +109,7 @@ public final class SingleConfigurationConfigurable myAlreadyAddedFiles = new ArrayList(); - private ArrayList myAlreadyAddedActions = new ArrayList(); private volatile ActionCallback myCurrentWorker = ActionCallback.DONE; private int myHistoryIndex = 0; boolean mySkipFocusGain = false; @@ -255,7 +254,7 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA }, null); } - private JBPopup myBalloon; + private volatile JBPopup myBalloon; private int myPopupActualWidth; private Component myFocusOwner; private ChooseByNamePopup myFileChooseByName; @@ -497,7 +496,7 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA public void run() { if (myCalcThread != null) { myCalcThread.cancel(); - myCalcThread = null; + //myCalcThread = null; } myAlarm.cancelAllRequests(); if (myBalloon != null && !myBalloon.isDisposed() && myPopup != null && !myPopup.isDisposed()) { @@ -1199,9 +1198,12 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA private class CalcThread implements Runnable { private final Project project; private final String pattern; - private ProgressIndicator myProgressIndicator = new ProgressIndicatorBase(); + private final ProgressIndicator myProgressIndicator = new ProgressIndicatorBase(); private final ActionCallback myDone = new ActionCallback(); - private SearchListModel myListModel = new SearchListModel(); + private final SearchListModel myListModel = new SearchListModel(); + private final ArrayList myAlreadyAddedFiles = new ArrayList(); + private final ArrayList myAlreadyAddedActions = new ArrayList(); + public CalcThread(Project project, String pattern) { this.project = project; @@ -1293,9 +1295,10 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA protected void check() { myProgressIndicator.checkCanceled(); if (myDone.isRejected()) throw new ProcessCanceledException(); + if (myBalloon == null || myBalloon.isDisposed()) throw new ProcessCanceledException(); } - private void buildToolWindows(String pattern) { + private synchronized void buildToolWindows(String pattern) { if (myActions == null) { if (myActionModel == null) { myActionModel = createActionModel(); @@ -1331,7 +1334,7 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA }); } - private void buildActionsAndSettings(String pattern) { + private synchronized void buildActionsAndSettings(String pattern) { final Set actions = new HashSet(); final Set settings = new HashSet(); final MinusculeMatcher matcher = new MinusculeMatcher("*" +pattern, NameUtil.MatchingCaseSensitivity.NONE); @@ -1384,7 +1387,7 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA }); } - private void buildFiles(final String pattern) { + private synchronized void buildFiles(final String pattern) { int filesCounter = 0; final Set elements = new LinkedHashSet(); final GlobalSearchScope scope = GlobalSearchScope.projectScope(project); @@ -1445,7 +1448,8 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA } } - private void buildSymbols(final String pattern) { + private synchronized void buildSymbols(final String pattern) { + check(); int symbolsCounter = 0; final Set elements = new LinkedHashSet(); final GlobalSearchScope scope = GlobalSearchScope.projectScope(project); @@ -1508,7 +1512,7 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA return null; } - private void buildRunConfigurations(String pattern) { + private synchronized void buildRunConfigurations(String pattern) { final List runConfigurations = new ArrayList(); MinusculeMatcher matcher = new MinusculeMatcher(pattern, NameUtil.MatchingCaseSensitivity.NONE); final ChooseRunConfigurationPopup.ItemWrapper[] wrappers = @@ -1541,7 +1545,7 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA } - private void buildClasses(final String pattern, boolean includeLibraries) { + private synchronized void buildClasses(final String pattern, boolean includeLibraries) { if (pattern.indexOf('.') != -1) { //todo[kb] it's not a mistake. If we search for "*.png" or "index.xml" in SearchEverywhere //todo[kb] we don't want to see Java classes started with Png or Xml. This approach should be reworked someday. @@ -1593,7 +1597,7 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA } } - private void buildRecentFiles(String pattern) { + private synchronized void buildRecentFiles(String pattern) { final MinusculeMatcher matcher = new MinusculeMatcher("*" + pattern, NameUtil.MatchingCaseSensitivity.NONE); final ArrayList files = new ArrayList(); final List selected = Arrays.asList(FileEditorManager.getInstance(project).getSelectedFiles()); @@ -1626,7 +1630,7 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA return myProgressIndicator.isCanceled() || myDone.isRejected(); } - private void buildTopHit(String pattern) { + private synchronized void buildTopHit(String pattern) { final List elements = new ArrayList(); final HistoryItem history = myHistoryItem; if (history != null) { @@ -1719,6 +1723,26 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA @Override public void run() { if (isCanceled()) return; + + + for (Object element : elements.toArray()) { + if (element instanceof AnAction) { + final AnAction action = (AnAction)element; + final AnActionEvent e = new AnActionEvent(myActionEvent.getInputEvent(), + myActionEvent.getDataContext(), + myActionEvent.getPlace(), + action.getTemplatePresentation(), + myActionEvent.getActionManager(), + myActionEvent.getModifiers()); + ActionUtil.performDumbAwareUpdate(action, e, false); + final Presentation presentation = e.getPresentation(); + if (!presentation.isEnabled() || !presentation.isVisible() || StringUtil.isEmpty(presentation.getText())) { + elements.remove(element); + } + if (isCanceled()) return; + } + } + if (isCanceled() || elements.isEmpty()) return; myListModel.myTitleIndexes.topHit = myListModel.size(); for (Object element : elements) { myListModel.addElement(element); @@ -1894,39 +1918,48 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA } } - protected synchronized void resetFields() { + protected void resetFields() { if (myBalloon!= null) { myBalloon.cancel(); myBalloon = null; } - myFileModel = null; - if (myFileChooseByName != null) { - myFileChooseByName.close(false); - myFileChooseByName = null; - } - if (myClassChooseByName != null) { - myClassChooseByName.close(false); - myClassChooseByName = null; - } - if (mySymbolsChooseByName != null) { - mySymbolsChooseByName.close(false); - mySymbolsChooseByName = null; - } - myClassModel = null; - myActionModel = null; - myActions = null; - mySymbolsModel = null; - myConfigurables.clear(); - myFocusComponent = null; - myContextComponent = null; - myFocusOwner = null; - myRenderer.myProject = null; - myCalcThread = null; - myPopup = null; - myHistoryIndex = 0; - myPopupActualWidth = 0; - myCurrentWorker = ActionCallback.DONE; - showAll.set(false); + myCurrentWorker.doWhenProcessed(new Runnable() { + @Override + public void run() { + myFileModel = null; + if (myFileChooseByName != null) { + myFileChooseByName.close(false); + myFileChooseByName = null; + } + if (myClassChooseByName != null) { + myClassChooseByName.close(false); + myClassChooseByName = null; + } + if (mySymbolsChooseByName != null) { + mySymbolsChooseByName.close(false); + mySymbolsChooseByName = null; + } + if (myCalcThread != null) { + synchronized (myCalcThread) { + myClassModel = null; + myActionModel = null; + myActions = null; + mySymbolsModel = null; + myConfigurables.clear(); + myFocusComponent = null; + myContextComponent = null; + myFocusOwner = null; + myRenderer.myProject = null; + myPopup = null; + myHistoryIndex = 0; + myPopupActualWidth = 0; + myCurrentWorker = ActionCallback.DONE; + showAll.set(false); + myCalcThread = null; + } + } + } + }); mySkipFocusGain = false; } diff --git a/platform/lang-impl/src/com/intellij/ide/bookmarks/Bookmark.java b/platform/lang-impl/src/com/intellij/ide/bookmarks/Bookmark.java index e6cd53e811f8..d22e251ed4ca 100644 --- a/platform/lang-impl/src/com/intellij/ide/bookmarks/Bookmark.java +++ b/platform/lang-impl/src/com/intellij/ide/bookmarks/Bookmark.java @@ -27,6 +27,7 @@ import com.intellij.navigation.NavigationItem; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.RangeMarker; import com.intellij.openapi.editor.colors.CodeInsightColors; +import com.intellij.openapi.editor.colors.EditorColors; import com.intellij.openapi.editor.colors.EditorColorsManager; import com.intellij.openapi.editor.ex.MarkupModelEx; import com.intellij.openapi.editor.ex.RangeHighlighterEx; @@ -335,11 +336,15 @@ public class Bookmark implements Navigatable { @Override public void paintIcon(Component c, Graphics g, int x, int y) { - g.setColor(ICON_BACKGROUND_COLOR); - g.fillRect(x, y, getIconWidth(), getIconHeight()); - g.setColor(JBColor.GRAY); - g.drawRect(x, y, getIconWidth(), getIconHeight()); - myIcon.paintIcon(c, g, x, y); + Graphics2D g2 = (Graphics2D)g.create(); + try { + Color gutterBackground = EditorColors.GUTTER_BACKGROUND.getDefaultColor(); + g2.setColor(gutterBackground); + g2.fillRoundRect(x, y, getIconWidth(), getIconHeight(), 4, 4); + myIcon.paintIcon(c, g2, x, y); + } finally { + g2.dispose(); + } } @Override diff --git a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/GotoActionModel.java b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/GotoActionModel.java index ccd5f23a42ad..ce59e892c6c2 100644 --- a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/GotoActionModel.java +++ b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/GotoActionModel.java @@ -312,7 +312,7 @@ public class GotoActionModel implements ChooseByNameModel, CustomMatcherModel, C @Override @NotNull public String[] getNames(boolean checkBoxState) { - final ArrayList result = new ArrayList(); + final LinkedHashSet result = new LinkedHashSet(); result.add(INTENTIONS_KEY); for (AnAction action : myActionsMap.keySet()) { result.add(getActionId(action)); diff --git a/platform/platform-api/src/com/intellij/ui/components/JBScrollPane.java b/platform/platform-api/src/com/intellij/ui/components/JBScrollPane.java index acb8f804a396..878434ad467a 100644 --- a/platform/platform-api/src/com/intellij/ui/components/JBScrollPane.java +++ b/platform/platform-api/src/com/intellij/ui/components/JBScrollPane.java @@ -220,17 +220,17 @@ public class JBScrollPane extends JScrollPane { if (extendViewportUnderVScrollbar) { viewportBounds.x = Math.min(viewportBounds.x, vsb.getX()); - viewportBounds.width = Math.max(viewportBounds.width, vsb.getX() + vsb.getWidth()); + viewportBounds.width = vsb.getX() + vsb.getWidth() - viewportBounds.x; } if (extendViewportUnderHScrollbar) { viewportBounds.y = Math.min(viewportBounds.y, hsb.getY()); - viewportBounds.height = Math.max(viewportBounds.height, hsb.getY() + hsb.getHeight()); + viewportBounds.height = hsb.getY() + hsb.getHeight() - viewportBounds.y; } if (extendViewportUnderVScrollbar) { if (hsb != null) { Rectangle scrollbarBounds = hsb.getBounds(); - scrollbarBounds.width = viewportBounds.width - scrollbarBounds.x; + scrollbarBounds.width = viewportBounds.x + viewportBounds.width - scrollbarBounds.x; hsb.setBounds(scrollbarBounds); } if (colHead != null) { @@ -244,7 +244,7 @@ public class JBScrollPane extends JScrollPane { if (extendViewportUnderHScrollbar) { if (vsb != null) { Rectangle scrollbarBounds = vsb.getBounds(); - scrollbarBounds.height = viewportBounds.height - scrollbarBounds.y; + scrollbarBounds.height = viewportBounds.y + viewportBounds.height - scrollbarBounds.y; vsb.setBounds(scrollbarBounds); } if (rowHead != null) { 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 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; 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; diff --git a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/AbbreviationManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/AbbreviationManagerImpl.java index 97196b75f3db..a7b2e7bc9d02 100644 --- a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/AbbreviationManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/AbbreviationManagerImpl.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. @@ -106,6 +106,12 @@ public class AbbreviationManagerImpl extends AbbreviationManager implements final String abbrValue = abbr.getAttributeValue("name"); if (abbrValue != null) { values.add(abbrValue); + List actionIds = myAbbreviation2ActionId.get(abbrValue); + if (actionIds == null) { + actionIds = new ArrayList(); + myAbbreviation2ActionId.put(abbrValue, actionIds); + } + actionIds.add(actionId); } } } 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() { diff --git a/platform/platform-impl/src/com/intellij/remote/RemoteSdkAdditionalData.java b/platform/platform-impl/src/com/intellij/remote/RemoteSdkAdditionalData.java index 1da39343b4c0..46bb03f039ff 100644 --- a/platform/platform-impl/src/com/intellij/remote/RemoteSdkAdditionalData.java +++ b/platform/platform-impl/src/com/intellij/remote/RemoteSdkAdditionalData.java @@ -22,7 +22,7 @@ import org.jetbrains.annotations.NotNull; * @author traff */ public interface RemoteSdkAdditionalData - extends SdkAdditionalData, RemoteSdkProducer, RemoteSdkProperties { + extends SdkAdditionalData, RemoteSdkCredentialsProducer, RemoteSdkProperties { void completeInitialization(); boolean isInitialized(); diff --git a/platform/platform-impl/src/com/intellij/remote/RemoteSdkCredentials.java b/platform/platform-impl/src/com/intellij/remote/RemoteSdkCredentials.java index 876f82771025..aeca525bd347 100644 --- a/platform/platform-impl/src/com/intellij/remote/RemoteSdkCredentials.java +++ b/platform/platform-impl/src/com/intellij/remote/RemoteSdkCredentials.java @@ -1,8 +1,5 @@ package com.intellij.remote; -import com.intellij.remote.MutableRemoteCredentials; -import com.intellij.remote.RemoteSdkProperties; - /** * @author traff */ diff --git a/platform/platform-impl/src/com/intellij/remote/RemoteSdkProducer.java b/platform/platform-impl/src/com/intellij/remote/RemoteSdkCredentialsProducer.java similarity index 94% rename from platform/platform-impl/src/com/intellij/remote/RemoteSdkProducer.java rename to platform/platform-impl/src/com/intellij/remote/RemoteSdkCredentialsProducer.java index 849d02d6d64f..0dfa214c9971 100644 --- a/platform/platform-impl/src/com/intellij/remote/RemoteSdkProducer.java +++ b/platform/platform-impl/src/com/intellij/remote/RemoteSdkCredentialsProducer.java @@ -21,7 +21,7 @@ import com.intellij.util.Consumer; /** * @author traff */ -public interface RemoteSdkProducer { +public interface RemoteSdkCredentialsProducer { /** * Synchronously returns remote sdk credentials * @return diff --git a/platform/testFramework/src/com/intellij/testFramework/UsefulTestCase.java b/platform/testFramework/src/com/intellij/testFramework/UsefulTestCase.java index 898d9d04bd28..751a3b9e9538 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; @@ -64,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; @@ -75,6 +69,9 @@ import java.lang.reflect.Modifier; 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; /** @@ -178,13 +175,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 +775,51 @@ 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); + } + 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); } } @@ -886,12 +909,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(); } diff --git a/platform/util/src/com/intellij/openapi/util/text/StringUtil.java b/platform/util/src/com/intellij/openapi/util/text/StringUtil.java index 859b75ef267b..f43da5722864 100644 --- a/platform/util/src/com/intellij/openapi/util/text/StringUtil.java +++ b/platform/util/src/com/intellij/openapi/util/text/StringUtil.java @@ -101,12 +101,12 @@ public class StringUtil extends StringUtilRt { }; @NotNull - public static String replace(@NonNls @NotNull String text, @NonNls @NotNull String oldS, @NonNls @Nullable String newS) { + public static String replace(@NonNls @NotNull String text, @NonNls @NotNull String oldS, @NonNls @NotNull String newS) { return replace(text, oldS, newS, false); } @NotNull - public static String replaceIgnoreCase(@NotNull String text, @NotNull String oldS, @Nullable String newS) { + public static String replaceIgnoreCase(@NonNls @NotNull String text, @NonNls @NotNull String oldS, @NonNls @NotNull String newS) { return replace(text, oldS, newS, true); } @@ -139,23 +139,20 @@ public class StringUtil extends StringUtilRt { return newBuffer == null ? buffer : newBuffer.toString(); } - public static String replace(@NotNull final String text, @NotNull final String oldS, @Nullable final String newS, boolean ignoreCase) { + public static String replace(@NonNls @NotNull final String text, @NonNls @NotNull final String oldS, @NonNls @NotNull final String newS, final boolean ignoreCase) { if (text.length() < oldS.length()) return text; - final String text1 = ignoreCase ? text.toLowerCase() : text; - final String oldS1 = ignoreCase ? oldS.toLowerCase() : oldS; StringBuilder newText = null; int i = 0; - while (i < text1.length()) { - int i1 = text1.indexOf(oldS1, i); + while (i < text.length()) { + final int i1 = ignoreCase? indexOfIgnoreCase(text, oldS, i) : text.indexOf(oldS, i); if (i1 < 0) { if (i == 0) return text; newText.append(text, i, text.length()); break; } else { - if (newS == null) return null; if (newText == null) newText = new StringBuilder(text.length() - i); newText.append(text, i, i1); newText.append(newS); 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(); diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/trivialif/ConvertToNestedIfIntention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/trivialif/ConvertToNestedIfIntention.java index c73febe194fd..aadbef9b2c60 100644 --- a/plugins/IntentionPowerPak/src/com/siyeh/ipp/trivialif/ConvertToNestedIfIntention.java +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/trivialif/ConvertToNestedIfIntention.java @@ -62,7 +62,7 @@ public class ConvertToNestedIfIntention extends Intention { if (returnValue == null || ErrorUtil.containsDeepError(returnValue)) { return; } - final String newStatementText = buildIf(returnValue, new StringBuilder()).toString(); + final String newStatementText = buildIf(returnValue, true, new StringBuilder()).toString(); final Project project = returnStatement.getProject(); final PsiElementFactory elementFactory = JavaPsiFacade.getInstance(project).getElementFactory(); final PsiBlockStatement blockStatement = (PsiBlockStatement)elementFactory.createStatementFromText("{" + newStatementText + "}", returnStatement); @@ -73,23 +73,23 @@ public class ConvertToNestedIfIntention extends Intention { PsiReplacementUtil.replaceStatement(returnStatement, "return false;"); } - private static StringBuilder buildIf(@Nullable PsiExpression expression, StringBuilder out) { + private static StringBuilder buildIf(@Nullable PsiExpression expression, boolean top, StringBuilder out) { if (expression instanceof PsiPolyadicExpression) { final PsiPolyadicExpression polyadicExpression = (PsiPolyadicExpression)expression; final PsiExpression[] operands = polyadicExpression.getOperands(); final IElementType tokenType = polyadicExpression.getOperationTokenType(); if (JavaTokenType.ANDAND.equals(tokenType)) { for (PsiExpression operand : operands) { - buildIf(operand, out); + buildIf(operand, false, out); } - if (!StringUtil.endsWith(out, "return true;")) { + if (top && !StringUtil.endsWith(out, "return true;")) { out.append("return true;"); } return out; } - else if (JavaTokenType.OROR.equals(tokenType)) { + else if (top && JavaTokenType.OROR.equals(tokenType)) { for (PsiExpression operand : operands) { - buildIf(operand, out); + buildIf(operand, false, out); if (!StringUtil.endsWith(out, "return true;")) { out.append("return true;"); } @@ -99,7 +99,7 @@ public class ConvertToNestedIfIntention extends Intention { } else if (expression instanceof PsiParenthesizedExpression) { final PsiParenthesizedExpression parenthesizedExpression = (PsiParenthesizedExpression)expression; - buildIf(parenthesizedExpression.getExpression(), out); + buildIf(parenthesizedExpression.getExpression(), top, out); return out; } if (expression != null) { diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/trivialif/convert_to_nested_if/OrStaircaseInside.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/trivialif/convert_to_nested_if/OrStaircaseInside.java new file mode 100644 index 000000000000..521db40592e9 --- /dev/null +++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/trivialif/convert_to_nested_if/OrStaircaseInside.java @@ -0,0 +1,7 @@ +package com.siyeh.ipp.trivialif.convert_to_nested_if; + +public class X { + boolean f(boolean a, boolean b, boolean c, boolean d) { + return a || (b && c) || d; + } +} diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/trivialif/convert_to_nested_if/OrStaircaseInside_after.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/trivialif/convert_to_nested_if/OrStaircaseInside_after.java new file mode 100644 index 000000000000..0f3ea890809f --- /dev/null +++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/trivialif/convert_to_nested_if/OrStaircaseInside_after.java @@ -0,0 +1,10 @@ +package com.siyeh.ipp.trivialif.convert_to_nested_if; + +public class X { + boolean f(boolean a, boolean b, boolean c, boolean d) { + if (a) return true; + if (b) if (c) return true; + if (d) return true; + return false; + } +} diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/trivialif/convert_to_nested_if/StaircaseWithOrInside.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/trivialif/convert_to_nested_if/StaircaseWithOrInside.java new file mode 100644 index 000000000000..81b9b0f86333 --- /dev/null +++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/trivialif/convert_to_nested_if/StaircaseWithOrInside.java @@ -0,0 +1,7 @@ +package com.siyeh.ipp.trivialif.convert_to_nested_if; + +public class X { + boolean f(boolean a, boolean b, boolean c, boolean d) { + return a && (b || c) && d; + } +} diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/trivialif/convert_to_nested_if/StaircaseWithOrInside_after.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/trivialif/convert_to_nested_if/StaircaseWithOrInside_after.java new file mode 100644 index 000000000000..768a17905219 --- /dev/null +++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/trivialif/convert_to_nested_if/StaircaseWithOrInside_after.java @@ -0,0 +1,8 @@ +package com.siyeh.ipp.trivialif.convert_to_nested_if; + +public class X { + boolean f(boolean a, boolean b, boolean c, boolean d) { + if (a) if (b || c) if (d) return true; + return false; + } +} diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/trivialif/convert_to_nested_if/StaircaseWithParenthesis.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/trivialif/convert_to_nested_if/StaircaseWithParenthesis.java new file mode 100644 index 000000000000..71c207f828b2 --- /dev/null +++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/trivialif/convert_to_nested_if/StaircaseWithParenthesis.java @@ -0,0 +1,19 @@ +package com.siyeh.ipp.trivialif.convert_to_nested_if; + +public class X { + public static boolean foo(double a, double b, double c) + { + // the following return statement is converted by "Convert to multiple 'ifs'" (on the second &&) to the below, incorrect if-then-else + return (a > c && a < b) && !bar1(a) && !bar2(a); + } + + private static boolean bar1(double a) + { + return true; + } + + private static boolean bar2(double a) + { + return true; + } +} diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/trivialif/convert_to_nested_if/StaircaseWithParenthesis_after.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/trivialif/convert_to_nested_if/StaircaseWithParenthesis_after.java new file mode 100644 index 000000000000..e17ed504d460 --- /dev/null +++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/trivialif/convert_to_nested_if/StaircaseWithParenthesis_after.java @@ -0,0 +1,20 @@ +package com.siyeh.ipp.trivialif.convert_to_nested_if; + +public class X { + public static boolean foo(double a, double b, double c) + { + // the following return statement is converted by "Convert to multiple 'ifs'" (on the second &&) to the below, incorrect if-then-else + if (a > c) if (a < b) if (!bar1(a)) if (!bar2(a)) return true; + return false; + } + + private static boolean bar1(double a) + { + return true; + } + + private static boolean bar2(double a) + { + return true; + } +} diff --git a/plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/trivialif/ConvertToNestedIfIntentionTest.java b/plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/trivialif/ConvertToNestedIfIntentionTest.java index 84b140376ff4..1515c61030f3 100644 --- a/plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/trivialif/ConvertToNestedIfIntentionTest.java +++ b/plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/trivialif/ConvertToNestedIfIntentionTest.java @@ -22,6 +22,9 @@ public class ConvertToNestedIfIntentionTest extends IPPTestCase { public void testNested() { doTest(); } public void testStaircase() { doTest(); } + public void testStaircaseWithParenthesis() { doTest(); } + public void testStaircaseWithOrInside() { doTest(); } + public void testOrStaircaseInside() { doTest(); } public void testOneLevelStaircase() { assertIntentionNotAvailable(); } public void testAndOrMixed() { doTest(); } 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(); } /** diff --git a/plugins/github/src/org/jetbrains/plugins/github/GithubCreateGistAction.java b/plugins/github/src/org/jetbrains/plugins/github/GithubCreateGistAction.java index 078f2f77ad64..43753142a5b2 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/GithubCreateGistAction.java +++ b/plugins/github/src/org/jetbrains/plugins/github/GithubCreateGistAction.java @@ -254,18 +254,29 @@ public class GithubCreateGistAction extends DumbAwareAction { } @NotNull - private static List getContentFromFile(@NotNull VirtualFile file, @NotNull Project project, @Nullable String prefix) { + private static List getContentFromFile(@NotNull final VirtualFile file, @NotNull Project project, @Nullable String prefix) { if (file.isDirectory()) { return getContentFromDirectory(file, project, prefix); } - Document document = FileDocumentManager.getInstance().getDocument(file); - String content; - if (document != null) { - content = document.getText(); - } - else { - content = readFile(file); - } + String content = ApplicationManager.getApplication().runReadAction(new Computable() { + @Nullable + @Override + public String compute() { + try { + Document document = FileDocumentManager.getInstance().getDocument(file); + if (document != null) { + return document.getText(); + } + else { + return new String(file.contentsToByteArray(), file.getCharset()); + } + } + catch (IOException e) { + LOG.info("Couldn't read contents of the file " + file, e); + return null; + } + } + }); if (content == null) { GithubNotifications.showWarning(project, FAILED_TO_CREATE_GIST, "Couldn't read the contents of the file " + file); return Collections.emptyList(); @@ -289,23 +300,6 @@ public class GithubCreateGistAction extends DumbAwareAction { return contents; } - @Nullable - private static String readFile(@NotNull final VirtualFile file) { - return ApplicationManager.getApplication().runReadAction(new Computable() { - @Nullable - @Override - public String compute() { - try { - return new String(file.contentsToByteArray(), file.getCharset()); - } - catch (IOException e) { - LOG.info("Couldn't read contents of the file " + file, e); - return null; - } - } - }); - } - private static String addPrefix(@NotNull String name, @Nullable String prefix, boolean addTrailingSlash) { String pref = prefix == null ? "" : prefix; pref += name; diff --git a/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleEditor.java b/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleEditor.java index 5abeb70cf985..dc3937d42f63 100644 --- a/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleEditor.java +++ b/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleEditor.java @@ -84,6 +84,7 @@ public class ResourceBundleEditor extends UserDataHolderBase implements FileEdit private final StructureViewComponent myStructureViewComponent; private final Map myEditors; + private String myOldPropertyName; private final ResourceBundle myResourceBundle; private final Map myTitledPanels; private final JComponent myNoPropertySelectedPanel = new NoPropertySelectedPanel().getComponent(); @@ -271,7 +272,9 @@ public class ResourceBundleEditor extends UserDataHolderBase implements FileEdit private void writeEditorPropertyValue(final Editor editor, final PropertiesFile propertiesFile) { final String currentValue = editor.getDocument().getText(); - final String selectedProperty = getSelectedPropertyName(); + final String currentSelectedProperty = getSelectedPropertyName(); + final String selectedProperty = myOldPropertyName == null ? currentSelectedProperty : myOldPropertyName; + assert selectedProperty != null; ApplicationManager.getApplication().runWriteAction(new Runnable() { @@ -505,10 +508,18 @@ public class ResourceBundleEditor extends UserDataHolderBase implements FileEdit } private void selectionChanged() { myBackSlashPressed.clear(); + final String currentSelectedPropertyName = getSelectedPropertyName(); + UIUtil.invokeLaterIfNeeded(new Runnable() { @Override public void run() { + if (myOldPropertyName != null && !myOldPropertyName.equals(currentSelectedPropertyName)) { + for (final Map.Entry entry : myEditors.entrySet()) { + writeEditorPropertyValue(entry.getValue(), entry.getKey()); + } + } updateEditorsFromProperties(); + myOldPropertyName = currentSelectedPropertyName; } }); } diff --git a/python/build/pycharm_community_build.gant b/python/build/pycharm_community_build.gant index 0d8c0be4fcfc..3b793ec4498f 100644 --- a/python/build/pycharm_community_build.gant +++ b/python/build/pycharm_community_build.gant @@ -173,7 +173,7 @@ public layoutCommunity(String classesPath, Set usedJars) { String tarRoot = isEap() ? "pycharm-community-$buildNumber" : "pycharm-community-${p("component.version.major")}.${p("component.version.minor")}" buildTarGz(tarRoot, "$paths.artifacts/pycharmPC-${buildNumber}.tar", [paths.distAll, paths.distUnix]) - String macAppRoot = isEap() ? "PyCharm CE ${p("component.version.major")}.${p("component.version.minor")} EAP.app" : "PyCharm CE.app" + String macAppRoot = isEap() ? "PyCharm CE ${p("component.version.major")}.${p("component.version.minor")} EAP.app/Contents" : "PyCharm CE.app/Contents" buildMacZip(macAppRoot, "${paths.artifacts}/pycharmPC-${buildNumber}.sit", [paths.distAll], paths.distMac) }