diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/JavaDebugProcess.java b/java/debugger/impl/src/com/intellij/debugger/engine/JavaDebugProcess.java index 50500c3864a7..09898a068e3a 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/JavaDebugProcess.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/JavaDebugProcess.java @@ -78,7 +78,7 @@ public class JavaDebugProcess extends XDebugProcess { return res; } - private JavaDebugProcess(@NotNull final XDebugSession session, final DebuggerSession javaSession) { + protected JavaDebugProcess(@NotNull final XDebugSession session, final DebuggerSession javaSession) { super(session); myJavaSession = javaSession; myEditorsProvider = new JavaDebuggerEditorsProvider(); diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/requests/RequestManagerImpl.java b/java/debugger/impl/src/com/intellij/debugger/engine/requests/RequestManagerImpl.java index 58296e2b7273..bf071e7b6ff1 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/requests/RequestManagerImpl.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/requests/RequestManagerImpl.java @@ -29,6 +29,7 @@ import com.intellij.debugger.requests.Requestor; import com.intellij.debugger.settings.DebuggerSettings; import com.intellij.debugger.ui.breakpoints.Breakpoint; import com.intellij.debugger.ui.breakpoints.FilteredRequestor; +import com.intellij.diagnostic.ThreadDumper; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; @@ -37,7 +38,6 @@ import com.intellij.openapi.util.Key; import com.intellij.psi.PsiClass; import com.intellij.ui.classFilter.ClassFilter; import com.intellij.util.containers.HashMap; -import com.intellij.xdebugger.XDebugSession; import com.sun.jdi.*; import com.sun.jdi.event.ClassPrepareEvent; import com.sun.jdi.request.*; @@ -287,7 +287,11 @@ public class RequestManagerImpl extends DebugProcessAdapterImpl implements Reque } } } - myEventRequestManager.deleteEventRequest(request); + try { + myEventRequestManager.deleteEventRequest(request); + } catch (Exception e) { + LOG.error("Exception in EventRequestManager.deleteEventRequest", e, ThreadDumper.dumpThreadsToString()); + } } catch (InvalidRequestStateException ignored) { // request is already deleted diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/deadCode/UnusedDeclarationInspectionBase.java b/java/java-analysis-impl/src/com/intellij/codeInspection/deadCode/UnusedDeclarationInspectionBase.java index 7a1f4e0979f7..95d10660076b 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/deadCode/UnusedDeclarationInspectionBase.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/deadCode/UnusedDeclarationInspectionBase.java @@ -37,6 +37,7 @@ import com.intellij.codeInspection.ex.JobDescriptor; import com.intellij.codeInspection.reference.*; import com.intellij.codeInspection.unusedSymbol.UnusedSymbolLocalInspectionBase; import com.intellij.codeInspection.util.RefFilter; +import com.intellij.ide.highlighter.JavaFileType; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.extensions.ExtensionPoint; @@ -44,12 +45,16 @@ import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.InvalidDataException; +import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.WriteExternalException; +import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; import com.intellij.psi.impl.PsiClassImplUtil; +import com.intellij.psi.search.DelegatingGlobalSearchScope; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.PsiNonJavaFileReferenceProcessor; import com.intellij.psi.search.PsiSearchHelper; +import com.intellij.psi.search.searches.ReferencesSearch; import com.intellij.psi.util.PsiMethodUtil; import com.intellij.util.containers.HashMap; import org.jdom.Element; @@ -309,8 +314,9 @@ public class UnusedDeclarationInspectionBase extends GlobalInspectionTool { ProgressManager.getInstance().runProcess(new Runnable() { @Override public void run() { - final PsiSearchHelper helper = PsiSearchHelper.SERVICE.getInstance(globalContext.getRefManager().getProject()); - globalContext.getRefManager().iterate(new RefJavaVisitor() { + final RefManager refManager = globalContext.getRefManager(); + final PsiSearchHelper helper = PsiSearchHelper.SERVICE.getInstance(refManager.getProject()); + refManager.iterate(new RefJavaVisitor() { @Override public void visitElement(@NotNull final RefEntity refEntity) { if (refEntity instanceof RefClass && strictUnreferencedFilter.accepts((RefClass)refEntity)) { @@ -325,18 +331,36 @@ public class UnusedDeclarationInspectionBase extends GlobalInspectionTool { } private void findExternalClassReferences(final RefClass refElement) { - PsiClass psiClass = refElement.getElement(); - String qualifiedName = psiClass.getQualifiedName(); + final PsiClass psiClass = refElement.getElement(); + String qualifiedName = psiClass != null ? psiClass.getQualifiedName() : null; if (qualifiedName != null) { - helper.processUsagesInNonJavaFiles(qualifiedName, - new PsiNonJavaFileReferenceProcessor() { - @Override - public boolean process(PsiFile file, int startOffset, int endOffset) { - getEntryPointsManager().addEntryPoint(refElement, false); - return false; - } - }, - GlobalSearchScope.projectScope(globalContext.getProject())); + final GlobalSearchScope projectScope = GlobalSearchScope.projectScope(globalContext.getProject()); + final PsiNonJavaFileReferenceProcessor processor = new PsiNonJavaFileReferenceProcessor() { + @Override + public boolean process(PsiFile file, int startOffset, int endOffset) { + getEntryPointsManager().addEntryPoint(refElement, false); + return false; + } + }; + final DelegatingGlobalSearchScope globalSearchScope = new DelegatingGlobalSearchScope(projectScope) { + @Override + public boolean contains(@NotNull VirtualFile file) { + return file.getFileType() != JavaFileType.INSTANCE && super.contains(file); + } + }; + + if (helper.processUsagesInNonJavaFiles(qualifiedName, processor, globalSearchScope)) { + final PsiReference reference = ReferencesSearch.search(psiClass, globalSearchScope).findFirst(); + if (reference != null) { + getEntryPointsManager().addEntryPoint(refElement, false); + for (PsiMethod method : psiClass.getMethods()) { + final RefElement refMethod = refManager.getReference(method); + if (refMethod != null) { + getEntryPointsManager().addEntryPoint(refMethod, false); + } + } + } + } } } }); diff --git a/java/java-tests/testData/psi/autodetect/notIndentedComment.java b/java/java-tests/testData/psi/autodetect/notIndentedComment.java new file mode 100644 index 000000000000..70537a3b96c3 --- /dev/null +++ b/java/java-tests/testData/psi/autodetect/notIndentedComment.java @@ -0,0 +1,24 @@ +import java.lang.System; + +public class MyOwn { + + public void run() { + int a = 2; +// my super comment + + int c = 3; + Runnable a = null; + System.out.println("Hello!"); + c += 3; + int re = 12; + re += 1; + c = re + c; + int q; + q = c * re + c; + c = q * 11 - 167; + System.out.println("Testing!"); + System.out.println("Hello!"); + c += 3; + } + +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/psi/autodetect/JavaAutoDetectIndentTest.java b/java/java-tests/testSrc/com/intellij/psi/autodetect/JavaAutoDetectIndentTest.java new file mode 100644 index 000000000000..e3600a290bea --- /dev/null +++ b/java/java-tests/testSrc/com/intellij/psi/autodetect/JavaAutoDetectIndentTest.java @@ -0,0 +1,39 @@ +/* + * 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.psi.autodetect; + +import com.intellij.JavaTestUtil; +import org.jetbrains.annotations.NotNull; + +public class JavaAutoDetectIndentTest extends AbstractIndentAutoDetectionTest { + + @NotNull + @Override + protected String getFileNameWithExtension() { + return getTestName(true) + ".java"; + } + + @NotNull + @Override + protected String getTestDataPath() { + return JavaTestUtil.getJavaTestDataPath() + + "/psi/autodetect/"; + } + + public void testNotIndentedComment() { + doTestIndentSize(3); + } +} 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 66117c140f79..80352b7c0a13 100644 --- a/platform/core-impl/src/com/intellij/psi/impl/PsiDocumentManagerBase.java +++ b/platform/core-impl/src/com/intellij/psi/impl/PsiDocumentManagerBase.java @@ -282,10 +282,10 @@ public abstract class PsiDocumentManagerBase extends PsiDocumentManager implemen } } - public boolean finishCommit(@NotNull final Document document, - @NotNull final List> finishProcessors, - final boolean synchronously, - @NotNull final Object reason) { + boolean finishCommit(@NotNull final Document document, + @NotNull final List> finishProcessors, + final boolean synchronously, + @NotNull final Object reason) { assert !myProject.isDisposed() : "Already disposed"; final boolean[] ok = {true}; ApplicationManager.getApplication().runWriteAction(new CommitToPsiFileAction(document, myProject) { 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 bdbbc364aa60..12300a2bcf45 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 @@ -759,17 +759,17 @@ public abstract class PsiFileImpl extends ElementBase implements PsiFileEx, PsiF @Override public PsiElement getFirstChild() { - return SharedImplUtil.getFirstChild(calcTreeElement()); + return SharedImplUtil.getFirstChild(getNode()); } @Override public PsiElement getLastChild() { - return SharedImplUtil.getLastChild(calcTreeElement()); + return SharedImplUtil.getLastChild(getNode()); } @Override public void acceptChildren(@NotNull PsiElementVisitor visitor) { - SharedImplUtil.acceptChildren(visitor, calcTreeElement()); + SharedImplUtil.acceptChildren(visitor, getNode()); } @Override diff --git a/platform/core-impl/src/com/intellij/psi/impl/source/resolve/ResolveCache.java b/platform/core-impl/src/com/intellij/psi/impl/source/resolve/ResolveCache.java index 4f2e44371b79..c2d54cca3302 100644 --- a/platform/core-impl/src/com/intellij/psi/impl/source/resolve/ResolveCache.java +++ b/platform/core-impl/src/com/intellij/psi/impl/source/resolve/ResolveCache.java @@ -128,7 +128,9 @@ public class ResolveCache { boolean isPoly, boolean isPhysical) { ProgressIndicatorProvider.checkCanceled(); - ApplicationManager.getApplication().assertReadAccessAllowed(); + if (isPhysical) { + ApplicationManager.getApplication().assertReadAccessAllowed(); + } int index = getIndex(isPhysical, incompleteCode, isPoly); ConcurrentMap map = getMap(index); diff --git a/platform/core-impl/src/com/intellij/psi/impl/source/tree/SharedImplUtil.java b/platform/core-impl/src/com/intellij/psi/impl/source/tree/SharedImplUtil.java index 4c93ca05f160..b9b3dd35d445 100644 --- a/platform/core-impl/src/com/intellij/psi/impl/source/tree/SharedImplUtil.java +++ b/platform/core-impl/src/com/intellij/psi/impl/source/tree/SharedImplUtil.java @@ -22,6 +22,7 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.psi.*; import com.intellij.psi.impl.CheckUtil; import com.intellij.psi.impl.DebugUtil; +import com.intellij.psi.impl.ElementBase; import com.intellij.psi.impl.source.SourceTreeToPsiMap; import com.intellij.psi.impl.source.codeStyle.CodeEditUtil; import com.intellij.psi.tree.IElementType; @@ -40,7 +41,7 @@ public class SharedImplUtil { } public static PsiElement getParent(ASTNode thisElement) { - if (CHECK_FOR_READ_ACTION) { + if (CHECK_FOR_READ_ACTION && thisElement instanceof ElementBase) { ApplicationManager.getApplication().assertReadAccessAllowed(); } return SourceTreeToPsiMap.treeElementToPsi(thisElement.getTreeParent()); @@ -82,7 +83,7 @@ public class SharedImplUtil { } public static FileElement findFileElement(@NotNull ASTNode element) { - if (CHECK_FOR_READ_ACTION) { + if (CHECK_FOR_READ_ACTION && element instanceof ElementBase) { ApplicationManager.getApplication().assertReadAccessAllowed(); } ASTNode parent = element.getTreeParent(); @@ -180,8 +181,8 @@ public class SharedImplUtil { return count; } - public static void acceptChildren(PsiElementVisitor visitor, CompositeElement root) { - TreeElement childNode = root.getFirstChildNode(); + public static void acceptChildren(PsiElementVisitor visitor, ASTNode root) { + ASTNode childNode = root.getFirstChildNode(); while (childNode != null) { final PsiElement psi; diff --git a/platform/core-impl/src/com/intellij/psi/stubs/StubTreeBuilder.java b/platform/core-impl/src/com/intellij/psi/stubs/StubTreeBuilder.java index d026bc284845..830915968efd 100644 --- a/platform/core-impl/src/com/intellij/psi/stubs/StubTreeBuilder.java +++ b/platform/core-impl/src/com/intellij/psi/stubs/StubTreeBuilder.java @@ -58,7 +58,7 @@ public class StubTreeBuilder { CharSequence contentAsText = inputData.getContentAsText(); FileContentImpl fileContent = (FileContentImpl)inputData; - PsiFile psi = fileContent.getPsiFileAccountingForUnsavedDocument(); + PsiFile psi = fileContent.getPsiFileForPsiDependentIndex(); psi = psi.getViewProvider().getStubBindingRoot(); psi.putUserData(IndexingDataKeys.FILE_TEXT_CONTENT_KEY, contentAsText); @@ -82,7 +82,7 @@ public class StubTreeBuilder { if (stubFileElementType != null) { StubBuilder stubBuilder = stubFileElementType.getBuilder(); if (stubBuilder instanceof LightStubBuilder) { - LightStubBuilder.FORCED_AST.set(fileContent.getLighterAST()); + LightStubBuilder.FORCED_AST.set(fileContent.getLighterASTForPsiDependentIndex()); } data = stubBuilder.buildStubTree(psi); } diff --git a/platform/core-impl/src/com/intellij/util/indexing/FileContentImpl.java b/platform/core-impl/src/com/intellij/util/indexing/FileContentImpl.java index 58521fdf0258..41184daab651 100644 --- a/platform/core-impl/src/com/intellij/util/indexing/FileContentImpl.java +++ b/platform/core-impl/src/com/intellij/util/indexing/FileContentImpl.java @@ -79,10 +79,10 @@ public final class FileContentImpl extends UserDataHolderBase implements FileCon return psi; } - public @NotNull LighterAST getLighterAST() { + public @NotNull LighterAST getLighterASTForPsiDependentIndex() { LighterAST lighterAST = getUserData(IndexingDataKeys.LIGHTER_AST_NODE_KEY); if (lighterAST == null) { - lighterAST = getPsiFileAccountingForUnsavedDocument().getNode().getLighterAST(); + lighterAST = getPsiFileForPsiDependentIndex().getNode().getLighterAST(); assert lighterAST != null; putUserData(IndexingDataKeys.LIGHTER_AST_NODE_KEY, lighterAST); } @@ -229,7 +229,7 @@ public final class FileContentImpl extends UserDataHolderBase implements FileCon myHash = hash; } - public PsiFile getPsiFileAccountingForUnsavedDocument() { + public PsiFile getPsiFileForPsiDependentIndex() { Document document = FileDocumentManager.getInstance().getCachedDocument(getFile()); PsiFile psi = null; if (document != null) { diff --git a/platform/duplicates-analysis/src/com/intellij/dupLocator/index/DuplicatesIndex.java b/platform/duplicates-analysis/src/com/intellij/dupLocator/index/DuplicatesIndex.java index 90b3dc93f387..bc0945b071ec 100644 --- a/platform/duplicates-analysis/src/com/intellij/dupLocator/index/DuplicatesIndex.java +++ b/platform/duplicates-analysis/src/com/intellij/dupLocator/index/DuplicatesIndex.java @@ -119,7 +119,7 @@ public class DuplicatesIndex extends FileBasedIndexExtension result = new THashMap(); - LighterAST ast = fileContent.getLighterAST(); + LighterAST ast = fileContent.getLighterASTForPsiDependentIndex(); assert ast != null; ((LightDuplicateProfile)profile).process(ast, new LightDuplicateProfile.Callback() { @Override @@ -134,7 +134,7 @@ public class DuplicatesIndex extends FileBasedIndexExtension> alignmentMappings; @NotNull public final Map> backwardShiftedAlignedBlocks; @NotNull public final CommonCodeStyleSettings.IndentOptions indentOptions; - public int maxAlignmentSpaces; + public final int maxAlignmentSpaces; public Context(@NotNull Document document, @NotNull AlignmentImpl alignment, diff --git a/platform/lang-impl/src/com/intellij/psi/codeStyle/autodetect/IndentOptionsDetectorImpl.java b/platform/lang-impl/src/com/intellij/psi/codeStyle/autodetect/IndentOptionsDetectorImpl.java index b05a58c0e967..5f56ecc9b264 100644 --- a/platform/lang-impl/src/com/intellij/psi/codeStyle/autodetect/IndentOptionsDetectorImpl.java +++ b/platform/lang-impl/src/com/intellij/psi/codeStyle/autodetect/IndentOptionsDetectorImpl.java @@ -15,6 +15,7 @@ */ package com.intellij.psi.codeStyle.autodetect; +import com.intellij.lang.Language; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Document; import com.intellij.openapi.project.Project; @@ -36,9 +37,11 @@ public class IndentOptionsDetectorImpl implements IndentOptionsDetector { private final PsiFile myFile; private final Project myProject; private final Document myDocument; + private final Language myLanguage; public IndentOptionsDetectorImpl(@NotNull PsiFile file) { myFile = file; + myLanguage = file.getLanguage(); myProject = file.getProject(); myDocument = PsiDocumentManager.getInstance(myProject).getDocument(myFile); } @@ -49,7 +52,7 @@ public class IndentOptionsDetectorImpl implements IndentOptionsDetector { IndentOptions indentOptions = (IndentOptions)CodeStyleSettingsManager.getSettings(myProject).getIndentOptions(myFile.getFileType()).clone(); if (myDocument != null) { - List linesInfo = new LineIndentInfoBuilder(myDocument.getCharsSequence()).build(); + List linesInfo = new LineIndentInfoBuilder(myDocument.getCharsSequence(), myLanguage).build(); IndentUsageStatistics stats = new IndentUsageStatisticsImpl(linesInfo); adjustIndentOptions(indentOptions, stats); } diff --git a/platform/lang-impl/src/com/intellij/psi/codeStyle/autodetect/LineIndentInfoBuilder.java b/platform/lang-impl/src/com/intellij/psi/codeStyle/autodetect/LineIndentInfoBuilder.java index 8efbbc495750..6df9580e9e88 100644 --- a/platform/lang-impl/src/com/intellij/psi/codeStyle/autodetect/LineIndentInfoBuilder.java +++ b/platform/lang-impl/src/com/intellij/psi/codeStyle/autodetect/LineIndentInfoBuilder.java @@ -15,9 +15,13 @@ */ package com.intellij.psi.codeStyle.autodetect; +import com.intellij.lang.Commenter; +import com.intellij.lang.Language; +import com.intellij.lang.LanguageCommenters; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.text.CharArrayUtil; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.List; @@ -26,10 +30,12 @@ public class LineIndentInfoBuilder { private final CharSequence myText; private final int myLength; + private final Commenter myCommenter; - public LineIndentInfoBuilder(@NotNull CharSequence text) { + public LineIndentInfoBuilder(@NotNull CharSequence text, @Nullable Language language) { myText = text; myLength = text.length(); + myCommenter = language != null ? LanguageCommenters.INSTANCE.forLanguage(language) : null; } @NotNull @@ -58,7 +64,7 @@ public class LineIndentInfoBuilder { @NotNull private LineIndentInfo createInfoFromWhiteSpaceRange(int lineStartOffset, int textStartOffset) { - if (myText.charAt(textStartOffset) == '*') { + if (startsWithComment(textStartOffset)) { return LineIndentInfo.LINE_WITH_COMMENT; } else if (CharArrayUtil.indexOf(myText, "\t", lineStartOffset, textStartOffset) > 0) { @@ -70,6 +76,25 @@ public class LineIndentInfoBuilder { } } + private boolean startsWithComment(int textStartOffset) { + if (myText.charAt(textStartOffset) == '*' || startsWithLineComment(textStartOffset)) { + return true; + } + + return false; + } + + private boolean startsWithLineComment(int textStartOffset) { + if (myCommenter == null) return false; + + String lineCommentPrefix = myCommenter.getLineCommentPrefix(); + if (lineCommentPrefix != null && CharArrayUtil.regionMatches(myText, textStartOffset, lineCommentPrefix)) { + return true; + } + + return false; + } + private int getLineEndOffset(int lineStartOffset) { int lineEndOffset = CharArrayUtil.indexOf(myText, "\n", lineStartOffset, myLength); if (lineEndOffset < 0) { diff --git a/platform/lang-impl/src/com/intellij/util/indexing/MapReduceIndex.java b/platform/lang-impl/src/com/intellij/util/indexing/MapReduceIndex.java index 95c2caba8da6..5236fec0f30a 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/MapReduceIndex.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/MapReduceIndex.java @@ -567,7 +567,7 @@ public class MapReduceIndex implements UpdatableIndex> top = new TreeSet>(COMPARATOR); - TreeSet> old = new TreeSet>(COMPARATOR); - - @Override - public void update(AnActionEvent e) { - e.getPresentation().setText("Top " + LIMIT + " disposables"); - } - - @Override - void reset() { - top.clear(); - old.clear(); - } - - @Override - public void actionPerformed(AnActionEvent e) { - old = new TreeSet>(top); - top.clear(); - ObjectTree tree = Disposer.getTree(); - Set roots = tree.getRootObjects(); - for (Disposable root : roots) { - checkDisposables(tree, root, top, LIMIT); - } - System.out.println("Top " + LIMIT + " disposables"); - for (Pair pair : top) { - System.out.println(pair.first.getClass().getName() + " (" + pair.second + " related)" + getChange(old, pair.first, pair.second)); - } - } - - private void checkDisposables(ObjectTree tree, Object key, Set> top, int limit) { - ObjectNode node = tree.getNode(key); - if (node == null) { - return; - } - Collection children = node.getChildren(); - top.add(Pair.create(key, children.size())); - trimToLimit(top, limit); - for (Object child : children) { - checkDisposables(tree, child, top, limit); - } - } - }; private static final ResettableAction RESET_THEM_ALL = new ResettableAction("Reset statistics") { @Override @@ -226,7 +182,7 @@ public class TopAnomaliesAction extends ActionGroup { } }; - private static ResettableAction[] CHILDREN = {TOP_PARENTS, TOP_UI_PROPERTIES, TOP_DISPOSABLE, RESET_THEM_ALL}; + private static ResettableAction[] CHILDREN = {TOP_PARENTS, TOP_UI_PROPERTIES, RESET_THEM_ALL}; @Override public void update(AnActionEvent e) { diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/VirtualDirectoryImpl.java b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/VirtualDirectoryImpl.java index 5b9d83d0a222..8fce7ea19ff0 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/VirtualDirectoryImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/VirtualDirectoryImpl.java @@ -57,7 +57,7 @@ public class VirtualDirectoryImpl extends VirtualFileSystemEntry { public static boolean CHECK = ApplicationManager.getApplication().isUnitTestMode(); - static final VirtualDirectoryImpl NULL_VIRTUAL_FILE = + private static final VirtualDirectoryImpl NULL_VIRTUAL_FILE = new VirtualDirectoryImpl(-42, null, null, null, LocalFileSystem.getInstance()) { @Override public String toString() { @@ -117,9 +117,7 @@ public class VirtualDirectoryImpl extends VirtualFileSystemEntry { // in this case we should remove it from there removeFromArray(indexInReal); } - if (CHECK) { - assertConsistency(ignoreCase, name); - } + assertConsistency(ignoreCase, name); } @Nullable // null if there can't be a child with this name, NULL_VIRTUAL_FILE @@ -284,7 +282,7 @@ public class VirtualDirectoryImpl extends VirtualFileSystemEntry { final boolean ignoreCase = !delegate.isCaseSensitive(); synchronized (myData) { if (allChildrenLoaded()) { - assertConsistency(ignoreCase); + assertConsistency(ignoreCase, ""); return getArraySafely(); } @@ -333,7 +331,9 @@ public class VirtualDirectoryImpl extends VirtualFileSystemEntry { if (getId() > 0) { myData.myChildrenIds = result; - assertConsistency(ignoreCase, childrenIds); + if (CHECK) { + assertConsistency(ignoreCase, Arrays.asList(childrenIds)); + } setChildrenLoaded(); } @@ -341,7 +341,7 @@ public class VirtualDirectoryImpl extends VirtualFileSystemEntry { } } - private void assertConsistency(boolean ignoreCase, @NotNull Object... details) { + private void assertConsistency(boolean ignoreCase, @NotNull Object details) { if (!CHECK || ApplicationInfoImpl.isInPerformanceTest()) return; int[] childrenIds = myData.myChildrenIds; for (int i = 1; i < childrenIds.length; i++) { diff --git a/platform/platform-impl/src/com/intellij/ui/docking/impl/DockManagerImpl.java b/platform/platform-impl/src/com/intellij/ui/docking/impl/DockManagerImpl.java index 37646a19292f..04033418742f 100644 --- a/platform/platform-impl/src/com/intellij/ui/docking/impl/DockManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/ui/docking/impl/DockManagerImpl.java @@ -595,7 +595,8 @@ public class DockManagerImpl extends DockManager implements PersistentStateCompo } }); - new UiNotifyConnector(((RootPaneContainer)frame).getContentPane(), myContainer); + UiNotifyConnector connector = new UiNotifyConnector(((RootPaneContainer)frame).getContentPane(), myContainer); + Disposer.register(myContainer, connector); } } diff --git a/platform/platform-tests/testSrc/com/intellij/psi/autodetect/AbstractIndentAutoDetectionTest.java b/platform/platform-tests/testSrc/com/intellij/psi/autodetect/AbstractIndentAutoDetectionTest.java new file mode 100644 index 000000000000..ab083bc3ba09 --- /dev/null +++ b/platform/platform-tests/testSrc/com/intellij/psi/autodetect/AbstractIndentAutoDetectionTest.java @@ -0,0 +1,107 @@ +/* + * 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.psi.autodetect; + +import com.intellij.openapi.editor.Document; +import com.intellij.psi.codeStyle.CodeStyleSettings; +import com.intellij.psi.codeStyle.CodeStyleSettingsManager; +import com.intellij.psi.codeStyle.CommonCodeStyleSettings; +import com.intellij.psi.codeStyle.autodetect.*; +import com.intellij.testFramework.LightPlatformCodeInsightTestCase; +import com.intellij.testFramework.PlatformTestCase; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.junit.Assert; + +import java.util.List; + +public abstract class AbstractIndentAutoDetectionTest extends LightPlatformCodeInsightTestCase { + + static { + PlatformTestCase.autodetectPlatformPrefix(); + } + + @NotNull + protected abstract String getFileNameWithExtension(); + + @Override + @NotNull + protected abstract String getTestDataPath(); + + protected void doTestMaxUsedIndent(int indentExpected, int timesUsedExpected) { + IndentUsageInfo maxIndentExpected = new IndentUsageInfo(indentExpected, timesUsedExpected); + IndentUsageInfo indentInfo = getMaxUsedIndentInfo(); + Assert.assertEquals("Indent size mismatch", maxIndentExpected.getIndentSize(), indentInfo.getIndentSize()); + Assert.assertEquals("Indent size usage number mismatch", maxIndentExpected.getTimesUsed(), indentInfo.getTimesUsed()); + } + + protected void doTestMaxUsedIndent(int indentExpected) { + IndentUsageInfo indentInfo = getMaxUsedIndentInfo(); + Assert.assertEquals("Indent size mismatch", indentExpected, indentInfo.getIndentSize()); + } + + protected void doTestTabsUsed() { + doTestTabsUsed(null); + } + + protected void doTestIndentSize(int expectedIndent) { + doTestIndentSize(null, expectedIndent); + } + + protected void doTestTabsUsed(@Nullable CommonCodeStyleSettings.IndentOptions defaultIndentOptions) { + configureByFile(getFileNameWithExtension()); + + if (defaultIndentOptions != null) { + setIndentOptions(defaultIndentOptions); + } + + CommonCodeStyleSettings.IndentOptions options = detectIndentOptions(); + Assert.assertTrue("Tab usage not detected", options.USE_TAB_CHARACTER); + } + + private void doTestIndentSize(@Nullable CommonCodeStyleSettings.IndentOptions defaultIndentOptions, int expectedIndent) { + configureByFile(getFileNameWithExtension()); + + if (defaultIndentOptions != null) { + setIndentOptions(defaultIndentOptions); + } + + CommonCodeStyleSettings.IndentOptions options = detectIndentOptions(); + Assert.assertFalse("Tab usage detected: ", options.USE_TAB_CHARACTER); + Assert.assertEquals("Indent mismatch", expectedIndent, options.INDENT_SIZE); + } + + private static void setIndentOptions(@NotNull CommonCodeStyleSettings.IndentOptions defaultIndentOptions) { + CodeStyleSettings settings = CodeStyleSettingsManager.getSettings(getProject()); + CommonCodeStyleSettings.IndentOptions indentOptions = settings.getIndentOptions(myFile.getFileType()); + indentOptions.copyFrom(defaultIndentOptions); + } + + @NotNull + private static CommonCodeStyleSettings.IndentOptions detectIndentOptions() { + IndentOptionsDetector detector = new IndentOptionsDetectorImpl(myFile); + return detector.getIndentOptions(); + } + + @NotNull + private IndentUsageInfo getMaxUsedIndentInfo() { + configureByFile(getFileNameWithExtension()); + Document document = getDocument(myFile); + List lines = new LineIndentInfoBuilder(document.getCharsSequence(), myFile.getLanguage()).build(); + IndentUsageStatistics statistics = new IndentUsageStatisticsImpl(lines); + return statistics.getKMostUsedIndentInfo(0); + } +} diff --git a/platform/platform-tests/testSrc/com/intellij/psi/autodetect/IndentAutoDetectionTest.java b/platform/platform-tests/testSrc/com/intellij/psi/autodetect/IndentAutoDetectionTest.java index 666a1cea6b29..28710f6d8f35 100644 --- a/platform/platform-tests/testSrc/com/intellij/psi/autodetect/IndentAutoDetectionTest.java +++ b/platform/platform-tests/testSrc/com/intellij/psi/autodetect/IndentAutoDetectionTest.java @@ -15,28 +15,38 @@ */ package com.intellij.psi.autodetect; -import com.intellij.openapi.editor.Document; -import com.intellij.psi.codeStyle.CodeStyleSettings; -import com.intellij.psi.codeStyle.CodeStyleSettingsManager; +import com.intellij.openapi.fileTypes.PlainTextLanguage; import com.intellij.psi.codeStyle.CommonCodeStyleSettings; -import com.intellij.psi.codeStyle.autodetect.*; -import com.intellij.testFramework.LightPlatformCodeInsightTestCase; +import com.intellij.psi.codeStyle.autodetect.LineIndentInfo; +import com.intellij.psi.codeStyle.autodetect.LineIndentInfoBuilder; import com.intellij.testFramework.PlatformTestCase; import com.intellij.testFramework.PlatformTestUtil; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import org.junit.Assert; import java.io.File; import java.util.List; -public class IndentAutoDetectionTest extends LightPlatformCodeInsightTestCase { - private static final String BASE_PATH = "codeStyle/autodetect/"; +public class IndentAutoDetectionTest extends AbstractIndentAutoDetectionTest { static { PlatformTestCase.initPlatformLangPrefix(); } + @NotNull + @Override + protected String getTestDataPath() { + return PlatformTestUtil.getCommunityPath().replace(File.separatorChar, '/') + + "/platform/platform-tests/testData/" + + "codeStyle/autodetect/"; + } + + @NotNull + protected String getFileNameWithExtension() { + return getTestName(true) + ".java"; + } + + public void testBigFileWithIndent2() { doTestIndentSize(2); } @@ -136,84 +146,12 @@ public class IndentAutoDetectionTest extends LightPlatformCodeInsightTestCase { ); } - public void doTestMaxUsedIndent(int indentExpected, int timesUsedExpected) { - IndentUsageInfo maxIndentExpected = new IndentUsageInfo(indentExpected, timesUsedExpected); - IndentUsageInfo indentInfo = getMaxUsedIndentInfo(); - Assert.assertEquals("Indent size mismatch", maxIndentExpected.getIndentSize(), indentInfo.getIndentSize()); - Assert.assertEquals("Indent size usage number mismatch", maxIndentExpected.getTimesUsed(), indentInfo.getTimesUsed()); - } - - public void doTestMaxUsedIndent(int indentExpected) { - IndentUsageInfo indentInfo = getMaxUsedIndentInfo(); - Assert.assertEquals("Indent size mismatch", indentExpected, indentInfo.getIndentSize()); - } - - private void doTestTabsUsed() { - doTestTabsUsed(null); - } - - private void doTestTabsUsed(@Nullable CommonCodeStyleSettings.IndentOptions defaultIndentOptions) { - configureByFile(getTestName(true) + ".java"); - - if (defaultIndentOptions != null) { - setIndentOptions(defaultIndentOptions); - } - - CommonCodeStyleSettings.IndentOptions options = detectIndentOptions(); - Assert.assertTrue("Tab usage not detected", options.USE_TAB_CHARACTER); - } - - private void doTestIndentSize(int expectedIndent) { - doTestIndentSize(null, expectedIndent); - } - - private void doTestIndentSize(@Nullable CommonCodeStyleSettings.IndentOptions defaultIndentOptions, int expectedIndent) { - configureByFile(getTestName(true) + ".java"); - - if (defaultIndentOptions != null) { - setIndentOptions(defaultIndentOptions); - } - - CommonCodeStyleSettings.IndentOptions options = detectIndentOptions(); - Assert.assertFalse("Tab usage detected: ", options.USE_TAB_CHARACTER); - Assert.assertEquals("Indent mismatch", expectedIndent, options.INDENT_SIZE); - } - - private static void setIndentOptions(@NotNull CommonCodeStyleSettings.IndentOptions defaultIndentOptions) { - CodeStyleSettings settings = CodeStyleSettingsManager.getSettings(getProject()); - CommonCodeStyleSettings.IndentOptions indentOptions = settings.getIndentOptions(myFile.getFileType()); - indentOptions.copyFrom(defaultIndentOptions); - } - - @NotNull - private static CommonCodeStyleSettings.IndentOptions detectIndentOptions() { - IndentOptionsDetector detector = new IndentOptionsDetectorImpl(myFile); - return detector.getIndentOptions(); - } - - @NotNull - private IndentUsageInfo getMaxUsedIndentInfo() { - configureByFile(getTestName(true) + ".java"); - Document document = getDocument(myFile); - List lines = new LineIndentInfoBuilder(document.getCharsSequence()).build(); - IndentUsageStatistics statistics = new IndentUsageStatisticsImpl(lines); - return statistics.getKMostUsedIndentInfo(0); - } - private static void doTestLineToIndentMapping(@NotNull CharSequence text, int... spacesForLine) { - List list = new LineIndentInfoBuilder(text).build(); + List list = new LineIndentInfoBuilder(text, PlainTextLanguage.INSTANCE).build(); Assert.assertEquals(list.size(), spacesForLine.length); for (int i = 0; i < spacesForLine.length; i++) { int indentSize = list.get(i).getIndentSize(); Assert.assertEquals("Mismatch on line " + i, spacesForLine[i], indentSize); } } - - @Override - @NotNull - public String getTestDataPath() { - return PlatformTestUtil.getCommunityPath().replace(File.separatorChar, '/') - + "/platform/platform-tests/testData/" - + BASE_PATH; - } } diff --git a/platform/util/src/com/intellij/openapi/util/objectTree/ObjectNode.java b/platform/util/src/com/intellij/openapi/util/objectTree/ObjectNode.java index 30c70460d9bf..e5fa4cd6784d 100644 --- a/platform/util/src/com/intellij/openapi/util/objectTree/ObjectNode.java +++ b/platform/util/src/com/intellij/openapi/util/objectTree/ObjectNode.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,24 +26,28 @@ import org.jetbrains.annotations.TestOnly; import java.util.Collection; import java.util.Collections; -import java.util.ListIterator; +import java.util.List; -public final class ObjectNode { +final class ObjectNode { private static final ObjectNode[] EMPTY_ARRAY = new ObjectNode[0]; private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.util.objectTree.ObjectNode"); private final ObjectTree myTree; - private ObjectNode myParent; + private ObjectNode myParent; // guarded by myTree.treeLock private final T myObject; - private SmartList> myChildren; + private List> myChildren; // guarded by myTree.treeLock private final Throwable myTrace; private final long myOwnModification; - public ObjectNode(@NotNull ObjectTree tree, @Nullable ObjectNode parentNode, @NotNull T object, long modification, @Nullable final Throwable trace) { + ObjectNode(@NotNull ObjectTree tree, + @Nullable ObjectNode parentNode, + @NotNull T object, + long modification, + @Nullable final Throwable trace) { myTree = tree; myParent = parentNode; myObject = object; @@ -55,43 +59,36 @@ public final class ObjectNode { @SuppressWarnings("unchecked") @NotNull private ObjectNode[] getChildrenArray() { - synchronized (myTree.treeLock) { - if (myChildren == null || myChildren.isEmpty()) return EMPTY_ARRAY; - return myChildren.toArray(new ObjectNode[myChildren.size()]); - } + List> children = myChildren; + if (children == null || children.isEmpty()) return EMPTY_ARRAY; + return children.toArray(new ObjectNode[children.size()]); } void addChild(@NotNull ObjectNode child) { - synchronized (myTree.treeLock) { - if (myChildren == null) { - myChildren = new SmartList>(); - } - myChildren.add(child); - child.myParent = this; + List> children = myChildren; + if (children == null) { + myChildren = new SmartList>(child); } + else { + children.add(child); + } + child.myParent = this; } void removeChild(@NotNull ObjectNode child) { - synchronized (myTree.treeLock) { - assert myChildren != null: "No children to remove child: " + this + ' ' + child; - ListIterator> iterator = myChildren.listIterator(myChildren.size()); - while (iterator.hasPrevious()) { - if (child.equals(iterator.previous())) { - iterator.remove(); - return; - } - } + List> children = myChildren; + if (children != null) { + children.remove(child); } + child.myParent = null; } - public ObjectNode getParent() { - synchronized (myTree.treeLock) { - return myParent; - } + ObjectNode getParent() { + return myParent; } @NotNull - public Collection> getChildren() { + Collection> getChildren() { synchronized (myTree.treeLock) { if (myChildren == null) return Collections.emptyList(); return Collections.unmodifiableCollection(myChildren); @@ -109,7 +106,10 @@ public final class ObjectNode { LOG.error(t); } - ObjectNode[] childrenArray = getChildrenArray(); + ObjectNode[] childrenArray; + synchronized (myTree.treeLock) { + childrenArray = getChildrenArray(); + } //todo: [kirillk] optimize for (int i = childrenArray.length - 1; i >= 0; i--) { childrenArray[i].execute(disposeTree, action); @@ -145,8 +145,8 @@ public final class ObjectNode { } private void remove() { - myTree.putNode(myObject, null); synchronized (myTree.treeLock) { + myTree.putNode(myObject, null); if (myParent == null) { myTree.removeRootObject(myObject); } @@ -157,10 +157,11 @@ public final class ObjectNode { } @NotNull - public T getObject() { + T getObject() { return myObject; } + @Override @NonNls public String toString() { return "Node: " + myObject.toString(); @@ -196,11 +197,12 @@ public final class ObjectNode { D findChildEqualTo(@NotNull D object) { synchronized (myTree.treeLock) { - SmartList> children = myChildren; + List> children = myChildren; if (children != null) { for (ObjectNode node : children) { T nodeObject = node.getObject(); if (nodeObject.equals(object)) { + //noinspection unchecked return (D)nodeObject; } } diff --git a/platform/util/src/com/intellij/openapi/util/objectTree/ObjectTree.java b/platform/util/src/com/intellij/openapi/util/objectTree/ObjectTree.java index 472248b2bde9..53ba8e5d885a 100644 --- a/platform/util/src/com/intellij/openapi/util/objectTree/ObjectTree.java +++ b/platform/util/src/com/intellij/openapi/util/objectTree/ObjectTree.java @@ -34,28 +34,26 @@ public final class ObjectTree { private final List myListeners = ContainerUtil.createLockFreeCopyOnWriteList(); // identity used here to prevent problems with hashCode/equals overridden by not very bright minds - private final Set myRootObjects = ContainerUtil.newIdentityTroveSet(); - private final Map> myObject2NodeMap = ContainerUtil.newIdentityTroveMap(); + private final Set myRootObjects = ContainerUtil.newIdentityTroveSet(); // guarded by treeLock + private final Map> myObject2NodeMap = ContainerUtil.newIdentityTroveMap(); // guarded by treeLock - private final List> myExecutedNodes = new ArrayList>(); - private final List myExecutedUnregisteredNodes = new ArrayList(); + private final List> myExecutedNodes = new ArrayList>(); // guarded by myExecutedNodes + private final List myExecutedUnregisteredNodes = new ArrayList(); // guarded by myExecutedUnregisteredNodes final Object treeLock = new Object(); private final AtomicLong myModification = new AtomicLong(0); - public ObjectNode getNode(@NotNull T object) { - synchronized (treeLock) { - return myObject2NodeMap.get(object); - } - } - public ObjectNode putNode(@NotNull T object, @Nullable("null means remove") ObjectNode node) { - synchronized (treeLock) { - return node == null ? myObject2NodeMap.remove(object) : myObject2NodeMap.put(object, node); - } + ObjectNode getNode(@NotNull T object) { + return myObject2NodeMap.get(object); } - public final List> getNodesInExecution() { + ObjectNode putNode(@NotNull T object, @Nullable("null means remove") ObjectNode node) { + return node == null ? myObject2NodeMap.remove(object) : myObject2NodeMap.put(object, node); + } + + @NotNull + final List> getNodesInExecution() { return myExecutedNodes; } @@ -105,8 +103,7 @@ public final class ObjectTree { @NotNull private ObjectNode createNodeFor(@NotNull T object, @Nullable ObjectNode parentNode, @Nullable final Throwable trace) { - final ObjectNode newNode = new ObjectNode(this, parentNode, object, getNextModification(), - trace); + final ObjectNode newNode = new ObjectNode(this, parentNode, object, getNextModification(), trace); if (parentNode == null) { myRootObjects.add(object); } @@ -114,12 +111,15 @@ public final class ObjectTree { return newNode; } - public long getNextModification() { + private long getNextModification() { return myModification.incrementAndGet(); } public final boolean executeAll(@NotNull T object, boolean disposeTree, @NotNull ObjectTreeAction action, boolean processUnregistered) { - ObjectNode node = getNode(object); + ObjectNode node; + synchronized (treeLock) { + node = getNode(object); + } if (node == null) { if (processUnregistered) { executeUnregistered(object, action); @@ -147,7 +147,7 @@ public final class ObjectTree { } finally { synchronized (recursiveGuard) { - int i = ArrayUtil.indexOf(recursiveGuard, object, Equality.IDENTITY); + int i = ArrayUtil.lastIndexOf(recursiveGuard, object, Equality.IDENTITY); assert i != -1; recursiveGuard.remove(i); } @@ -159,11 +159,12 @@ public final class ObjectTree { } public final void executeChildAndReplace(@NotNull T toExecute, @NotNull T toReplace, boolean disposeTree, @NotNull ObjectTreeAction action) { - final ObjectNode toExecuteNode = getNode(toExecute); - assert toExecuteNode != null : "Object " + toExecute + " wasn't registered or already disposed"; - + final ObjectNode toExecuteNode; T parentObject; synchronized (treeLock) { + toExecuteNode = getNode(toExecute); + assert toExecuteNode != null : "Object " + toExecute + " wasn't registered or already disposed"; + final ObjectNode parent = toExecuteNode.getParent(); assert parent != null : "Object " + toExecute + " is not connected to the tree - doesn't have parent"; parentObject = parent.getObject(); @@ -174,11 +175,13 @@ public final class ObjectTree { } public boolean containsKey(@NotNull T object) { - return getNode(object) != null; + synchronized (treeLock) { + return getNode(object) != null; + } } @TestOnly - public void assertNoReferenceKeptInTree(@NotNull T disposable) { + void assertNoReferenceKeptInTree(@NotNull T disposable) { synchronized (treeLock) { Collection> nodes = myObject2NodeMap.values(); for (ObjectNode node : nodes) { @@ -187,57 +190,53 @@ public final class ObjectTree { } } - public void removeRootObject(@NotNull T object) { - synchronized (treeLock) { - myRootObjects.remove(object); - } + void removeRootObject(@NotNull T object) { + myRootObjects.remove(object); } @SuppressWarnings({"UseOfSystemOutOrSystemErr", "HardCodedStringLiteral"}) public void assertIsEmpty(boolean throwError) { - for (T object : myRootObjects) { - if (object == null) continue; - final ObjectNode objectNode = getNode(object); - if (objectNode == null) continue; + synchronized (treeLock) { + for (T object : myRootObjects) { + if (object == null) continue; + final ObjectNode objectNode = getNode(object); + if (objectNode == null) continue; - final Throwable trace = objectNode.getTrace(); - RuntimeException exception = new RuntimeException("Memory leak detected: " + object + " of class " + object.getClass() - + "\nSee the cause for the corresponding Disposer.register() stacktrace:\n", - trace); - if (throwError) { - throw exception; + final Throwable trace = objectNode.getTrace(); + RuntimeException exception = new RuntimeException("Memory leak detected: " + object + " of class " + object.getClass() + + "\nSee the cause for the corresponding Disposer.register() stacktrace:\n", + trace); + if (throwError) { + throw exception; + } + LOG.error(exception); } - LOG.error(exception); } } @TestOnly public boolean isEmpty() { - return myRootObjects.isEmpty(); - } - - @TestOnly - public void clearAll() { - myRootObjects.clear(); - myExecutedNodes.clear(); - myExecutedUnregisteredNodes.clear(); - myObject2NodeMap.clear(); + synchronized (treeLock) { + return myRootObjects.isEmpty(); + } } @NotNull - public Set getRootObjects() { - return myRootObjects; + Set getRootObjects() { + synchronized (treeLock) { + return myRootObjects; + } } - public void addListener(@NotNull ObjectTreeListener listener) { + void addListener(@NotNull ObjectTreeListener listener) { myListeners.add(listener); } - public void removeListener(@NotNull ObjectTreeListener listener) { + void removeListener(@NotNull ObjectTreeListener listener) { myListeners.remove(listener); } - void fireRegistered(@NotNull Object object) { + private void fireRegistered(@NotNull Object object) { for (ObjectTreeListener each : myListeners) { each.objectRegistered(object); } @@ -249,8 +248,10 @@ public final class ObjectTree { } } - public int size() { - return myObject2NodeMap.size(); + int size() { + synchronized (treeLock) { + return myObject2NodeMap.size(); + } } @Nullable @@ -262,7 +263,7 @@ public final class ObjectTree { } } - public long getModification() { + long getModification() { return myModification.get(); } } diff --git a/platform/util/src/com/intellij/util/io/PersistentHashMapValueStorage.java b/platform/util/src/com/intellij/util/io/PersistentHashMapValueStorage.java index c0318baf2f16..1c94078f62f6 100644 --- a/platform/util/src/com/intellij/util/io/PersistentHashMapValueStorage.java +++ b/platform/util/src/com/intellij/util/io/PersistentHashMapValueStorage.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -160,7 +160,7 @@ public class PersistentHashMapValueStorage { final PersistentHashMap.CompactionRecordInfo info = records.peek(); if (info.valueAddress >= readStartOffset) { if (info.valueAddress >= lastReadOffset) { - throw new IOException("Value storage is corrupted: value file size:" + mySize + ", readStartOffset:"+ readStartOffset + ", record address:"+info.valueAddress); + throw new IOException("Value storage is corrupted: value file size:" + mySize + ", readStartOffset:"+ readStartOffset + ", record address:"+info.valueAddress+"; file: "+myPath); } // record start is inside our buffer diff --git a/platform/util/testSrc/com/intellij/openapi/util/DisposerTest.java b/platform/util/testSrc/com/intellij/openapi/util/objectTree/DisposerTest.java similarity index 98% rename from platform/util/testSrc/com/intellij/openapi/util/DisposerTest.java rename to platform/util/testSrc/com/intellij/openapi/util/objectTree/DisposerTest.java index 7d9c21e79c2f..ce4132496aea 100644 --- a/platform/util/testSrc/com/intellij/openapi/util/DisposerTest.java +++ b/platform/util/testSrc/com/intellij/openapi/util/objectTree/DisposerTest.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. @@ -13,9 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.intellij.openapi.util; +package com.intellij.openapi.util.objectTree; import com.intellij.openapi.Disposable; +import com.intellij.openapi.util.Disposer; import junit.framework.TestCase; import org.jetbrains.annotations.NonNls; diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangesViewManager.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangesViewManager.java index 8630f7ffbe50..075927b4fa80 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangesViewManager.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangesViewManager.java @@ -201,7 +201,7 @@ public class ChangesViewManager implements ChangesViewI, JDOMExternalizable, Pro } }); if (ApplicationManager.getApplication().isHeadlessEnvironment()) return; - myContent = ContentFactory.SERVICE.getInstance().createContent(createChangeViewComponent(), "Local", false); + myContent = ContentFactory.SERVICE.getInstance().createContent(createChangeViewComponent(), ChangesViewContentManager.LOCAL_CHANGES, false); myContent.setCloseable(false); myContentManager.addContent(myContent); diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/SelectInChangesViewTarget.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/SelectInChangesViewTarget.java index f91bbc63f9e4..2a2f759716d7 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/SelectInChangesViewTarget.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/SelectInChangesViewTarget.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. @@ -53,7 +53,7 @@ public class SelectInChangesViewTarget implements SelectInTarget, DumbAware { final VirtualFile file = context.getVirtualFile(); Runnable runnable = new Runnable() { public void run() { - ChangesViewContentManager.getInstance(myProject).selectContent("Local"); + ChangesViewContentManager.getInstance(myProject).selectContent(ChangesViewContentManager.LOCAL_CHANGES); ChangesViewManager.getInstance(myProject).selectFile(file); } }; diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/shelf/ShelvedChangesViewManager.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/shelf/ShelvedChangesViewManager.java index 22efde10e5dc..8cad5f820d96 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/shelf/ShelvedChangesViewManager.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/shelf/ShelvedChangesViewManager.java @@ -185,7 +185,7 @@ public class ShelvedChangesViewManager implements ProjectComponent { if (changeLists.size() == 0) { if (myContent != null) { myContentManager.removeContent(myContent); - myContentManager.selectContent("Local"); + myContentManager.selectContent(ChangesViewContentManager.LOCAL_CHANGES); } myContent = null; } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesViewContentManager.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesViewContentManager.java index feddadcacfd3..5923ed170556 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesViewContentManager.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesViewContentManager.java @@ -283,7 +283,11 @@ public class ChangesViewContentManager extends AbstractProjectComponent implemen } } - private static final String[] ourPresetOrder = {"Local", "Repository", "Incoming", "Shelf"}; + public static final String LOCAL_CHANGES = Registry.is("vcs.merge.toolwindows") ? "Local Changes" : "Local"; + public static final String REPOSITORY = "Repository"; + public static final String INCOMING = "Incoming"; + public static final String SHELF = "Shelf"; + private static final String[] ourPresetOrder = {LOCAL_CHANGES, REPOSITORY, INCOMING, SHELF}; private static List doPresetOrdering(final List contents) { final List result = new ArrayList(contents.size()); for (final String preset : ourPresetOrder) { diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VisiblePackBuilder.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VisiblePackBuilder.java index 6c9fe6cd135c..c171707d7dbb 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VisiblePackBuilder.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VisiblePackBuilder.java @@ -91,7 +91,7 @@ class VisiblePackBuilder { } VisibleGraph visibleGraph; - if (((matchingHeads != null) && matchingHeads.isEmpty()) || ((matchingCommits != null) && matchingCommits.isEmpty())) { + if (matchesNothing(matchingHeads) || matchesNothing(matchingCommits)) { visibleGraph = EmptyVisibleGraph.getInstance(); } else { @@ -100,6 +100,10 @@ class VisiblePackBuilder { return Pair.create(new VisiblePack(dataPack, visibleGraph, canRequestMore), commitCount); } + private static boolean matchesNothing(@Nullable Collection matchingSet) { + return matchingSet != null && matchingSet.isEmpty(); + } + private VisiblePack applyHashFilter(@NotNull DataPack dataPack, @NotNull Collection hashes, @NotNull PermanentGraph.SortType sortType) { @@ -160,25 +164,24 @@ class VisiblePackBuilder { @NotNull final PermanentGraph permanentGraph, @NotNull List detailsFilters, @Nullable final Set matchingHeads) { - final int commitIndex = myHashMap.getCommitIndex(commit.getId()); - return ContainerUtil.and(detailsFilters, new Condition() { + boolean matchesAllDetails = ContainerUtil.and(detailsFilters, new Condition() { @Override public boolean value(VcsLogDetailsFilter filter) { - if (!filter.matches(commit)) { - return false; - } - if (matchingHeads == null) { - return true; - } - Set containingBranches = permanentGraph.getContainingBranches(commitIndex); - return ContainerUtil.exists(containingBranches, new Condition() { - @Override - public boolean value(Integer integer) { - return matchingHeads.contains(integer); - } - }); + return filter.matches(commit); } }); + return matchesAllDetails && matchesAnyHead(permanentGraph, commit, matchingHeads); + } + + private boolean matchesAnyHead(@NotNull PermanentGraph permanentGraph, + @NotNull VcsCommitMetadata commit, + @Nullable Set matchingHeads) { + if (matchingHeads == null) { + return true; + } + // TODO O(n^2) + int commitIndex = myHashMap.getCommitIndex(commit.getId()); + return ContainerUtil.intersects(permanentGraph.getContainingBranches(commitIndex), matchingHeads); } @Nullable diff --git a/platform/vcs-log/impl/test/com/intellij/vcs/log/impl/HashSerializeTest.java b/platform/vcs-log/impl/test/com/intellij/vcs/log/impl/HashSerializeTest.java index af8c703e1811..7ce352c05f04 100644 --- a/platform/vcs-log/impl/test/com/intellij/vcs/log/impl/HashSerializeTest.java +++ b/platform/vcs-log/impl/test/com/intellij/vcs/log/impl/HashSerializeTest.java @@ -16,11 +16,14 @@ package com.intellij.vcs.log.impl; import com.intellij.openapi.util.io.FileUtil; +import com.intellij.util.containers.ContainerUtil; import com.intellij.util.io.DataOutputStream; import org.jetbrains.annotations.NotNull; import org.junit.Test; import java.io.*; +import java.util.Arrays; +import java.util.List; import static org.junit.Assert.assertEquals; @@ -30,7 +33,7 @@ public class HashSerializeTest { public void full_hash() throws IOException { HashImpl hash = (HashImpl)HashImpl.build("d35ee91fad4a04bce0ea91a762cc8f3bf3e1929f"); File file = writeToTempFile(hash); - HashImpl newHash = readFromFile(file); + HashImpl newHash = readFromFile(file).get(0); assertEquals(hash, newHash); } @@ -38,16 +41,28 @@ public class HashSerializeTest { public void short_hash() throws IOException { HashImpl hash = (HashImpl)HashImpl.build("d35ee91"); File file = writeToTempFile(hash); - HashImpl newHash = readFromFile(file); + HashImpl newHash = readFromFile(file).get(0); assertEquals(hash, newHash); } + + @Test + public void two_different_hashes() throws IOException { + HashImpl hash1 = (HashImpl)HashImpl.build("d35ee91"); + HashImpl hash2 = (HashImpl)HashImpl.build("d35ee91fad4a04bce0ea91a762cc8f3bf3e1929f"); + File file = writeToTempFile(hash1, hash2); + List hashes = readFromFile(file); + assertEquals(Arrays.asList(hash1, hash2), hashes); + + } @NotNull - private static File writeToTempFile(@NotNull HashImpl hash) throws IOException { + private static File writeToTempFile(@NotNull HashImpl... hashes) throws IOException { File file = FileUtil.createTempFile("", ""); DataOutputStream out = new DataOutputStream(new FileOutputStream(file)); try { - hash.write(out); + for (HashImpl hash : hashes) { + hash.write(out); + } } finally { out.close(); @@ -56,15 +71,17 @@ public class HashSerializeTest { } @NotNull - private static HashImpl readFromFile(@NotNull File file) throws IOException { - HashImpl newHash; + private static List readFromFile(@NotNull File file) throws IOException { + List result = ContainerUtil.newArrayList(); DataInputStream in = new DataInputStream(new FileInputStream(file)); try { - newHash = (HashImpl)HashImpl.read(in); + while (in.available() > 0) { + result.add((HashImpl)HashImpl.read(in)); + } } finally { in.close(); } - return newHash; + return result; } } diff --git a/python/build/resources/logo.bmp b/python/build/resources/logo.bmp index 64ce8132c1e2..3e8f6719d7f7 100644 Binary files a/python/build/resources/logo.bmp and b/python/build/resources/logo.bmp differ diff --git a/python/helpers/pydev/pydevd_file_utils.py b/python/helpers/pydev/pydevd_file_utils.py index 147aa66b946d..4a4081b60d25 100644 --- a/python/helpers/pydev/pydevd_file_utils.py +++ b/python/helpers/pydev/pydevd_file_utils.py @@ -119,7 +119,7 @@ def _NormFile(filename): if r[ind] == "!": ind+=1 inner_path = r[ind:] - if inner_path.startswith('/'): + if inner_path.startswith('/') or inner_path.startswith('\\'): inner_path = inner_path[1:] r = zip_path + "/" + inner_path @@ -152,7 +152,7 @@ def exists(file): return None try: - if inner_path.startswith('/'): + if inner_path.startswith('/') or inner_path.startswith('\\'): inner_path = inner_path[1:] info = zip.getinfo(inner_path) diff --git a/python/pydevSrc/com/jetbrains/python/debugger/pydev/MultiProcessDebugger.java b/python/pydevSrc/com/jetbrains/python/debugger/pydev/MultiProcessDebugger.java index 21b9d8be2867..06a6864adb63 100644 --- a/python/pydevSrc/com/jetbrains/python/debugger/pydev/MultiProcessDebugger.java +++ b/python/pydevSrc/com/jetbrains/python/debugger/pydev/MultiProcessDebugger.java @@ -1,5 +1,7 @@ package com.jetbrains.python.debugger.pydev; +import com.google.common.base.Function; +import com.google.common.collect.Collections2; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Sets; @@ -202,6 +204,17 @@ public class MultiProcessDebugger implements ProcessDebugger { return debugger; } else { + // thread is not found in registry - lets search for it in attached debuggers + + for (ProcessDebugger d : myOtherDebuggers) { + for (PyThreadInfo thread : d.getThreads()) { + if (threadId.equals(thread.getId())) { + return d; + } + } + } + + //if not found then return main debugger return myMainDebugger; } } @@ -240,37 +253,48 @@ public class MultiProcessDebugger implements ProcessDebugger { @Override public Collection getThreads() { - List threads = Lists.newArrayList(myMainDebugger.getThreads()); - - List result = Lists.newArrayList(); - cleanOtherDebuggers(); - collectAndRegisterOtherDebuggersThreads(threads); //we don't register mainDebugger as it is default if there is no mapping - + List threads = collectAllThreads(); if (myOtherDebuggers.size() > 0) { //here we add process id to thread name in case there are more then one process - threads = addProcessIdToThreadName(threads, result); + return Collections.unmodifiableCollection(Collections2.transform(threads, new Function() { + @Override + public PyThreadInfo apply(PyThreadInfo t) { + String threadName = ThreadRegistry.threadName(t.getName(), t.getId()); + PyThreadInfo newThread = + new PyThreadInfo(t.getId(), threadName, t.getFrames(), + t.getStopReason(), + t.getMessage()); + newThread.updateState(t.getState(), t.getFrames()); + return newThread; + } + })); + } + else { + return Collections.unmodifiableCollection(threads); } - - return Collections.unmodifiableCollection(threads); } - private static List addProcessIdToThreadName(List threads, List result) { - for (PyThreadInfo t : threads) { - String threadName = ThreadRegistry.threadName(t.getName(), t.getId()); - PyThreadInfo newThread = - new PyThreadInfo(t.getId(), threadName, t.getFrames(), - t.getStopReason(), - t.getMessage()); - newThread.updateState(t.getState(), t.getFrames()); - result.add(newThread); + private List collectAllThreads() { + List result = Lists.newArrayList(); + + result.addAll(myMainDebugger.getThreads()); + + //collect threads and add them to registry to faster access + //we don't register mainDebugger as it is default if there is no mapping + for (RemoteDebugger d : myOtherDebuggers) { + result.addAll(d.getThreads()); + for (PyThreadInfo t : d.getThreads()) { + myThreadRegistry.register(t.getId(), d); + } } - threads = result; - return threads; + + return result; } + private void cleanOtherDebuggers() { synchronized (myOtherDebuggers) { removeDisconnected(getOtherDebuggers()); @@ -299,15 +323,6 @@ public class MultiProcessDebugger implements ProcessDebugger { } } - private void collectAndRegisterOtherDebuggersThreads(List threads) { - for (RemoteDebugger d : getOtherDebuggers()) { - threads.addAll(d.getThreads()); - for (PyThreadInfo t : d.getThreads()) { - myThreadRegistry.register(t.getId(), d); - } - } - } - private ArrayList getOtherDebuggers() { synchronized (myOtherDebuggers) { return Lists.newArrayList(myOtherDebuggers); diff --git a/python/resources/pycharm_core_about.png b/python/resources/pycharm_core_about.png index ceed226afd1e..50cf5843e800 100644 Binary files a/python/resources/pycharm_core_about.png and b/python/resources/pycharm_core_about.png differ diff --git a/python/resources/pycharm_core_about@2x.png b/python/resources/pycharm_core_about@2x.png index b7d07aba32bf..7f6f9242cf88 100644 Binary files a/python/resources/pycharm_core_about@2x.png and b/python/resources/pycharm_core_about@2x.png differ diff --git a/python/resources/pycharm_core_logo.png b/python/resources/pycharm_core_logo.png index 9bc912b49bdf..959a3b94519f 100644 Binary files a/python/resources/pycharm_core_logo.png and b/python/resources/pycharm_core_logo.png differ diff --git a/python/resources/pycharm_core_logo@2x.png b/python/resources/pycharm_core_logo@2x.png index 0f4595c230f7..d24fc44a4479 100644 Binary files a/python/resources/pycharm_core_logo@2x.png and b/python/resources/pycharm_core_logo@2x.png differ diff --git a/python/src/com/jetbrains/python/console/PydevConsoleCommunication.java b/python/src/com/jetbrains/python/console/PydevConsoleCommunication.java index c27cfbe0ca0a..5e516b4fbf96 100644 --- a/python/src/com/jetbrains/python/console/PydevConsoleCommunication.java +++ b/python/src/com/jetbrains/python/console/PydevConsoleCommunication.java @@ -532,6 +532,8 @@ public class PydevConsoleCommunication extends AbstractConsoleCommunication impl public void changeVariable(PyDebugValue variable, String value) throws PyDebuggerException { if (myClient != null) { try { + // NOTE: The actual change is being scheduled in the exec_queue in main thread + // This method is async now Object ret = myClient.execute(CHANGE_VARIABLE, new Object[]{variable.getEvaluationExpression(), value}); checkError(ret); } diff --git a/python/testSrc/com/jetbrains/env/python/PythonConsoleTest.java b/python/testSrc/com/jetbrains/env/python/PythonConsoleTest.java index 4134b1697851..2d9399f2587c 100644 --- a/python/testSrc/com/jetbrains/env/python/PythonConsoleTest.java +++ b/python/testSrc/com/jetbrains/env/python/PythonConsoleTest.java @@ -122,8 +122,9 @@ public class PythonConsoleTest extends PyEnvTestCase { setValue("x", "2"); - assertTrue("Variable has wrong value", - hasValue("x", "2")); + exec("print(x)"); + + waitForOutput("2"); } }); }