Merge remote-tracking branch 'origin/master'
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -282,10 +282,10 @@ public abstract class PsiDocumentManagerBase extends PsiDocumentManager implemen
|
||||
}
|
||||
}
|
||||
|
||||
public boolean finishCommit(@NotNull final Document document,
|
||||
@NotNull final List<Processor<Document>> finishProcessors,
|
||||
final boolean synchronously,
|
||||
@NotNull final Object reason) {
|
||||
boolean finishCommit(@NotNull final Document document,
|
||||
@NotNull final List<Processor<Document>> finishProcessors,
|
||||
final boolean synchronously,
|
||||
@NotNull final Object reason) {
|
||||
assert !myProject.isDisposed() : "Already disposed";
|
||||
final boolean[] ok = {true};
|
||||
ApplicationManager.getApplication().runWriteAction(new CommitToPsiFileAction(document, myProject) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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<TRef, TResult> map = getMap(index);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -119,7 +119,7 @@ public class DuplicatesIndex extends FileBasedIndexExtension<Integer, TIntArrayL
|
||||
|
||||
if (profile instanceof LightDuplicateProfile && ourEnabledLightProfiles) {
|
||||
final THashMap<Integer, TIntArrayList> result = new THashMap<Integer, TIntArrayList>();
|
||||
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<Integer, TIntArrayL
|
||||
MyFragmentsCollector collector = new MyFragmentsCollector(profile, ((LanguageFileType)type).getLanguage());
|
||||
DuplocateVisitor visitor = profile.createVisitor(collector, true);
|
||||
|
||||
visitor.visitNode(fileContent.getPsiFileAccountingForUnsavedDocument());
|
||||
visitor.visitNode(fileContent.getPsiFileForPsiDependentIndex());
|
||||
|
||||
return collector.getMap();
|
||||
}
|
||||
|
||||
@@ -29,20 +29,17 @@ import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.ui.tree.TreeUtil;
|
||||
import com.intellij.util.ui.tree.WideSelectionTreeUI;
|
||||
import com.intellij.vcs.log.Hash;
|
||||
import com.intellij.vcs.log.ui.VcsLogUiImpl;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
import javax.swing.event.CellEditorListener;
|
||||
import javax.swing.event.ChangeEvent;
|
||||
import javax.swing.event.TreeSelectionEvent;
|
||||
import javax.swing.event.TreeSelectionListener;
|
||||
import javax.swing.event.*;
|
||||
import javax.swing.tree.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.*;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.EventObject;
|
||||
@@ -55,6 +52,7 @@ public class PushLog extends JPanel implements TypeSafeDataProvider {
|
||||
private final ChangesBrowser myChangesBrowser;
|
||||
private final CheckboxTree myTree;
|
||||
private final MyTreeCellRenderer myTreeCellRenderer;
|
||||
private final JScrollPane myScrollPane;
|
||||
private boolean myShouldRepaint = false;
|
||||
|
||||
public PushLog(Project project, final CheckedTreeNode root) {
|
||||
@@ -113,6 +111,7 @@ public class PushLog extends JPanel implements TypeSafeDataProvider {
|
||||
}
|
||||
}
|
||||
};
|
||||
myTree.setUI(new MyTreeUi());
|
||||
myTree.setBorder(new EmptyBorder(2, 0, 0, 0)); //additional vertical indent
|
||||
myTree.setEditable(true);
|
||||
myTree.setHorizontalAutoScrollingEnabled(false);
|
||||
@@ -164,7 +163,6 @@ public class PushLog extends JPanel implements TypeSafeDataProvider {
|
||||
//override default tree behaviour.
|
||||
myTree.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "");
|
||||
|
||||
myTree.setRowHeight(0);
|
||||
ToolTipManager.sharedInstance().registerComponent(myTree);
|
||||
PopupHandler.installPopupHandler(myTree, VcsLogUiImpl.POPUP_ACTION_GROUP, COMMIT_MENU);
|
||||
|
||||
@@ -176,11 +174,15 @@ public class PushLog extends JPanel implements TypeSafeDataProvider {
|
||||
setDefaultEmptyText();
|
||||
|
||||
Splitter splitter = new Splitter(false, 0.7f);
|
||||
splitter.setFirstComponent(ScrollPaneFactory.createScrollPane(myTree));
|
||||
myScrollPane = ScrollPaneFactory.createScrollPane(myTree);
|
||||
myScrollPane.setOpaque(false);
|
||||
splitter.setFirstComponent(myScrollPane);
|
||||
splitter.setSecondComponent(myChangesBrowser);
|
||||
|
||||
setLayout(new BorderLayout());
|
||||
add(splitter);
|
||||
myTree.setMinimumSize(new Dimension(200, myTree.getPreferredSize().height));
|
||||
myTree.setRowHeight(0);
|
||||
}
|
||||
|
||||
private void updateChangesView() {
|
||||
@@ -431,4 +433,59 @@ public class PushLog extends JPanel implements TypeSafeDataProvider {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class MyTreeUi extends WideSelectionTreeUI {
|
||||
|
||||
private final ComponentListener myTreeSizeListener = new ComponentAdapter() {
|
||||
@Override
|
||||
public void componentResized(ComponentEvent e) {
|
||||
// invalidate, revalidate etc may have no 'size' effects, you need to manually invalidateSizes before.
|
||||
updateSizes();
|
||||
}
|
||||
};
|
||||
|
||||
private final AncestorListener myTreeAncestorListener = new AncestorListenerAdapter() {
|
||||
@Override
|
||||
public void ancestorMoved(AncestorEvent event) {
|
||||
super.ancestorMoved(event);
|
||||
updateSizes();
|
||||
}
|
||||
};
|
||||
|
||||
private void updateSizes() {
|
||||
treeState.invalidateSizes();
|
||||
tree.repaint();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void installListeners() {
|
||||
super.installListeners();
|
||||
tree.addComponentListener(myTreeSizeListener);
|
||||
tree.addAncestorListener(myTreeAncestorListener);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void uninstallListeners() {
|
||||
tree.removeComponentListener(myTreeSizeListener);
|
||||
tree.removeAncestorListener(myTreeAncestorListener);
|
||||
super.uninstallListeners();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AbstractLayoutCache.NodeDimensions createNodeDimensions() {
|
||||
return new NodeDimensionsHandler() {
|
||||
@Override
|
||||
public Rectangle getNodeDimensions(Object value, int row, int depth, boolean expanded, Rectangle size) {
|
||||
Rectangle dimensions = super.getNodeDimensions(value, row, depth, expanded, size);
|
||||
dimensions.width = myScrollPane != null
|
||||
? Math.max(myScrollPane.getViewport().getWidth() - getRowX(row, depth), dimensions.width)
|
||||
: Math.max(myTree.getMinimumSize().width, dimensions.width);
|
||||
return dimensions;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -71,7 +71,7 @@ public interface BlockAlignmentProcessor {
|
||||
@NotNull public final Map<AbstractBlockWrapper, Set<AbstractBlockWrapper>> alignmentMappings;
|
||||
@NotNull public final Map<LeafBlockWrapper, Set<LeafBlockWrapper>> backwardShiftedAlignedBlocks;
|
||||
@NotNull public final CommonCodeStyleSettings.IndentOptions indentOptions;
|
||||
public int maxAlignmentSpaces;
|
||||
public final int maxAlignmentSpaces;
|
||||
|
||||
public Context(@NotNull Document document,
|
||||
@NotNull AlignmentImpl alignment,
|
||||
|
||||
@@ -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<LineIndentInfo> linesInfo = new LineIndentInfoBuilder(myDocument.getCharsSequence()).build();
|
||||
List<LineIndentInfo> linesInfo = new LineIndentInfoBuilder(myDocument.getCharsSequence(), myLanguage).build();
|
||||
IndentUsageStatistics stats = new IndentUsageStatisticsImpl(linesInfo);
|
||||
adjustIndentOptions(indentOptions, stats);
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -567,7 +567,7 @@ public class MapReduceIndex<Key, Value, Input> implements UpdatableIndex<Key,Val
|
||||
|
||||
private Integer getHashOfContent(FileContent content) throws IOException {
|
||||
if (myIsPsiBackedIndex && myHasSnapshotMapping && content instanceof FileContentImpl) {
|
||||
// psi backed index should use existing psi to build index value (FileContentImpl.getPsiFileAccountingForUnsavedDocument())
|
||||
// psi backed index should use existing psi to build index value (FileContentImpl.getPsiFileForPsiDependentIndex())
|
||||
// so we should use different bytes to calculate hash(Id)
|
||||
Integer previouslyCalculatedUncommittedHashId = content.getUserData(ourSavedUncommittedHashIdKey);
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2012 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.
|
||||
@@ -15,14 +15,10 @@
|
||||
*/
|
||||
package com.intellij.internal.anomalies;
|
||||
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.actionSystem.ActionGroup;
|
||||
import com.intellij.openapi.actionSystem.AnAction;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.objectTree.ObjectNode;
|
||||
import com.intellij.openapi.util.objectTree.ObjectTree;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -31,7 +27,10 @@ import java.awt.*;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.*;
|
||||
import java.util.Comparator;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
|
||||
/**
|
||||
* User: Vassiliy.Kudryashov
|
||||
@@ -169,49 +168,6 @@ public class TopAnomaliesAction extends ActionGroup {
|
||||
}
|
||||
};
|
||||
|
||||
private static final ResettableAction TOP_DISPOSABLE = new ResettableAction("Disposable") {
|
||||
TreeSet<Pair<Object, Integer>> top = new TreeSet<Pair<Object, Integer>>(COMPARATOR);
|
||||
TreeSet<Pair<Object, Integer>> old = new TreeSet<Pair<Object, Integer>>(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<Pair<Object, Integer>>(top);
|
||||
top.clear();
|
||||
ObjectTree<Disposable> tree = Disposer.getTree();
|
||||
Set<Disposable> roots = tree.getRootObjects();
|
||||
for (Disposable root : roots) {
|
||||
checkDisposables(tree, root, top, LIMIT);
|
||||
}
|
||||
System.out.println("Top " + LIMIT + " disposables");
|
||||
for (Pair<Object, Integer> 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<Pair<Object, Integer>> 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) {
|
||||
|
||||
@@ -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++) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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<LineIndentInfo> lines = new LineIndentInfoBuilder(document.getCharsSequence(), myFile.getLanguage()).build();
|
||||
IndentUsageStatistics statistics = new IndentUsageStatisticsImpl(lines);
|
||||
return statistics.getKMostUsedIndentInfo(0);
|
||||
}
|
||||
}
|
||||
@@ -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<LineIndentInfo> 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<LineIndentInfo> list = new LineIndentInfoBuilder(text).build();
|
||||
List<LineIndentInfo> 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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<T> {
|
||||
final class ObjectNode<T> {
|
||||
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<T> myTree;
|
||||
|
||||
private ObjectNode<T> myParent;
|
||||
private ObjectNode<T> myParent; // guarded by myTree.treeLock
|
||||
private final T myObject;
|
||||
|
||||
private SmartList<ObjectNode<T>> myChildren;
|
||||
private List<ObjectNode<T>> myChildren; // guarded by myTree.treeLock
|
||||
private final Throwable myTrace;
|
||||
|
||||
private final long myOwnModification;
|
||||
|
||||
public ObjectNode(@NotNull ObjectTree<T> tree, @Nullable ObjectNode<T> parentNode, @NotNull T object, long modification, @Nullable final Throwable trace) {
|
||||
ObjectNode(@NotNull ObjectTree<T> tree,
|
||||
@Nullable ObjectNode<T> parentNode,
|
||||
@NotNull T object,
|
||||
long modification,
|
||||
@Nullable final Throwable trace) {
|
||||
myTree = tree;
|
||||
myParent = parentNode;
|
||||
myObject = object;
|
||||
@@ -55,43 +59,36 @@ public final class ObjectNode<T> {
|
||||
@SuppressWarnings("unchecked")
|
||||
@NotNull
|
||||
private ObjectNode<T>[] getChildrenArray() {
|
||||
synchronized (myTree.treeLock) {
|
||||
if (myChildren == null || myChildren.isEmpty()) return EMPTY_ARRAY;
|
||||
return myChildren.toArray(new ObjectNode[myChildren.size()]);
|
||||
}
|
||||
List<ObjectNode<T>> children = myChildren;
|
||||
if (children == null || children.isEmpty()) return EMPTY_ARRAY;
|
||||
return children.toArray(new ObjectNode[children.size()]);
|
||||
}
|
||||
|
||||
void addChild(@NotNull ObjectNode<T> child) {
|
||||
synchronized (myTree.treeLock) {
|
||||
if (myChildren == null) {
|
||||
myChildren = new SmartList<ObjectNode<T>>();
|
||||
}
|
||||
myChildren.add(child);
|
||||
child.myParent = this;
|
||||
List<ObjectNode<T>> children = myChildren;
|
||||
if (children == null) {
|
||||
myChildren = new SmartList<ObjectNode<T>>(child);
|
||||
}
|
||||
else {
|
||||
children.add(child);
|
||||
}
|
||||
child.myParent = this;
|
||||
}
|
||||
|
||||
void removeChild(@NotNull ObjectNode<T> child) {
|
||||
synchronized (myTree.treeLock) {
|
||||
assert myChildren != null: "No children to remove child: " + this + ' ' + child;
|
||||
ListIterator<ObjectNode<T>> iterator = myChildren.listIterator(myChildren.size());
|
||||
while (iterator.hasPrevious()) {
|
||||
if (child.equals(iterator.previous())) {
|
||||
iterator.remove();
|
||||
return;
|
||||
}
|
||||
}
|
||||
List<ObjectNode<T>> children = myChildren;
|
||||
if (children != null) {
|
||||
children.remove(child);
|
||||
}
|
||||
child.myParent = null;
|
||||
}
|
||||
|
||||
public ObjectNode<T> getParent() {
|
||||
synchronized (myTree.treeLock) {
|
||||
return myParent;
|
||||
}
|
||||
ObjectNode<T> getParent() {
|
||||
return myParent;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Collection<ObjectNode<T>> getChildren() {
|
||||
Collection<ObjectNode<T>> getChildren() {
|
||||
synchronized (myTree.treeLock) {
|
||||
if (myChildren == null) return Collections.emptyList();
|
||||
return Collections.unmodifiableCollection(myChildren);
|
||||
@@ -109,7 +106,10 @@ public final class ObjectNode<T> {
|
||||
LOG.error(t);
|
||||
}
|
||||
|
||||
ObjectNode<T>[] childrenArray = getChildrenArray();
|
||||
ObjectNode<T>[] 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<T> {
|
||||
}
|
||||
|
||||
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<T> {
|
||||
}
|
||||
|
||||
@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<T> {
|
||||
|
||||
<D extends Disposable> D findChildEqualTo(@NotNull D object) {
|
||||
synchronized (myTree.treeLock) {
|
||||
SmartList<ObjectNode<T>> children = myChildren;
|
||||
List<ObjectNode<T>> children = myChildren;
|
||||
if (children != null) {
|
||||
for (ObjectNode<T> node : children) {
|
||||
T nodeObject = node.getObject();
|
||||
if (nodeObject.equals(object)) {
|
||||
//noinspection unchecked
|
||||
return (D)nodeObject;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,28 +34,26 @@ public final class ObjectTree<T> {
|
||||
private final List<ObjectTreeListener> myListeners = ContainerUtil.createLockFreeCopyOnWriteList();
|
||||
|
||||
// identity used here to prevent problems with hashCode/equals overridden by not very bright minds
|
||||
private final Set<T> myRootObjects = ContainerUtil.newIdentityTroveSet();
|
||||
private final Map<T, ObjectNode<T>> myObject2NodeMap = ContainerUtil.newIdentityTroveMap();
|
||||
private final Set<T> myRootObjects = ContainerUtil.newIdentityTroveSet(); // guarded by treeLock
|
||||
private final Map<T, ObjectNode<T>> myObject2NodeMap = ContainerUtil.newIdentityTroveMap(); // guarded by treeLock
|
||||
|
||||
private final List<ObjectNode<T>> myExecutedNodes = new ArrayList<ObjectNode<T>>();
|
||||
private final List<T> myExecutedUnregisteredNodes = new ArrayList<T>();
|
||||
private final List<ObjectNode<T>> myExecutedNodes = new ArrayList<ObjectNode<T>>(); // guarded by myExecutedNodes
|
||||
private final List<T> myExecutedUnregisteredNodes = new ArrayList<T>(); // guarded by myExecutedUnregisteredNodes
|
||||
|
||||
final Object treeLock = new Object();
|
||||
|
||||
private final AtomicLong myModification = new AtomicLong(0);
|
||||
|
||||
public ObjectNode<T> getNode(@NotNull T object) {
|
||||
synchronized (treeLock) {
|
||||
return myObject2NodeMap.get(object);
|
||||
}
|
||||
}
|
||||
public ObjectNode<T> putNode(@NotNull T object, @Nullable("null means remove") ObjectNode<T> node) {
|
||||
synchronized (treeLock) {
|
||||
return node == null ? myObject2NodeMap.remove(object) : myObject2NodeMap.put(object, node);
|
||||
}
|
||||
ObjectNode<T> getNode(@NotNull T object) {
|
||||
return myObject2NodeMap.get(object);
|
||||
}
|
||||
|
||||
public final List<ObjectNode<T>> getNodesInExecution() {
|
||||
ObjectNode<T> putNode(@NotNull T object, @Nullable("null means remove") ObjectNode<T> node) {
|
||||
return node == null ? myObject2NodeMap.remove(object) : myObject2NodeMap.put(object, node);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
final List<ObjectNode<T>> getNodesInExecution() {
|
||||
return myExecutedNodes;
|
||||
}
|
||||
|
||||
@@ -105,8 +103,7 @@ public final class ObjectTree<T> {
|
||||
|
||||
@NotNull
|
||||
private ObjectNode<T> createNodeFor(@NotNull T object, @Nullable ObjectNode<T> parentNode, @Nullable final Throwable trace) {
|
||||
final ObjectNode<T> newNode = new ObjectNode<T>(this, parentNode, object, getNextModification(),
|
||||
trace);
|
||||
final ObjectNode<T> newNode = new ObjectNode<T>(this, parentNode, object, getNextModification(), trace);
|
||||
if (parentNode == null) {
|
||||
myRootObjects.add(object);
|
||||
}
|
||||
@@ -114,12 +111,15 @@ public final class ObjectTree<T> {
|
||||
return newNode;
|
||||
}
|
||||
|
||||
public long getNextModification() {
|
||||
private long getNextModification() {
|
||||
return myModification.incrementAndGet();
|
||||
}
|
||||
|
||||
public final boolean executeAll(@NotNull T object, boolean disposeTree, @NotNull ObjectTreeAction<T> action, boolean processUnregistered) {
|
||||
ObjectNode<T> node = getNode(object);
|
||||
ObjectNode<T> node;
|
||||
synchronized (treeLock) {
|
||||
node = getNode(object);
|
||||
}
|
||||
if (node == null) {
|
||||
if (processUnregistered) {
|
||||
executeUnregistered(object, action);
|
||||
@@ -147,7 +147,7 @@ public final class ObjectTree<T> {
|
||||
}
|
||||
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<T> {
|
||||
}
|
||||
|
||||
public final void executeChildAndReplace(@NotNull T toExecute, @NotNull T toReplace, boolean disposeTree, @NotNull ObjectTreeAction<T> action) {
|
||||
final ObjectNode<T> toExecuteNode = getNode(toExecute);
|
||||
assert toExecuteNode != null : "Object " + toExecute + " wasn't registered or already disposed";
|
||||
|
||||
final ObjectNode<T> toExecuteNode;
|
||||
T parentObject;
|
||||
synchronized (treeLock) {
|
||||
toExecuteNode = getNode(toExecute);
|
||||
assert toExecuteNode != null : "Object " + toExecute + " wasn't registered or already disposed";
|
||||
|
||||
final ObjectNode<T> 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<T> {
|
||||
}
|
||||
|
||||
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<ObjectNode<T>> nodes = myObject2NodeMap.values();
|
||||
for (ObjectNode<T> node : nodes) {
|
||||
@@ -187,57 +190,53 @@ public final class ObjectTree<T> {
|
||||
}
|
||||
}
|
||||
|
||||
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<T> objectNode = getNode(object);
|
||||
if (objectNode == null) continue;
|
||||
synchronized (treeLock) {
|
||||
for (T object : myRootObjects) {
|
||||
if (object == null) continue;
|
||||
final ObjectNode<T> 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<T> getRootObjects() {
|
||||
return myRootObjects;
|
||||
Set<T> 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<T> {
|
||||
}
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return myObject2NodeMap.size();
|
||||
int size() {
|
||||
synchronized (treeLock) {
|
||||
return myObject2NodeMap.size();
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -262,7 +263,7 @@ public final class ObjectTree<T> {
|
||||
}
|
||||
}
|
||||
|
||||
public long getModification() {
|
||||
long getModification() {
|
||||
return myModification.get();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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<Content> doPresetOrdering(final List<Content> contents) {
|
||||
final List<Content> result = new ArrayList<Content>(contents.size());
|
||||
for (final String preset : ourPresetOrder) {
|
||||
|
||||
@@ -91,7 +91,7 @@ class VisiblePackBuilder {
|
||||
}
|
||||
|
||||
VisibleGraph<Integer> 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 <T> boolean matchesNothing(@Nullable Collection<T> matchingSet) {
|
||||
return matchingSet != null && matchingSet.isEmpty();
|
||||
}
|
||||
|
||||
private VisiblePack applyHashFilter(@NotNull DataPack dataPack,
|
||||
@NotNull Collection<String> hashes,
|
||||
@NotNull PermanentGraph.SortType sortType) {
|
||||
@@ -160,25 +164,24 @@ class VisiblePackBuilder {
|
||||
@NotNull final PermanentGraph<Integer> permanentGraph,
|
||||
@NotNull List<VcsLogDetailsFilter> detailsFilters,
|
||||
@Nullable final Set<Integer> matchingHeads) {
|
||||
final int commitIndex = myHashMap.getCommitIndex(commit.getId());
|
||||
return ContainerUtil.and(detailsFilters, new Condition<VcsLogDetailsFilter>() {
|
||||
boolean matchesAllDetails = ContainerUtil.and(detailsFilters, new Condition<VcsLogDetailsFilter>() {
|
||||
@Override
|
||||
public boolean value(VcsLogDetailsFilter filter) {
|
||||
if (!filter.matches(commit)) {
|
||||
return false;
|
||||
}
|
||||
if (matchingHeads == null) {
|
||||
return true;
|
||||
}
|
||||
Set<Integer> containingBranches = permanentGraph.getContainingBranches(commitIndex);
|
||||
return ContainerUtil.exists(containingBranches, new Condition<Integer>() {
|
||||
@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<Integer> permanentGraph,
|
||||
@NotNull VcsCommitMetadata commit,
|
||||
@Nullable Set<Integer> matchingHeads) {
|
||||
if (matchingHeads == null) {
|
||||
return true;
|
||||
}
|
||||
// TODO O(n^2)
|
||||
int commitIndex = myHashMap.getCommitIndex(commit.getId());
|
||||
return ContainerUtil.intersects(permanentGraph.getContainingBranches(commitIndex), matchingHeads);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
||||
@@ -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<HashImpl> 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<HashImpl> readFromFile(@NotNull File file) throws IOException {
|
||||
List<HashImpl> 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;
|
||||
}
|
||||
}
|
||||
|
||||
|
Before Width: | Height: | Size: 151 KiB After Width: | Height: | Size: 151 KiB |
@@ -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)
|
||||
|
||||
@@ -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<PyThreadInfo> getThreads() {
|
||||
List<PyThreadInfo> threads = Lists.newArrayList(myMainDebugger.getThreads());
|
||||
|
||||
List<PyThreadInfo> result = Lists.newArrayList();
|
||||
|
||||
cleanOtherDebuggers();
|
||||
|
||||
collectAndRegisterOtherDebuggersThreads(threads); //we don't register mainDebugger as it is default if there is no mapping
|
||||
|
||||
List<PyThreadInfo> 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<PyThreadInfo, PyThreadInfo>() {
|
||||
@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<PyThreadInfo> addProcessIdToThreadName(List<PyThreadInfo> threads, List<PyThreadInfo> 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<PyThreadInfo> collectAllThreads() {
|
||||
List<PyThreadInfo> 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<PyThreadInfo> threads) {
|
||||
for (RemoteDebugger d : getOtherDebuggers()) {
|
||||
threads.addAll(d.getThreads());
|
||||
for (PyThreadInfo t : d.getThreads()) {
|
||||
myThreadRegistry.register(t.getId(), d);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private ArrayList<RemoteDebugger> getOtherDebuggers() {
|
||||
synchronized (myOtherDebuggers) {
|
||||
return Lists.newArrayList(myOtherDebuggers);
|
||||
|
||||
|
Before Width: | Height: | Size: 9.6 KiB After Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 61 KiB |
|
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 44 KiB |
|
Before Width: | Height: | Size: 66 KiB After Width: | Height: | Size: 84 KiB |
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||