From deddecae3c223e9ad0ff545560df17a0a0a11bc0 Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Fri, 14 Nov 2014 01:46:48 +0300 Subject: [PATCH 01/48] svn: Refactored SvnFileSystemListenerWrapper - code simplified --- .../idea/svn/SvnFileSystemListener.java | 2 +- .../svn/SvnFileSystemListenerWrapper.java | 46 ++++++------------- 2 files changed, 15 insertions(+), 33 deletions(-) diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnFileSystemListener.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnFileSystemListener.java index 06e3f3bcc8d0..7216268b1225 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnFileSystemListener.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnFileSystemListener.java @@ -61,7 +61,7 @@ import java.io.File; import java.io.IOException; import java.util.*; -public class SvnFileSystemListener extends CommandAdapter implements LocalFileOperationsHandler { +public class SvnFileSystemListener implements LocalFileOperationsHandler { private static final Logger LOG = Logger.getInstance("#org.jetbrains.idea.svn.SvnFileSystemListener"); private final LocalFileSystem myLfs; diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnFileSystemListenerWrapper.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnFileSystemListenerWrapper.java index 8f23eeb8d0a8..a2889fc1e70e 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnFileSystemListenerWrapper.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnFileSystemListenerWrapper.java @@ -16,8 +16,8 @@ package org.jetbrains.idea.svn; import com.intellij.openapi.Disposable; +import com.intellij.openapi.command.CommandAdapter; import com.intellij.openapi.command.CommandEvent; -import com.intellij.openapi.command.CommandListener; import com.intellij.openapi.command.CommandProcessor; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectLocator; @@ -27,6 +27,7 @@ import com.intellij.openapi.vfs.LocalFileOperationsHandler; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.ThrowableConsumer; +import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.Nullable; import java.io.IOException; @@ -34,19 +35,17 @@ import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.Arrays; -import java.util.HashMap; import java.util.Map; public class SvnFileSystemListenerWrapper { private final LocalFileOperationsHandler myProxy; - private final CommandListener myListener; + private final MyCommandListener myListener; public SvnFileSystemListenerWrapper(final SvnFileSystemListener delegate) { - final MyCommandListener listener = new MyCommandListener(delegate); - myListener = listener; - final MyStorage storage = new MyStorage(listener); - myProxy = (LocalFileOperationsHandler) Proxy.newProxyInstance(LocalFileOperationsHandler.class.getClassLoader(), - new Class[]{LocalFileOperationsHandler.class}, new MyInvoker(storage, delegate)); + myListener = new MyCommandListener(delegate); + myProxy = (LocalFileOperationsHandler)Proxy + .newProxyInstance(LocalFileOperationsHandler.class.getClassLoader(), new Class[]{LocalFileOperationsHandler.class}, + new MyInvoker(new MyStorage(myListener), delegate)); } public void registerSelf() { @@ -59,7 +58,7 @@ public class SvnFileSystemListenerWrapper { CommandProcessor.getInstance().removeCommandListener(myListener); } - private static class MyCommandListener implements CommandListener, MyMarker { + private static class MyCommandListener extends CommandAdapter { private volatile boolean myInCommand; private final SvnFileSystemListener myDelegate; @@ -84,36 +83,19 @@ public class SvnFileSystemListenerWrapper { myDelegate.commandStarted(event); } - public void beforeCommandFinished(CommandEvent event) { - myDelegate.beforeCommandFinished(event); - } - public void commandFinished(CommandEvent event) { myInCommand = false; myDelegate.commandFinished(event); } - - public void undoTransparentActionStarted() { - myDelegate.undoTransparentActionStarted(); - } - - public void undoTransparentActionFinished() { - myDelegate.undoTransparentActionFinished(); - } - } - - private interface MyMarker { - void start(final Project project); - void finish(final Project project); } private static class MyStorage implements InvocationHandler { - private final MyMarker myMarker; + private final MyCommandListener myListener; private final Map> myStarted; - private MyStorage(final MyMarker marker) { - myMarker = marker; - myStarted = new HashMap>(); + private MyStorage(final MyCommandListener listener) { + myListener = listener; + myStarted = ContainerUtil.newHashMap(); } @Nullable @@ -131,7 +113,7 @@ public class SvnFileSystemListenerWrapper { if (project != null) { final Pair pair = myStarted.get(project); if (pair != null && method.getName().equals(pair.getFirst()) && Arrays.equals(args, pair.getSecond())) { - myMarker.finish(project); + myListener.finish(project); } } //dont return null for auto unboxing to not face NPE @@ -143,7 +125,7 @@ public class SvnFileSystemListenerWrapper { System.arraycopy(args, 0, newArr, 0, args.length); final Project project = getProject(args); if (project != null) { - myMarker.start(project); + myListener.start(project); myStarted.put(project, Pair.create(method.getName(), newArr)); Disposer.register(project, new Disposable() { public void dispose() { From 82b4848be16a176887aae373f6ddd33a631f39ab Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Fri, 14 Nov 2014 02:04:24 +0300 Subject: [PATCH 02/48] svn: Refactored SvnFileSystemListener - removed unused code, code simplified, warnings fixed --- .../idea/svn/SvnFileSystemListener.java | 131 +++++++----------- 1 file changed, 50 insertions(+), 81 deletions(-) diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnFileSystemListener.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnFileSystemListener.java index 7216268b1225..4f452515e430 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnFileSystemListener.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnFileSystemListener.java @@ -19,7 +19,6 @@ package org.jetbrains.idea.svn; import com.intellij.openapi.application.Application; import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.command.CommandAdapter; import com.intellij.openapi.command.CommandEvent; import com.intellij.openapi.command.undo.UndoManager; import com.intellij.openapi.diagnostic.Logger; @@ -32,7 +31,6 @@ import com.intellij.openapi.util.Couple; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vcs.*; -import com.intellij.openapi.vcs.actions.VcsContextFactory; import com.intellij.openapi.vcs.changes.ChangeListManager; import com.intellij.openapi.vcs.changes.VcsDirtyScopeManager; import com.intellij.openapi.vfs.LocalFileOperationsHandler; @@ -44,6 +42,7 @@ import com.intellij.util.ThrowableConsumer; import com.intellij.util.containers.Convertor; import com.intellij.util.containers.MultiMap; import com.intellij.vcsUtil.ActionWithTempFile; +import com.intellij.vcsUtil.VcsUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.svn.api.Depth; @@ -113,12 +112,10 @@ public class SvnFileSystemListener implements LocalFileOperationsHandler { exceptionList.add(handleMoveException(e)); } - private VcsException handleMoveException(@NotNull Exception e) { + private static VcsException handleMoveException(@NotNull Exception e) { VcsException vcsException; - if (e instanceof SVNException && SVNErrorCode.ENTRY_EXISTS.equals(((SVNException)e).getErrorMessage().getErrorCode())) { - vcsException = createMoveTargetExistsError(e); - } - else if (e instanceof SvnBindException && ((SvnBindException)e).contains(SVNErrorCode.ENTRY_EXISTS)) { + if (e instanceof SVNException && SVNErrorCode.ENTRY_EXISTS.equals(((SVNException)e).getErrorMessage().getErrorCode()) || + e instanceof SvnBindException && ((SvnBindException)e).contains(SVNErrorCode.ENTRY_EXISTS)) { vcsException = createMoveTargetExistsError(e); } else if (e instanceof VcsException) { @@ -225,8 +222,6 @@ public class SvnFileSystemListener implements LocalFileOperationsHandler { final SvnVcs vcs = getVCS(toDir); final SvnVcs sourceVcs = getVCS(file); - if (vcs == null && sourceVcs == null) return false; - if (vcs == null) { return false; } @@ -237,13 +232,11 @@ public class SvnFileSystemListener implements LocalFileOperationsHandler { } if (isPendingAdd(vcs.getProject(), toDir)) { - myMovedFiles.add(new MovedFileInfo(sourceVcs.getProject(), srcFile, dstFile)); return true; } else { - final VirtualFile oldParent = file.getParent(); - myFilesToRefresh.add(oldParent); + myFilesToRefresh.add(file.getParent()); myFilesToRefresh.add(toDir); return doMove(sourceVcs, srcFile, dstFile); } @@ -272,19 +265,10 @@ public class SvnFileSystemListener implements LocalFileOperationsHandler { final boolean is17OrLater = format.isOrGreater(WorkingCopyFormat.ONE_DOT_SEVEN); if (is17OrLater) { Status srcStatus = getFileStatus(vcs, src); - final File toDir = dst.getParentFile(); - Status dstStatus = getFileStatus(vcs, toDir); - final boolean srcUnversioned = srcStatus == null || srcStatus.is(StatusType.STATUS_UNVERSIONED); - if (srcUnversioned && (dstStatus == null || dstStatus.is(StatusType.STATUS_UNVERSIONED))) { + if (isUnversioned(srcStatus) && (isUnversioned(vcs, dst.getParentFile()) || isUnversioned(vcs, dst)) || + for17move(vcs, src, dst, isUndo, srcStatus)) { return false; } - if (srcUnversioned) { - Status dstWasStatus = getFileStatus(vcs, dst); - if (dstWasStatus == null || dstWasStatus.is(StatusType.STATUS_UNVERSIONED)) { - return false; - } - } - if (for17move(vcs, src, dst, isUndo, srcStatus)) return false; } else { if (for16move(vcs, src, dst, isUndo)) return false; } @@ -301,9 +285,12 @@ public class SvnFileSystemListener implements LocalFileOperationsHandler { return true; } - private final static Set ourStatusesForUndoMove = new HashSet(); - static { - ourStatusesForUndoMove.add(StatusType.STATUS_ADDED); + private static boolean isUnversioned(@Nullable Status status) { + return status == null || status.is(StatusType.STATUS_UNVERSIONED); + } + + private static boolean isUnversioned(@NotNull SvnVcs vcs, @NotNull File file) { + return isUnversioned(getFileStatus(vcs, file)); } private boolean for17move(final SvnVcs vcs, final File src, final File dst, boolean undo, Status srcStatus) throws VcsException { @@ -314,7 +301,7 @@ public class SvnFileSystemListener implements LocalFileOperationsHandler { myUndoingMove = true; createRevertAction(vcs, dst, true).execute(); copyUnversionedMembersOfDirectory(src, dst); - if (srcStatus == null || srcStatus.is(StatusType.STATUS_UNVERSIONED)) { + if (isUnversioned(srcStatus)) { FileUtil.delete(src); } else { createRevertAction(vcs, src, true).execute(); @@ -323,8 +310,7 @@ public class SvnFileSystemListener implements LocalFileOperationsHandler { } else { if (doUsualMove(vcs, src)) return true; // check destination directory - final Status dstParentStatus = getFileStatus(vcs, dst.getParentFile()); - if (dstParentStatus == null || dstParentStatus.is(StatusType.STATUS_UNVERSIONED)) { + if (isUnversioned(vcs, dst.getParentFile())) { try { copyFileOrDir(src, dst); } @@ -348,7 +334,7 @@ public class SvnFileSystemListener implements LocalFileOperationsHandler { }.execute(); } - private void copyUnversionedMembersOfDirectory(final File src, final File dst) throws SvnBindException { + private static void copyUnversionedMembersOfDirectory(final File src, final File dst) throws SvnBindException { if (src.isDirectory()) { final SvnBindException[] exc = new SvnBindException[1]; FileUtil.processFilesRecursively(src, new Processor() { @@ -374,7 +360,7 @@ public class SvnFileSystemListener implements LocalFileOperationsHandler { } } - private void copyFileOrDir(File src, File dst) throws IOException { + private static void copyFileOrDir(File src, File dst) throws IOException { if (src.isDirectory()) { FileUtil.copyDir(src, dst); } else { @@ -382,45 +368,38 @@ public class SvnFileSystemListener implements LocalFileOperationsHandler { } } - private boolean doUsualMove(SvnVcs vcs, File src) { + private static boolean doUsualMove(SvnVcs vcs, File src) { // if src is not under version control, do usual move. Status srcStatus = getFileStatus(vcs, src); return srcStatus == null || srcStatus.is(StatusType.STATUS_UNVERSIONED, StatusType.STATUS_OBSTRUCTED, StatusType.STATUS_MISSING, StatusType.STATUS_EXTERNAL); } - private boolean for16move(SvnVcs vcs, final File src, final File dst, boolean undo) throws VcsException { + private boolean for16move(SvnVcs vcs, final File src, final File dst, final boolean undo) throws VcsException { final SVNMoveClient mover = vcs.getSvnKitManager().createMoveClient(); if (undo) { myUndoingMove = true; restoreFromUndoStorage(dst); - new RepeatSvnActionThroughBusy() { - @Override - protected void executeImpl() throws VcsException { - try { + } + else if (doUsualMove(vcs, src)) return true; + + new RepeatSvnActionThroughBusy() { + @Override + protected void executeImpl() throws VcsException { + try { + if (undo) { mover.undoMove(src, dst); } - catch (SVNException e) { - throw new SvnBindException(e); - } - } - }.execute(); - } - else { - // if src is not under version control, do usual move. - if (doUsualMove(vcs, src)) return true; - new RepeatSvnActionThroughBusy() { - @Override - protected void executeImpl() throws VcsException { - try { + else { mover.doMove(src, dst); } - catch (SVNException e) { - throw new SvnBindException(e); - } } - }.execute(); - } + catch (SVNException e) { + throw new SvnBindException(e); + } + } + }.execute(); + return false; } @@ -482,10 +461,7 @@ public class SvnFileSystemListener implements LocalFileOperationsHandler { if (VcsShowConfirmationOption.Value.DO_NOTHING_SILENTLY.equals(value)) return false; final File ioFile = getIOFile(file); - if (! SvnUtil.isSvnVersioned(vcs.getProject(), ioFile.getParentFile())) { - return false; - } - if (SvnUtil.isWorkingCopyRoot(ioFile)) { + if (!SvnUtil.isSvnVersioned(vcs, ioFile.getParentFile()) || SvnUtil.isWorkingCopyRoot(ioFile)) { return false; } @@ -503,7 +479,6 @@ public class SvnFileSystemListener implements LocalFileOperationsHandler { return true; } else { - if (vcs != null) { if (isAboveSourceOfCopyOrMove(vcs.getProject(), ioFile)) { myDeletedFiles.putValue(vcs.getProject(), ioFile); return true; @@ -521,13 +496,14 @@ public class SvnFileSystemListener implements LocalFileOperationsHandler { // packages deleted from disk should not be deleted from svn (IDEADEV-16066) if (file.isDirectory() || isUndo(vcs)) return true; } - } return false; } } @NotNull - private RepeatSvnActionThroughBusy createRevertAction(@NotNull final SvnVcs vcs, @NotNull final File file, final boolean recursive) { + private static RepeatSvnActionThroughBusy createRevertAction(@NotNull final SvnVcs vcs, + @NotNull final File file, + final boolean recursive) { return new RepeatSvnActionThroughBusy() { @Override protected void executeImpl() throws VcsException { @@ -537,7 +513,7 @@ public class SvnFileSystemListener implements LocalFileOperationsHandler { } @NotNull - private RepeatSvnActionThroughBusy createDeleteAction(@NotNull final SvnVcs vcs, @NotNull final File file, final boolean force) { + private static RepeatSvnActionThroughBusy createDeleteAction(@NotNull final SvnVcs vcs, @NotNull final File file, final boolean force) { return new RepeatSvnActionThroughBusy() { @Override protected void executeImpl() throws VcsException { @@ -597,7 +573,7 @@ public class SvnFileSystemListener implements LocalFileOperationsHandler { } File ioDir = getIOFile(dir); boolean pendingAdd = isPendingAdd(vcs.getProject(), dir); - if (! SvnUtil.isSvnVersioned(vcs.getProject(), ioDir) && ! pendingAdd) { + if (!SvnUtil.isSvnVersioned(vcs, ioDir) && !pendingAdd) { return false; } final File targetFile = new File(ioDir, name); @@ -772,7 +748,7 @@ public class SvnFileSystemListener implements LocalFileOperationsHandler { } } - private void runInBackground(final Project project, final String name, final Runnable runnable) { + private static void runInBackground(final Project project, final String name, final Runnable runnable) { if (ApplicationManager.getApplication().isDispatchThread()) { ProgressManager.getInstance().runProcessWithProgressSynchronously(runnable, name, false, project); } else { @@ -780,7 +756,7 @@ public class SvnFileSystemListener implements LocalFileOperationsHandler { } } - private Runnable createAdditionRunnable(final Project project, + private static Runnable createAdditionRunnable(final Project project, final SvnVcs vcs, final Map copyFromMap, final Collection filesToProcess, @@ -828,7 +804,7 @@ public class SvnFileSystemListener implements LocalFileOperationsHandler { }; } - private Collection promptAboutAddition(SvnVcs vcs, + private static Collection promptAboutAddition(SvnVcs vcs, List addedVFiles, VcsShowConfirmationOption.Value value, AbstractVcsHelper vcsHelper) { @@ -900,7 +876,7 @@ public class SvnFileSystemListener implements LocalFileOperationsHandler { filesToProcess.addAll(confirmed); } } - if (filesToProcess != null && ! filesToProcess.isEmpty()) { + if (!filesToProcess.isEmpty()) { runInBackground(project, "Deleting files from Subversion", createDeleteRunnable(project, vcs, filesToProcess, exceptions)); } final List deletedFilesFiles = ObjectsConvertor.convert(deletedFiles, new Convertor, FilePath>() { @@ -915,9 +891,7 @@ public class SvnFileSystemListener implements LocalFileOperationsHandler { myFilesToRefresh.add(parent.getVirtualFile()); } } - if (filesToProcess != null) { - deletedFilesFiles.removeAll(filesToProcess); - } + deletedFilesFiles.removeAll(filesToProcess); for (FilePath file : deletedFilesFiles) { FileUtil.delete(file.getIOFile()); } @@ -930,7 +904,7 @@ public class SvnFileSystemListener implements LocalFileOperationsHandler { } } - private Runnable createDeleteRunnable(final Project project, + private static Runnable createDeleteRunnable(final Project project, final SvnVcs vcs, final Collection filesToProcess, final List exceptions) { @@ -957,7 +931,7 @@ public class SvnFileSystemListener implements LocalFileOperationsHandler { }; } - private Collection promptAboutDeletion(List> deletedFiles, + private static Collection promptAboutDeletion(List> deletedFiles, SvnVcs vcs, VcsShowConfirmationOption.Value value, AbstractVcsHelper vcsHelper) { @@ -1001,9 +975,9 @@ public class SvnFileSystemListener implements LocalFileOperationsHandler { myT = vcs.getFactory(file).createStatusClient().doStatus(file, false); } }.compute(); - boolean isAdded = StatusType.STATUS_ADDED.equals(status.getNodeStatus()); - final FilePath filePath = VcsContextFactory.SERVICE.getInstance().createFilePathOn(file); - if (isAdded) { + + final FilePath filePath = VcsUtil.getFilePath(file); + if (StatusType.STATUS_ADDED.equals(status.getNodeStatus())) { deleteAnyway.add(filePath); } else { deletedFiles.add(Pair.create(filePath, vcs.getWorkingCopyFormat(file))); @@ -1060,11 +1034,6 @@ public class SvnFileSystemListener implements LocalFileOperationsHandler { } } - private static boolean isUndoOrRedo(@NotNull final Project project) { - final UndoManager undoManager = UndoManager.getInstance(project); - return undoManager.isUndoInProgress() || undoManager.isRedoInProgress(); - } - private static boolean isUndo(SvnVcs vcs) { if (vcs == null || vcs.getProject() == null) { return false; From add8e92d749775ec8f2509fab76ed8f0e8021317 Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Fri, 14 Nov 2014 13:14:03 +0300 Subject: [PATCH 03/48] svn: Removed SvnFileSystemListenerWrapper - corresponding logic moved to SvnFileSystemListener --- .../idea/svn/SvnApplicationSettings.java | 8 +- .../idea/svn/SvnFileSystemListener.java | 56 +++++- .../svn/SvnFileSystemListenerWrapper.java | 169 ------------------ 3 files changed, 55 insertions(+), 178 deletions(-) delete mode 100644 plugins/svn4idea/src/org/jetbrains/idea/svn/SvnFileSystemListenerWrapper.java diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnApplicationSettings.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnApplicationSettings.java index 72a1539efcf4..fb3bf081d8d5 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnApplicationSettings.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnApplicationSettings.java @@ -18,6 +18,7 @@ package org.jetbrains.idea.svn; import com.intellij.openapi.application.PathManager; import com.intellij.openapi.components.*; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Disposer; import org.tmatesoft.svn.core.SVNException; import org.tmatesoft.svn.core.SVNURL; @@ -35,7 +36,7 @@ import java.util.List; )} ) public class SvnApplicationSettings implements PersistentStateComponent { - private SvnFileSystemListenerWrapper myVFSHandler; + private SvnFileSystemListener myVFSHandler; private int mySvnProjectCount; private LimitedStringsList myLimitedStringsList; @@ -90,8 +91,7 @@ public class SvnApplicationSettings implements PersistentStateComponent> myUndoStorageContents = new ArrayList>(); private boolean myUndoingMove = false; + private boolean myIsInCommand; + @Nullable private Project myGuessedProject; + public SvnFileSystemListener() { myLfs = LocalFileSystem.getInstance(); + + myLfs.registerAuxiliaryFileOperationsHandler(this); + CommandProcessor.getInstance().addCommandListener(this); + } + + @Override + public void dispose() { + myLfs.unregisterAuxiliaryFileOperationsHandler(this); + CommandProcessor.getInstance().removeCommandListener(this); } private void addToMoveExceptions(@NotNull final Project project, @NotNull final Exception e) { @@ -134,6 +150,8 @@ public class SvnFileSystemListener implements LocalFileOperationsHandler { @Nullable public File copy(final VirtualFile file, final VirtualFile toDir, final String copyName) throws IOException { + startOperation(file); + SvnVcs vcs = getVCS(toDir); if (vcs == null) { vcs = getVCS(file); @@ -217,6 +235,8 @@ public class SvnFileSystemListener implements LocalFileOperationsHandler { } public boolean move(VirtualFile file, VirtualFile toDir) throws IOException { + startOperation(file); + File srcFile = getIOFile(file); File dstFile = new File(getIOFile(toDir), file.getName()); @@ -243,6 +263,8 @@ public class SvnFileSystemListener implements LocalFileOperationsHandler { } public boolean rename(VirtualFile file, String newName) throws IOException { + startOperation(file); + File srcFile = getIOFile(file); File dstFile = new File(srcFile.getParentFile(), newName); SvnVcs vcs = getVCS(file); @@ -430,10 +452,14 @@ public class SvnFileSystemListener implements LocalFileOperationsHandler { public boolean createFile(VirtualFile dir, String name) throws IOException { + startOperation(dir); + return createItem(dir, name, false, false); } public boolean createDirectory(VirtualFile dir, String name) throws IOException { + startOperation(dir); + return createItem(dir, name, true, false); } @@ -452,6 +478,8 @@ public class SvnFileSystemListener implements LocalFileOperationsHandler { * deleted: do nothing, return true (strange) */ public boolean delete(VirtualFile file) throws IOException { + startOperation(file); + final SvnVcs vcs = getVCS(file); if (vcs != null && SvnUtil.isAdminDirectory(file)) { return true; @@ -619,25 +647,29 @@ public class SvnFileSystemListener implements LocalFileOperationsHandler { return false; } - public void commandStarted(CommandEvent event) { + @Override + public void commandStarted(@NotNull CommandEvent event) { + myIsInCommand = true; myUndoingMove = false; final Project project = event.getProject(); if (project == null) return; commandStarted(project); } - void commandStarted(final Project project) { + void commandStarted(@NotNull Project project) { myUndoingMove = false; myMoveExceptions.remove(project); } - public void commandFinished(CommandEvent event) { + @Override + public void commandFinished(@NotNull CommandEvent event) { + myIsInCommand = false; final Project project = event.getProject(); if (project == null) return; commandFinished(project); } - void commandFinished(final Project project) { + void commandFinished(@NotNull Project project) { checkOverwrites(project); if (myAddedFiles.containsKey(project)) { processAddedFiles(project); @@ -1042,6 +1074,20 @@ public class SvnFileSystemListener implements LocalFileOperationsHandler { return UndoManager.getInstance(p).isUndoInProgress(); } + public void startOperation(@NotNull VirtualFile file) { + if (!myIsInCommand) { + // currently actions like "new project", "import project" (probably also others) are not performed under command + myGuessedProject = ProjectLocator.getInstance().guessProjectForFile(file); + if (myGuessedProject != null) { + commandStarted(myGuessedProject); + } + } + } + public void afterDone(final ThrowableConsumer invoker) { + if (!myIsInCommand && myGuessedProject != null) { + commandFinished(myGuessedProject); + myGuessedProject = null; + } } } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnFileSystemListenerWrapper.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnFileSystemListenerWrapper.java deleted file mode 100644 index a2889fc1e70e..000000000000 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnFileSystemListenerWrapper.java +++ /dev/null @@ -1,169 +0,0 @@ -/* - * Copyright 2000-2014 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.jetbrains.idea.svn; - -import com.intellij.openapi.Disposable; -import com.intellij.openapi.command.CommandAdapter; -import com.intellij.openapi.command.CommandEvent; -import com.intellij.openapi.command.CommandProcessor; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.project.ProjectLocator; -import com.intellij.openapi.util.Disposer; -import com.intellij.openapi.util.Pair; -import com.intellij.openapi.vfs.LocalFileOperationsHandler; -import com.intellij.openapi.vfs.LocalFileSystem; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.util.ThrowableConsumer; -import com.intellij.util.containers.ContainerUtil; -import org.jetbrains.annotations.Nullable; - -import java.io.IOException; -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.Method; -import java.lang.reflect.Proxy; -import java.util.Arrays; -import java.util.Map; - -public class SvnFileSystemListenerWrapper { - private final LocalFileOperationsHandler myProxy; - private final MyCommandListener myListener; - - public SvnFileSystemListenerWrapper(final SvnFileSystemListener delegate) { - myListener = new MyCommandListener(delegate); - myProxy = (LocalFileOperationsHandler)Proxy - .newProxyInstance(LocalFileOperationsHandler.class.getClassLoader(), new Class[]{LocalFileOperationsHandler.class}, - new MyInvoker(new MyStorage(myListener), delegate)); - } - - public void registerSelf() { - LocalFileSystem.getInstance().registerAuxiliaryFileOperationsHandler(myProxy); - CommandProcessor.getInstance().addCommandListener(myListener); - } - - public void unregisterSelf() { - LocalFileSystem.getInstance().unregisterAuxiliaryFileOperationsHandler(myProxy); - CommandProcessor.getInstance().removeCommandListener(myListener); - } - - private static class MyCommandListener extends CommandAdapter { - private volatile boolean myInCommand; - private final SvnFileSystemListener myDelegate; - - public MyCommandListener(final SvnFileSystemListener delegate) { - myDelegate = delegate; - } - - public void start(final Project project) { - if (!myInCommand && project != null) { - myDelegate.commandStarted(project); - } - } - - public void finish(final Project project) { - if (! myInCommand && project != null) { - myDelegate.commandFinished(project); - } - } - - public void commandStarted(CommandEvent event) { - myInCommand = true; - myDelegate.commandStarted(event); - } - - public void commandFinished(CommandEvent event) { - myInCommand = false; - myDelegate.commandFinished(event); - } - } - - private static class MyStorage implements InvocationHandler { - private final MyCommandListener myListener; - private final Map> myStarted; - - private MyStorage(final MyCommandListener listener) { - myListener = listener; - myStarted = ContainerUtil.newHashMap(); - } - - @Nullable - private static Project getProject(Object[] args) { - for (Object arg : args) { - if (arg instanceof VirtualFile) { - return ProjectLocator.getInstance().guessProjectForFile((VirtualFile) arg); - } - } - return null; - } - - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - final Project project = getProject(args); - if (project != null) { - final Pair pair = myStarted.get(project); - if (pair != null && method.getName().equals(pair.getFirst()) && Arrays.equals(args, pair.getSecond())) { - myListener.finish(project); - } - } - //dont return null for auto unboxing to not face NPE - return "boolean".equals(method.getReturnType().getName()) ? Boolean.TRUE : null; - } - - private void register(final Method method, final Object[] args) { - final Object[] newArr = new Object[args.length]; - System.arraycopy(args, 0, newArr, 0, args.length); - final Project project = getProject(args); - if (project != null) { - myListener.start(project); - myStarted.put(project, Pair.create(method.getName(), newArr)); - Disposer.register(project, new Disposable() { - public void dispose() { - myStarted.remove(project); - } - }); - } - } - } - - private static class MyInvoker implements InvocationHandler { - private final Object myDelegate; - private final MyStorage myParent; - private final LocalFileOperationsHandler myParentProxy; - - private MyInvoker(final MyStorage parent, Object delegate) { - myParent = parent; - myDelegate = delegate; - myParentProxy = (LocalFileOperationsHandler) Proxy.newProxyInstance(LocalFileOperationsHandler.class.getClassLoader(), - new Class[]{LocalFileOperationsHandler.class}, myParent); - } - - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - if ("afterDone".equals(method.getName()) && args.length == 1) { - ((ThrowableConsumer)args[0]).consume(myParentProxy); - return null; - } - - if (LocalFileOperationsHandler.class.equals(method.getDeclaringClass())) { - myParent.register(method, args); - } - if ("equals".equals(method.getName())) { - return args[0].equals(this); - } - else if ("hashCode".equals(method.getName())) { - return 1; - } - return method.invoke(myDelegate, args); - } - } -} From ac6ba0c1dadf4937894cc114a4234214829adb0c Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Fri, 14 Nov 2014 17:41:02 +0300 Subject: [PATCH 04/48] svn: Use common "Jump to Source" action (instead of custom "Open" action) to open files from repository browser --- .../svn/dialogs/RepositoryBrowserDialog.java | 23 +++---------------- 1 file changed, 3 insertions(+), 20 deletions(-) diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/RepositoryBrowserDialog.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/RepositoryBrowserDialog.java index 83d895b93ffc..6f386abf1fa6 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/RepositoryBrowserDialog.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/RepositoryBrowserDialog.java @@ -25,7 +25,6 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.fileChooser.FileChooser; import com.intellij.openapi.fileChooser.FileChooserDescriptor; import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory; -import com.intellij.openapi.fileEditor.FileEditorManager; import com.intellij.openapi.ide.CopyPasteManager; import com.intellij.openapi.options.ConfigurationException; import com.intellij.openapi.progress.ProgressIndicator; @@ -192,6 +191,7 @@ public class RepositoryBrowserDialog extends DialogWrapper { } protected JPopupMenu createPopup(boolean toolWindow) { + ActionManager actionManager = ActionManager.getInstance(); DefaultActionGroup group = new DefaultActionGroup(); DefaultActionGroup newGroup = new DefaultActionGroup("_New", true); final RepositoryBrowserComponent browser = getRepositoryBrowser(); @@ -200,7 +200,7 @@ public class RepositoryBrowserDialog extends DialogWrapper { group.add(newGroup); group.addSeparator(); if (toolWindow) { - group.add(new OpenAction()); + group.add(actionManager.getAction(IdeActions.ACTION_EDIT_SOURCE)); group.add(new HistoryAction()); } group.add(new CheckoutAction()); @@ -218,7 +218,7 @@ public class RepositoryBrowserDialog extends DialogWrapper { group.add(new RefreshAction(browser)); group.add(new EditLocationAction(browser)); group.add(new DiscardLocationAction(browser)); - ActionPopupMenu menu = ActionManager.getInstance().createActionPopupMenu(PLACE_MENU, group); + ActionPopupMenu menu = actionManager.createActionPopupMenu(PLACE_MENU, group); return menu.getComponent(); } @@ -928,23 +928,6 @@ public class RepositoryBrowserDialog extends DialogWrapper { } } - protected class OpenAction extends AnAction { - public void update(AnActionEvent e) { - e.getPresentation().setEnabled(false); - if (myVCS == null) { - return; - } - e.getPresentation().setText("_Open", true); - e.getPresentation().setEnabled(getRepositoryBrowser().getSelectedVcsFile() != null); - } - public void actionPerformed(AnActionEvent e) { - VirtualFile vcsVF = getRepositoryBrowser().getSelectedVcsFile(); - if (vcsVF != null) { - FileEditorManager.getInstance(myVCS.getProject()).openFile(vcsVF, true); - } - } - } - protected class DetailsAction extends ToggleAction { private boolean myIsSelected; From 0d463f635d1926d218a181fceaffd23b790c43a8 Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Fri, 14 Nov 2014 19:18:18 +0300 Subject: [PATCH 05/48] IDEA-104113 Disable SelectInAction action for svn repository browser - provide custom Navigatable instance (instead of OpenFileDescriptor instance) --- .../svn/dialogs/RepositoryBrowserComponent.java | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/RepositoryBrowserComponent.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/RepositoryBrowserComponent.java index f7e54a64f0ad..d6eaf61509bf 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/RepositoryBrowserComponent.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/RepositoryBrowserComponent.java @@ -18,13 +18,13 @@ package org.jetbrains.idea.svn.dialogs; import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.CommonDataKeys; import com.intellij.openapi.actionSystem.DataProvider; -import com.intellij.openapi.fileEditor.OpenFileDescriptor; import com.intellij.openapi.fileTypes.FileTypeManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.vcs.vfs.VcsFileSystem; import com.intellij.openapi.vcs.vfs.VcsVirtualFile; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.pom.NavigatableAdapter; import com.intellij.ui.ScrollPaneFactory; import com.intellij.ui.SpeedSearchComparator; import com.intellij.ui.TreeSpeedSearch; @@ -282,7 +282,18 @@ public class RepositoryBrowserComponent extends JPanel implements Disposable, Da return null; } final VirtualFile vcsFile = getSelectedVcsFile(); - return vcsFile != null ? new OpenFileDescriptor(project, vcsFile) : null; + + // do not return OpenFileDescriptor instance here as in that case SelectInAction will be enabled and its invocation (using keyboard) + // will raise error - see IDEA-104113 - because of the following operations inside SelectInAction.actionPerformed(): + // - at first VcsVirtualFile content will be loaded which for svn results in showing progress dialog + // - then DataContext from SelectInAction will still be accessed which results in error as current event count has already changed + // (because of progress dialog) + return vcsFile != null ? new NavigatableAdapter() { + @Override + public void navigate(boolean requestFocus) { + navigate(project, vcsFile, requestFocus); + } + } : null; } else if (CommonDataKeys.PROJECT.is(dataId)) { return myVCS.getProject(); } From 0fac3a17ff60085daaee9bfc18a5d7c2440bb206 Mon Sep 17 00:00:00 2001 From: Elizaveta Shashkova Date: Mon, 17 Nov 2014 21:18:07 +0300 Subject: [PATCH 06/48] enable Inspect in debugger for long string attributes --- .../jetbrains/python/debugger/PyDebugValue.java | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/python/pydevSrc/com/jetbrains/python/debugger/PyDebugValue.java b/python/pydevSrc/com/jetbrains/python/debugger/PyDebugValue.java index 26f81dddf56a..66eee2fb8a91 100644 --- a/python/pydevSrc/com/jetbrains/python/debugger/PyDebugValue.java +++ b/python/pydevSrc/com/jetbrains/python/debugger/PyDebugValue.java @@ -15,7 +15,7 @@ import javax.swing.*; // todo: null modifier for modify modules, class objects etc. public class PyDebugValue extends XNamedValue { private static final Logger LOG = Logger.getInstance("#com.jetbrains.python.pydev.PyDebugValue"); - public static final int MAX_VALUE = 512; + public static final int MAX_VALUE = 256; private String myTempName = null; private final String myType; @@ -134,12 +134,23 @@ public class PyDebugValue extends XNamedValue { return "__len__".equals(name); } + private String getFullName() { + String result = myName; + PyDebugValue parent = myParent; + while (parent != null) { + result = "." + result; + result = parent.getName() + result; + parent = parent.getParent(); + } + return result; + } + @Override public void computePresentation(@NotNull XValueNode node, @NotNull XValuePlace place) { String value = PyTypeHandler.format(this); if (value.length() >= MAX_VALUE) { - node.setFullValueEvaluator(new PyFullValueEvaluator(myFrameAccessor, myName)); + node.setFullValueEvaluator(new PyFullValueEvaluator(myFrameAccessor, getFullName())); value = value.substring(0, MAX_VALUE); } From 9d088ce88e6725d1439c7f4222f7b23e621b9b42 Mon Sep 17 00:00:00 2001 From: Sergey Savenko Date: Mon, 17 Nov 2014 20:02:04 +0300 Subject: [PATCH 07/48] XmlSerializerImpl: do not cache uninitialized bindings --- .../util/src/com/intellij/util/xmlb/XmlSerializerImpl.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/platform/util/src/com/intellij/util/xmlb/XmlSerializerImpl.java b/platform/util/src/com/intellij/util/xmlb/XmlSerializerImpl.java index d693b722b56b..e42a7a50a532 100644 --- a/platform/util/src/com/intellij/util/xmlb/XmlSerializerImpl.java +++ b/platform/util/src/com/intellij/util/xmlb/XmlSerializerImpl.java @@ -116,7 +116,12 @@ class XmlSerializerImpl { if (binding == null) { binding = _getNonCachedClassBinding(aClass, accessor, originalType); map.put(key, binding); - binding.init(); + try { + binding.init(); + } catch (XmlSerializationException e) { + map.remove(key); + throw e; + } } return binding; } From 94728b736ce6df2dbae6c827fd320569a658e14b Mon Sep 17 00:00:00 2001 From: Alexey Gopachenko Date: Mon, 17 Nov 2014 19:33:22 +0100 Subject: [PATCH 08/48] Faster leaf node search CR-IU-897 --- .../psi/impl/source/tree/CompositeElement.java | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/platform/core-impl/src/com/intellij/psi/impl/source/tree/CompositeElement.java b/platform/core-impl/src/com/intellij/psi/impl/source/tree/CompositeElement.java index f8bfc611ce55..c0b7d3352bb4 100644 --- a/platform/core-impl/src/com/intellij/psi/impl/source/tree/CompositeElement.java +++ b/platform/core-impl/src/com/intellij/psi/impl/source/tree/CompositeElement.java @@ -163,21 +163,28 @@ public class CompositeElement extends TreeElement { startFind: while (true) { TreeElement child = element.getFirstChildNode(); + TreeElement lastChild = element.getLastChildNode(); + boolean fwd = lastChild == null || (lastChild.getStartOffset() + lastChild.getTextLength() - child.getStartOffset()) / 2 > offset; + if (!fwd) { + child = lastChild; + offset = element.getTextLength() - offset; + } while (child != null) { final int textLength = child.getTextLength(); - if (textLength > offset) { + if (textLength > offset || !fwd && textLength >= offset) { if (child instanceof LeafElement) { if (child instanceof ForeignLeafPsiElement) { - child = child.getTreeNext(); + child = fwd ? child.getTreeNext() : child.getTreePrev(); continue; } return (LeafElement)child; } + offset = fwd ? offset : child.getTextLength() - offset; element = child; continue startFind; } offset -= textLength; - child = child.getTreeNext(); + child = fwd ? child.getTreeNext() : child.getTreePrev(); } return null; } From 939f5702ba095252e93719a4ebbc48c4fca5243e Mon Sep 17 00:00:00 2001 From: Sergey Malenkov Date: Mon, 17 Nov 2014 21:35:37 +0300 Subject: [PATCH 09/48] IDEA-131773 Fix mac shortcuts handling on Ubuntu --- platform/util/src/com/intellij/util/ui/UIUtil.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/platform/util/src/com/intellij/util/ui/UIUtil.java b/platform/util/src/com/intellij/util/ui/UIUtil.java index 97352ca3ef1a..d483e1301aa2 100644 --- a/platform/util/src/com/intellij/util/ui/UIUtil.java +++ b/platform/util/src/com/intellij/util/ui/UIUtil.java @@ -515,11 +515,7 @@ public class UIUtil { char c = e.getKeyChar(); if (c < 0x20 || c == 0x7F) return false; - if (SystemInfo.isMac) { - return !e.isMetaDown() && !e.isControlDown(); - } - - return !e.isAltDown() && !e.isControlDown(); + return !e.isMetaDown() && !e.isAltDown() && !e.isControlDown(); } public static int getStringY(@NotNull final String string, @NotNull final Rectangle bounds, @NotNull final Graphics2D g) { From b2d8421c93a5f61f1be3b53b42aaf4aaa487ca87 Mon Sep 17 00:00:00 2001 From: Alexey Gopachenko Date: Mon, 17 Nov 2014 19:49:13 +0100 Subject: [PATCH 10/48] Reduce Injection-related passes overhead, esp. for big files with not much injections CR-IU-894 --- .../impl/InjectedGeneralHighlightingPass.java | 11 ++++++++--- .../codeInsight/daemon/impl/LineMarkersPass.java | 14 ++++++++++---- .../tree/injected/InjectedLanguageManagerImpl.java | 8 ++++++++ .../source/tree/injected/InjectedLanguageUtil.java | 2 +- 4 files changed, 27 insertions(+), 8 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/InjectedGeneralHighlightingPass.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/InjectedGeneralHighlightingPass.java index fbab8ef759aa..a9b3cff485fc 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/InjectedGeneralHighlightingPass.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/InjectedGeneralHighlightingPass.java @@ -38,9 +38,11 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.util.*; import com.intellij.openapi.util.registry.Registry; import com.intellij.psi.*; +import com.intellij.psi.impl.source.tree.injected.InjectedLanguageManagerImpl; import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil; import com.intellij.psi.impl.source.tree.injected.Place; import com.intellij.psi.tree.IElementType; +import com.intellij.util.CommonProcessors; import com.intellij.util.Processor; import gnu.trove.THashSet; import org.jetbrains.annotations.NotNull; @@ -80,6 +82,7 @@ public class InjectedGeneralHighlightingPass extends GeneralHighlightingPass imp final List outside = new ArrayList(); List insideRanges = new ArrayList(); List outsideRanges = new ArrayList(); + //TODO: this thing is just called TWICE with same arguments eating CPU on huge files :( Divider.divideInsideAndOutside(myFile, myStartOffset, myEndOffset, myPriorityRange, inside, insideRanges, outside, outsideRanges, false, FILE_FILTER); @@ -148,7 +151,7 @@ public class InjectedGeneralHighlightingPass extends GeneralHighlightingPass imp final Set outInjected = new THashSet(); List injected = InjectedLanguageUtil.getCachedInjectedDocuments(myFile); - Collection hosts = new THashSet(elements1.size() + elements2.size() + injected.size()); + final Collection hosts = new THashSet(elements1.size() + elements2.size() + injected.size()); //rehighlight all injected PSI regardless the range, //since change in one place can lead to invalidation of injected PSI in (completely) other place. @@ -165,8 +168,10 @@ public class InjectedGeneralHighlightingPass extends GeneralHighlightingPass imp hosts.add(context); } } - hosts.addAll(elements1); - hosts.addAll(elements2); + InjectedLanguageManagerImpl injectedLanguageManager = InjectedLanguageManagerImpl.getInstanceImpl(myProject); + Processor collectInjectableProcessor = new CommonProcessors.CollectProcessor(hosts); + injectedLanguageManager.processInjectableElements(elements1, collectInjectableProcessor); + injectedLanguageManager.processInjectableElements(elements2, collectInjectableProcessor); final PsiLanguageInjectionHost.InjectedPsiVisitor visitor = new PsiLanguageInjectionHost.InjectedPsiVisitor() { @Override diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/LineMarkersPass.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/LineMarkersPass.java index 19a247f4a4a1..530e979d1db0 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/LineMarkersPass.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/LineMarkersPass.java @@ -48,9 +48,11 @@ import com.intellij.openapi.project.IndexNotReadyException; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.TextRange; import com.intellij.psi.*; +import com.intellij.psi.impl.source.tree.injected.InjectedLanguageManagerImpl; import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil; import com.intellij.util.Function; import com.intellij.util.FunctionUtil; +import com.intellij.util.Processor; import gnu.trove.THashSet; import gnu.trove.TIntObjectHashMap; import org.jetbrains.annotations.NotNull; @@ -201,7 +203,7 @@ public class LineMarkersPass extends TextEditorHighlightingPass implements LineM public static void collectLineMarkersForInjected(@NotNull final List result, @NotNull List elements, @NotNull final LineMarkersProcessor processor, - @NotNull PsiFile file, + @NotNull final PsiFile file, @NotNull final ProgressIndicator progress) { final InjectedLanguageManager manager = InjectedLanguageManager.getInstance(file.getProject()); final List injectedMarkers = new ArrayList(); @@ -213,9 +215,13 @@ public class LineMarkersPass extends TextEditorHighlightingPass implements LineM injectedFiles.add(injectedPsi); } }; - for (int i = 0, size = elements.size(); i < size; ++i) { - InjectedLanguageUtil.enumerate(elements.get(i), file, false, collectingVisitor); - } + InjectedLanguageManagerImpl.getInstanceImpl(file.getProject()).processInjectableElements(elements, new Processor() { + @Override + public boolean process(PsiElement element) { + InjectedLanguageUtil.enumerate(element, file, false, collectingVisitor); + return true; + } + }); for (PsiFile injectedPsi : injectedFiles) { final Project project = injectedPsi.getProject(); Document document = PsiDocumentManager.getInstance(project).getCachedDocument(injectedPsi); diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/tree/injected/InjectedLanguageManagerImpl.java b/platform/lang-impl/src/com/intellij/psi/impl/source/tree/injected/InjectedLanguageManagerImpl.java index 34b8f9b06ef8..b2c7d1411fdb 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/source/tree/injected/InjectedLanguageManagerImpl.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/source/tree/injected/InjectedLanguageManagerImpl.java @@ -228,6 +228,14 @@ public class InjectedLanguageManagerImpl extends InjectedLanguageManager impleme private final Set myManualInjectors = Collections.synchronizedSet(new LinkedHashSet()); private volatile ClassMapCachingNulls cachedInjectors; + public void processInjectableElements(Collection in, Processor processor) { + ClassMapCachingNulls map = getInjectorMap(); + for (PsiElement element : in) { + if (map.get(element.getClass()) != null) + processor.process(element); + } + } + private ClassMapCachingNulls getInjectorMap() { ClassMapCachingNulls cached = cachedInjectors; if (cached != null) { diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/tree/injected/InjectedLanguageUtil.java b/platform/lang-impl/src/com/intellij/psi/impl/source/tree/injected/InjectedLanguageUtil.java index 5ed96453c85e..96f318b3e72b 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/source/tree/injected/InjectedLanguageUtil.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/source/tree/injected/InjectedLanguageUtil.java @@ -307,7 +307,7 @@ public class InjectedLanguageUtil { MultiHostRegistrarImpl registrar = null; PsiElement current = element; nextParent: - while (current != null && current != hostPsiFile) { + while (current != null && current != hostPsiFile && !(current instanceof PsiDirectory)) { ProgressManager.checkCanceled(); if ("EL".equals(current.getLanguage().getID())) break; ParameterizedCachedValue data = current.getUserData(INJECTED_PSI); From bc2e9a17c27fec7e42a9a749ba44202e305fefbe Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Mon, 17 Nov 2014 17:54:12 +0100 Subject: [PATCH 11/48] external coverage: load vcs file content if local history is obsolete (IDEA-89576) --- plugins/coverage-common/coverage-common.iml | 4 +- .../intellij/coverage/SrcFileAnnotator.java | 53 ++++++++++++++++++- 2 files changed, 53 insertions(+), 4 deletions(-) diff --git a/plugins/coverage-common/coverage-common.iml b/plugins/coverage-common/coverage-common.iml index 389fc6b1bd7e..3217ead3d827 100644 --- a/plugins/coverage-common/coverage-common.iml +++ b/plugins/coverage-common/coverage-common.iml @@ -30,6 +30,6 @@ + - - + \ No newline at end of file diff --git a/plugins/coverage-common/src/com/intellij/coverage/SrcFileAnnotator.java b/plugins/coverage-common/src/com/intellij/coverage/SrcFileAnnotator.java index c327d760e10d..8b79d0047e4d 100644 --- a/plugins/coverage-common/src/com/intellij/coverage/SrcFileAnnotator.java +++ b/plugins/coverage-common/src/com/intellij/coverage/SrcFileAnnotator.java @@ -34,6 +34,13 @@ import com.intellij.openapi.util.Key; import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.text.LineTokenizer; +import com.intellij.openapi.vcs.AbstractVcs; +import com.intellij.openapi.vcs.FilePath; +import com.intellij.openapi.vcs.VcsException; +import com.intellij.openapi.vcs.actions.VcsContextFactory; +import com.intellij.openapi.vcs.history.VcsFileRevision; +import com.intellij.openapi.vcs.history.VcsHistoryProvider; +import com.intellij.openapi.vcs.history.VcsHistorySession; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiFile; import com.intellij.reference.SoftReference; @@ -46,11 +53,13 @@ import com.intellij.util.Alarm; import com.intellij.util.Function; import com.intellij.util.diff.Diff; import com.intellij.util.diff.FilesTooBigForDiffException; +import com.intellij.vcsUtil.VcsUtil; import gnu.trove.TIntIntHashMap; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.File; +import java.io.IOException; import java.util.*; /** @@ -194,11 +203,16 @@ public class SrcFileAnnotator implements Disposable { synchronized (LOCK) { if (myOldContent == null) { if (ApplicationManager.getApplication().isDispatchThread()) return null; - final byte[] byteContent = LocalHistory.getInstance().getByteContent(f, new FileRevisionTimestampComparator() { + final LocalHistory localHistory = LocalHistory.getInstance(); + byte[] byteContent = localHistory.getByteContent(f, new FileRevisionTimestampComparator() { public boolean isSuitable(long revisionTimestamp) { return revisionTimestamp < date; } }); + + if (byteContent == null && f.getTimeStamp() > date) { + byteContent = loadFromVersionControl(date, f); + } myOldContent = new SoftReference(byteContent); } oldContent = myOldContent.get(); @@ -211,7 +225,7 @@ public class SrcFileAnnotator implements Disposable { String[] oldLines = oldToNew ? coveredLines : currentLines; String[] newLines = oldToNew ? currentLines : coveredLines; - Diff.Change change = null; + Diff.Change change; try { change = Diff.buildChanges(oldLines, newLines); } @@ -222,6 +236,41 @@ public class SrcFileAnnotator implements Disposable { return new SoftReference(getCoverageVersionToCurrentLineMapping(change, oldLines.length)); } + @Nullable + private byte[] loadFromVersionControl(long date, VirtualFile f) { + try { + final AbstractVcs vcs = VcsUtil.getVcsFor(myProject, f); + if (vcs == null) return null; + + final VcsHistoryProvider historyProvider = vcs.getVcsHistoryProvider(); + if (historyProvider == null) return null; + + final FilePath filePath = VcsContextFactory.SERVICE.getInstance().createFilePathOn(f); + final VcsHistorySession session = historyProvider.createSessionFor(filePath); + if (session == null) return null; + + final List list = session.getRevisionList(); + + if (list != null) { + for (VcsFileRevision revision : list) { + final Date revisionDate = revision.getRevisionDate(); + if (revisionDate == null) { + return null; + } + + if (revisionDate.getTime() < date) { + return revision.loadContent(); + } + } + } + } + catch (Exception e) { + LOG.info(e); + return null; + } + return null; + } + public void showCoverageInformation(final CoverageSuitesBundle suite) { if (myEditor == null || myFile == null) return; final MarkupModel markupModel = DocumentMarkupModel.forDocument(myDocument, myProject, true); From 62a23236ba1579d40d1791b294cda8947c1b2873 Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Mon, 17 Nov 2014 18:14:37 +0100 Subject: [PATCH 12/48] prefer project from current context over first opened project --- .../intellij/openapi/project/ProjectUtil.java | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/platform/lang-api/src/com/intellij/openapi/project/ProjectUtil.java b/platform/lang-api/src/com/intellij/openapi/project/ProjectUtil.java index cc01782b7541..0dac0d7d3b0c 100644 --- a/platform/lang-api/src/com/intellij/openapi/project/ProjectUtil.java +++ b/platform/lang-api/src/com/intellij/openapi/project/ProjectUtil.java @@ -115,16 +115,21 @@ public class ProjectUtil { } @NotNull - public static Project guessCurrentProject(JComponent component) { + public static Project guessCurrentProject(@Nullable JComponent component) { Project project = null; - Project[] openProjects = ProjectManager.getInstance().getOpenProjects(); - if (openProjects.length > 0) project = openProjects[0]; - if (project == null) { - DataContext dataContext = component == null ? DataManager.getInstance().getDataContext() : DataManager.getInstance().getDataContext(component); - project = CommonDataKeys.PROJECT.getData(dataContext); + if (component != null) { + project = CommonDataKeys.PROJECT.getData(DataManager.getInstance().getDataContext(component)); } if (project == null) { - project = ProjectManager.getInstance().getDefaultProject(); + Project[] openProjects = ProjectManager.getInstance().getOpenProjects(); + if (openProjects.length > 0) project = openProjects[0]; + if (project == null) { + DataContext dataContext = DataManager.getInstance().getDataContext(); + project = CommonDataKeys.PROJECT.getData(dataContext); + } + if (project == null) { + project = ProjectManager.getInstance().getDefaultProject(); + } } return project; } From 44c89fb317a607b0e5b7322ab7c745ff127d3de5 Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Mon, 17 Nov 2014 18:44:44 +0100 Subject: [PATCH 13/48] configure annotations button: guess project after creation (IDEA-132950) --- .../deadCode/UnusedDeclarationInspection.java | 19 ++----------------- .../ex/EntryPointsManagerImpl.java | 7 ++++++- .../UnusedParametersInspection.java | 5 ++--- .../codeInspection/ex/EntryPointsManager.java | 6 ++++++ 4 files changed, 16 insertions(+), 21 deletions(-) diff --git a/java/java-impl/src/com/intellij/codeInspection/deadCode/UnusedDeclarationInspection.java b/java/java-impl/src/com/intellij/codeInspection/deadCode/UnusedDeclarationInspection.java index ef5544775adb..b01ca0a8039b 100644 --- a/java/java-impl/src/com/intellij/codeInspection/deadCode/UnusedDeclarationInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/deadCode/UnusedDeclarationInspection.java @@ -15,14 +15,11 @@ */ package com.intellij.codeInspection.deadCode; -import com.intellij.codeInspection.GlobalInspectionContext; import com.intellij.codeInspection.InspectionsBundle; -import com.intellij.codeInspection.ex.EntryPointsManager; +import com.intellij.codeInspection.ex.EntryPointsManagerImpl; import com.intellij.codeInspection.reference.EntryPoint; import com.intellij.codeInspection.unusedSymbol.UnusedSymbolLocalInspection; import com.intellij.codeInspection.unusedSymbol.UnusedSymbolLocalInspectionBase; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.project.ProjectManager; import com.intellij.ui.components.JBTabbedPane; import org.jetbrains.annotations.TestOnly; @@ -53,17 +50,6 @@ public class UnusedDeclarationInspection extends UnusedDeclarationInspectionBase return tabs; } - private Project guessProject() { - final GlobalInspectionContext context = getContext(); - Project project = context == null ? null : context.getProject(); - - if (project == null) { - Project[] openProjects = ProjectManager.getInstance().getOpenProjects(); - project = openProjects.length == 0 ? ProjectManager.getInstance().getDefaultProject() : openProjects[0]; - } - return project; - } - private class OptionsPanel extends JPanel { private final JCheckBox myMainsCheckbox; private final JCheckBox myAppletToEntries; @@ -141,8 +127,7 @@ public class UnusedDeclarationInspection extends UnusedDeclarationInspectionBase gc.gridy++; add(myNonJavaCheckbox, gc); - Project project = guessProject(); - JButton configureAnnotations = EntryPointsManager.getInstance(project).createConfigureAnnotationsBtn(); + JButton configureAnnotations = EntryPointsManagerImpl.createConfigureAnnotationsButton(); gc.fill = GridBagConstraints.NONE; gc.gridy++; gc.insets.top = 10; diff --git a/java/java-impl/src/com/intellij/codeInspection/ex/EntryPointsManagerImpl.java b/java/java-impl/src/com/intellij/codeInspection/ex/EntryPointsManagerImpl.java index 209f7ef827fb..2ef2dc12829b 100644 --- a/java/java-impl/src/com/intellij/codeInspection/ex/EntryPointsManagerImpl.java +++ b/java/java-impl/src/com/intellij/codeInspection/ex/EntryPointsManagerImpl.java @@ -28,6 +28,7 @@ import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer; import com.intellij.codeInspection.util.SpecialAnnotationsUtil; import com.intellij.openapi.components.*; import com.intellij.openapi.project.Project; +import com.intellij.openapi.project.ProjectUtil; import com.intellij.openapi.ui.DialogWrapper; import org.jdom.Element; @@ -73,11 +74,15 @@ public class EntryPointsManagerImpl extends EntryPointsManagerBase implements Pe @Override public JButton createConfigureAnnotationsBtn() { + return createConfigureAnnotationsButton(); + } + + public static JButton createConfigureAnnotationsButton() { final JButton configureAnnotations = new JButton("Configure annotations..."); configureAnnotations.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - configureAnnotations(); + getInstance(ProjectUtil.guessCurrentProject(configureAnnotations)).configureAnnotations(); } }); return configureAnnotations; diff --git a/java/java-impl/src/com/intellij/codeInspection/unusedParameters/UnusedParametersInspection.java b/java/java-impl/src/com/intellij/codeInspection/unusedParameters/UnusedParametersInspection.java index bb97f5cd78d5..9e1f28254b65 100644 --- a/java/java-impl/src/com/intellij/codeInspection/unusedParameters/UnusedParametersInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/unusedParameters/UnusedParametersInspection.java @@ -29,10 +29,10 @@ import com.intellij.codeInsight.FileModificationService; import com.intellij.codeInsight.daemon.GroupNames; import com.intellij.codeInspection.*; import com.intellij.codeInspection.ex.EntryPointsManager; +import com.intellij.codeInspection.ex.EntryPointsManagerImpl; import com.intellij.codeInspection.reference.*; import com.intellij.codeInspection.unusedSymbol.UnusedSymbolLocalInspectionBase; import com.intellij.openapi.project.Project; -import com.intellij.openapi.project.ProjectUtil; import com.intellij.openapi.util.Comparing; import com.intellij.psi.*; import com.intellij.psi.search.PsiReferenceProcessor; @@ -234,8 +234,7 @@ public class UnusedParametersInspection extends GlobalJavaBatchInspectionTool { @Override public JComponent createOptionsPanel() { final JPanel panel = new JPanel(new GridBagLayout()); - Project project = ProjectUtil.guessCurrentProject(panel); - panel.add(EntryPointsManager.getInstance(project).createConfigureAnnotationsBtn(), + panel.add(EntryPointsManagerImpl.createConfigureAnnotationsButton(), new GridBagConstraints(0, 0, 1, 1, 1, 1, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0)); return panel; diff --git a/platform/analysis-api/src/com/intellij/codeInspection/ex/EntryPointsManager.java b/platform/analysis-api/src/com/intellij/codeInspection/ex/EntryPointsManager.java index 14a9002d109c..02f3f3cfac1a 100644 --- a/platform/analysis-api/src/com/intellij/codeInspection/ex/EntryPointsManager.java +++ b/platform/analysis-api/src/com/intellij/codeInspection/ex/EntryPointsManager.java @@ -29,6 +29,8 @@ import com.intellij.psi.PsiElement; import org.jetbrains.annotations.NotNull; import javax.swing.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; public abstract class EntryPointsManager implements Disposable { public static EntryPointsManager getInstance(Project project) { @@ -50,6 +52,10 @@ public abstract class EntryPointsManager implements Disposable { public abstract void configureAnnotations(); + /** + * {@link com.intellij.codeInspection.ex.EntryPointsManagerImpl#createConfigureAnnotationsButton()} should be used instead + */ + @Deprecated public abstract JButton createConfigureAnnotationsBtn(); public abstract boolean isEntryPoint(@NotNull PsiElement element); From 10846bc7c47add60b03d9da73248e25dcca4d767 Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Mon, 17 Nov 2014 19:47:17 +0100 Subject: [PATCH 14/48] field may be local: ignore all fields referenced by qualifier (IDEA-133017) --- .../FieldCanBeLocalInspectionBase.java | 15 +++++++++++++++ .../fieldReferencedFromAnotherObject/expected.xml | 9 +++++++++ .../src/Test.java | 15 +++++++++++++++ .../codeInspection/FieldCanBeLocalTest.java | 1 + 4 files changed, 40 insertions(+) create mode 100644 java/java-tests/testData/inspection/fieldCanBeLocal/fieldReferencedFromAnotherObject/expected.xml create mode 100644 java/java-tests/testData/inspection/fieldCanBeLocal/fieldReferencedFromAnotherObject/src/Test.java diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/varScopeCanBeNarrowed/FieldCanBeLocalInspectionBase.java b/java/java-analysis-impl/src/com/intellij/codeInspection/varScopeCanBeNarrowed/FieldCanBeLocalInspectionBase.java index e13f3e66a198..d2dfb1f5c6a8 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/varScopeCanBeNarrowed/FieldCanBeLocalInspectionBase.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/varScopeCanBeNarrowed/FieldCanBeLocalInspectionBase.java @@ -31,6 +31,8 @@ import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.WriteExternalException; import com.intellij.psi.*; import com.intellij.psi.controlFlow.*; +import com.intellij.psi.search.LocalSearchScope; +import com.intellij.psi.search.searches.ReferencesSearch; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.util.Processor; @@ -75,6 +77,19 @@ public class FieldCanBeLocalInspectionBase extends BaseJavaBatchLocalInspectionT for (final PsiField field : candidates) { if (usedFields.contains(field) && !hasImplicitReadOrWriteUsage(field, implicitUsageProviders)) { + if (!ReferencesSearch.search(field, new LocalSearchScope(aClass)).forEach(new Processor() { + @Override + public boolean process(PsiReference reference) { + final PsiElement element = reference.getElement(); + if (element instanceof PsiReferenceExpression) { + final PsiElement qualifier = ((PsiReferenceExpression)element).getQualifier(); + return qualifier == null || qualifier instanceof PsiThisExpression && ((PsiThisExpression)qualifier).getQualifier() == null; + } + return true; + } + })) { + continue; + } final String message = InspectionsBundle.message("inspection.field.can.be.local.problem.descriptor"); final ArrayList fixes = new ArrayList(); SpecialAnnotationsUtilBase.createAddToSpecialAnnotationFixes(field, new Processor() { diff --git a/java/java-tests/testData/inspection/fieldCanBeLocal/fieldReferencedFromAnotherObject/expected.xml b/java/java-tests/testData/inspection/fieldCanBeLocal/fieldReferencedFromAnotherObject/expected.xml new file mode 100644 index 000000000000..28a09cdef54c --- /dev/null +++ b/java/java-tests/testData/inspection/fieldCanBeLocal/fieldReferencedFromAnotherObject/expected.xml @@ -0,0 +1,9 @@ + + + + Test.java + 3 + Field can be local + Field can be converted to a local variable + + diff --git a/java/java-tests/testData/inspection/fieldCanBeLocal/fieldReferencedFromAnotherObject/src/Test.java b/java/java-tests/testData/inspection/fieldCanBeLocal/fieldReferencedFromAnotherObject/src/Test.java new file mode 100644 index 000000000000..3ea480d779c9 --- /dev/null +++ b/java/java-tests/testData/inspection/fieldCanBeLocal/fieldReferencedFromAnotherObject/src/Test.java @@ -0,0 +1,15 @@ +class G { + private G foo; + private int bar; + + public G(final G gFoo) { + foo = gFoo; + bar = 1; + System.out.println(this.bar); + + G g = this; + while (g.foo != null) { + g = g.foo; + } + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/FieldCanBeLocalTest.java b/java/java-tests/testSrc/com/intellij/codeInspection/FieldCanBeLocalTest.java index db303c699ddc..3470669e2dfe 100644 --- a/java/java-tests/testSrc/com/intellij/codeInspection/FieldCanBeLocalTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInspection/FieldCanBeLocalTest.java @@ -39,6 +39,7 @@ public class FieldCanBeLocalTest extends InspectionTestCase { public void testFieldWithImmutableType() throws Exception {doTest();} public void testFieldUsedForWritingInLambda() throws Exception {doTest();} public void testStaticQualifiedFieldAccessForWriting() throws Exception {doTest();} + public void testFieldReferencedFromAnotherObject() throws Exception {doTest();} public void testIgnoreAnnotated() throws Exception { final FieldCanBeLocalInspection inspection = new FieldCanBeLocalInspection(); doTestConfigured(inspection); From bdb37fdc9ab9245028ee0ac84a3a21d77c80f647 Mon Sep 17 00:00:00 2001 From: "Maxim.Mossienko" Date: Mon, 17 Nov 2014 19:55:36 +0100 Subject: [PATCH 15/48] Calculate icon under progress, cancellable with pending write action (IDEA-132991) --- .../src/com/intellij/ui/DeferredIconImpl.java | 48 +++++++++++++++---- 1 file changed, 39 insertions(+), 9 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/ui/DeferredIconImpl.java b/platform/lang-impl/src/com/intellij/ui/DeferredIconImpl.java index 2cb330c71114..d01aa1c06faa 100644 --- a/platform/lang-impl/src/com/intellij/ui/DeferredIconImpl.java +++ b/platform/lang-impl/src/com/intellij/ui/DeferredIconImpl.java @@ -22,10 +22,15 @@ package com.intellij.ui; import com.intellij.concurrency.Job; import com.intellij.concurrency.JobLauncher; import com.intellij.ide.PowerSaveMode; +import com.intellij.openapi.application.ApplicationAdapter; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.application.ex.ApplicationManagerEx; import com.intellij.openapi.progress.ProcessCanceledException; +import com.intellij.openapi.progress.ProgressManager; +import com.intellij.openapi.progress.util.ProgressIndicatorBase; import com.intellij.openapi.project.IndexNotReadyException; +import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.registry.Registry; import com.intellij.ui.tabs.impl.TabLabel; import com.intellij.util.Alarm; @@ -119,18 +124,43 @@ public class DeferredIconImpl implements DeferredIcon { final long startTime = System.currentTimeMillis(); if (myNeedReadAction) { - if (!ApplicationManagerEx.getApplicationEx().tryRunReadAction(new Runnable() { + final ProgressIndicatorBase progress = new ProgressIndicatorBase(); + final ApplicationAdapter listener = new ApplicationAdapter() { + @Override + public void beforeWriteActionStart(Object action) { + progress.cancel(); + } + }; + ApplicationManager.getApplication().invokeAndWait(new Runnable() { @Override public void run() { - IconDeferrerImpl.evaluateDeferred(evalRunnable); - if (myAutoUpdatable) { - myLastCalcTime = System.currentTimeMillis(); - myLastTimeSpent = myLastCalcTime - startTime; - } + ApplicationManager.getApplication().addApplicationListener(listener); } - })) { - myIsScheduled = false; - return; + }, ModalityState.any()); + try { + final Ref cancelled = new Ref(); + ProgressManager.getInstance().runProcess(new Runnable() { + @Override + public void run() { + if (!ApplicationManagerEx.getApplicationEx().tryRunReadAction(new Runnable() { + @Override + public void run() { + IconDeferrerImpl.evaluateDeferred(evalRunnable); + if (myAutoUpdatable) { + myLastCalcTime = System.currentTimeMillis(); + myLastTimeSpent = myLastCalcTime - startTime; + } + } + })) { + myIsScheduled = false; + cancelled.set(Boolean.TRUE); + } + } + }, progress); + if (cancelled.get() == Boolean.TRUE) return; + } catch(ProcessCanceledException e) {} + finally { + ApplicationManager.getApplication().removeApplicationListener(listener); } } else { From ee666e691d219f05382f1a76958501aa0eebfe1b Mon Sep 17 00:00:00 2001 From: Alexander Zolotov Date: Mon, 17 Nov 2014 20:57:46 +0300 Subject: [PATCH 16/48] Update display name and description of 'expand live template' action --- .../src/messages/ActionsBundle.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platform/platform-resources-en/src/messages/ActionsBundle.properties b/platform/platform-resources-en/src/messages/ActionsBundle.properties index 138a5e3b60b5..ca93464c5653 100644 --- a/platform/platform-resources-en/src/messages/ActionsBundle.properties +++ b/platform/platform-resources-en/src/messages/ActionsBundle.properties @@ -523,8 +523,8 @@ action.ClassNameCompletion.description=Complete class name and add import for it action.InsertLiveTemplate.text=Insert Live _Template... action.InsertLiveTemplate.description=Show popup list of live templates starting with the specified prefix action.ExpandLiveTemplateByTab.text=Expand Live Template by Tab -action.ExpandLiveTemplateCustom.text=Expand Live Template -action.ExpandLiveTemplateCustom.description=Invoke the live template with the prefix typed in the editor +action.ExpandLiveTemplateCustom.text=Expand Live Template / Emmet Abbreviation +action.ExpandLiveTemplateCustom.description=Invoke the live template that bound to 'Custom shortcut' with the prefix typed in the editor action.SurroundWithLiveTemplate.text=Surround with Live Tem_plate... action.SurroundWithLiveTemplate.description=Surrounds the selection with one of the template action.CommentByLineComment.text=Comment with _Line Comment From 7b5a901c7ddd70956a7211035636485b91cf9314 Mon Sep 17 00:00:00 2001 From: Alexander Zolotov Date: Mon, 17 Nov 2014 22:04:46 +0300 Subject: [PATCH 17/48] Weaken instanceof on delete it fixes the situation when ASTDelegatePsiElement is placed inside LazyParseableElement --- .../intellij/extapi/psi/ASTDelegatePsiElement.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/platform/core-impl/src/com/intellij/extapi/psi/ASTDelegatePsiElement.java b/platform/core-impl/src/com/intellij/extapi/psi/ASTDelegatePsiElement.java index fbcb7afc0731..6cbb68219ef2 100644 --- a/platform/core-impl/src/com/intellij/extapi/psi/ASTDelegatePsiElement.java +++ b/platform/core-impl/src/com/intellij/extapi/psi/ASTDelegatePsiElement.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 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. @@ -32,7 +32,10 @@ import com.intellij.psi.impl.PsiElementBase; import com.intellij.psi.impl.PsiManagerEx; import com.intellij.psi.impl.source.SourceTreeToPsiMap; import com.intellij.psi.impl.source.codeStyle.CodeEditUtil; -import com.intellij.psi.impl.source.tree.*; +import com.intellij.psi.impl.source.tree.ChangeUtil; +import com.intellij.psi.impl.source.tree.CompositeElement; +import com.intellij.psi.impl.source.tree.SharedImplUtil; +import com.intellij.psi.impl.source.tree.TreeElement; import com.intellij.psi.tree.IElementType; import com.intellij.psi.tree.TokenSet; import com.intellij.psi.util.PsiUtilCore; @@ -334,9 +337,9 @@ public abstract class ASTDelegatePsiElement extends PsiElementBase { CheckUtil.checkWritable(this); ((ASTDelegatePsiElement)parent).deleteChildInternal(getNode()); } - else if (parent instanceof CompositePsiElement) { + else if (parent instanceof CompositeElement) { CheckUtil.checkWritable(this); - ((CompositePsiElement)parent).deleteChildInternal(getNode()); + ((CompositeElement)parent).deleteChildInternal(getNode()); } else if (parent instanceof PsiFile) { CheckUtil.checkWritable(this); From ba0cba456e7c9ec20645c96888306234cbcb11e4 Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Mon, 17 Nov 2014 20:14:42 +0100 Subject: [PATCH 18/48] invert if: stop at lambda level (IDEA-133023) --- .../intention/impl/InvertIfConditionAction.java | 3 ++- .../invertIfCondition/afterInsideLambda.java | 13 +++++++++++++ .../invertIfCondition/beforeInsideLambda.java | 11 +++++++++++ 3 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 java/java-tests/testData/codeInsight/invertIfCondition/afterInsideLambda.java create mode 100644 java/java-tests/testData/codeInsight/invertIfCondition/beforeInsideLambda.java diff --git a/java/java-impl/src/com/intellij/codeInsight/intention/impl/InvertIfConditionAction.java b/java/java-impl/src/com/intellij/codeInsight/intention/impl/InvertIfConditionAction.java index 9815601a16c9..6815ca94c9df 100644 --- a/java/java-impl/src/com/intellij/codeInsight/intention/impl/InvertIfConditionAction.java +++ b/java/java-impl/src/com/intellij/codeInsight/intention/impl/InvertIfConditionAction.java @@ -158,8 +158,9 @@ public class InvertIfConditionAction extends PsiElementBaseIntentionAction { } private static PsiElement findCodeBlock(PsiIfStatement ifStatement) { - PsiElement e = PsiTreeUtil.getParentOfType(ifStatement, PsiMethod.class, PsiClassInitializer.class); + PsiElement e = PsiTreeUtil.getParentOfType(ifStatement, PsiMethod.class, PsiClassInitializer.class, PsiLambdaExpression.class); if (e instanceof PsiMethod) return ((PsiMethod) e).getBody(); + if (e instanceof PsiLambdaExpression) return ((PsiLambdaExpression)e).getBody(); if (e instanceof PsiClassInitializer) return ((PsiClassInitializer) e).getBody(); return null; } diff --git a/java/java-tests/testData/codeInsight/invertIfCondition/afterInsideLambda.java b/java/java-tests/testData/codeInsight/invertIfCondition/afterInsideLambda.java new file mode 100644 index 000000000000..0c58356b054b --- /dev/null +++ b/java/java-tests/testData/codeInsight/invertIfCondition/afterInsideLambda.java @@ -0,0 +1,13 @@ +// "Invert If Condition" "true" +class A { + public void foo() { + Runnable r = () -> { + if (System.currentTimeMillis() <= 1) { + System.err.println("Elvis lives"); + } + else { + return; + } + }; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/invertIfCondition/beforeInsideLambda.java b/java/java-tests/testData/codeInsight/invertIfCondition/beforeInsideLambda.java new file mode 100644 index 000000000000..85aa03f9edac --- /dev/null +++ b/java/java-tests/testData/codeInsight/invertIfCondition/beforeInsideLambda.java @@ -0,0 +1,11 @@ +// "Invert If Condition" "true" +class A { + public void foo() { + Runnable r = () -> { + if (System.currentTimeMillis() > 1) { + return; + } + System.err.println("Elvis lives"); + }; + } +} \ No newline at end of file From 93c98d2e432d9b77c238ced975d721f64cd1b4e6 Mon Sep 17 00:00:00 2001 From: peter Date: Mon, 17 Nov 2014 19:26:57 +0100 Subject: [PATCH 19/48] don't decompile super classes when overriding their methods --- .../src/com/intellij/ide/util/MemberChooser.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/ide/util/MemberChooser.java b/platform/lang-impl/src/com/intellij/ide/util/MemberChooser.java index 2ced07e8e3a6..2addc59170b4 100644 --- a/platform/lang-impl/src/com/intellij/ide/util/MemberChooser.java +++ b/platform/lang-impl/src/com/intellij/ide/util/MemberChooser.java @@ -27,6 +27,8 @@ import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.ui.VerticalFlowLayout; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.Ref; +import com.intellij.psi.PsiCompiledElement; +import com.intellij.psi.PsiElement; import com.intellij.psi.codeStyle.CodeStyleSettings; import com.intellij.psi.codeStyle.CodeStyleSettingsManager; import com.intellij.ui.*; @@ -904,8 +906,11 @@ public class MemberChooser extends DialogWrapper implemen @Override public int compare(ElementNode n1, ElementNode n2) { if (n1.getDelegate() instanceof ClassMemberWithElement && n2.getDelegate() instanceof ClassMemberWithElement) { - return ((ClassMemberWithElement)n1.getDelegate()).getElement().getTextOffset() - - ((ClassMemberWithElement)n2.getDelegate()).getElement().getTextOffset(); + PsiElement element1 = ((ClassMemberWithElement)n1.getDelegate()).getElement(); + PsiElement element2 = ((ClassMemberWithElement)n2.getDelegate()).getElement(); + if (!(element1 instanceof PsiCompiledElement) && !(element2 instanceof PsiCompiledElement)) { + return element1.getTextOffset() - element2.getTextOffset(); + } } return n1.getOrder() - n2.getOrder(); } From 43774da42d8076e7e1e818e2d9e51b06f468a114 Mon Sep 17 00:00:00 2001 From: peter Date: Mon, 17 Nov 2014 19:39:11 +0100 Subject: [PATCH 20/48] fix UI leak after pressing Enter in a speed search --- .../openapi/wm/ex/ToolWindowManagerEx.java | 2 ++ .../wm/impl/ToolWindowHeadlessManagerImpl.java | 4 ++++ .../openapi/wm/impl/ToolWindowManagerImpl.java | 5 +++++ .../src/com/intellij/ui/SpeedSearchBase.java | 14 +++++++++----- 4 files changed, 20 insertions(+), 5 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/ex/ToolWindowManagerEx.java b/platform/platform-impl/src/com/intellij/openapi/wm/ex/ToolWindowManagerEx.java index 2bff2a10d5cd..d8414ddc37ed 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/ex/ToolWindowManagerEx.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/ex/ToolWindowManagerEx.java @@ -15,6 +15,7 @@ */ package com.intellij.openapi.wm.ex; +import com.intellij.openapi.Disposable; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Condition; import com.intellij.openapi.wm.ToolWindowAnchor; @@ -35,6 +36,7 @@ public abstract class ToolWindowManagerEx extends ToolWindowManager { } public abstract void addToolWindowManagerListener(@NotNull ToolWindowManagerListener l); + public abstract void addToolWindowManagerListener(@NotNull ToolWindowManagerListener l, @NotNull Disposable parentDisposable); public abstract void removeToolWindowManagerListener(@NotNull ToolWindowManagerListener l); /** diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowHeadlessManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowHeadlessManagerImpl.java index 5fa360235cb2..24e04e100369 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowHeadlessManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowHeadlessManagerImpl.java @@ -217,6 +217,10 @@ public class ToolWindowHeadlessManagerImpl extends ToolWindowManagerEx { } + @Override + public void addToolWindowManagerListener(@NotNull ToolWindowManagerListener l, @NotNull Disposable parentDisposable) { + } + @Override public void removeToolWindowManagerListener(@NotNull ToolWindowManagerListener l) { } diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowManagerImpl.java index 8acebb5b5bfd..598d13fcb830 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowManagerImpl.java @@ -566,6 +566,11 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements myDispatcher.addListener(l); } + @Override + public void addToolWindowManagerListener(@NotNull ToolWindowManagerListener l, @NotNull Disposable parentDisposable) { + myDispatcher.addListener(l, parentDisposable); + } + @Override public void removeToolWindowManagerListener(@NotNull ToolWindowManagerListener l) { myDispatcher.removeListener(l); diff --git a/platform/platform-impl/src/com/intellij/ui/SpeedSearchBase.java b/platform/platform-impl/src/com/intellij/ui/SpeedSearchBase.java index 76985ad77362..6f20a456c4c7 100644 --- a/platform/platform-impl/src/com/intellij/ui/SpeedSearchBase.java +++ b/platform/platform-impl/src/com/intellij/ui/SpeedSearchBase.java @@ -18,6 +18,7 @@ package com.intellij.ui; import com.intellij.featureStatistics.FeatureUsageTracker; import com.intellij.ide.DataManager; import com.intellij.ide.ui.UISettings; +import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.CommonDataKeys; @@ -25,6 +26,7 @@ import com.intellij.openapi.actionSystem.CustomShortcutSet; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.text.StringUtil; @@ -65,6 +67,7 @@ public abstract class SpeedSearchBase extends SpeedSear private boolean myClearSearchOnNavigateNoMatch = false; @NonNls protected static final String ENTERED_PREFIX_PROPERTY_NAME = "enteredPrefix"; + private Disposable myListenerDisposable; public SpeedSearchBase(Comp component) { myComponent = component; @@ -522,10 +525,9 @@ public abstract class SpeedSearchBase extends SpeedSear myPopupLayeredPane.validate(); myPopupLayeredPane.repaint(); myPopupLayeredPane = null; - - if (project != null) { - ((ToolWindowManagerEx)ToolWindowManager.getInstance(project)).removeToolWindowManagerListener(myWindowManagerListener); - } + + Disposer.dispose(myListenerDisposable); + myListenerDisposable = null; } else if (searchPopup != null) { FeatureUsageTracker.getInstance().triggerFeatureUsed("ui.tree.speedsearch"); @@ -543,7 +545,9 @@ public abstract class SpeedSearchBase extends SpeedSear if (mySearchPopup == null || !myComponent.isDisplayable()) return; if (project != null) { - ((ToolWindowManagerEx)ToolWindowManager.getInstance(project)).addToolWindowManagerListener(myWindowManagerListener); + myListenerDisposable = Disposer.newDisposable(); + ToolWindowManagerEx toolWindowManager = (ToolWindowManagerEx)ToolWindowManager.getInstance(project); + toolWindowManager.addToolWindowManagerListener(myWindowManagerListener, myListenerDisposable); } JRootPane rootPane = myComponent.getRootPane(); if (rootPane != null) { From 9ea0186933e7eb2ec7fd6a5966b52c1b222eeebd Mon Sep 17 00:00:00 2001 From: peter Date: Mon, 17 Nov 2014 20:14:40 +0100 Subject: [PATCH 21/48] fix UI leak via contents of FrameWrapper that stayed forever in Window.allWindows --- .../platform-impl/src/com/intellij/openapi/ui/FrameWrapper.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/platform/platform-impl/src/com/intellij/openapi/ui/FrameWrapper.java b/platform/platform-impl/src/com/intellij/openapi/ui/FrameWrapper.java index c6e037e5d30e..0b1789faf66d 100644 --- a/platform/platform-impl/src/com/intellij/openapi/ui/FrameWrapper.java +++ b/platform/platform-impl/src/com/intellij/openapi/ui/FrameWrapper.java @@ -218,6 +218,8 @@ public class FrameWrapper implements Disposable, DataProvider { myStatusBar = null; } + frame.dispose(); + myDisposed = true; } From dede69b0ee3cf658cf24fceb329d6553dfb65962 Mon Sep 17 00:00:00 2001 From: peter Date: Mon, 17 Nov 2014 20:20:18 +0100 Subject: [PATCH 22/48] when possible, build method hierarchy only for specific names --- .../psi/impl/PsiSuperMethodImplUtil.java | 101 ++++++------------ 1 file changed, 30 insertions(+), 71 deletions(-) diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/PsiSuperMethodImplUtil.java b/java/java-psi-impl/src/com/intellij/psi/impl/PsiSuperMethodImplUtil.java index 87a45bf8cdeb..e5ae3926e4ca 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/PsiSuperMethodImplUtil.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/PsiSuperMethodImplUtil.java @@ -28,6 +28,8 @@ import com.intellij.psi.search.searches.DeepestSuperMethodsSearch; import com.intellij.psi.search.searches.SuperMethodsSearch; import com.intellij.psi.util.*; import com.intellij.util.*; +import com.intellij.util.containers.ConcurrentFactoryMap; +import com.intellij.util.containers.FactoryMap; import gnu.trove.THashMap; import gnu.trove.THashSet; import gnu.trove.TObjectHashingStrategy; @@ -43,7 +45,20 @@ public class PsiSuperMethodImplUtil { @NotNull @Override public Map fun(PsiClass dom) { - return buildMethodHierarchy(dom, PsiSubstitutor.EMPTY, true, new THashSet(), false); + return buildMethodHierarchy(dom, null, PsiSubstitutor.EMPTY, true, new THashSet(), false); + } + }); + private static final PsiCacheKey>, PsiClass> SIGNATURES_BY_NAME_KEY = PsiCacheKey + .create("SIGNATURES_BY_NAME_KEY", new Function>>() { + @Override + public FactoryMap> fun(final PsiClass psiClass) { + return new ConcurrentFactoryMap>() { + @Nullable + @Override + protected Map create(String methodName) { + return buildMethodHierarchy(psiClass, methodName, PsiSubstitutor.EMPTY, true, new THashSet(), false); + } + }; } }); @@ -112,6 +127,7 @@ public class PsiSuperMethodImplUtil { @NotNull private static Map buildMethodHierarchy(@NotNull PsiClass aClass, + @Nullable String nameHint, @NotNull PsiSubstitutor substitutor, final boolean includePrivates, @NotNull final Set visited, @@ -144,7 +160,7 @@ public class PsiSuperMethodImplUtil { }); PsiMethod[] methods = aClass.getMethods(); - if (aClass instanceof PsiClassImpl) { + if ((nameHint == null || "values".equals(nameHint)) && aClass instanceof PsiClassImpl) { final PsiMethod valuesMethod = ((PsiClassImpl)aClass).getValuesMethod(); if (valuesMethod != null) { methods = ArrayUtil.append(methods, valuesMethod); @@ -155,6 +171,7 @@ public class PsiSuperMethodImplUtil { if (!method.isValid()) { throw new PsiInvalidElementAccessException(method, "class.valid=" + aClass.isValid() + "; name=" + method.getName()); } + if (nameHint != null && !nameHint.equals(method.getName())) continue; if (!includePrivates && method.hasModifierProperty(PsiModifier.PRIVATE)) continue; final MethodSignatureBackedByPsiMethod signature = MethodSignatureBackedByPsiMethod.create(method, substitutor, isInRawContext); HierarchicalMethodSignatureImpl newH = new HierarchicalMethodSignatureImpl(signature); @@ -180,7 +197,7 @@ public class PsiSuperMethodImplUtil { PsiSubstitutor finalSubstitutor = obtainFinalSubstitutor(superClass, superSubstitutor, substitutor, isInRawContext); final boolean isInRawContextSuper = (isInRawContext || PsiUtil.isRawSubstitutor(superClass, superSubstitutor)) && superClass.getTypeParameters().length != 0; - Map superResult = buildMethodHierarchy(superClass, finalSubstitutor, false, visited, isInRawContextSuper); + Map superResult = buildMethodHierarchy(superClass, nameHint, finalSubstitutor, false, visited, isInRawContextSuper); visited.remove(superClass); List> flattened = new ArrayList>(); @@ -366,7 +383,7 @@ public class PsiSuperMethodImplUtil { PsiClass aClass = method.getContainingClass(); HierarchicalMethodSignature result = null; if (aClass != null) { - result = getSignaturesMap(aClass).get(method.getSignature(PsiSubstitutor.EMPTY)); + result = SIGNATURES_BY_NAME_KEY.getValue(aClass).get(method.getName()).get(method.getSignature(PsiSubstitutor.EMPTY)); } if (result == null) { result = new HierarchicalMethodSignatureImpl((MethodSignatureBackedByPsiMethod)method.getSignature(PsiSubstitutor.EMPTY)); @@ -395,40 +412,14 @@ public class PsiSuperMethodImplUtil { if (!canHaveSuperMethod(method, true, false)) return false; - Map cachedMap = SIGNATURES_FOR_CLASS_KEY.getCachedValueOrNull(aClass); - if (cachedMap != null) { - HierarchicalMethodSignature signature = cachedMap.get(method.getSignature(PsiSubstitutor.EMPTY)); - if (signature != null) { - List superSignatures = signature.getSuperSignatures(); - for (HierarchicalMethodSignature superSignature : superSignatures) { - if (!superMethodProcessor.process(superSignature.getMethod())) return false; - } - return true; + Map cachedMap = SIGNATURES_BY_NAME_KEY.getValue(aClass).get(method.getName()); + HierarchicalMethodSignature signature = cachedMap.get(method.getSignature(PsiSubstitutor.EMPTY)); + if (signature != null) { + List superSignatures = signature.getSuperSignatures(); + for (HierarchicalMethodSignature superSignature : superSignatures) { + if (!superMethodProcessor.process(superSignature.getMethod())) return false; } } - - PsiClassType[] directSupers = aClass.getSuperTypes(); - for (PsiClassType directSuper : directSupers) { - PsiClassType.ClassResolveResult resolveResult = directSuper.resolveGenerics(); - if (resolveResult.getSubstitutor() != PsiSubstitutor.EMPTY) { - // generics - break; - } - PsiClass directSuperClass = resolveResult.getElement(); - if (directSuperClass == null) continue; - PsiMethod[] candidates = directSuperClass.findMethodsBySignature(method, false); - for (PsiMethod candidate : candidates) { - if (PsiUtil.canBeOverriden(candidate)) { - if (!superMethodProcessor.process(candidate)) return false; - } - } - return true; - } - - List superSignatures = method.getHierarchicalMethodSignature().getSuperSignatures(); - for (HierarchicalMethodSignature superSignature : superSignatures) { - if (!superMethodProcessor.process(superSignature.getMethod())) return false; - } return true; } @@ -444,42 +435,10 @@ public class PsiSuperMethodImplUtil { if (!canHaveSuperMethod(method, true, false)) return false; - PsiMethod[] superMethods = null; - Map cachedMap = SIGNATURES_FOR_CLASS_KEY.getCachedValueOrNull(aClass); - if (cachedMap != null) { - HierarchicalMethodSignature signature = cachedMap.get(method.getSignature(PsiSubstitutor.EMPTY)); - if (signature != null) { - superMethods = MethodSignatureUtil.convertMethodSignaturesToMethods(signature.getSuperSignatures()); - } - } - if (superMethods == null) { - PsiClassType[] directSupers = aClass.getSuperTypes(); - List found = null; - boolean canceled = false; - for (PsiClassType directSuper : directSupers) { - PsiClassType.ClassResolveResult resolveResult = directSuper.resolveGenerics(); - if (resolveResult.getSubstitutor() != PsiSubstitutor.EMPTY) { - // generics - canceled = true; - break; - } - PsiClass directSuperClass = resolveResult.getElement(); - if (directSuperClass == null) continue; - PsiMethod[] candidates = directSuperClass.findMethodsBySignature(method, false); - if (candidates.length != 0) { - if (found == null) found = new ArrayList(); - for (PsiMethod candidate : candidates) { - if (PsiUtil.canBeOverriden(candidate)) found.add(candidate); - } - } - } - superMethods = canceled ? null : found == null ? PsiMethod.EMPTY_ARRAY : found.toArray(new PsiMethod[found.size()]); - } - if (superMethods == null) { - superMethods = MethodSignatureUtil.convertMethodSignaturesToMethods(method.getHierarchicalMethodSignature().getSuperSignatures()); - } + Map cachedMap = SIGNATURES_BY_NAME_KEY.getValue(aClass).get(method.getName()); + HierarchicalMethodSignature signature = cachedMap.get(method.getSignature(PsiSubstitutor.EMPTY)); - for (PsiMethod superCandidate : superMethods) { + for (PsiMethod superCandidate : MethodSignatureUtil.convertMethodSignaturesToMethods(signature.getSuperSignatures())) { if (superMethod.equals(superCandidate) || isSuperMethodSmart(superCandidate, superMethod)) return true; } return false; From 0a411c19604852277ae8cd81cb6702c83081fcea Mon Sep 17 00:00:00 2001 From: Mikhail Golubev Date: Tue, 18 Nov 2014 01:02:36 +0300 Subject: [PATCH 23/48] PY-14365 Do not show object and __Classobj in AutoImportQuickFix Excluded them from the list of base classes that may be shown in description and list items in the quick fix UI. --- .../imports/ImportCandidateHolder.java | 20 +++++++++++-------- .../main.py | 1 + .../module.py | 2 ++ .../com/jetbrains/python/PyQuickFixTest.java | 10 ++++++++++ 4 files changed, 25 insertions(+), 8 deletions(-) create mode 100644 python/testData/inspections/objectBaseIsNotShownInAutoImportQuickfix/main.py create mode 100644 python/testData/inspections/objectBaseIsNotShownInAutoImportQuickfix/module.py diff --git a/python/src/com/jetbrains/python/codeInsight/imports/ImportCandidateHolder.java b/python/src/com/jetbrains/python/codeInsight/imports/ImportCandidateHolder.java index e62910144b45..a5c9a10d0454 100644 --- a/python/src/com/jetbrains/python/codeInsight/imports/ImportCandidateHolder.java +++ b/python/src/com/jetbrains/python/codeInsight/imports/ImportCandidateHolder.java @@ -25,10 +25,14 @@ import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiFileSystemItem; import com.intellij.psi.util.QualifiedName; +import com.intellij.util.Function; +import com.intellij.util.containers.ContainerUtil; import com.jetbrains.python.psi.*; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.List; + /** * An immutable holder of information for one auto-import candidate. *

@@ -131,15 +135,15 @@ class ImportCandidateHolder implements Comparable { sb.append(((PyFunction)myImportable).getParameterList().getPresentableText(false)); } else if (myImportable instanceof PyClass) { - final PyClass[] supers = ((PyClass)myImportable).getSuperClasses(); - if (supers.length > 0) { + final List supers = ContainerUtil.mapNotNull(((PyClass)myImportable).getSuperClasses(), new Function() { + @Override + public String fun(PyClass cls) { + return PyUtil.isObjectClass(cls) ? null : cls.getName(); + } + }); + if (!supers.isEmpty()) { sb.append("("); - // ", ".join(x.getName() for x in getSuperClasses()) - final String[] superNames = new String[supers.length]; - for (int i = 0; i < supers.length; i += 1) { - superNames[i] = supers[i].getName(); - } - sb.append(StringUtil.join(superNames, ", ")); + StringUtil.join(supers, ", ", sb); sb.append(")"); } } diff --git a/python/testData/inspections/objectBaseIsNotShownInAutoImportQuickfix/main.py b/python/testData/inspections/objectBaseIsNotShownInAutoImportQuickfix/main.py new file mode 100644 index 000000000000..b5e5da256cfa --- /dev/null +++ b/python/testData/inspections/objectBaseIsNotShownInAutoImportQuickfix/main.py @@ -0,0 +1 @@ +MyOldStyleClass diff --git a/python/testData/inspections/objectBaseIsNotShownInAutoImportQuickfix/module.py b/python/testData/inspections/objectBaseIsNotShownInAutoImportQuickfix/module.py new file mode 100644 index 000000000000..4652e3d0f87e --- /dev/null +++ b/python/testData/inspections/objectBaseIsNotShownInAutoImportQuickfix/module.py @@ -0,0 +1,2 @@ +class MyOldStyleClass: + pass diff --git a/python/testSrc/com/jetbrains/python/PyQuickFixTest.java b/python/testSrc/com/jetbrains/python/PyQuickFixTest.java index 6cc2e578fb30..4b9b5ca42e0c 100644 --- a/python/testSrc/com/jetbrains/python/PyQuickFixTest.java +++ b/python/testSrc/com/jetbrains/python/PyQuickFixTest.java @@ -50,6 +50,16 @@ public class PyQuickFixTest extends PyTestCase { PyUnresolvedReferencesInspection.class, "Import 'importFromModule.foo.baz'", true, true); } + // PY-14365 + public void testObjectBaseIsNotShownInAutoImportQuickfix() { + myFixture.copyDirectoryToProject("objectBaseIsNotShownInAutoImportQuickfix", ""); + myFixture.configureByFile("main.py"); + myFixture.enableInspections(PyUnresolvedReferencesInspection.class); + final IntentionAction intention = myFixture.findSingleIntention("Import"); + assertNotNull(intention); + assertEquals("Import 'module.MyOldStyleClass'", intention.getText()); + } + public void testImportFromModuleStar() { // PY-6302 myFixture.enableInspections(PyUnresolvedReferencesInspection.class); myFixture.copyDirectoryToProject("importFromModuleStar", ""); From 99f4933e7087433bcf755260b2f2589e9a65c0ff Mon Sep 17 00:00:00 2001 From: Mikhail Golubev Date: Tue, 18 Nov 2014 01:18:16 +0300 Subject: [PATCH 24/48] PY-9209 Insert a space after '#' sign when using smart enter in comment --- .../PyCommentBreakerEnterProcessor.java | 10 +++++++--- python/testData/codeInsight/smartEnter/comment.py | 2 +- .../testData/codeInsight/smartEnter/comment_after.py | 4 ++-- .../smartEnter/spaceInsertedAfterHashSignInComment.py | 2 ++ .../spaceInsertedAfterHashSignInComment_after.py | 3 +++ .../testSrc/com/jetbrains/python/PySmartEnterTest.java | 5 +++++ 6 files changed, 20 insertions(+), 6 deletions(-) create mode 100644 python/testData/codeInsight/smartEnter/spaceInsertedAfterHashSignInComment.py create mode 100644 python/testData/codeInsight/smartEnter/spaceInsertedAfterHashSignInComment_after.py diff --git a/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/enterProcessors/PyCommentBreakerEnterProcessor.java b/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/enterProcessors/PyCommentBreakerEnterProcessor.java index ee8394defe9e..0a6abd4b084b 100644 --- a/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/enterProcessors/PyCommentBreakerEnterProcessor.java +++ b/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/enterProcessors/PyCommentBreakerEnterProcessor.java @@ -19,6 +19,7 @@ import com.intellij.openapi.editor.CaretModel; import com.intellij.openapi.editor.Editor; import com.intellij.psi.PsiComment; import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiWhiteSpace; import com.intellij.psi.util.PsiTreeUtil; import com.jetbrains.python.codeInsight.editorActions.smartEnter.SmartEnterUtil; @@ -34,12 +35,15 @@ public class PyCommentBreakerEnterProcessor implements EnterProcessor { return false; } final CaretModel caretModel = editor.getCaretModel(); - final PsiElement atCaret = psiElement.getContainingFile().findElementAt(caretModel.getOffset()); + PsiElement atCaret = psiElement.getContainingFile().findElementAt(caretModel.getOffset()); + if (atCaret instanceof PsiWhiteSpace) { + atCaret = atCaret.getPrevSibling(); + } final PsiElement comment = PsiTreeUtil.getParentOfType(atCaret, PsiComment.class, false); if (comment != null) { SmartEnterUtil.plainEnter(editor); - editor.getDocument().insertString(caretModel.getOffset(), "#"); - caretModel.moveToOffset(caretModel.getOffset() + 1); + editor.getDocument().insertString(caretModel.getOffset(), "# "); + caretModel.moveToOffset(caretModel.getOffset() + 2); return true; } return false; diff --git a/python/testData/codeInsight/smartEnter/comment.py b/python/testData/codeInsight/smartEnter/comment.py index c776b2a05afb..edf9e80daaf9 100644 --- a/python/testData/codeInsight/smartEnter/comment.py +++ b/python/testData/codeInsight/smartEnter/comment.py @@ -1 +1 @@ -#comment \ No newline at end of file +# comment \ No newline at end of file diff --git a/python/testData/codeInsight/smartEnter/comment_after.py b/python/testData/codeInsight/smartEnter/comment_after.py index 374c22d6a10a..129e53e20712 100644 --- a/python/testData/codeInsight/smartEnter/comment_after.py +++ b/python/testData/codeInsight/smartEnter/comment_after.py @@ -1,2 +1,2 @@ -#comment -# \ No newline at end of file +# comment +# \ No newline at end of file diff --git a/python/testData/codeInsight/smartEnter/spaceInsertedAfterHashSignInComment.py b/python/testData/codeInsight/smartEnter/spaceInsertedAfterHashSignInComment.py new file mode 100644 index 000000000000..d2f1f9bdb19d --- /dev/null +++ b/python/testData/codeInsight/smartEnter/spaceInsertedAfterHashSignInComment.py @@ -0,0 +1,2 @@ +# foo +pass \ No newline at end of file diff --git a/python/testData/codeInsight/smartEnter/spaceInsertedAfterHashSignInComment_after.py b/python/testData/codeInsight/smartEnter/spaceInsertedAfterHashSignInComment_after.py new file mode 100644 index 000000000000..9e0b9db075d8 --- /dev/null +++ b/python/testData/codeInsight/smartEnter/spaceInsertedAfterHashSignInComment_after.py @@ -0,0 +1,3 @@ +# foo +# +pass \ No newline at end of file diff --git a/python/testSrc/com/jetbrains/python/PySmartEnterTest.java b/python/testSrc/com/jetbrains/python/PySmartEnterTest.java index e58988010645..a4db79654658 100644 --- a/python/testSrc/com/jetbrains/python/PySmartEnterTest.java +++ b/python/testSrc/com/jetbrains/python/PySmartEnterTest.java @@ -189,4 +189,9 @@ public class PySmartEnterTest extends PyTestCase { public void testWithOnlyColonMissing() { doTest(); } + + // PY-9209 + public void testSpaceInsertedAfterHashSignInComment() { + doTest(); + } } From 2d1a05ffb153acf6bc5d67259aead24a13298e8a Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Tue, 18 Nov 2014 03:10:32 +0300 Subject: [PATCH 25/48] IDEA-131822 Fixed initializing repository root url in DirectoryEntry instances provided by BrowseClient for command line --- .../idea/svn/browse/CmdBrowseClient.java | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/browse/CmdBrowseClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/browse/CmdBrowseClient.java index bceb516caef3..239e7b6ab225 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/browse/CmdBrowseClient.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/browse/CmdBrowseClient.java @@ -29,6 +29,7 @@ import org.jetbrains.idea.svn.commandLine.CommandExecutor; import org.jetbrains.idea.svn.commandLine.CommandUtil; import org.jetbrains.idea.svn.commandLine.SvnBindException; import org.jetbrains.idea.svn.commandLine.SvnCommandName; +import org.jetbrains.idea.svn.info.Info; import org.jetbrains.idea.svn.lock.Lock; import org.tmatesoft.svn.core.SVNException; import org.tmatesoft.svn.core.SVNURL; @@ -62,9 +63,10 @@ public class CmdBrowseClient extends BaseSvnClient implements BrowseClient { parameters.add("--xml"); CommandExecutor command = execute(myVcs, target, SvnCommandName.list, parameters, null); + Info info = myFactory.createInfoClient().doInfo(target.getURL(), target.getPegRevision(), revision); try { - parseOutput(target.getURL(), command, handler); + parseOutput(target.getURL(), command, handler, info != null ? info.getRepositoryRootURL() : null); } catch (SVNException e) { throw new SvnBindException(e); @@ -89,15 +91,18 @@ public class CmdBrowseClient extends BaseSvnClient implements BrowseClient { return listener.getCommittedRevision(); } - private static void parseOutput(@NotNull SVNURL url, @NotNull CommandExecutor command, @Nullable DirectoryEntryConsumer handler) - throws VcsException, SVNException { + private static void parseOutput(@NotNull SVNURL url, + @NotNull CommandExecutor command, + @Nullable DirectoryEntryConsumer handler, + @Nullable SVNURL repositoryUrl) + throws VcsException, SVNException { try { TargetLists lists = CommandUtil.parse(command.getOutput(), TargetLists.class); if (handler != null && lists != null) { for (TargetList list : lists.lists) { for (Entry entry : list.entries) { - handler.consume(entry.toDirectoryEntry(url)); + handler.consume(entry.toDirectoryEntry(url, repositoryUrl)); } } } @@ -140,9 +145,8 @@ public class CmdBrowseClient extends BaseSvnClient implements BrowseClient { public Lock.Builder lock; @NotNull - public DirectoryEntry toDirectoryEntry(@NotNull SVNURL url) throws SVNException { - // TODO: repository is not used for now - return new DirectoryEntry(url.appendPath(name, false), null, PathUtil.getFileName(name), kind, + public DirectoryEntry toDirectoryEntry(@NotNull SVNURL url, @Nullable SVNURL repositoryUrl) throws SVNException { + return new DirectoryEntry(url.appendPath(name, false), repositoryUrl, PathUtil.getFileName(name), kind, commit != null ? commit.build() : null, name); } } From 68e4b6a7932b404ef7b1daf0516c7284c725d9f0 Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Tue, 18 Nov 2014 05:42:55 +0300 Subject: [PATCH 26/48] svn: Refactored BranchConfigurationDialog.configureBranches() - parameters inlined, code simplified --- .../src/org/jetbrains/idea/svn/SvnUtil.java | 9 ----- .../BranchConfigurationDialog.java | 40 ++++++------------- .../branchConfig/ConfigureBranchesAction.java | 2 +- .../branchConfig/CreateBranchOrTagDialog.java | 2 +- .../svn/branchConfig/SelectBranchPopup.java | 2 +- .../idea/svn/dialogs/CopiesPanel.java | 2 +- 6 files changed, 16 insertions(+), 41 deletions(-) diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnUtil.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnUtil.java index 5fc354cb614b..a955b7094d26 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnUtil.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnUtil.java @@ -510,15 +510,6 @@ public class SvnUtil { } } - @Nullable - public static VirtualFile correctRoot(final Project project, final VirtualFile file) { - if (file.getPath().length() == 0) { - // project root - return project.getBaseDir(); - } - return file; - } - public static boolean checkRepositoryVersion15(@NotNull SvnVcs vcs, @NotNull String url) { // Merge info tracking is supported in repositories since svn 1.5 (June 2008) - see http://subversion.apache.org/docs/release-notes/. // But still some users use 1.4 repositories and currently we need to know if repository supports merge info for some code flows. diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/BranchConfigurationDialog.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/BranchConfigurationDialog.java index 0e0fce947088..0714c6c04c50 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/BranchConfigurationDialog.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/BranchConfigurationDialog.java @@ -24,6 +24,7 @@ import com.intellij.openapi.ui.MultiLineLabelUI; import com.intellij.openapi.ui.TextFieldWithBrowseButton; import com.intellij.openapi.util.Pair; import com.intellij.openapi.vcs.VcsException; +import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.ui.*; import com.intellij.ui.components.JBList; @@ -31,7 +32,10 @@ import com.intellij.util.ObjectUtils; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.idea.svn.*; +import org.jetbrains.idea.svn.RootUrlInfo; +import org.jetbrains.idea.svn.SvnBundle; +import org.jetbrains.idea.svn.SvnUtil; +import org.jetbrains.idea.svn.SvnVcs; import org.jetbrains.idea.svn.commandLine.SvnBindException; import org.jetbrains.idea.svn.dialogs.SelectLocationDialog; import org.tmatesoft.svn.core.SVNURL; @@ -42,7 +46,6 @@ import javax.swing.event.DocumentEvent; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; -import java.io.File; import java.util.ArrayList; import java.util.List; @@ -188,34 +191,19 @@ public class BranchConfigurationDialog extends DialogWrapper { return "Subversion.BranchConfigurationDialog"; } - public static void configureBranches(final Project project, final VirtualFile file) { - configureBranches(project, file, false); - } - - public static void configureBranches(final Project project, final VirtualFile file, final boolean isRoot) { - final VirtualFile vcsRoot = (isRoot) ? file : getRoot(project, file); - if (vcsRoot == null) { + public static void configureBranches(final Project project, @Nullable VirtualFile file) { + if (file == null) { return; } - final VirtualFile directory = SvnUtil.correctRoot(project, file); - if (directory == null) { - return; - } - final RootUrlInfo wcRoot = SvnVcs.getInstance(project).getSvnFileUrlMapping().getWcRootForFilePath(new File(directory.getPath())); + final RootUrlInfo wcRoot = SvnVcs.getInstance(project).getSvnFileUrlMapping().getWcRootForFilePath(VfsUtilCore.virtualToIoFile(file)); if (wcRoot == null) { return; } - final SVNURL rootUrl = wcRoot.getRepositoryUrlUrl(); - if (rootUrl == null) { - Messages.showErrorDialog(project, SvnBundle.message("configure.branches.error.no.connection.title"), - SvnBundle.message("configure.branches.title")); - return; - } SvnBranchConfigurationNew configuration; try { - configuration = SvnBranchConfigurationManager.getInstance(project).get(vcsRoot); + configuration = SvnBranchConfigurationManager.getInstance(project).get(file); } catch (VcsException ex) { Messages.showErrorDialog(project, "Error loading branch configuration: " + ex.getMessage(), @@ -224,18 +212,14 @@ public class BranchConfigurationDialog extends DialogWrapper { } final SvnBranchConfigurationNew clonedConfiguration = configuration.copy(); - BranchConfigurationDialog dlg = new BranchConfigurationDialog(project, clonedConfiguration, rootUrl, vcsRoot, wcRoot.getUrl()); + BranchConfigurationDialog dlg = + new BranchConfigurationDialog(project, clonedConfiguration, wcRoot.getRepositoryUrlUrl(), file, wcRoot.getUrl()); dlg.show(); if (dlg.isOK()) { - SvnBranchConfigurationManager.getInstance(project).setConfiguration(vcsRoot, clonedConfiguration); + SvnBranchConfigurationManager.getInstance(project).setConfiguration(file, clonedConfiguration); } } - private static VirtualFile getRoot(Project project, VirtualFile file) { - RootUrlInfo path = SvnVcs.getInstance(project).getSvnFileUrlMapping().getWcRootForFilePath(new File(file.getPath())); - return path == null ? null : path.getVirtualFile(); - } - private static class MyListModel extends AbstractListModel { private final SvnBranchConfigurationNew myConfiguration; private List myBranchUrls; diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/ConfigureBranchesAction.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/ConfigureBranchesAction.java index 3615c4b4792d..0d65165d05cf 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/ConfigureBranchesAction.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/ConfigureBranchesAction.java @@ -61,6 +61,6 @@ public class ConfigureBranchesAction extends AnAction implements DumbAware { return; } final SvnChangeList svnList = (SvnChangeList) cls[0]; - BranchConfigurationDialog.configureBranches(project, svnList.getRoot(), true); + BranchConfigurationDialog.configureBranches(project, svnList.getRoot()); } } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/CreateBranchOrTagDialog.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/CreateBranchOrTagDialog.java index 95ae986dd72d..37cc859bfbf2 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/CreateBranchOrTagDialog.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/CreateBranchOrTagDialog.java @@ -184,7 +184,7 @@ public class CreateBranchOrTagDialog extends DialogWrapper { }); myBranchTagBaseComboBox.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { - BranchConfigurationDialog.configureBranches(project, mySrcVirtualFile, true); + BranchConfigurationDialog.configureBranches(project, mySrcVirtualFile); updateBranchTagBases(); updateControls(); } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/SelectBranchPopup.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/SelectBranchPopup.java index 445ce4e9afe3..90b7c663da40 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/SelectBranchPopup.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/SelectBranchPopup.java @@ -173,7 +173,7 @@ public class SelectBranchPopup { if (CONFIGURE_MESSAGE.equals(selectedValue)) { return doFinalStep(new Runnable() { public void run() { - BranchConfigurationDialog.configureBranches(myProject, myVcsRoot, true); + BranchConfigurationDialog.configureBranches(myProject, myVcsRoot); } }); } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/CopiesPanel.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/CopiesPanel.java index 1286c88ecb29..d06b67093aa6 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/CopiesPanel.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/CopiesPanel.java @@ -221,7 +221,7 @@ public class CopiesPanel { if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) { if (CONFIGURE_BRANCHES.equals(e.getDescription())) { if (! checkRoot(root, wcInfo.getPath(), " invoke Configure Branches")) return; - BranchConfigurationDialog.configureBranches(myProject, root, true); + BranchConfigurationDialog.configureBranches(myProject, root); } else if (FIX_DEPTH.equals(e.getDescription())) { final int result = Messages.showOkCancelDialog(myVcs.getProject(), "You are going to checkout into '" + wcInfo.getPath() + "' with 'infinity' depth.\n" + From dbaa1c3cf4928af37ecdf9a288b5634ef616a4cf Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Tue, 18 Nov 2014 06:40:00 +0300 Subject: [PATCH 27/48] svn: Refactored BranchConfigurationDialog - explicitly open repository browser for selecting "trunk" on currently used repository url instead of using entered "trunk" value and detecting repository url for it (as browse button is disabled anyway if entered "trunk" value is not child of current repository url) --- .../idea/svn/branchConfig/BranchConfigurationDialog.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/BranchConfigurationDialog.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/BranchConfigurationDialog.java index 0714c6c04c50..dc197605ed5c 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/BranchConfigurationDialog.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/BranchConfigurationDialog.java @@ -81,9 +81,10 @@ public class BranchConfigurationDialog extends DialogWrapper { myTrunkLocationTextField.setText(configuration.getTrunkUrl()); myTrunkLocationTextField.addActionListener(new ActionListener() { public void actionPerformed(final ActionEvent e) { - final String selectedUrl = SelectLocationDialog.selectLocation(project, myTrunkLocationTextField.getText()); - if (selectedUrl != null) { - myTrunkLocationTextField.setText(selectedUrl); + Pair selectionData = SelectLocationDialog.selectLocation(project, rootUrl); + + if (selectionData != null && selectionData.getFirst() != null) { + myTrunkLocationTextField.setText(selectionData.getFirst()); } } }); From 5f123fe920a666d3c910de0c3c52da7e27976a87 Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Tue, 18 Nov 2014 06:47:51 +0300 Subject: [PATCH 28/48] IDEA-103447 Made browse button for selecting "trunk" (during branches configuration) always enabled --- .../idea/svn/branchConfig/BranchConfigurationDialog.java | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/BranchConfigurationDialog.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/BranchConfigurationDialog.java index dc197605ed5c..d157fee66cbd 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/BranchConfigurationDialog.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/BranchConfigurationDialog.java @@ -158,7 +158,6 @@ public class BranchConfigurationDialog extends DialogWrapper { boolean isAncestor = SVNURLUtil.isAncestor(myRootUrl, url); boolean areNotSame = isAncestor && !url.equals(myRootUrl); - myTrunkLocationTextField.getButton().setEnabled(isAncestor); if (areNotSame) { myConfiguration.setTrunkUrl(url.toDecodedString()); } From baf4d5ea3f0a9e15f444e0879c092d39ab1def55 Mon Sep 17 00:00:00 2001 From: "Egor.Ushakov" Date: Tue, 18 Nov 2014 12:27:20 +0300 Subject: [PATCH 29/48] IDEA-24742 When execution point is highlighted using border style instead of color, an extra line is... - fix after review --- .../intellij/openapi/editor/impl/BorderEffect.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/BorderEffect.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/BorderEffect.java index 8f578d2f1cf0..8f7e6ffa4d94 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/BorderEffect.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/BorderEffect.java @@ -131,12 +131,13 @@ public class BorderEffect { int startX = startPoint.x; int startY = startPoint.y; int endX = endPoint.x; + int lineHeight = editor.getLineHeight(); if (height == 0) { int width = endX == startX ? 1 : endX - startX - 1; if (effectType == EffectType.ROUNDED_BOX) { - UIUtil.drawRectPickedOut((Graphics2D)g, startX, startY, width, editor.getLineHeight() - 1); + UIUtil.drawRectPickedOut((Graphics2D)g, startX, startY, width, lineHeight - 1); } else { - g.drawRect(startX, startY, width, editor.getLineHeight() - 1); + g.drawRect(startX, startY, width, lineHeight - 1); } return; } @@ -145,12 +146,12 @@ public class BorderEffect { border.verticalRel(height - 1); border.horizontalTo(endX); if (endX > 0) { - border.verticalRel(editor.getLineHeight()); + border.verticalRel(lineHeight); border.horizontalTo(0); border.verticalRel(-height + 1); } - else { - border.verticalTo(startY + editor.getLineHeight() - 1); + else if (height > lineHeight) { + border.verticalRel(-height + lineHeight + 1); } border.horizontalTo(startX); border.verticalTo(startY); From c29b4bbdc67caa7885d2f2fc12d8299125866474 Mon Sep 17 00:00:00 2001 From: peter Date: Tue, 18 Nov 2014 10:39:34 +0100 Subject: [PATCH 30/48] copyright plugin: don't hold psiFile in invokeLater runnable preventing it to be gc-ed in tests --- .../com/maddyhome/idea/copyright/CopyrightManager.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/copyright/src/com/maddyhome/idea/copyright/CopyrightManager.java b/plugins/copyright/src/com/maddyhome/idea/copyright/CopyrightManager.java index 0305c3764de3..e3828664403f 100644 --- a/plugins/copyright/src/com/maddyhome/idea/copyright/CopyrightManager.java +++ b/plugins/copyright/src/com/maddyhome/idea/copyright/CopyrightManager.java @@ -100,13 +100,13 @@ public class CopyrightManager extends AbstractProjectComponent implements Persis if (module == null) return; if (!newFileTracker.poll(virtualFile)) return; if (!fileTypeUtil.isSupportedFile(virtualFile)) return; - final PsiFile file = psiManager.findFile(virtualFile); - if (file == null) return; + if (psiManager.findFile(virtualFile) == null) return; application.invokeLater(new Runnable() { @Override public void run() { - if (myProject.isDisposed()) return; - if (file.isValid() && file.isWritable()) { + if (!virtualFile.isValid()) return; + final PsiFile file = psiManager.findFile(virtualFile); + if (file != null && file.isWritable()) { final CopyrightProfile opts = getCopyrightOptions(file); if (opts != null) { new UpdateCopyrightProcessor(myProject, module, file).run(); From 5e3b801c04d89f3c20cb9daff8154cc10b5dde32 Mon Sep 17 00:00:00 2001 From: peter Date: Tue, 18 Nov 2014 10:52:18 +0100 Subject: [PATCH 31/48] index consistency fixes * use last committed document stamp for unsaved/uncommitted documents * during psi commit, return psi mod stamp and not the document's one * during multi-tree psi commit, indices should use the main tree's AST content and not the semi-updated parallel trees * consider documents committed after changes in absence of PSI --- .../intellij/index/IndexGeneratedTest.groovy | 60 +++++++++++++++++++ .../testSrc/com/intellij/index/IndexTest.java | 12 +--- .../com/intellij/psi/PsiDocumentManager.java | 9 +++ .../psi/SingleRootFileViewProvider.java | 21 ++++++- .../psi/impl/PsiDocumentManagerBase.java | 23 ++++--- .../intellij/psi/impl/source/PsiFileImpl.java | 1 + .../util/indexing/FileBasedIndexImpl.java | 17 ++---- .../intellij/mock/MockPsiDocumentManager.java | 5 ++ 8 files changed, 115 insertions(+), 33 deletions(-) create mode 100644 java/java-tests/testSrc/com/intellij/index/IndexGeneratedTest.groovy diff --git a/java/java-tests/testSrc/com/intellij/index/IndexGeneratedTest.groovy b/java/java-tests/testSrc/com/intellij/index/IndexGeneratedTest.groovy new file mode 100644 index 000000000000..9bc126f39078 --- /dev/null +++ b/java/java-tests/testSrc/com/intellij/index/IndexGeneratedTest.groovy @@ -0,0 +1,60 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.index +import com.intellij.openapi.command.WriteCommandAction +import com.intellij.openapi.fileEditor.FileDocumentManager +import com.intellij.openapi.vfs.VfsUtil +import com.intellij.psi.JavaPsiFacade +import com.intellij.psi.PsiDocumentManager +import com.intellij.psi.PsiFile +import com.intellij.psi.impl.PsiManagerEx +import com.intellij.psi.search.GlobalSearchScope +import com.intellij.testFramework.PlatformTestUtil +import com.intellij.testFramework.fixtures.JavaCodeInsightFixtureTestCase +import com.intellij.util.TimeoutUtil + +class IndexGeneratedTest extends JavaCodeInsightFixtureTestCase { + protected void invokeTestRunnable(Runnable runnable) { + WriteCommandAction.runWriteCommandAction(project, runnable) + } + + public void "test changing a file without psi makes the document committed and updates index"() { + def psiFile = myFixture.addFileToProject("Foo.java", "class Foo {}") + def vFile = psiFile.virtualFile + def scope = GlobalSearchScope.allScope(project) + + FileDocumentManager.instance.getDocument(vFile).text = "import zoo.Zoo; class Foo1 {}" + assert PsiDocumentManager.getInstance(project).uncommittedDocuments + psiFile = null + + PlatformTestUtil.tryGcSoftlyReachableObjects() + + println 'sleeping' + TimeoutUtil.sleep(10000) + + assert !((PsiManagerEx) psiManager).fileManager.getCachedPsiFile(vFile) + + FileDocumentManager.instance.saveAllDocuments() + + VfsUtil.saveText(vFile, "class Foo3 {}") + + assert !PsiDocumentManager.getInstance(project).uncommittedDocuments + + assert JavaPsiFacade.getInstance(project).findClass("Foo3", scope) + } + + +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/index/IndexTest.java b/java/java-tests/testSrc/com/intellij/index/IndexTest.java index 93130e085e91..9a0b50ff4871 100644 --- a/java/java-tests/testSrc/com/intellij/index/IndexTest.java +++ b/java/java-tests/testSrc/com/intellij/index/IndexTest.java @@ -36,7 +36,6 @@ import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.PsiSearchHelper; import com.intellij.testFramework.PlatformTestUtil; import com.intellij.testFramework.PsiTestUtil; -import com.intellij.testFramework.SkipSlowTestLocally; import com.intellij.util.indexing.MapIndexStorage; import com.intellij.util.indexing.StorageException; import com.intellij.util.io.*; @@ -52,7 +51,6 @@ import java.util.*; * @author Eugene Zhuravlev * Date: Dec 12, 2007 */ -@SkipSlowTestLocally public class IndexTest extends CodeInsightTestCase { public void testUpdate() throws StorageException, IOException { @@ -241,7 +239,7 @@ public class IndexTest extends CodeInsightTestCase { }); } - public void _testCollectedPsiWithDocumentChangedCommittedAndChangedAgain() throws IOException { + public void testCollectedPsiWithDocumentChangedCommittedAndChangedAgain() throws IOException { VirtualFile dir = getVirtualFile(createTempDirectory()); PsiTestUtil.addSourceContentToRoots(myModule, dir); @@ -267,13 +265,7 @@ public class IndexTest extends CodeInsightTestCase { assertNull(((PsiManagerEx)PsiManager.getInstance(getProject())).getFileManager().getCachedPsiFile(vFile)); PsiClass foo = myJavaFacade.findClass("Foo", scope); - assertNotNull(foo); - assertTrue(foo.isValid()); - assertEquals("class Foo {}", foo.getText()); - assertTrue(foo.isValid()); - - PsiDocumentManager.getInstance(myProject).commitAllDocuments(); - assertNull(myJavaFacade.findClass("Foo", scope)); + assertNull(foo); } }); } diff --git a/platform/core-api/src/com/intellij/psi/PsiDocumentManager.java b/platform/core-api/src/com/intellij/psi/PsiDocumentManager.java index d2a7a9aefdbc..d05b11e47de1 100644 --- a/platform/core-api/src/com/intellij/psi/PsiDocumentManager.java +++ b/platform/core-api/src/com/intellij/psi/PsiDocumentManager.java @@ -109,6 +109,15 @@ public abstract class PsiDocumentManager { @NotNull public abstract CharSequence getLastCommittedText(@NotNull Document document); + /** + * @return for uncommitted documents, the last stamp before the document change: the same stamp that current PSI should have. + * For committed documents, just their stamp. + * + * @see Document#getModificationStamp() + * @see FileViewProvider#getModificationStamp() + */ + public abstract long getLastCommittedStamp(@NotNull Document document); + /** * Returns the list of documents which have been modified but not committed. * diff --git a/platform/core-impl/src/com/intellij/psi/SingleRootFileViewProvider.java b/platform/core-impl/src/com/intellij/psi/SingleRootFileViewProvider.java index 63a7f205c11c..6899460bf235 100644 --- a/platform/core-impl/src/com/intellij/psi/SingleRootFileViewProvider.java +++ b/platform/core-impl/src/com/intellij/psi/SingleRootFileViewProvider.java @@ -165,7 +165,6 @@ public class SingleRootFileViewProvider extends UserDataHolderBase implements Fi @Override public void beforeContentsSynchronized() { - unsetPsiContent(); } @Override @@ -501,7 +500,20 @@ public class SingleRootFileViewProvider extends UserDataHolderBase implements Fi @Override public long getModificationStamp() { - return getVirtualFile().getModificationStamp(); + final VirtualFile virtualFile = getVirtualFile(); + if (virtualFile instanceof LightVirtualFile) { + Document doc = getCachedDocument(); + if (doc != null) return getLastCommittedStamp(doc); + return virtualFile.getModificationStamp(); + } + + final Document document = getDocument(); + if (document == null) { + return virtualFile.getModificationStamp(); + } + else { + return getLastCommittedStamp(document); + } } @NonNls @@ -514,6 +526,9 @@ public class SingleRootFileViewProvider extends UserDataHolderBase implements Fi private CharSequence getLastCommittedText(Document document) { return PsiDocumentManager.getInstance(myManager.getProject()).getLastCommittedText(document); } + private long getLastCommittedStamp(Document document) { + return PsiDocumentManager.getInstance(myManager.getProject()).getLastCommittedStamp(document); + } private class DocumentContent implements Content { @NonNls @@ -534,7 +549,7 @@ public class SingleRootFileViewProvider extends UserDataHolderBase implements Fi @Override public long getModificationStamp() { Document document = com.intellij.reference.SoftReference.dereference(myDocument); - if (document != null) return document.getModificationStamp(); + if (document != null) return getLastCommittedStamp(document); return myVirtualFile.getModificationStamp(); } } diff --git a/platform/core-impl/src/com/intellij/psi/impl/PsiDocumentManagerBase.java b/platform/core-impl/src/com/intellij/psi/impl/PsiDocumentManagerBase.java index 9bd52662a5b3..bdc83f8098cb 100644 --- a/platform/core-impl/src/com/intellij/psi/impl/PsiDocumentManagerBase.java +++ b/platform/core-impl/src/com/intellij/psi/impl/PsiDocumentManagerBase.java @@ -34,6 +34,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.FileIndexFacade; import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.Key; +import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.Ref; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; @@ -67,7 +68,7 @@ public abstract class PsiDocumentManagerBase extends PsiDocumentManager implemen private final PsiManager myPsiManager; private final DocumentCommitProcessor myDocumentCommitProcessor; protected final Set myUncommittedDocuments = ContainerUtil.newConcurrentSet(); - private final Map myLastCommittedTexts = ContainerUtil.newConcurrentMap(); + private final Map> myLastCommittedTexts = ContainerUtil.newConcurrentMap(); private volatile boolean myIsCommitInProgress; private final PsiToDocumentSynchronizer mySynchronizer; @@ -558,8 +559,14 @@ public abstract class PsiDocumentManagerBase extends PsiDocumentManager implemen @Override @NotNull public CharSequence getLastCommittedText(@NotNull Document document) { - CharSequence text = myLastCommittedTexts.get(document); - return text != null ? text : document.getImmutableCharSequence(); + Pair pair = myLastCommittedTexts.get(document); + return pair != null ? pair.first : document.getImmutableCharSequence(); + } + + @Override + public long getLastCommittedStamp(@NotNull Document document) { + Pair pair = myLastCommittedTexts.get(document); + return pair != null ? pair.second : document.getModificationStamp(); } @Override @@ -595,7 +602,7 @@ public abstract class PsiDocumentManagerBase extends PsiDocumentManager implemen public void beforeDocumentChange(@NotNull DocumentEvent event) { final Document document = event.getDocument(); if (!(document instanceof DocumentWindow) && !myLastCommittedTexts.containsKey(document)) { - myLastCommittedTexts.put(document, document.getImmutableCharSequence()); + myLastCommittedTexts.put(document, Pair.create(document.getImmutableCharSequence(), document.getModificationStamp())); } VirtualFile virtualFile = FileDocumentManager.getInstance().getFile(document); @@ -713,14 +720,16 @@ public abstract class PsiDocumentManagerBase extends PsiDocumentManager implemen } public void handleCommitWithoutPsi(@NotNull Document document) { - final CharSequence prevText = myLastCommittedTexts.remove(document); - if (prevText == null) { + final Pair prevPair = myLastCommittedTexts.remove(document); + if (prevPair == null) { return; } if (!myProject.isInitialized() || myProject.isDisposed()) { return; } + + myUncommittedDocuments.remove(document); VirtualFile virtualFile = FileDocumentManager.getInstance().getFile(document); if (virtualFile == null || !FileIndexFacade.getInstance(myProject).isInContent(virtualFile)) { @@ -738,7 +747,7 @@ public abstract class PsiDocumentManagerBase extends PsiDocumentManager implemen public void run() { psiFile.getViewProvider().beforeContentsSynchronized(); synchronized (PsiLock.LOCK) { - final int oldLength = prevText.length(); + final int oldLength = prevPair.first.length(); PsiManagerImpl manager = (PsiManagerImpl)psiFile.getManager(); BlockSupportImpl.sendBeforeChildrenChangeEvent(manager, psiFile, true); BlockSupportImpl.sendBeforeChildrenChangeEvent(manager, psiFile, false); diff --git a/platform/core-impl/src/com/intellij/psi/impl/source/PsiFileImpl.java b/platform/core-impl/src/com/intellij/psi/impl/source/PsiFileImpl.java index 12300a2bcf45..cc0be29ae7e3 100644 --- a/platform/core-impl/src/com/intellij/psi/impl/source/PsiFileImpl.java +++ b/platform/core-impl/src/com/intellij/psi/impl/source/PsiFileImpl.java @@ -389,6 +389,7 @@ public abstract class PsiFileImpl extends ElementBase implements PsiFileEx, PsiF DebugUtil.finishPsiModification(); } } + myViewProvider.contentsSynchronized(); } private void clearStub(@NotNull String reason) { diff --git a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java index 989ff0b07105..d8dd50719cf6 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java @@ -1349,9 +1349,6 @@ public class FileBasedIndexImpl extends FileBasedIndex { boolean allDocsProcessed = true; try { for (Document document : documents) { - if (psiBasedIndex && project != null && PsiDocumentManager.getInstance(project).isUncommited(document)) { - continue; - } allDocsProcessed &= indexUnsavedDocument(document, indexId, project, filter, restrictedFile); ProgressManager.checkCanceled(); } @@ -1451,7 +1448,7 @@ public class FileBasedIndexImpl extends FileBasedIndex { return false; } - final PsiFile dominantContentFile = findDominantPsiForDocument(document, project); + final PsiFile dominantContentFile = project == null ? null : findLatestKnownPsiForUncomittedDocument(document, project); final DocumentContent content; if (dominantContentFile != null && dominantContentFile.getViewProvider().getModificationStamp() != document.getModificationStamp()) { @@ -1461,7 +1458,9 @@ public class FileBasedIndexImpl extends FileBasedIndex { content = new AuthenticContent(document); } - final long currentDocStamp = content.getModificationStamp(); + boolean psiBasedIndex = myPsiDependentIndices.contains(requestedIndexId); + + final long currentDocStamp = psiBasedIndex ? PsiDocumentManager.getInstance(project).getLastCommittedStamp(document) : content.getModificationStamp(); final long previousDocStamp = myLastIndexedDocStamps.getAndSet(document, requestedIndexId, currentDocStamp); if (currentDocStamp != previousDocStamp) { final CharSequence contentText = content.getText(); @@ -1509,14 +1508,6 @@ public class FileBasedIndexImpl extends FileBasedIndex { private final TaskQueue myContentlessIndicesUpdateQueue = new TaskQueue(10000); - @Nullable - private PsiFile findDominantPsiForDocument(@NotNull Document document, @Nullable Project project) { - PsiFile psiFile = myTransactionMap.get(document); - if (psiFile != null) return psiFile; - - return project == null ? null : findLatestKnownPsiForUncomittedDocument(document, project); - } - private final StorageGuard myStorageLock = new StorageGuard(); private volatile boolean myPreviousDataBufferingState; private final Object myBufferingStateUpdateLock = new Object(); diff --git a/platform/testFramework/src/com/intellij/mock/MockPsiDocumentManager.java b/platform/testFramework/src/com/intellij/mock/MockPsiDocumentManager.java index 2881d4b4b238..1318032fdcb6 100644 --- a/platform/testFramework/src/com/intellij/mock/MockPsiDocumentManager.java +++ b/platform/testFramework/src/com/intellij/mock/MockPsiDocumentManager.java @@ -62,6 +62,11 @@ public class MockPsiDocumentManager extends PsiDocumentManager { return document.getImmutableCharSequence(); } + @Override + public long getLastCommittedStamp(@NotNull Document document) { + return document.getModificationStamp(); + } + @Override @NotNull public Document[] getUncommittedDocuments() { From 0ff7b0839912b27b2b4c0840de1c234d419d00b6 Mon Sep 17 00:00:00 2001 From: peter Date: Tue, 18 Nov 2014 10:53:07 +0100 Subject: [PATCH 32/48] use less memory for storing parent commits in GraphCommitImpl --- .../vcs/log/graph/GraphCommitImpl.java | 38 +++++++++++++++++-- 1 file changed, 34 insertions(+), 4 deletions(-) diff --git a/platform/vcs-log/graph/src/com/intellij/vcs/log/graph/GraphCommitImpl.java b/platform/vcs-log/graph/src/com/intellij/vcs/log/graph/GraphCommitImpl.java index 99a0337d969f..a8b3dcfc0027 100644 --- a/platform/vcs-log/graph/src/com/intellij/vcs/log/graph/GraphCommitImpl.java +++ b/platform/vcs-log/graph/src/com/intellij/vcs/log/graph/GraphCommitImpl.java @@ -15,20 +15,29 @@ */ package com.intellij.vcs.log.graph; +import com.intellij.util.ArrayUtil; +import com.intellij.util.containers.ImmutableList; import org.jetbrains.annotations.NotNull; import java.util.List; -public class GraphCommitImpl implements GraphCommit { +public class GraphCommitImpl extends ImmutableList implements GraphCommit{ @NotNull private final CommitId myId; - @NotNull private final List myParents; + @NotNull private final Object myParents; private final long myTimestamp; public GraphCommitImpl(@NotNull CommitId id, @NotNull List parents, long timestamp) { myId = id; - myParents = parents; myTimestamp = timestamp; + if (parents.isEmpty()) { + myParents = ArrayUtil.EMPTY_OBJECT_ARRAY; + } else if (parents.size() == 1) { + myParents = parents.get(0); + assert !(myParents instanceof Object[]); + } else { + myParents = parents.toArray(); + } } @NotNull @@ -40,7 +49,28 @@ public class GraphCommitImpl implements GraphCommit { @NotNull @Override public List getParents() { - return myParents; + return this; + } + + @SuppressWarnings("unchecked") + @Override + public CommitId get(int index) { + if (myParents instanceof Object[]) { + Object[] array = (Object[])myParents; + if (index < 0 || index >= array.length) { + throw new ArrayIndexOutOfBoundsException(index); + } + return (CommitId)array[index]; + } + if (index != 0) { + throw new ArrayIndexOutOfBoundsException(index); + } + return (CommitId)myParents; + } + + @Override + public int size() { + return myParents instanceof Object[] ? ((Object[])myParents).length : 1; } @Override From f83ca52d34b4ecc30a1bdf6b287a7cd7b6aaa5e8 Mon Sep 17 00:00:00 2001 From: peter Date: Tue, 18 Nov 2014 10:57:50 +0100 Subject: [PATCH 33/48] run gdsl scripts concurrently --- .../groovy/dsl/GroovyDslFileIndex.java | 81 +++++++------------ 1 file changed, 31 insertions(+), 50 deletions(-) diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/dsl/GroovyDslFileIndex.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/dsl/GroovyDslFileIndex.java index d8a41b52bd86..991425131df9 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/dsl/GroovyDslFileIndex.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/dsl/GroovyDslFileIndex.java @@ -16,18 +16,17 @@ package org.jetbrains.plugins.groovy.dsl; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ex.ApplicationUtil; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.fileEditor.impl.LoadTextUtil; +import com.intellij.openapi.progress.EmptyProgressIndicator; import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectManager; import com.intellij.openapi.roots.ProjectFileIndex; import com.intellij.openapi.roots.ProjectRootManager; -import com.intellij.openapi.util.Key; -import com.intellij.openapi.util.ModificationTracker; -import com.intellij.openapi.util.Pair; -import com.intellij.openapi.util.Trinity; +import com.intellij.openapi.util.*; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; @@ -44,10 +43,9 @@ import com.intellij.psi.util.CachedValueProvider; import com.intellij.psi.util.CachedValuesManager; import com.intellij.psi.util.PsiModificationTracker; import com.intellij.reference.SoftReference; -import com.intellij.util.ConcurrencyUtil; +import com.intellij.util.ExceptionUtil; import com.intellij.util.Function; import com.intellij.util.PathUtil; -import com.intellij.util.concurrency.Semaphore; import com.intellij.util.containers.ConcurrentMultiMap; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.MultiMap; @@ -68,10 +66,7 @@ import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil; import java.io.File; import java.io.IOException; import java.util.*; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicReference; +import java.util.concurrent.*; import java.util.regex.Pattern; /** @@ -89,10 +84,7 @@ public class GroovyDslFileIndex extends ScalarIndexExtension { private static final MultiMap>> filesInProcessing = new ConcurrentMultiMap>>(); - private static final ThreadPoolExecutor ourPool = new ThreadPoolExecutor(0, 1, 10, TimeUnit.SECONDS, new LinkedBlockingQueue(), ConcurrencyUtil.newNamedThreadFactory("Groovy DSL File Index Executor")); - private final EnumeratorStringDescriptor myKeyDescriptor = new EnumeratorStringDescriptor(); - private static final byte[] ENABLED_FLAG = new byte[]{(byte)239}; public GroovyDslFileIndex() { VirtualFileManager.getInstance().addVirtualFileListener(new VirtualFileAdapter() { @@ -296,6 +288,7 @@ public class GroovyDslFileIndex extends ScalarIndexExtension { return SoftReference.dereference(ourStandardScripts); } + @Nullable private static List> getStandardScripts() { List> result = derefStandardScripts(); if (result != null) { @@ -303,28 +296,17 @@ public class GroovyDslFileIndex extends ScalarIndexExtension { } final GroovyFrameworkConfigNotification[] extensions = GroovyFrameworkConfigNotification.EP_NAME.getExtensions(); - - final Semaphore semaphore = new Semaphore(); - semaphore.down(); - final AtomicReference>> ref = new AtomicReference>>(); - - if (ApplicationManager.getApplication().isWriteAccessAllowed()) { - // If this method is called with write lock acquired, then the background computation shouldn't acquire read lock. - // Otherwise, we'll get a deadlock: this method will wait for the result of the background computation holding the write lock - // and the background computation won't finish because of waiting for the read lock. - // Dirty workaround: currently the background computation acquires read lock to only initialize GroovyDslExecutor, - // so, preventive GroovyDslExecutor initialization should help - GroovyDslExecutor.getIdeaVersion(); - } - ourPool.execute(new Runnable() { - @SuppressWarnings("AssignmentToStaticFieldFromInstanceMethod") + Callable>> action = new Callable>>() { @Override - public void run() { + public List> call() throws Exception { + if (GdslUtil.ourGdslStopped) { + return null; + } + try { List> pairs = derefStandardScripts(); if (pairs != null) { - ref.set(pairs); - return; + return pairs; } Set classes = new HashSet(ContainerUtil.map2Set(extensions, new Function() { @@ -365,32 +347,31 @@ public class GroovyDslFileIndex extends ScalarIndexExtension { } } } + //noinspection AssignmentToStaticFieldFromInstanceMethod ourStandardScripts = new SoftReference>>(executors); - ref.set(executors); + return executors; } catch (Throwable e) { - ref.set(new ArrayList>()); //noinspection InstanceofCatchParameter if (e instanceof Error) { GdslUtil.stopGdsl(); } LOG.error(e); - } - finally { - semaphore.up(); + return null; } } - }); + }; - while (true) { - ProgressManager.checkCanceled(); - - if (GdslUtil.ourGdslStopped) { - return Collections.emptyList(); - } - if (ref.get() != null || semaphore.waitFor(20)) { - return ref.get(); + try { + if (ApplicationManager.getApplication().isDispatchThread()) { + return action.call(); } + return ApplicationUtil.runWithCheckCanceled(action, new EmptyProgressIndicator()); + } + catch (Exception e) { + ExceptionUtil.rethrowUnchecked(e); + LOG.error(e); + return null; } } @@ -409,9 +390,10 @@ public class GroovyDslFileIndex extends ScalarIndexExtension { List result = new ArrayList(); List> standardScripts = getStandardScripts(); - assert standardScripts != null; - for (Pair pair : standardScripts) { - result.add(new GroovyDslScript(project, null, pair.second, pair.first.getPath())); + if (standardScripts != null) { + for (Pair pair : standardScripts) { + result.add(new GroovyDslScript(project, null, pair.second, pair.first.getPath())); + } } final LinkedBlockingQueue> queue = @@ -521,8 +503,7 @@ public class GroovyDslFileIndex extends ScalarIndexExtension { final boolean isNewRequest = !filesInProcessing.containsKey(fileUrl); filesInProcessing.putValue(fileUrl, queue); if (isNewRequest) { - ourPool.execute(parseScript); //todo bring back multi-threading when Groovy team fixes http://jira.codehaus.org/browse/GROOVY-4292 - //ApplicationManager.getApplication().executeOnPooledThread(parseScript); + ApplicationManager.getApplication().executeOnPooledThread(parseScript); } } } From 742c300d62d401ea5a4cf1e44fe843957bba9bcd Mon Sep 17 00:00:00 2001 From: peter Date: Tue, 18 Nov 2014 11:03:02 +0100 Subject: [PATCH 34/48] IndexGeneratedTest: no sleep, please --- .../testSrc/com/intellij/index/IndexGeneratedTest.groovy | 3 --- 1 file changed, 3 deletions(-) diff --git a/java/java-tests/testSrc/com/intellij/index/IndexGeneratedTest.groovy b/java/java-tests/testSrc/com/intellij/index/IndexGeneratedTest.groovy index 9bc126f39078..8e06c9bdf5a4 100644 --- a/java/java-tests/testSrc/com/intellij/index/IndexGeneratedTest.groovy +++ b/java/java-tests/testSrc/com/intellij/index/IndexGeneratedTest.groovy @@ -42,9 +42,6 @@ class IndexGeneratedTest extends JavaCodeInsightFixtureTestCase { PlatformTestUtil.tryGcSoftlyReachableObjects() - println 'sleeping' - TimeoutUtil.sleep(10000) - assert !((PsiManagerEx) psiManager).fileManager.getCachedPsiFile(vFile) FileDocumentManager.instance.saveAllDocuments() From 241779162390349ba3a32f6e46d703a7f3a94da4 Mon Sep 17 00:00:00 2001 From: Dennis Ushakov Date: Mon, 17 Nov 2014 17:34:16 +0100 Subject: [PATCH 35/48] get file language from file type to make sure that JS dialects are using JS settings #WEB-14120 fixed --- .../dupLocator/treeHash/NodeSpecificHasherBase.java | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/platform/duplicates-analysis/src/com/intellij/dupLocator/treeHash/NodeSpecificHasherBase.java b/platform/duplicates-analysis/src/com/intellij/dupLocator/treeHash/NodeSpecificHasherBase.java index ef2e92fad8be..7b7553e0293d 100644 --- a/platform/duplicates-analysis/src/com/intellij/dupLocator/treeHash/NodeSpecificHasherBase.java +++ b/platform/duplicates-analysis/src/com/intellij/dupLocator/treeHash/NodeSpecificHasherBase.java @@ -7,8 +7,11 @@ import com.intellij.dupLocator.iterators.SiblingNodeIterator; import com.intellij.dupLocator.util.DuplocatorUtil; import com.intellij.dupLocator.util.NodeFilter; import com.intellij.lang.Language; +import com.intellij.openapi.fileTypes.FileType; +import com.intellij.openapi.fileTypes.LanguageFileType; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiErrorElement; +import com.intellij.psi.PsiFile; import com.intellij.psi.PsiWhiteSpace; import com.intellij.psi.impl.source.tree.LeafElement; import com.intellij.psi.tree.IElementType; @@ -131,7 +134,14 @@ public class NodeSpecificHasherBase extends NodeSpecificHasher { @Override public void visitNode(@NotNull PsiElement node) { - final Language language = node.getLanguage(); + Language language = null; + if (node instanceof PsiFile) { + FileType fileType = ((PsiFile)node).getFileType(); + if (fileType instanceof LanguageFileType) { + language = ((LanguageFileType)fileType).getLanguage(); + } + } + if (language == null) language = node.getLanguage(); if ((myForIndexing || mySettings.SELECTED_PROFILES.contains(language.getDisplayName())) && myDuplicatesProfile.isMyLanguage(language)) { From acfb8f31fae6591e21fcdf00453e15a0393ff948 Mon Sep 17 00:00:00 2001 From: Dennis Ushakov Date: Mon, 17 Nov 2014 18:23:39 +0100 Subject: [PATCH 36/48] use namespace from tag, not empty one #WEB-14165 fixed --- .../html/impl/RelaxedHtmlFromSchemaElementDescriptor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xml/xml-psi-impl/src/com/intellij/html/impl/RelaxedHtmlFromSchemaElementDescriptor.java b/xml/xml-psi-impl/src/com/intellij/html/impl/RelaxedHtmlFromSchemaElementDescriptor.java index 1de12639ca1a..c8cba3f84d0e 100644 --- a/xml/xml-psi-impl/src/com/intellij/html/impl/RelaxedHtmlFromSchemaElementDescriptor.java +++ b/xml/xml-psi-impl/src/com/intellij/html/impl/RelaxedHtmlFromSchemaElementDescriptor.java @@ -36,7 +36,7 @@ public class RelaxedHtmlFromSchemaElementDescriptor extends XmlElementDescriptor } public static XmlAttributeDescriptor[] getCommonAttributeDescriptors(XmlTag context) { - final XmlNSDescriptor nsDescriptor = context != null ? context.getNSDescriptor("", false) : null; + final XmlNSDescriptor nsDescriptor = context != null ? context.getNSDescriptor(context.getNamespace(), false) : null; if (nsDescriptor != null) { for (XmlElementDescriptor descriptor : nsDescriptor.getRootElementsDescriptors(null)) { final String name = descriptor.getName(); From e7eca438c5203048cbde51034cf2da05babf4bd1 Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Mon, 17 Nov 2014 18:25:17 +0300 Subject: [PATCH 37/48] diagnostics --- .../ex/InspectionProfileImpl.java | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/platform/analysis-impl/src/com/intellij/codeInspection/ex/InspectionProfileImpl.java b/platform/analysis-impl/src/com/intellij/codeInspection/ex/InspectionProfileImpl.java index 70577a37ff24..9709dcd8592d 100644 --- a/platform/analysis-impl/src/com/intellij/codeInspection/ex/InspectionProfileImpl.java +++ b/platform/analysis-impl/src/com/intellij/codeInspection/ex/InspectionProfileImpl.java @@ -75,7 +75,7 @@ public class InspectionProfileImpl extends ProfileEx implements ModifiableModel, @TestOnly public static boolean INIT_INSPECTIONS = false; private static Map ourMergers = null; - final InspectionToolRegistrar myRegistrar; + private final InspectionToolRegistrar myRegistrar; @NotNull private final Map myDeinstalledInspectionsSettings; private final ExternalInfo myExternalInfo = new ExternalInfo(); @@ -342,9 +342,9 @@ public class InspectionProfileImpl extends ProfileEx implements ModifiableModel, inspectionElement.setAttribute(CLASS_TAG, toolName); toolList.writeExternal(inspectionElement); - if (areSettingsMerged(toolName, inspectionElement)) continue; - - element.addContent(inspectionElement); + if (!areSettingsMerged(toolName, inspectionElement)) { + element.addContent(inspectionElement); + } } else { element.addContent(toolElement.clone()); @@ -378,13 +378,12 @@ public class InspectionProfileImpl extends ProfileEx implements ModifiableModel, if (mainToolId != null) { InspectionToolWrapper dependentEntryWrapper = getInspectionTool(mainToolId, project); - if (dependentEntryWrapper != null) { - if (!dependentEntries.add(dependentEntryWrapper)) { - collectDependentInspections(dependentEntryWrapper, dependentEntries, project); - } + if (dependentEntryWrapper == null) { + LOG.error("Can't find main tool: '" + mainToolId+"' which was specified in "+toolWrapper); + return; } - else { - LOG.error("Can't find main tool: " + mainToolId); + if (!dependentEntries.add(dependentEntryWrapper)) { + collectDependentInspections(dependentEntryWrapper, dependentEntries, project); } } } @@ -1015,6 +1014,7 @@ public class InspectionProfileImpl extends ProfileEx implements ModifiableModel, } } + @Override @NotNull public String toString() { return mySource == null ? getName() : getName() + " (copy)"; From 2b99690747867498f6af3e61d091eaea09b77632 Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Mon, 17 Nov 2014 18:37:28 +0300 Subject: [PATCH 38/48] EA-58415 --- .../ex/GlobalInspectionContextImpl.java | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ex/GlobalInspectionContextImpl.java b/platform/lang-impl/src/com/intellij/codeInspection/ex/GlobalInspectionContextImpl.java index 400127979dd5..6abcb85c8318 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ex/GlobalInspectionContextImpl.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ex/GlobalInspectionContextImpl.java @@ -60,13 +60,13 @@ import com.intellij.psi.search.LocalSearchScope; import com.intellij.psi.search.SearchScope; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.ui.content.*; +import com.intellij.util.ConcurrencyUtil; import com.intellij.util.Processor; import com.intellij.util.SequentialModalProgressTask; import com.intellij.util.TripleFunction; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.HashMap; import com.intellij.util.ui.UIUtil; -import gnu.trove.THashMap; import gnu.trove.THashSet; import org.jdom.Document; import org.jdom.Element; @@ -78,7 +78,9 @@ import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; +import java.lang.reflect.Constructor; import java.util.*; +import java.util.concurrent.ConcurrentMap; public class GlobalInspectionContextImpl extends GlobalInspectionContextBase implements GlobalInspectionContext { private static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.ex.GlobalInspectionContextImpl"); @@ -592,7 +594,7 @@ public class GlobalInspectionContextImpl extends GlobalInspectionContextBase imp } } - private final Map myPresentationMap = new THashMap(); + private final ConcurrentMap myPresentationMap = ContainerUtil.newConcurrentMap(); @NotNull public InspectionToolPresentation getPresentation(@NotNull InspectionToolWrapper toolWrapper) { InspectionToolPresentation presentation = myPresentationMap.get(toolWrapper); @@ -601,12 +603,15 @@ public class GlobalInspectionContextImpl extends GlobalInspectionContextBase imp DefaultInspectionToolPresentation.class.getName()); try { - presentation = (InspectionToolPresentation)Class.forName(presentationClass).getConstructor(InspectionToolWrapper.class, GlobalInspectionContextImpl.class).newInstance(toolWrapper, this); + Constructor constructor = + Class.forName(presentationClass).getConstructor(InspectionToolWrapper.class, GlobalInspectionContextImpl.class); + presentation = (InspectionToolPresentation)constructor.newInstance(toolWrapper, this); } catch (Exception e) { LOG.error(e); + throw new RuntimeException(e); } - myPresentationMap.put(toolWrapper, presentation); + presentation = ConcurrencyUtil.cacheOrGet(myPresentationMap, toolWrapper, presentation); } return presentation; } From 93bff1331deec52a992bbdc707dd06dfb6fb0b5b Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Mon, 17 Nov 2014 18:48:37 +0300 Subject: [PATCH 39/48] diagnostics --- .../intellij/openapi/components/impl/ComponentManagerImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 df1bfa77a451..ef244898400d 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 @@ -277,7 +277,7 @@ public abstract class ComponentManagerImpl extends UserDataHolderBase implements MutablePicoContainer container = myPicoContainer; if (container == null || myDisposeCompleted) { ProgressManager.checkCanceled(); - throw new AssertionError("Already disposed"); + throw new AssertionError("Already disposed: "+toString()); } return container; } From 0b6091ff71a3ece704dcf5ad5e74b00f76f779a0 Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Mon, 17 Nov 2014 19:08:27 +0300 Subject: [PATCH 40/48] file type test --- .../fileTypes/impl/FileTypeManagerImpl.java | 56 ++++++++++++++++--- ...EnforcedPlaintTextFileTypeManagerTest.java | 2 + .../openapi/fileTypes/impl/FileTypesTest.java | 16 ++++-- 3 files changed, 61 insertions(+), 13 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/fileTypes/impl/FileTypeManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/fileTypes/impl/FileTypeManagerImpl.java index 9b1fd384dfa3..8ccfaf2faac3 100644 --- a/platform/platform-impl/src/com/intellij/openapi/fileTypes/impl/FileTypeManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/fileTypes/impl/FileTypeManagerImpl.java @@ -77,9 +77,11 @@ public class FileTypeManagerImpl extends FileTypeManagerEx implements NamedJDOME private static final int VERSION = 11; private static final Key FILE_TYPE_KEY = Key.create("FILE_TYPE_KEY"); + // cached auto-detected file type. If the file was auto-detected as plain text or binary + // then the value is null and autoDetectedAsText, autoDetectedAsBinary and autoDetectWasRun sets are used instead. private static final Key DETECTED_FROM_CONTENT_FILE_TYPE_KEY = Key.create("DETECTED_FROM_CONTENT_FILE_TYPE_KEY"); private static final int DETECT_BUFFER_SIZE = 8192; // the number of bytes to read from the file to feed to the file type detector - private boolean RE_DETECT_ASYNC = !ApplicationManager.getApplication().isUnitTestMode(); + private static boolean RE_DETECT_ASYNC = !ApplicationManager.getApplication().isUnitTestMode(); private final Set myDefaultTypes = new THashSet(); private final List mySpecialFileTypes = new ArrayList(); @@ -257,6 +259,9 @@ public class FileTypeManagerImpl extends FileTypeManagerEx implements NamedJDOME } }); files.remove(null); + if (toLog()) { + System.out.println("F: VFS events: " + events); + } if (!files.isEmpty() && RE_DETECT_ASYNC) { reDetectQueue.offer(files); } @@ -264,6 +269,10 @@ public class FileTypeManagerImpl extends FileTypeManagerEx implements NamedJDOME }); } + private static boolean toLog() { + return RE_DETECT_ASYNC && ApplicationManager.getApplication().isUnitTestMode(); + } + private final TransferToPooledThreadQueue> reDetectQueue = new TransferToPooledThreadQueue>("File type re-detect", Conditions.alwaysFalse(), -1, new Processor>() { @Override public boolean process(Collection files) { @@ -284,12 +293,20 @@ public class FileTypeManagerImpl extends FileTypeManagerEx implements NamedJDOME private void reDetect(@NotNull Collection files) { final List changed = new ArrayList(); for (VirtualFile file : files) { - if (wasAutoDetectedBefore(file) && isDetectable(file)) { + boolean shouldRedetect = wasAutoDetectedBefore(file) && isDetectable(file); + if (toLog()) { + System.out.println("F: Redetect file: " + file.getName() + "; shouldRedetect: " + shouldRedetect); + } + if (shouldRedetect) { FileType before = file.getFileType(); FileType after = detectFromContent(file); + if (toLog()) { + System.out.println("F: After redetect file: " + file.getName() + "; before: " + before.getName() + "; after: " + after.getName()+"; now getFileType()="+file.getFileType().getName()); + } + if (before != after) { changed.add(file); - LOG.debug(file+" type was re-detected. Was: "+before+"; now: "+after); + LOG.debug(file+" type was re-detected. Was: "+before.getName()+"; now: "+after.getName()); } } } @@ -392,6 +409,9 @@ public class FileTypeManagerImpl extends FileTypeManagerEx implements NamedJDOME public static void cacheFileType(@NotNull VirtualFile file, @Nullable FileType fileType) { file.putUserData(FILE_TYPE_KEY, fileType); + if (toLog()) { + System.out.println("F: Cached file type for "+file.getName()+" to "+(fileType == null ? null : fileType.getName())); + } } @Override @@ -409,12 +429,20 @@ public class FileTypeManagerImpl extends FileTypeManagerEx implements NamedJDOME for (int i = 0; i < mySpecialFileTypes.size(); i++) { FileTypeIdentifiableByVirtualFile type = mySpecialFileTypes.get(i); if (type.isMyFileType(file)) { + if (toLog()) { + System.out.println("F: Special file type for "+file.getName()+"; type: "+type.getName()); + } return type; } } fileType = getFileTypeByFileName(file.getNameSequence()); - if (fileType != UnknownFileType.INSTANCE) return fileType; + if (fileType != UnknownFileType.INSTANCE) { + if (toLog()) { + System.out.println("F: By name file type for "+file.getName()+"; type: "+fileType.getName()); + } + return fileType; + } if (!(file instanceof StubVirtualFile)) { fileType = getOrDetectFromContent(file); @@ -430,8 +458,13 @@ public class FileTypeManagerImpl extends FileTypeManagerEx implements NamedJDOME int id = ((VirtualFileWithId)file).getId(); if (id < 0) return UnknownFileType.INSTANCE; if (autoDetectWasRun.get(id)) { - return autoDetectedAsText.get(id) ? FileTypes.PLAIN_TEXT : autoDetectedAsBinary.get(id) ? UnknownFileType.INSTANCE : - ObjectUtils.notNull(file.getUserData(DETECTED_FROM_CONTENT_FILE_TYPE_KEY), FileTypes.PLAIN_TEXT); + FileType type = autoDetectedAsText.get(id) ? FileTypes.PLAIN_TEXT : + autoDetectedAsBinary.get(id) ? UnknownFileType.INSTANCE : + ObjectUtils.notNull(file.getUserData(DETECTED_FROM_CONTENT_FILE_TYPE_KEY), FileTypes.PLAIN_TEXT); + if (toLog()) { + System.out.println("F: getFileType("+file.getName()+") = "+type.getName()); + } + return type; } boolean wasDetectedAsText = false; boolean wasDetectedAsBinary = false; @@ -465,6 +498,10 @@ public class FileTypeManagerImpl extends FileTypeManagerEx implements NamedJDOME fileType = detectFromContent(file); } + if (toLog()) { + System.out.println("F: getFileType after detect run("+file.getName()+") = "+fileType.getName()); + } + return fileType; } @@ -501,6 +538,7 @@ public class FileTypeManagerImpl extends FileTypeManagerEx implements NamedJDOME autoDetectedAsText.set(id, wasAutodetectedAsText); autoDetectedAsBinary.set(id, wasAutodetectedAsBinary); if (wasAutodetectedAsText || wasAutodetectedAsBinary) { + file.putUserData(DETECTED_FROM_CONTENT_FILE_TYPE_KEY, null); return; } } @@ -535,9 +573,8 @@ public class FileTypeManagerImpl extends FileTypeManagerEx implements NamedJDOME long start = System.currentTimeMillis(); try { final InputStream inputStream = ((FileSystemInterface)file.getFileSystem()).getInputStream(file); - final Ref result; + final Ref result = new Ref(UnknownFileType.INSTANCE); try { - result = new Ref(UnknownFileType.INSTANCE); FileUtil.processFirstBytes(inputStream, DETECT_BUFFER_SIZE, new Processor() { @Override public boolean process(ByteSequence byteSequence) { @@ -574,6 +611,9 @@ public class FileTypeManagerImpl extends FileTypeManagerEx implements NamedJDOME inputStream.close(); } FileType fileType = result.get(); + if (toLog()) { + System.out.println("F: Redetect run for file: " + file.getName() + "; result: "+fileType.getName()); + } if (LOG.isDebugEnabled()) { LOG.debug(file + "; type=" + fileType.getDescription() + "; " + counterAutoDetect); diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/fileTypes/EnforcedPlaintTextFileTypeManagerTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/fileTypes/EnforcedPlaintTextFileTypeManagerTest.java index b7cefc60d1f6..70670acf3097 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/fileTypes/EnforcedPlaintTextFileTypeManagerTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/fileTypes/EnforcedPlaintTextFileTypeManagerTest.java @@ -19,6 +19,7 @@ import com.intellij.openapi.file.exclude.EnforcedPlainTextFileTypeFactory; import com.intellij.openapi.file.exclude.EnforcedPlainTextFileTypeManager; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.testFramework.fixtures.LightPlatformCodeInsightFixtureTestCase; +import com.intellij.util.ui.UIUtil; /** * @author Rustam Vishnyakov @@ -30,6 +31,7 @@ public class EnforcedPlaintTextFileTypeManagerTest extends LightPlatformCodeInsi FileType originalType = file.getFileType(); assertEquals("JAVA", originalType.getName()); manager.markAsPlainText(getProject(), file); + UIUtil.dispatchAllInvocationEvents(); // reparseFiles in invokeLater FileType changedType = file.getFileType(); assertEquals(EnforcedPlainTextFileTypeFactory.ENFORCED_PLAIN_TEXT, changedType.getName()); manager.resetOriginalFileType(getProject(), file); diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/fileTypes/impl/FileTypesTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/fileTypes/impl/FileTypesTest.java index df484cce9a83..2ac2dbe89422 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/fileTypes/impl/FileTypesTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/fileTypes/impl/FileTypesTest.java @@ -278,14 +278,16 @@ public class FileTypesTest extends PlatformTestCase { } public void testReDetectOnContentsChange() throws IOException { - FileType fileType = FileTypeRegistry.getInstance().getFileTypeByFileName("x" + ModuleFileType.DOT_DEFAULT_EXTENSION); + final FileTypeRegistry fileTypeManager = FileTypeRegistry.getInstance(); + assertTrue(fileTypeManager.getClass().getName(), fileTypeManager instanceof FileTypeManagerImpl); + FileType fileType = fileTypeManager.getFileTypeByFileName("x" + ModuleFileType.DOT_DEFAULT_EXTENSION); assertTrue(fileType.toString(), fileType instanceof ModuleFileType); - fileType = FileTypeRegistry.getInstance().getFileTypeByFileName("x" + ProjectFileType.DOT_DEFAULT_EXTENSION); + fileType = fileTypeManager.getFileTypeByFileName("x" + ProjectFileType.DOT_DEFAULT_EXTENSION); assertTrue(fileType.toString(), fileType instanceof ProjectFileType); - FileType module = FileTypeRegistry.getInstance().findFileTypeByName("IDEA_MODULE"); + FileType module = fileTypeManager.findFileTypeByName("IDEA_MODULE"); assertNotNull(module); assertFalse(module.equals(PlainTextFileType.INSTANCE)); - FileType project = FileTypeRegistry.getInstance().findFileTypeByName("IDEA_PROJECT"); + FileType project = fileTypeManager.findFileTypeByName("IDEA_PROJECT"); assertNotNull(project); assertFalse(project.equals(PlainTextFileType.INSTANCE)); @@ -296,7 +298,7 @@ public class FileTypesTest extends PlatformTestCase { public FileType detect(@NotNull VirtualFile file, @NotNull ByteSequence firstBytes, @Nullable CharSequence firstCharsIfText) { detectorCalled.add(file); String text = firstCharsIfText.toString(); - FileType result = text.startsWith("TYPE:") ? FileTypeRegistry.getInstance().findFileTypeByName(StringUtil.trimStart(text, "TYPE:")) : null; + FileType result = text.startsWith("TYPE:") ? fileTypeManager.findFileTypeByName(StringUtil.trimStart(text, "TYPE:")) : null; System.out.println("T: my detector run for "+file.getName()+"; result: "+(result == null ? null : result.getName())); return result; } @@ -308,6 +310,7 @@ public class FileTypesTest extends PlatformTestCase { }; Extensions.getRootArea().getExtensionPoint(FileTypeRegistry.FileTypeDetector.EP_NAME).registerExtension(detector); try { + System.out.println("T: ------"); File d = createTempDirectory(); File f = new File(d, "xx.asfdasdfas"); FileUtil.writeToFile(f, "akjdhfksdjgf"); @@ -315,13 +318,16 @@ public class FileTypesTest extends PlatformTestCase { ensureRedetected(vFile, detectorCalled); assertTrue(vFile.getFileType().toString(), vFile.getFileType() instanceof PlainTextFileType); + System.out.println("T: ------"); VfsUtil.saveText(vFile, "TYPE:IDEA_MODULE"); ensureRedetected(vFile, detectorCalled); assertTrue(vFile.getFileType().toString(), vFile.getFileType() instanceof ModuleFileType); + System.out.println("T: ------"); VfsUtil.saveText(vFile, "TYPE:IDEA_PROJECT"); ensureRedetected(vFile, detectorCalled); assertTrue(vFile.getFileType().toString(), vFile.getFileType() instanceof ProjectFileType); + System.out.println("T: ------"); } finally { Extensions.getRootArea().getExtensionPoint(FileTypeRegistry.FileTypeDetector.EP_NAME).unregisterExtension(detector); From 9c58cac7526cceb613eaf0e37bc3c4faf2bb0d6e Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Tue, 18 Nov 2014 12:33:39 +0300 Subject: [PATCH 41/48] wrong usages of showAndGetOk() --- .../intellij/openapi/ui/DialogWrapper.java | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/platform/platform-api/src/com/intellij/openapi/ui/DialogWrapper.java b/platform/platform-api/src/com/intellij/openapi/ui/DialogWrapper.java index 8273f9dd3463..d429f14c97d9 100644 --- a/platform/platform-api/src/com/intellij/openapi/ui/DialogWrapper.java +++ b/platform/platform-api/src/com/intellij/openapi/ui/DialogWrapper.java @@ -1176,9 +1176,7 @@ public abstract class DialogWrapper { } protected void init() { - if (!SwingUtilities.isEventDispatchThread()) { - LOG.error("Dialog must be init in EDT only: "+Thread.currentThread()); - } + ensureEventDispatchThread(); myErrorText = new ErrorText(); myErrorText.setVisible(false); @@ -1197,7 +1195,7 @@ public abstract class DialogWrapper { final CustomShortcutSet sc = new CustomShortcutSet(SHOW_OPTION_KEYSTROKE); final AnAction toggleShowOptions = new AnAction() { @Override - public void actionPerformed(AnActionEvent e) { + public void actionPerformed(@NotNull AnActionEvent e) { expandNextOptionButton(); } }; @@ -1548,7 +1546,7 @@ public abstract class DialogWrapper { * @throws IllegalStateException if the dialog is invoked not on the event dispatch thread */ public void show() { - showAndGetOk(); + invokeShow(); } public boolean showAndGet() { @@ -1559,16 +1557,23 @@ public abstract class DialogWrapper { /** * You need this method ONLY for NON-MODAL dialogs. Otherwise, use {@link #show()} or {@link #showAndGet()}. * - * @return result callback + * @return result callback which set to "Done" on dialog close, and then its {@code getResult()} will contain {@code isOK()} */ @NotNull public AsyncResult showAndGetOk() { + if (isModal()) { + throw new IllegalStateException("The showAndGetOk() method is for modeless dialogs only"); + } + return invokeShow(); + } + + @NotNull + private AsyncResult invokeShow() { final AsyncResult result = new AsyncResult(); ensureEventDispatchThread(); registerKeyboardShortcuts(); - final Disposable uiParent = Disposer.get("ui"); if (uiParent != null) { // may be null if no app yet (license agreement) Disposer.register(uiParent, myDisposable); // ensure everything is disposed on app quit @@ -1600,7 +1605,6 @@ public abstract class DialogWrapper { } private void registerKeyboardShortcuts() { - final JRootPane rootPane = getRootPane(); if (rootPane == null) return; @@ -2010,7 +2014,7 @@ public abstract class DialogWrapper { */ private static void ensureEventDispatchThread() { if (!EventQueue.isDispatchThread()) { - throw new IllegalStateException("The DialogWrapper can be used only on event dispatch thread."); + throw new IllegalStateException("The DialogWrapper can be used only in event dispatch thread. Current thread: "+Thread.currentThread()); } } @@ -2121,7 +2125,7 @@ public abstract class DialogWrapper { return true; } - public void setValidationInfo(@Nullable ValidationInfo info) { + private void setValidationInfo(@Nullable ValidationInfo info) { myInfo = info; } } From 5bffb5198d7cab684e09a1125b104d61bde43a76 Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Tue, 18 Nov 2014 12:55:19 +0300 Subject: [PATCH 42/48] IDEA-132931 ProgressManager does not cancel all threads running under same WrappedProgressIndicator indicator --- .../progress/impl/ProgressManagerImpl.java | 22 +++++++------- .../progress/impl/ProgressIndicatorTest.java | 29 +++++++++++++++++++ 2 files changed, 39 insertions(+), 12 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/progress/impl/ProgressManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/progress/impl/ProgressManagerImpl.java index 878e60099b50..51f14f8e2bd9 100644 --- a/platform/platform-impl/src/com/intellij/openapi/progress/impl/ProgressManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/progress/impl/ProgressManagerImpl.java @@ -56,7 +56,7 @@ import java.util.concurrent.atomic.AtomicReference; public class ProgressManagerImpl extends ProgressManager implements Disposable { private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.progress.impl.ProgressManagerImpl"); - public static final int CHECK_CANCELED_DELAY_MILLIS = 10; + static final int CHECK_CANCELED_DELAY_MILLIS = 10; private final AtomicInteger myCurrentUnsafeProgressCount = new AtomicInteger(0); private final AtomicInteger myCurrentModalProgressCount = new AtomicInteger(0); @@ -321,19 +321,17 @@ public class ProgressManagerImpl extends ProgressManager implements Disposable { Set threads = threadsUnderIndicator.get(indicator); if (threads != null) { for (Thread thread : threads) { - ProgressIndicator currentIndicator = getCurrentIndicator(thread); - boolean underCancelledIndicator = currentIndicator == indicator; - - if (!underCancelledIndicator && currentIndicator instanceof WrappedProgressIndicator) { - while(currentIndicator instanceof WrappedProgressIndicator) { - ProgressIndicator originalProgressIndicator = ((WrappedProgressIndicator)currentIndicator).getOriginalProgressIndicator(); - if (originalProgressIndicator == indicator) { - underCancelledIndicator = true; - break; - } - currentIndicator = originalProgressIndicator; + boolean underCancelledIndicator = false; + for (ProgressIndicator currentIndicator = getCurrentIndicator(thread); + currentIndicator != null; + currentIndicator = currentIndicator instanceof WrappedProgressIndicator ? + ((WrappedProgressIndicator)currentIndicator).getOriginalProgressIndicator() : null) { + if (currentIndicator == indicator) { + underCancelledIndicator = true; + break; } } + if (underCancelledIndicator) { threadsUnderCanceledIndicator.add(thread); } diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/progress/impl/ProgressIndicatorTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/progress/impl/ProgressIndicatorTest.java index f1884e98875b..5545d44c9d8a 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/progress/impl/ProgressIndicatorTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/progress/impl/ProgressIndicatorTest.java @@ -22,6 +22,7 @@ import com.intellij.openapi.application.ex.ApplicationManagerEx; import com.intellij.openapi.progress.*; import com.intellij.openapi.progress.util.ProgressIndicatorBase; import com.intellij.openapi.progress.util.ProgressIndicatorUtils; +import com.intellij.openapi.progress.util.ProgressWrapper; import com.intellij.openapi.progress.util.ReadTask; import com.intellij.openapi.util.EmptyRunnable; import com.intellij.openapi.wm.ex.ProgressIndicatorEx; @@ -373,6 +374,34 @@ public class ProgressIndicatorTest extends LightPlatformTestCase { }).assertTiming(); } + public void testWrapperIndicatorGotCanceledTooWhenInnerIndicatorHas() { + final ProgressIndicator progress = new ProgressIndicatorBase(){ + @Override + protected boolean isCancelable() { + return true; + } + }; + try { + ProgressManager.getInstance().executeProcessUnderProgress(new Runnable() { + @Override + public void run() { + assertFalse(ProgressManagerImpl.threadsUnderCanceledIndicator.contains(Thread.currentThread())); + assertTrue(!progress.isCanceled()); + progress.cancel(); + assertTrue(ProgressManagerImpl.threadsUnderCanceledIndicator.contains(Thread.currentThread())); + assertTrue(progress.isCanceled()); + while (true) { // wait for PCE + ProgressManager.checkCanceled(); + } + } + }, ProgressWrapper.wrap(progress)); + fail("PCE must have been thrown"); + } + catch (ProcessCanceledException ignored) { + + } + } + private static class ProgressIndicatorStub implements ProgressIndicatorEx { private volatile boolean myCanceled; From 854ad0fd986750fd340397175d7b2e0f70fcaf81 Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Tue, 18 Nov 2014 12:55:32 +0300 Subject: [PATCH 43/48] cleanup --- .../file/exclude/EnforcedPlainTextFileTypeFactory.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/openapi/file/exclude/EnforcedPlainTextFileTypeFactory.java b/platform/lang-impl/src/com/intellij/openapi/file/exclude/EnforcedPlainTextFileTypeFactory.java index 2729a15e40db..d70b45f60f2a 100644 --- a/platform/lang-impl/src/com/intellij/openapi/file/exclude/EnforcedPlainTextFileTypeFactory.java +++ b/platform/lang-impl/src/com/intellij/openapi/file/exclude/EnforcedPlainTextFileTypeFactory.java @@ -51,10 +51,7 @@ public class EnforcedPlainTextFileTypeFactory extends FileTypeFactory { @Override public boolean isMyFileType(@NotNull VirtualFile file) { - if (isMarkedAsPlainText(file)) { - return true; - } - return false; + return isMarkedAsPlainText(file); } @NotNull From 3d7d10faf3f127254676442729a2c2c3685a6a01 Mon Sep 17 00:00:00 2001 From: Alexander Marchuk Date: Tue, 18 Nov 2014 13:47:27 +0300 Subject: [PATCH 44/48] use array Evaluation Expression (now works for dicts, tuples, etc. PY-14421) --- python/helpers/pydev/pydev_console_utils.py | 2 +- python/helpers/pydev/pydevd_comm.py | 6 +++--- .../console/PydevConsoleCommunication.java | 9 +-------- .../debugger/array/AsyncArrayTableModel.java | 2 +- .../debugger/array/NumpyArrayTable.java | 19 +++---------------- 5 files changed, 9 insertions(+), 29 deletions(-) diff --git a/python/helpers/pydev/pydev_console_utils.py b/python/helpers/pydev/pydev_console_utils.py index d12419e19e57..043351587155 100644 --- a/python/helpers/pydev/pydev_console_utils.py +++ b/python/helpers/pydev/pydev_console_utils.py @@ -387,7 +387,7 @@ class BaseInterpreterInterface: def getArray(self, attr, roffset, coffset, rows, cols, format): xml = "" - name = ".".join(attr.split("\t")) + name = attr.split("\t")[-1] array = pydevd_vars.evalInContext(name, self.getNamespace(), self.getNamespace()) if rows == -1 and cols == -1: diff --git a/python/helpers/pydev/pydevd_comm.py b/python/helpers/pydev/pydevd_comm.py index 8b7596d5818c..8f5fea6f0fb2 100644 --- a/python/helpers/pydev/pydevd_comm.py +++ b/python/helpers/pydev/pydevd_comm.py @@ -974,15 +974,15 @@ class InternalGetArray(InternalThreadCommand): self.thread_id = thread_id self.frame_id = frame_id self.scope = scope - self.name = ".".join(attrs.split("\t")) + self.name = attrs.split("\t")[-1] self.attrs = attrs self.roffset = int(roffset) self.coffset = int(coffset) self.rows = int(rows) self.cols = int(cols) self.format = format - if hasattr(self.format, 'decode'): - self.format = self.format.decode('utf-8') + if hasattr(self.format, 'encode'): + self.format = self.format.encode('utf-8') def doIt(self, dbg): try: diff --git a/python/src/com/jetbrains/python/console/PydevConsoleCommunication.java b/python/src/com/jetbrains/python/console/PydevConsoleCommunication.java index 6d237301c293..71cef8164bcd 100644 --- a/python/src/com/jetbrains/python/console/PydevConsoleCommunication.java +++ b/python/src/com/jetbrains/python/console/PydevConsoleCommunication.java @@ -554,14 +554,7 @@ public class PydevConsoleCommunication extends AbstractConsoleCommunication impl throws PyDebuggerException { if (myClient != null) { try { - String fullName = var.getName(); - PyDebugValue child = var; - while (child.getParent() != null) { - child = child.getParent(); - fullName = child.getName() + "\t" + fullName; - } - - Object ret = myClient.execute(GET_ARRAY, new Object[]{fullName, rowOffset, colOffset, rows, cols, format}); + Object ret = myClient.execute(GET_ARRAY, new Object[]{var.getName(), rowOffset, colOffset, rows, cols, format}); if (ret instanceof String) { return ProtocolParser.parseArrayValues((String)ret, this); } diff --git a/python/src/com/jetbrains/python/debugger/array/AsyncArrayTableModel.java b/python/src/com/jetbrains/python/debugger/array/AsyncArrayTableModel.java index 3eb47155d316..c25ef27b6b17 100644 --- a/python/src/com/jetbrains/python/debugger/array/AsyncArrayTableModel.java +++ b/python/src/com/jetbrains/python/debugger/array/AsyncArrayTableModel.java @@ -51,7 +51,7 @@ public class AsyncArrayTableModel extends AbstractTableModel { final PyDebugValue value = myProvider.getDebugValue(); final PyDebugValue slicedValue = new PyDebugValue(myProvider.getSliceText(), value.getType(), value.getValue(), value.isContainer(), value.isErrorOnEval(), - value.getFrameAccessor()); + value.getParent(), value.getFrameAccessor()); ListenableFutureTask task = ListenableFutureTask.create(new Callable() { @Override diff --git a/python/src/com/jetbrains/python/debugger/array/NumpyArrayTable.java b/python/src/com/jetbrains/python/debugger/array/NumpyArrayTable.java index 6a2122e9b7f1..bab68147db79 100644 --- a/python/src/com/jetbrains/python/debugger/array/NumpyArrayTable.java +++ b/python/src/com/jetbrains/python/debugger/array/NumpyArrayTable.java @@ -167,7 +167,7 @@ public class NumpyArrayTable { } public void init() { - init(myValue.getName(), false); + init(getDebugValue().getEvaluationExpression(), false); } public void init(final String slice, final boolean inPlace) { @@ -181,14 +181,8 @@ public class NumpyArrayTable { public void run() { final PyDebugValue value = getDebugValue(); PyDebugValue parent = value.getParent(); - String sl = slice; - - if (slice.contains(".")) { - sl = slice.substring(slice.lastIndexOf(".") + 1); - } - final PyDebugValue slicedValue = - new PyDebugValue(sl, value.getType(), value.getValue(), value.isContainer(), value.isErrorOnEval(), + new PyDebugValue(slice, value.getType(), value.getValue(), value.isContainer(), value.isErrorOnEval(), parent, value.getFrameAccessor()); final String format = getFormat().isEmpty() ? "%" : getFormat(); @@ -433,14 +427,7 @@ public class NumpyArrayTable { } public String getNodeFullName() { - String fullName = getDebugValue().getName(); - PyDebugValue child = getDebugValue(); - while (child.getParent() != null) { - child = child.getParent(); - fullName = child.getName() + "." + fullName; - } - - return fullName; + return getDebugValue().getEvaluationExpression(); } public String getFormat() { From 4037ebe345aea5f69f317094a2e8a035b969d3b3 Mon Sep 17 00:00:00 2001 From: peter Date: Tue, 18 Nov 2014 11:42:34 +0100 Subject: [PATCH 45/48] fixture-based IndexTest --- .../testSrc/com/intellij/index/IndexTest.java | 246 ++++++------------ .../JavaCodeInsightFixtureTestCase.java | 5 +- 2 files changed, 80 insertions(+), 171 deletions(-) diff --git a/java/java-tests/testSrc/com/intellij/index/IndexTest.java b/java/java-tests/testSrc/com/intellij/index/IndexTest.java index 9a0b50ff4871..e88f1692879e 100644 --- a/java/java-tests/testSrc/com/intellij/index/IndexTest.java +++ b/java/java-tests/testSrc/com/intellij/index/IndexTest.java @@ -15,7 +15,6 @@ */ package com.intellij.index; -import com.intellij.codeInsight.CodeInsightTestCase; import com.intellij.openapi.command.WriteCommandAction; import com.intellij.openapi.command.impl.CurrentEditorProvider; import com.intellij.openapi.command.impl.UndoManagerImpl; @@ -27,15 +26,13 @@ import com.intellij.openapi.fileEditor.FileEditorManager; import com.intellij.openapi.fileTypes.PlainTextFileType; import com.intellij.openapi.util.Factory; import com.intellij.openapi.util.io.FileUtil; -import com.intellij.openapi.vfs.VfsUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.newvfs.impl.VirtualFileSystemEntry; import com.intellij.psi.*; -import com.intellij.psi.impl.PsiManagerEx; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.PsiSearchHelper; import com.intellij.testFramework.PlatformTestUtil; -import com.intellij.testFramework.PsiTestUtil; +import com.intellij.testFramework.fixtures.JavaCodeInsightFixtureTestCase; import com.intellij.util.indexing.MapIndexStorage; import com.intellij.util.indexing.StorageException; import com.intellij.util.io.*; @@ -51,7 +48,15 @@ import java.util.*; * @author Eugene Zhuravlev * Date: Dec 12, 2007 */ -public class IndexTest extends CodeInsightTestCase { +public class IndexTest extends JavaCodeInsightFixtureTestCase { + @Override + protected void invokeTestRunnable(@NotNull Runnable runnable) throws Exception { + if ("testUndoToFileContentForUnsavedCommittedDocument".equals(getName())) { + super.invokeTestRunnable(runnable); + } else { + WriteCommandAction.runWriteCommandAction(getProject(), runnable); + } + } public void testUpdate() throws StorageException, IOException { final File storageFile = FileUtil.createTempFile("indextest", "storage"); @@ -115,7 +120,7 @@ public class IndexTest extends CodeInsightTestCase { } } - private PersistentHashMap> createMetaIndex(File metaIndexFile) throws IOException { + private static PersistentHashMap> createMetaIndex(File metaIndexFile) throws IOException { return new PersistentHashMap>(metaIndexFile, new EnumeratorIntegerDescriptor(), new DataExternalizer>() { @Override public void save(@NotNull DataOutput out, Collection value) throws IOException { @@ -137,233 +142,136 @@ public class IndexTest extends CodeInsightTestCase { }); } - /* - public void testStubIndexUnsavedDocumentsIndexing() throws IncorrectOperationException, IOException, StorageException { - IdeaTestUtil.registerExtension(StubIndexExtension.EP_NAME, new TextStubIndexExtension(), getTestRootDisposable()); - IdeaTestUtil.registerExtension(StubIndexExtension.EP_NAME, new ClassNameStubIndexExtension(), getTestRootDisposable()); - FileTypeManager.getInstance().registerFileType(TestFileType.INSTANCE, "fff"); - final FFFLangParserDefinition parserDefinition = new FFFLangParserDefinition(); - LanguageParserDefinitions.INSTANCE.addExplicitExtension(FFFLanguage.INSTANCE, parserDefinition); - - final TestStubElementType stubType = new TestStubElementType(); - SerializationManager.getInstance().registerSerializer(TestStubElement.class, stubType); - - final File fffFile = new File(FileUtil.createTempDirectory("testing", "stubindex"), "MyClass.fff"); - fffFile.createNewFile(); - - final VirtualFile vFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(fffFile); - - assertNotNull(vFile); - assertEquals(TestFileType.INSTANCE, vFile.getFileType()); - - try { - final MockPsiFile psiFile = new MockPsiFile(vFile, MockPsiManager.getInstance(myProject)); - - final MockPsiClass cls = new MockPsiClass("com.company.MyClass"); - psiFile.add(cls); - - final MockPsiMethod aaaMethod = new MockPsiMethod("aaa"); - cls.addMethod(aaaMethod); - final MockPsiMethod bbbMethod = new MockPsiMethod("bbb"); - cls.addMethod(bbbMethod); - - final PsiFileStubImpl fileStub = new PsiFileStubImpl(psiFile); - final TestStubElement clsStub = stubType.createStub(cls, fileStub); - stubType.createStub(aaaMethod, clsStub); - stubType.createStub(bbbMethod, clsStub); - - final ByteArrayOutputStream arrayStream = new ByteArrayOutputStream(); - SerializationManager.getInstance().serialize(fileStub, new DataOutputStream(arrayStream)); - - final FileBasedIndex fbi = FileBasedIndex.getInstance(); - final UpdatableIndex stubUpdatingIndex = fbi.getIndex(StubUpdatingIndex.INDEX_ID); - final MemoryIndexStorage storage = (MemoryIndexStorage)((MapReduceIndex)stubUpdatingIndex).getStorage(); - - // initial - final int fileId = FileBasedIndex.getFileId(vFile); - final byte[] bytes = arrayStream.toByteArray(); - stubUpdatingIndex.update(fileId, new FileContent(vFile, bytes), null); - - final ValueContainer data = stubUpdatingIndex.getData(fileId); - final List trees = data.toValueList(); - - final SerializedStubTree tree = assertOneElement(trees); - - assertTrue(Comparing.equal(bytes, tree.getBytes())); - - final StubElement deserialized = tree.getStub(); - } - finally { - LanguageParserDefinitions.INSTANCE.removeExplicitExtension(FFFLanguage.INSTANCE, parserDefinition); - } - - } - */ - private static void assertDataEquals(List actual, T... expected) { assertTrue(new HashSet(Arrays.asList(expected)).equals(new HashSet(actual))); } public void testCollectedPsiWithChangedDocument() throws IOException { - VirtualFile dir = getVirtualFile(createTempDirectory()); - PsiTestUtil.addSourceContentToRoots(myModule, dir); + final VirtualFile vFile = myFixture.addClass("class Foo {}").getContainingFile().getVirtualFile(); - final VirtualFile vFile = createChildData(dir, "Foo.java"); - VfsUtil.saveText(vFile, "class Foo {}"); + assertNotNull(findClass("Foo")); + PsiFile psiFile = getPsiManager().findFile(vFile); + assertNotNull(psiFile); - final GlobalSearchScope scope = GlobalSearchScope.allScope(getProject()); - assertNotNull(myJavaFacade.findClass("Foo", scope)); - WriteCommandAction.runWriteCommandAction(null, new Runnable() { - @Override - public void run() { - PsiFile psiFile = PsiManager.getInstance(getProject()).findFile(vFile); - assertNotNull(psiFile); + Document document = FileDocumentManager.getInstance().getDocument(vFile); + document.deleteString(0, document.getTextLength()); + assertNotNull(findClass("Foo")); - Document document = FileDocumentManager.getInstance().getDocument(vFile); - document.deleteString(0, document.getTextLength()); - assertNotNull(myJavaFacade.findClass("Foo", scope)); + psiFile = null; + PlatformTestUtil.tryGcSoftlyReachableObjects(); + assertNull(getPsiManager().getFileManager().getCachedPsiFile(vFile)); - psiFile = null; - PlatformTestUtil.tryGcSoftlyReachableObjects(); - assertNull(((PsiManagerEx)PsiManager.getInstance(getProject())).getFileManager().getCachedPsiFile(vFile)); + PsiClass foo = findClass("Foo"); + assertNotNull(foo); + assertTrue(foo.isValid()); + assertEquals("class Foo {}", foo.getText()); + assertTrue(foo.isValid()); - PsiClass foo = myJavaFacade.findClass("Foo", scope); - assertNotNull(foo); - assertTrue(foo.isValid()); - assertEquals("class Foo {}", foo.getText()); - assertTrue(foo.isValid()); - - PsiDocumentManager.getInstance(myProject).commitAllDocuments(); - assertNull(myJavaFacade.findClass("Foo", scope)); - } - }); + PsiDocumentManager.getInstance(getProject()).commitAllDocuments(); + assertNull(findClass("Foo")); } public void testCollectedPsiWithDocumentChangedCommittedAndChangedAgain() throws IOException { - VirtualFile dir = getVirtualFile(createTempDirectory()); - PsiTestUtil.addSourceContentToRoots(myModule, dir); + final VirtualFile vFile = myFixture.addClass("class Foo {}").getContainingFile().getVirtualFile(); - final VirtualFile vFile = createChildData(dir, "Foo.java"); - VfsUtil.saveText(vFile, "class Foo {}"); + assertNotNull(findClass("Foo")); + PsiFile psiFile = getPsiManager().findFile(vFile); + assertNotNull(psiFile); - final GlobalSearchScope scope = GlobalSearchScope.allScope(getProject()); - assertNotNull(myJavaFacade.findClass("Foo", scope)); - WriteCommandAction.runWriteCommandAction(null, new Runnable() { - @Override - public void run() { - PsiFile psiFile = PsiManager.getInstance(getProject()).findFile(vFile); - assertNotNull(psiFile); + Document document = FileDocumentManager.getInstance().getDocument(vFile); + document.deleteString(0, document.getTextLength()); + PsiDocumentManager.getInstance(getProject()).commitAllDocuments(); + document.insertString(0, " "); + //assertNotNull(myJavaFacade.findClass("Foo", scope)); - Document document = FileDocumentManager.getInstance().getDocument(vFile); - document.deleteString(0, document.getTextLength()); - PsiDocumentManager.getInstance(myProject).commitAllDocuments(); - document.insertString(0, " "); - //assertNotNull(myJavaFacade.findClass("Foo", scope)); + psiFile = null; + PlatformTestUtil.tryGcSoftlyReachableObjects(); + assertNull(getPsiManager().getFileManager().getCachedPsiFile(vFile)); - psiFile = null; - PlatformTestUtil.tryGcSoftlyReachableObjects(); - assertNull(((PsiManagerEx)PsiManager.getInstance(getProject())).getFileManager().getCachedPsiFile(vFile)); + PsiClass foo = findClass("Foo"); + assertNull(foo); + } - PsiClass foo = myJavaFacade.findClass("Foo", scope); - assertNull(foo); - } - }); + private PsiClass findClass(String name) { + return JavaPsiFacade.getInstance(getProject()).findClass(name, GlobalSearchScope.allScope(getProject())); } public void testSavedUncommittedDocument() throws IOException { - VirtualFile dir = getVirtualFile(createTempDirectory()); - PsiTestUtil.addSourceContentToRoots(myModule, dir); + final VirtualFile vFile = myFixture.addFileToProject("Foo.java", "").getVirtualFile(); - final VirtualFile vFile = createChildData(dir, "Foo.java"); - VfsUtil.saveText(vFile, ""); + assertNull(findClass("Foo")); + PsiFile psiFile = getPsiManager().findFile(vFile); + assertNotNull(psiFile); - final GlobalSearchScope scope = GlobalSearchScope.allScope(getProject()); - assertNull(myJavaFacade.findClass("Foo", scope)); - WriteCommandAction.runWriteCommandAction(null, new Runnable() { - @Override - public void run() { - PsiFile psiFile = PsiManager.getInstance(getProject()).findFile(vFile); - assertNotNull(psiFile); + long count = getPsiManager().getModificationTracker().getModificationCount(); - long count = PsiManager.getInstance(myProject).getModificationTracker().getModificationCount(); + Document document = FileDocumentManager.getInstance().getDocument(vFile); + document.insertString(0, "class Foo {}"); + FileDocumentManager.getInstance().saveDocument(document); - Document document = FileDocumentManager.getInstance().getDocument(vFile); - document.insertString(0, "class Foo {}"); - FileDocumentManager.getInstance().saveDocument(document); + assertTrue(count == getPsiManager().getModificationTracker().getModificationCount()); + assertNull(findClass("Foo")); - assertTrue(count == PsiManager.getInstance(myProject).getModificationTracker().getModificationCount()); - assertNull(myJavaFacade.findClass("Foo", scope)); - - PsiDocumentManager.getInstance(myProject).commitAllDocuments(); - assertNotNull(myJavaFacade.findClass("Foo", scope)); - assertNotNull(myJavaFacade.findClass("Foo", scope).getText()); - // if Foo exists now, mod count should be different - assertTrue(count != PsiManager.getInstance(myProject).getModificationTracker().getModificationCount()); - } - }); + PsiDocumentManager.getInstance(getProject()).commitAllDocuments(); + assertNotNull(findClass("Foo")); + assertNotNull(findClass("Foo").getText()); + // if Foo exists now, mod count should be different + assertTrue(count != getPsiManager().getModificationTracker().getModificationCount()); } public void testSkipUnknownFileTypes() throws IOException { - VirtualFile dir = getVirtualFile(createTempDirectory()); - PsiTestUtil.addSourceContentToRoots(myModule, dir); - - final VirtualFile vFile = createChildData(dir, "Foo.test"); - VfsUtil.saveText(vFile, "Foo"); + final VirtualFile vFile = myFixture.addFileToProject("Foo.test", "Foo").getVirtualFile(); assertEquals(PlainTextFileType.INSTANCE, vFile.getFileType()); - assertOneElement(PsiSearchHelper.SERVICE.getInstance(myProject).findFilesWithPlainTextWords("Foo")); + final PsiSearchHelper helper = PsiSearchHelper.SERVICE.getInstance(getProject()); + assertOneElement(helper.findFilesWithPlainTextWords("Foo")); final Document document = FileDocumentManager.getInstance().getDocument(vFile); //todo should file type be changed silently without events? //assertEquals(UnknownFileType.INSTANCE, vFile.getFileType()); - final PsiFile file = getPsiFile(document); + final PsiFile file = PsiDocumentManager.getInstance(getProject()).getPsiFile(document); assertInstanceOf(file, PsiPlainTextFile.class); assertEquals("Foo", file.getText()); - assertOneElement(PsiSearchHelper.SERVICE.getInstance(myProject).findFilesWithPlainTextWords("Foo")); + assertOneElement(helper.findFilesWithPlainTextWords("Foo")); - WriteCommandAction.runWriteCommandAction(myProject, new Runnable() { + WriteCommandAction.runWriteCommandAction(getProject(), new Runnable() { @Override public void run() { document.insertString(0, " "); assertEquals("Foo", file.getText()); - assertOneElement(PsiSearchHelper.SERVICE.getInstance(myProject).findFilesWithPlainTextWords("Foo")); + assertOneElement(helper.findFilesWithPlainTextWords("Foo")); FileDocumentManager.getInstance().saveDocument(document); assertEquals("Foo", file.getText()); - assertOneElement(PsiSearchHelper.SERVICE.getInstance(myProject).findFilesWithPlainTextWords("Foo")); + assertOneElement(helper.findFilesWithPlainTextWords("Foo")); - PsiDocumentManager.getInstance(myProject).commitAllDocuments(); + PsiDocumentManager.getInstance(getProject()).commitAllDocuments(); assertEquals(" Foo", file.getText()); - assertOneElement(PsiSearchHelper.SERVICE.getInstance(myProject).findFilesWithPlainTextWords("Foo")); + assertOneElement(helper.findFilesWithPlainTextWords("Foo")); } }); } public void testUndoToFileContentForUnsavedCommittedDocument() throws IOException { - VirtualFile dir = getVirtualFile(createTempDirectory()); - PsiTestUtil.addSourceContentToRoots(myModule, dir); - - final VirtualFile vFile = createChildData(dir, "Foo.java"); - VfsUtil.saveText(vFile, "class Foo {}"); + final VirtualFile vFile = myFixture.addClass("class Foo {}").getContainingFile().getVirtualFile(); ((VirtualFileSystemEntry)vFile).setModificationStamp(0); // as unchanged file final Document document = FileDocumentManager.getInstance().getDocument(vFile); assertTrue(document != null && document.getModificationStamp() == 0); - final GlobalSearchScope scope = GlobalSearchScope.projectScope(myProject); - assertNotNull(myJavaFacade.findClass("Foo", scope)); + assertNotNull(findClass("Foo")); - WriteCommandAction.runWriteCommandAction(myProject, new Runnable() { + WriteCommandAction.runWriteCommandAction(getProject(), new Runnable() { @Override public void run() { document.insertString(0, "import Bar;\n"); - PsiDocumentManager.getInstance(myProject).commitAllDocuments(); - assertNotNull(myJavaFacade.findClass("Foo", scope)); + PsiDocumentManager.getInstance(getProject()).commitAllDocuments(); + assertNotNull(findClass("Foo")); } }); final UndoManager undoManager = UndoManager.getInstance(getProject()); - final FileEditor selectedEditor = FileEditorManager.getInstance(myProject).openFile(vFile, false)[0]; + final FileEditor selectedEditor = FileEditorManager.getInstance(getProject()).openFile(vFile, false)[0]; ((UndoManagerImpl)undoManager).setEditorProvider(new CurrentEditorProvider() { @Override public FileEditor getCurrentEditor() { @@ -375,6 +283,6 @@ public class IndexTest extends CodeInsightTestCase { FileDocumentManager.getInstance().saveDocument(document); undoManager.undo(selectedEditor); - assertNotNull(myJavaFacade.findClass("Foo", scope)); + assertNotNull(findClass("Foo")); } } diff --git a/java/testFramework/src/com/intellij/testFramework/fixtures/JavaCodeInsightFixtureTestCase.java b/java/testFramework/src/com/intellij/testFramework/fixtures/JavaCodeInsightFixtureTestCase.java index 6262638088f6..22a514a3903a 100644 --- a/java/testFramework/src/com/intellij/testFramework/fixtures/JavaCodeInsightFixtureTestCase.java +++ b/java/testFramework/src/com/intellij/testFramework/fixtures/JavaCodeInsightFixtureTestCase.java @@ -21,6 +21,7 @@ import com.intellij.openapi.project.Project; import com.intellij.psi.JavaPsiFacade; import com.intellij.psi.PsiElementFactory; import com.intellij.psi.PsiManager; +import com.intellij.psi.impl.PsiManagerEx; import com.intellij.testFramework.IdeaTestCase; import com.intellij.testFramework.UsefulTestCase; import com.intellij.testFramework.builders.JavaModuleFixtureBuilder; @@ -105,8 +106,8 @@ public abstract class JavaCodeInsightFixtureTestCase extends UsefulTestCase{ return myFixture.getProject(); } - protected PsiManager getPsiManager() { - return PsiManager.getInstance(getProject()); + protected PsiManagerEx getPsiManager() { + return (PsiManagerEx)PsiManager.getInstance(getProject()); } public PsiElementFactory getElementFactory() { From 8cb24d9b5c9e05ae36124c94a3c11d39feb6277c Mon Sep 17 00:00:00 2001 From: peter Date: Tue, 18 Nov 2014 11:44:52 +0100 Subject: [PATCH 46/48] IndexTest -> groovy --- .../{IndexTest.java => IndexTest.groovy} | 60 ++++++++----------- 1 file changed, 26 insertions(+), 34 deletions(-) rename java/java-tests/testSrc/com/intellij/index/{IndexTest.java => IndexTest.groovy} (89%) diff --git a/java/java-tests/testSrc/com/intellij/index/IndexTest.java b/java/java-tests/testSrc/com/intellij/index/IndexTest.groovy similarity index 89% rename from java/java-tests/testSrc/com/intellij/index/IndexTest.java rename to java/java-tests/testSrc/com/intellij/index/IndexTest.groovy index e88f1692879e..ed1efa093b33 100644 --- a/java/java-tests/testSrc/com/intellij/index/IndexTest.java +++ b/java/java-tests/testSrc/com/intellij/index/IndexTest.groovy @@ -13,37 +13,29 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.intellij.index; - -import com.intellij.openapi.command.WriteCommandAction; -import com.intellij.openapi.command.impl.CurrentEditorProvider; -import com.intellij.openapi.command.impl.UndoManagerImpl; -import com.intellij.openapi.command.undo.UndoManager; -import com.intellij.openapi.editor.Document; -import com.intellij.openapi.fileEditor.FileDocumentManager; -import com.intellij.openapi.fileEditor.FileEditor; -import com.intellij.openapi.fileEditor.FileEditorManager; -import com.intellij.openapi.fileTypes.PlainTextFileType; -import com.intellij.openapi.util.Factory; -import com.intellij.openapi.util.io.FileUtil; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.openapi.vfs.newvfs.impl.VirtualFileSystemEntry; -import com.intellij.psi.*; -import com.intellij.psi.search.GlobalSearchScope; -import com.intellij.psi.search.PsiSearchHelper; -import com.intellij.testFramework.PlatformTestUtil; -import com.intellij.testFramework.fixtures.JavaCodeInsightFixtureTestCase; -import com.intellij.util.indexing.MapIndexStorage; -import com.intellij.util.indexing.StorageException; -import com.intellij.util.io.*; -import org.jetbrains.annotations.NotNull; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.File; -import java.io.IOException; -import java.util.*; - +package com.intellij.index +import com.intellij.openapi.command.WriteCommandAction +import com.intellij.openapi.command.impl.CurrentEditorProvider +import com.intellij.openapi.command.impl.UndoManagerImpl +import com.intellij.openapi.command.undo.UndoManager +import com.intellij.openapi.editor.Document +import com.intellij.openapi.fileEditor.FileDocumentManager +import com.intellij.openapi.fileEditor.FileEditor +import com.intellij.openapi.fileEditor.FileEditorManager +import com.intellij.openapi.fileTypes.PlainTextFileType +import com.intellij.openapi.util.Factory +import com.intellij.openapi.util.io.FileUtil +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.openapi.vfs.newvfs.impl.VirtualFileSystemEntry +import com.intellij.psi.* +import com.intellij.psi.search.GlobalSearchScope +import com.intellij.psi.search.PsiSearchHelper +import com.intellij.testFramework.PlatformTestUtil +import com.intellij.testFramework.fixtures.JavaCodeInsightFixtureTestCase +import com.intellij.util.indexing.MapIndexStorage +import com.intellij.util.indexing.StorageException +import com.intellij.util.io.* +import org.jetbrains.annotations.NotNull /** * @author Eugene Zhuravlev * Date: Dec 12, 2007 @@ -131,11 +123,11 @@ public class IndexTest extends JavaCodeInsightFixtureTestCase { } @Override - public Collection read(@NotNull DataInput in) throws IOException { - final int size = DataInputOutputUtil.readINT(in); + public Collection read(@NotNull DataInput _in) throws IOException { + final int size = DataInputOutputUtil.readINT(_in); final List list = new ArrayList(); for (int idx = 0; idx < size; idx++) { - list.add(in.readUTF()); + list.add(_in.readUTF()); } return list; } From 43dfc060abaeddcfdc42809eeaee0b88ae0a1848 Mon Sep 17 00:00:00 2001 From: peter Date: Tue, 18 Nov 2014 11:47:49 +0100 Subject: [PATCH 47/48] merge IndexGeneratedTest into IndexTest --- .../intellij/index/IndexGeneratedTest.groovy | 57 ------------------- .../com/intellij/index/IndexTest.groovy | 25 ++++++++ .../intellij/index/IndexTestGenerator.scala | 7 ++- 3 files changed, 30 insertions(+), 59 deletions(-) delete mode 100644 java/java-tests/testSrc/com/intellij/index/IndexGeneratedTest.groovy diff --git a/java/java-tests/testSrc/com/intellij/index/IndexGeneratedTest.groovy b/java/java-tests/testSrc/com/intellij/index/IndexGeneratedTest.groovy deleted file mode 100644 index 8e06c9bdf5a4..000000000000 --- a/java/java-tests/testSrc/com/intellij/index/IndexGeneratedTest.groovy +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2000-2014 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.intellij.index -import com.intellij.openapi.command.WriteCommandAction -import com.intellij.openapi.fileEditor.FileDocumentManager -import com.intellij.openapi.vfs.VfsUtil -import com.intellij.psi.JavaPsiFacade -import com.intellij.psi.PsiDocumentManager -import com.intellij.psi.PsiFile -import com.intellij.psi.impl.PsiManagerEx -import com.intellij.psi.search.GlobalSearchScope -import com.intellij.testFramework.PlatformTestUtil -import com.intellij.testFramework.fixtures.JavaCodeInsightFixtureTestCase -import com.intellij.util.TimeoutUtil - -class IndexGeneratedTest extends JavaCodeInsightFixtureTestCase { - protected void invokeTestRunnable(Runnable runnable) { - WriteCommandAction.runWriteCommandAction(project, runnable) - } - - public void "test changing a file without psi makes the document committed and updates index"() { - def psiFile = myFixture.addFileToProject("Foo.java", "class Foo {}") - def vFile = psiFile.virtualFile - def scope = GlobalSearchScope.allScope(project) - - FileDocumentManager.instance.getDocument(vFile).text = "import zoo.Zoo; class Foo1 {}" - assert PsiDocumentManager.getInstance(project).uncommittedDocuments - psiFile = null - - PlatformTestUtil.tryGcSoftlyReachableObjects() - - assert !((PsiManagerEx) psiManager).fileManager.getCachedPsiFile(vFile) - - FileDocumentManager.instance.saveAllDocuments() - - VfsUtil.saveText(vFile, "class Foo3 {}") - - assert !PsiDocumentManager.getInstance(project).uncommittedDocuments - - assert JavaPsiFacade.getInstance(project).findClass("Foo3", scope) - } - - -} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/index/IndexTest.groovy b/java/java-tests/testSrc/com/intellij/index/IndexTest.groovy index ed1efa093b33..64492f94d62a 100644 --- a/java/java-tests/testSrc/com/intellij/index/IndexTest.groovy +++ b/java/java-tests/testSrc/com/intellij/index/IndexTest.groovy @@ -25,9 +25,11 @@ import com.intellij.openapi.fileEditor.FileEditorManager import com.intellij.openapi.fileTypes.PlainTextFileType import com.intellij.openapi.util.Factory import com.intellij.openapi.util.io.FileUtil +import com.intellij.openapi.vfs.VfsUtil import com.intellij.openapi.vfs.VirtualFile import com.intellij.openapi.vfs.newvfs.impl.VirtualFileSystemEntry import com.intellij.psi.* +import com.intellij.psi.impl.PsiManagerEx import com.intellij.psi.search.GlobalSearchScope import com.intellij.psi.search.PsiSearchHelper import com.intellij.testFramework.PlatformTestUtil @@ -277,4 +279,27 @@ public class IndexTest extends JavaCodeInsightFixtureTestCase { assertNotNull(findClass("Foo")); } + + public void "test changing a file without psi makes the document committed and updates index"() { + def psiFile = myFixture.addFileToProject("Foo.java", "class Foo {}") + def vFile = psiFile.virtualFile + def scope = GlobalSearchScope.allScope(project) + + FileDocumentManager.instance.getDocument(vFile).text = "import zoo.Zoo; class Foo1 {}" + assert PsiDocumentManager.getInstance(project).uncommittedDocuments + psiFile = null + + PlatformTestUtil.tryGcSoftlyReachableObjects() + + assert !((PsiManagerEx) psiManager).fileManager.getCachedPsiFile(vFile) + + FileDocumentManager.instance.saveAllDocuments() + + VfsUtil.saveText(vFile, "class Foo3 {}") + + assert !PsiDocumentManager.getInstance(project).uncommittedDocuments + + assert JavaPsiFacade.getInstance(project).findClass("Foo3", scope) + } + } diff --git a/java/java-tests/testSrc/com/intellij/index/IndexTestGenerator.scala b/java/java-tests/testSrc/com/intellij/index/IndexTestGenerator.scala index ae6727bd9928..98d0268adfba 100644 --- a/java/java-tests/testSrc/com/intellij/index/IndexTestGenerator.scala +++ b/java/java-tests/testSrc/com/intellij/index/IndexTestGenerator.scala @@ -25,8 +25,11 @@ import org.scalacheck._ import scala.collection.JavaConversions._ /** - * Run this class to generate randomized tests for IDEA VFS/document/PSI/index subsystem interaction using ScalaCheck. - * When a test fails, a test method code (in Groovy) is printed which should be copied to a normal test class and debugged there. + * Run this class to generate randomized tests for IDEA VFS/document/PSI/index subsystem interaction using ScalaCheck.

+ * + * When a test fails, a test method code (in Groovy) is printed which should be copied to a normal test class (IndexTest) + * and debugged there.

+ * * The generated test may contain some excessive declarations and checks that should be corrected manually. * After the fix, that generated test should be renamed according to the underlying issue it found and committed to the repository. * From ea8a4bf27ffe18543119051c32b7c04b552522e1 Mon Sep 17 00:00:00 2001 From: "Egor.Ushakov" Date: Tue, 18 Nov 2014 14:00:17 +0300 Subject: [PATCH 48/48] IDEA-75013 Create "Duplicate" (Ctrl+D) action for watch expression --- .../impl/frame/XWatchesViewImpl.java | 3 ++ .../frame/actions/XDuplicateWatchAction.java | 45 +++++++++++++++++++ .../frame/actions/XWatchesTreeActionBase.java | 1 + 3 files changed, 49 insertions(+) create mode 100644 platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/actions/XDuplicateWatchAction.java diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XWatchesViewImpl.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XWatchesViewImpl.java index 8b94e2c4858a..a1d9e1ef39aa 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XWatchesViewImpl.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XWatchesViewImpl.java @@ -40,6 +40,7 @@ import com.intellij.xdebugger.frame.XStackFrame; import com.intellij.xdebugger.impl.XDebugSessionImpl; import com.intellij.xdebugger.impl.actions.XDebuggerActions; import com.intellij.xdebugger.impl.breakpoints.XExpressionImpl; +import com.intellij.xdebugger.impl.frame.actions.XDuplicateWatchAction; import com.intellij.xdebugger.impl.ui.XDebugSessionData; import com.intellij.xdebugger.impl.ui.XDebugSessionTab; import com.intellij.xdebugger.impl.ui.tree.XDebuggerTree; @@ -88,6 +89,8 @@ public class XWatchesViewImpl extends XDebugView implements DnDNativeTarget, XWa CustomShortcutSet f2Shortcut = new CustomShortcutSet(KeyStroke.getKeyStroke(KeyEvent.VK_F2, 0)); actionManager.getAction(XDebuggerActions.XEDIT_WATCH).registerCustomShortcutSet(f2Shortcut, tree); + new XDuplicateWatchAction().registerCustomShortcutSet(ActionManager.getInstance().getAction(IdeActions.ACTION_EDITOR_DUPLICATE).getShortcutSet(), tree); + DnDManager.getInstance().registerTarget(this, tree); myRootNode = new WatchesRootNode(tree, this, session.getSessionData().getWatchExpressions()); tree.setRoot(myRootNode, false); diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/actions/XDuplicateWatchAction.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/actions/XDuplicateWatchAction.java new file mode 100644 index 000000000000..d29545d3deaf --- /dev/null +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/actions/XDuplicateWatchAction.java @@ -0,0 +1,45 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.xdebugger.impl.frame.actions; + +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.xdebugger.impl.frame.XWatchesView; +import com.intellij.xdebugger.impl.ui.tree.XDebuggerTree; +import com.intellij.xdebugger.impl.ui.tree.nodes.WatchNode; +import com.intellij.xdebugger.impl.ui.tree.nodes.XDebuggerTreeNode; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +/** + * @author 1 + */ +public class XDuplicateWatchAction extends XWatchesTreeActionBase { + + protected boolean isEnabled(@NotNull final AnActionEvent e, @NotNull XDebuggerTree tree) { + return !getSelectedNodes(tree, WatchNode.class).isEmpty(); + } + + @Override + protected void perform(@NotNull AnActionEvent e, @NotNull XDebuggerTree tree, @NotNull XWatchesView watchesView) { + XDebuggerTreeNode root = tree.getRoot(); + List nodes = getSelectedNodes(tree, WatchNode.class); + for (WatchNode node : nodes) { + int index = root.getIndex(node); + watchesView.addWatchExpression(node.getExpression(), index + 1, true); + } + } +} diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/actions/XWatchesTreeActionBase.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/actions/XWatchesTreeActionBase.java index e35ab54f1fe5..297d66a4f55a 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/actions/XWatchesTreeActionBase.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/actions/XWatchesTreeActionBase.java @@ -30,6 +30,7 @@ import java.util.List; * @author nik */ public abstract class XWatchesTreeActionBase extends AnAction { + @NotNull protected static List getSelectedNodes(final @NotNull XDebuggerTree tree, Class nodeClass) { List list = new ArrayList(); TreePath[] selectionPaths = tree.getSelectionPaths();