From 7d8033950329ef6b335db6a2c51b894d3bdc6746 Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Thu, 6 Nov 2014 15:15:11 +0300 Subject: [PATCH 01/34] Fixed redundant checks and code style --- .../impl/references/PyImportReference.java | 66 ++++++++++--------- 1 file changed, 34 insertions(+), 32 deletions(-) diff --git a/python/src/com/jetbrains/python/psi/impl/references/PyImportReference.java b/python/src/com/jetbrains/python/psi/impl/references/PyImportReference.java index 69eb8a6dd0da..be7921bd6b22 100644 --- a/python/src/com/jetbrains/python/psi/impl/references/PyImportReference.java +++ b/python/src/com/jetbrains/python/psi/impl/references/PyImportReference.java @@ -157,8 +157,8 @@ public class PyImportReference extends PyReferenceImpl { } ASTNode node = myElement.getNode(); while (node != null) { - final IElementType node_type = node.getElementType(); - if (node_type == PyTokenTypes.IMPORT_KEYWORD) { + final IElementType nodeType = node.getElementType(); + if (nodeType == PyTokenTypes.IMPORT_KEYWORD) { return true; } node = node.getTreeNext(); @@ -175,7 +175,7 @@ public class PyImportReference extends PyReferenceImpl { public ImportVariantCollector(@NotNull TypeEvalContext context) { myContext = context; PsiFile currentFile = myElement.getContainingFile(); - if (currentFile != null) currentFile = currentFile.getOriginalFile(); + currentFile = currentFile.getOriginalFile(); myCurrentFile = currentFile; myNamesAlready = new HashSet(); myObjects = new ArrayList(); @@ -187,15 +187,15 @@ public class PyImportReference extends PyReferenceImpl { // NOTE: could use getPointInImport() // are we in "import _" or "from foo import _"? - PyFromImportStatement from_import = PsiTreeUtil.getParentOfType(myElement, PyFromImportStatement.class); - if (from_import != null && myElement.getParent() != from_import) { // in "from foo import _" - PyReferenceExpression src = from_import.getImportSource(); + PyFromImportStatement fromImport = PsiTreeUtil.getParentOfType(myElement, PyFromImportStatement.class); + if (fromImport != null && myElement.getParent() != fromImport) { // in "from foo import _" + PyReferenceExpression src = fromImport.getImportSource(); if (src != null) { - PsiElement mod_candidate = src.getReference().resolve(); - if (mod_candidate instanceof PyExpression) { - addImportedNames(from_import.getImportElements()); // don't propose already imported items + PsiElement modCandidate = src.getReference().resolve(); + if (modCandidate instanceof PyExpression) { + addImportedNames(fromImport.getImportElements()); // don't propose already imported items // try to collect submodules - PyExpression module = (PyExpression)mod_candidate; + PyExpression module = (PyExpression)modCandidate; PyType qualifierType = myContext.getType(module); if (qualifierType != null) { ProcessingContext ctx = new ProcessingContext(); @@ -204,18 +204,18 @@ public class PyImportReference extends PyReferenceImpl { } return myObjects.toArray(); } - else if (mod_candidate instanceof PsiDirectory) { - fillFromDir((PsiDirectory)mod_candidate, ImportKeywordHandler.INSTANCE); + else if (modCandidate instanceof PsiDirectory) { + fillFromDir((PsiDirectory)modCandidate, ImportKeywordHandler.INSTANCE); return myObjects.toArray(); } } else { // null source, must be a "from ... import" - relativeLevel = from_import.getRelativeLevel(); + relativeLevel = fromImport.getRelativeLevel(); if (relativeLevel > 0) { - PsiDirectory relative_dir = ResolveImportUtil.stepBackFrom(myCurrentFile, relativeLevel); - if (relative_dir != null) { - addImportedNames(from_import.getImportElements()); - fillFromDir(relative_dir, null); + PsiDirectory relativeDir = ResolveImportUtil.stepBackFrom(myCurrentFile, relativeLevel); + if (relativeDir != null) { + addImportedNames(fromImport.getImportElements()); + fillFromDir(relativeDir, null); } } } @@ -226,21 +226,21 @@ public class PyImportReference extends PyReferenceImpl { relativeLevel += 1; n = n.getTreePrev(); } - if (from_import != null) { - addImportedNames(from_import.getImportElements()); + if (fromImport != null) { + addImportedNames(fromImport.getImportElements()); if (!alreadyHasImportKeyword()) { insertHandler = ImportKeywordHandler.INSTANCE; } } else { myNamesAlready.add(PyNames.FUTURE_MODULE); // never add it to "import ..." - PyImportStatement import_stmt = PsiTreeUtil.getParentOfType(myElement, PyImportStatement.class); - if (import_stmt != null) { - addImportedNames(import_stmt.getImportElements()); + PyImportStatement importStatement = PsiTreeUtil.getParentOfType(myElement, PyImportStatement.class); + if (importStatement != null) { + addImportedNames(importStatement.getImportElements()); } } // look at dir by level - if (myCurrentFile != null && (relativeLevel >= 0 || !ResolveImportUtil.isAbsoluteImportEnabledFor(myCurrentFile))) { + if ((relativeLevel >= 0 || !ResolveImportUtil.isAbsoluteImportEnabledFor(myCurrentFile))) { final PsiDirectory containingDirectory = myCurrentFile.getContainingDirectory(); if (containingDirectory != null) { QualifiedName thisQName = QualifiedNameFinder.findShortestImportableQName(containingDirectory); @@ -268,9 +268,9 @@ public class PyImportReference extends PyReferenceImpl { } } - private void addImportedNames(@NotNull PyImportElement[] import_elts) { - for (PyImportElement ielt : import_elts) { - PyReferenceExpression ref = ielt.getImportReferenceExpression(); + private void addImportedNames(@NotNull PyImportElement[] importElements) { + for (PyImportElement element : importElements) { + PyReferenceExpression ref = element.getImportReferenceExpression(); if (ref != null) { String s = ref.getReferencedName(); if (s != null) myNamesAlready.add(s); @@ -278,22 +278,24 @@ public class PyImportReference extends PyReferenceImpl { } } - // adds variants found under given dir - private void fillFromDir(PsiDirectory target_dir, @Nullable InsertHandler insertHandler) { - if (target_dir != null) { - PsiFile initPy = target_dir.findFile(PyNames.INIT_DOT_PY); + /** + * Adds variants found under given dir. + */ + private void fillFromDir(PsiDirectory targetDir, @Nullable InsertHandler insertHandler) { + if (targetDir != null) { + PsiFile initPy = targetDir.findFile(PyNames.INIT_DOT_PY); if (initPy instanceof PyFile) { PyModuleType moduleType = new PyModuleType((PyFile)initPy); ProcessingContext context = new ProcessingContext(); context.put(PyType.CTX_NAMES, myNamesAlready); - Object[] completionVariants = moduleType.getCompletionVariants("", (PyExpression)getElement(), context); + Object[] completionVariants = moduleType.getCompletionVariants("", getElement(), context); if (insertHandler != null) { replaceInsertHandler(completionVariants, insertHandler); } myObjects.addAll(Arrays.asList(completionVariants)); } else { - myObjects.addAll(PyModuleType.getSubModuleVariants(target_dir, myElement, myNamesAlready)); + myObjects.addAll(PyModuleType.getSubModuleVariants(targetDir, myElement, myNamesAlready)); } } } From 017bf71da625d4112e75516a75341db29e90d989 Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Thu, 6 Nov 2014 15:37:58 +0300 Subject: [PATCH 02/34] Fixed completion for 'import ' (PY-7375) --- .../com/jetbrains/python/psi/types/PyModuleType.java | 8 +++++--- .../completion/importNamespacePackage/a.after.py | 1 + .../testData/completion/importNamespacePackage/a.py | 1 + .../com/jetbrains/python/Py3CompletionTest.java | 12 ++++++++++++ 4 files changed, 19 insertions(+), 3 deletions(-) create mode 100644 python/testData/completion/importNamespacePackage/a.after.py create mode 100644 python/testData/completion/importNamespacePackage/a.py diff --git a/python/src/com/jetbrains/python/psi/types/PyModuleType.java b/python/src/com/jetbrains/python/psi/types/PyModuleType.java index 0aec8612c989..8db0b716194f 100644 --- a/python/src/com/jetbrains/python/psi/types/PyModuleType.java +++ b/python/src/com/jetbrains/python/psi/types/PyModuleType.java @@ -245,7 +245,7 @@ public class PyModuleType implements PyType { // Modules don't descend from obje * not suitable for import. */ @NotNull - private static List getSubmodulesList(final PsiDirectory directory) { + private static List getSubmodulesList(final PsiDirectory directory, @Nullable PsiElement anchor) { List result = new ArrayList(); if (directory != null) { // just in case @@ -259,7 +259,9 @@ public class PyModuleType implements PyType { // Modules don't descend from obje } // dir modules for (PsiDirectory dir : directory.getSubdirectories()) { - if (dir.findFile(PyNames.INIT_DOT_PY) instanceof PyFile) result.add(dir); + if (PyUtil.isPackage(dir, anchor)) { + result.add(dir); + } } } return result; @@ -365,7 +367,7 @@ public class PyModuleType implements PyType { // Modules don't descend from obje PsiElement location, Set namesAlready) { List result = new ArrayList(); - for (PsiFileSystemItem item : getSubmodulesList(directory)) { + for (PsiFileSystemItem item : getSubmodulesList(directory, location)) { if (item != location.getContainingFile().getOriginalFile()) { LookupElement lookupElement = buildFileLookupElement(item, namesAlready); if (lookupElement != null) { diff --git a/python/testData/completion/importNamespacePackage/a.after.py b/python/testData/completion/importNamespacePackage/a.after.py new file mode 100644 index 000000000000..3a900b8dcab9 --- /dev/null +++ b/python/testData/completion/importNamespacePackage/a.after.py @@ -0,0 +1 @@ +import nspkg1 diff --git a/python/testData/completion/importNamespacePackage/a.py b/python/testData/completion/importNamespacePackage/a.py new file mode 100644 index 000000000000..bbb3f11374c9 --- /dev/null +++ b/python/testData/completion/importNamespacePackage/a.py @@ -0,0 +1 @@ +import nspk diff --git a/python/testSrc/com/jetbrains/python/Py3CompletionTest.java b/python/testSrc/com/jetbrains/python/Py3CompletionTest.java index ca7c3c2649f3..a950cf6584c5 100644 --- a/python/testSrc/com/jetbrains/python/Py3CompletionTest.java +++ b/python/testSrc/com/jetbrains/python/Py3CompletionTest.java @@ -69,6 +69,13 @@ public class Py3CompletionTest extends PyTestCase { myFixture.checkResultByFile(testName + ".after.py"); } + private void doMultiFileTest() { + myFixture.copyDirectoryToProject("completion/" + getTestName(true), ""); + myFixture.configureByFile("a.py"); + myFixture.completeBasic(); + myFixture.checkResultByFile("completion/" + getTestName(true) + "/a.after.py"); + } + private List doTestByText(String text) { myFixture.configureByText(PythonFileType.INSTANCE, text); myFixture.completeBasic(); @@ -93,4 +100,9 @@ public class Py3CompletionTest extends PyTestCase { setLanguageLevel(null); } } + + // PY-7375 + public void testImportNamespacePackage() { + doMultiFileTest(); + } } From a9db68a8422372a976d4183e67e8a71edb9ed53e Mon Sep 17 00:00:00 2001 From: Alexander Marchuk Date: Thu, 6 Nov 2014 15:57:02 +0300 Subject: [PATCH 03/34] fix slicing --- python/helpers/pydev/pydevd_comm.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/python/helpers/pydev/pydevd_comm.py b/python/helpers/pydev/pydevd_comm.py index d26c965c88bd..166966011ef7 100644 --- a/python/helpers/pydev/pydevd_comm.py +++ b/python/helpers/pydev/pydevd_comm.py @@ -996,16 +996,17 @@ class InternalGetArray(InternalThreadCommand): cols = 1 elif self.rows == 1 or self.cols == 1: is_row = True if (self.rows == 1) else False - pure_1d = False if (len(var) == 1) else True + if is_row: + var = var[self.roffset:] + else: + var = var[self.coffset:] - if not pure_1d: + if len(var) == 1: var = var[0] if is_row: - var = var[self.coffset:] cols = min(cols, len(var)) else: - var = var[self.roffset:] rows = min(rows, len(var)) else: var = var[self.roffset:, self.coffset:] From 47c24d9a7c6c86a5f35e4a7997c55bef01da61a8 Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Thu, 6 Nov 2014 16:00:06 +0300 Subject: [PATCH 04/34] Cleanup --- .../com/jetbrains/python/psi/types/PyImportedModuleType.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/python/src/com/jetbrains/python/psi/types/PyImportedModuleType.java b/python/src/com/jetbrains/python/psi/types/PyImportedModuleType.java index 9fcbe52ed8d0..b5734eddfa05 100644 --- a/python/src/com/jetbrains/python/psi/types/PyImportedModuleType.java +++ b/python/src/com/jetbrains/python/psi/types/PyImportedModuleType.java @@ -19,6 +19,7 @@ import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.codeInsight.lookup.LookupElementBuilder; import com.intellij.psi.PsiDirectory; import com.intellij.psi.PsiElement; +import com.intellij.util.ArrayUtil; import com.intellij.util.ProcessingContext; import com.jetbrains.python.codeInsight.controlflow.ScopeOwner; import com.jetbrains.python.codeInsight.dataflow.scope.ScopeUtil; @@ -82,7 +83,7 @@ public class PyImportedModuleType implements PyType { } } } - return result.toArray(new Object[result.size()]); + return ArrayUtil.toObjectArray(result); } public String getName() { From 7a416056789549a290dc468fe8ca7aca30ac6647 Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Thu, 6 Nov 2014 16:40:44 +0300 Subject: [PATCH 05/34] Fixed completion for 'import .' (PY-5422, PY-3770, PY-10354) --- .../python/psi/impl/PyReferenceExpressionImpl.java | 12 +++++++++++- .../python/psi/types/PyImportedModuleType.java | 14 +++++++++----- .../importQualifiedNamespacePackage/a.after.py | 1 + .../importQualifiedNamespacePackage/a.py | 1 + .../importQualifiedNamespacePackage/nspkg1/bar.py | 0 .../importQualifiedNamespacePackage/nspkg1/foo.py | 0 .../com/jetbrains/python/Py3CompletionTest.java | 5 +++++ 7 files changed, 27 insertions(+), 6 deletions(-) create mode 100644 python/testData/completion/importQualifiedNamespacePackage/a.after.py create mode 100644 python/testData/completion/importQualifiedNamespacePackage/a.py create mode 100644 python/testData/completion/importQualifiedNamespacePackage/nspkg1/bar.py create mode 100644 python/testData/completion/importQualifiedNamespacePackage/nspkg1/foo.py diff --git a/python/src/com/jetbrains/python/psi/impl/PyReferenceExpressionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyReferenceExpressionImpl.java index 1fc91e0334ec..a4ba8f8ead5d 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyReferenceExpressionImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyReferenceExpressionImpl.java @@ -374,10 +374,20 @@ public class PyReferenceExpressionImpl extends PyElementImpl implements PyRefere return context.getType((PyTypedElement)target); } if (target instanceof PsiDirectory) { - PsiFile file = ((PsiDirectory)target).findFile(PyNames.INIT_DOT_PY); + final PsiDirectory dir = (PsiDirectory)target; + PsiFile file = dir.findFile(PyNames.INIT_DOT_PY); if (file != null) { return getTypeFromTarget(file, context, anchor); } + if (context.maySwitchToAST(anchor) && PyUtil.isPackage(dir, anchor)) { + final PyImportElement importElement = PsiTreeUtil.getParentOfType(anchor, PyImportElement.class); + final PsiFile containingFile = anchor.getContainingFile(); + if (importElement != null && containingFile instanceof PyFile) { + final QualifiedName qualifiedName = QualifiedName.fromComponents(dir.getName()); + final PyImportedModule module = new PyImportedModule(importElement, (PyFile)containingFile, qualifiedName); + return new PyImportedModuleType(module); + } + } } return null; } diff --git a/python/src/com/jetbrains/python/psi/types/PyImportedModuleType.java b/python/src/com/jetbrains/python/psi/types/PyImportedModuleType.java index b5734eddfa05..bc26a1a87ba2 100644 --- a/python/src/com/jetbrains/python/psi/types/PyImportedModuleType.java +++ b/python/src/com/jetbrains/python/psi/types/PyImportedModuleType.java @@ -19,16 +19,13 @@ import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.codeInsight.lookup.LookupElementBuilder; import com.intellij.psi.PsiDirectory; import com.intellij.psi.PsiElement; +import com.intellij.psi.util.QualifiedName; import com.intellij.util.ArrayUtil; import com.intellij.util.ProcessingContext; import com.jetbrains.python.codeInsight.controlflow.ScopeOwner; import com.jetbrains.python.codeInsight.dataflow.scope.ScopeUtil; -import com.jetbrains.python.psi.AccessDirection; -import com.jetbrains.python.psi.PyExpression; -import com.jetbrains.python.psi.PyFile; -import com.jetbrains.python.psi.PyImportElement; +import com.jetbrains.python.psi.*; import com.jetbrains.python.psi.impl.PyImportedModule; -import com.intellij.psi.util.QualifiedName; import com.jetbrains.python.psi.resolve.PyResolveContext; import com.jetbrains.python.psi.resolve.RatedResolveResult; import com.jetbrains.python.psi.resolve.ResolveImportUtil; @@ -83,6 +80,13 @@ public class PyImportedModuleType implements PyType { } } } + final PsiElement resolved = myImportedModule.resolve(); + if (resolved instanceof PsiDirectory) { + final PsiDirectory dir = (PsiDirectory)resolved; + if (PyUtil.isPackage(dir, location)) { + result.addAll(PyModuleType.getSubModuleVariants(dir, location, null)); + } + } return ArrayUtil.toObjectArray(result); } diff --git a/python/testData/completion/importQualifiedNamespacePackage/a.after.py b/python/testData/completion/importQualifiedNamespacePackage/a.after.py new file mode 100644 index 000000000000..c0b0b049717a --- /dev/null +++ b/python/testData/completion/importQualifiedNamespacePackage/a.after.py @@ -0,0 +1 @@ +import nspkg1.foo diff --git a/python/testData/completion/importQualifiedNamespacePackage/a.py b/python/testData/completion/importQualifiedNamespacePackage/a.py new file mode 100644 index 000000000000..737dcb8bad5d --- /dev/null +++ b/python/testData/completion/importQualifiedNamespacePackage/a.py @@ -0,0 +1 @@ +import nspkg1.f diff --git a/python/testData/completion/importQualifiedNamespacePackage/nspkg1/bar.py b/python/testData/completion/importQualifiedNamespacePackage/nspkg1/bar.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testData/completion/importQualifiedNamespacePackage/nspkg1/foo.py b/python/testData/completion/importQualifiedNamespacePackage/nspkg1/foo.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testSrc/com/jetbrains/python/Py3CompletionTest.java b/python/testSrc/com/jetbrains/python/Py3CompletionTest.java index a950cf6584c5..96ce44eeb467 100644 --- a/python/testSrc/com/jetbrains/python/Py3CompletionTest.java +++ b/python/testSrc/com/jetbrains/python/Py3CompletionTest.java @@ -105,4 +105,9 @@ public class Py3CompletionTest extends PyTestCase { public void testImportNamespacePackage() { doMultiFileTest(); } + + // PY-5422 + public void testImportQualifiedNamespacePackage() { + doMultiFileTest(); + } } From c4a5dcfdfc4deecd05f5e4ecd31d810ce0fdc87b Mon Sep 17 00:00:00 2001 From: Dmitry Trofimov Date: Thu, 6 Nov 2014 14:46:41 +0100 Subject: [PATCH 06/34] Revert method rename for compatibility. --- .../com/intellij/xdebugger/impl/ui/XDebuggerEditorBase.java | 4 ++-- .../xdebugger/impl/ui/XDebuggerExpressionComboBox.java | 2 +- .../intellij/xdebugger/impl/ui/XDebuggerMultilineEditor.java | 2 +- .../jetbrains/python/debugger/array/ArrayTableCellEditor.java | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebuggerEditorBase.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebuggerEditorBase.java index 05d56161bade..4d7d65fff3c5 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebuggerEditorBase.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebuggerEditorBase.java @@ -142,7 +142,7 @@ public abstract class XDebuggerEditorBase { public abstract JComponent getComponent(); - protected abstract void setEditorText(XExpression text); + protected abstract void doSetText(XExpression text); public void setExpression(@Nullable XExpression text) { if (text == null) { @@ -174,7 +174,7 @@ public abstract class XDebuggerEditorBase { myChooseFactory.setDisabledIcon(IconLoader.getDisabledIcon(icon)); } - setEditorText(text); + doSetText(text); } @Nullable diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebuggerExpressionComboBox.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebuggerExpressionComboBox.java index eaff436919db..3039d2acda7f 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebuggerExpressionComboBox.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebuggerExpressionComboBox.java @@ -128,7 +128,7 @@ public class XDebuggerExpressionComboBox extends XDebuggerEditorBase { } @Override - protected void setEditorText(XExpression text) { + protected void doSetText(XExpression text) { if (myComboBox.getItemCount() > 0) { myComboBox.setSelectedIndex(0); } diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebuggerMultilineEditor.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebuggerMultilineEditor.java index 386bca17e856..b2222ce556c5 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebuggerMultilineEditor.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebuggerMultilineEditor.java @@ -69,7 +69,7 @@ public class XDebuggerMultilineEditor extends XDebuggerEditorBase { } @Override - protected void setEditorText(XExpression text) { + protected void doSetText(XExpression text) { myExpression = text; Language language = text.getLanguage(); FileType fileType = language != null ? language.getAssociatedFileType() : getEditorsProvider().getFileType(); diff --git a/python/src/com/jetbrains/python/debugger/array/ArrayTableCellEditor.java b/python/src/com/jetbrains/python/debugger/array/ArrayTableCellEditor.java index 6095d1d0047d..05ba00ebd17a 100644 --- a/python/src/com/jetbrains/python/debugger/array/ArrayTableCellEditor.java +++ b/python/src/com/jetbrains/python/debugger/array/ArrayTableCellEditor.java @@ -143,7 +143,7 @@ public class ArrayTableCellEditor extends AbstractCellEditor implements TableCel } @Override - protected void setEditorText(XExpression text) { + protected void doSetText(XExpression text) { myEditorTextField.setText(text.getExpression()); } From 660d0e796bee12d2037d094683882fe63e1461b8 Mon Sep 17 00:00:00 2001 From: "Maxim.Mossienko" Date: Thu, 6 Nov 2014 14:30:42 +0100 Subject: [PATCH 07/34] extra care for possible NPE during matching PsiClass implementations with null qname --- .../structuralsearch/impl/matcher/JavaMatchingVisitor.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/JavaMatchingVisitor.java b/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/JavaMatchingVisitor.java index e963ec91c2fc..a540080d95d9 100644 --- a/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/JavaMatchingVisitor.java +++ b/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/JavaMatchingVisitor.java @@ -420,7 +420,7 @@ public class JavaMatchingVisitor extends JavaElementVisitor { (elements2 != null) ? elements2.getReferenceElements() : PsiElement.EMPTY_ARRAY ); } - + private boolean compareClasses(final PsiClass clazz, final PsiClass clazz2) { final PsiClass saveClazz = this.myClazz; final MatchContext.MatchedElementsListener oldListener = myMatchingVisitor.getMatchContext().getMatchedElementsListener(); @@ -838,6 +838,7 @@ public class JavaMatchingVisitor extends JavaElementVisitor { String text2; if (el2 instanceof PsiClass) { text2 = ((PsiClass)el2).getQualifiedName(); + if (text2 == null) text2 = el2.getText(); } else { text2 = el2.getText(); } From 14bf4ccd40a11e92f8add17cf981107e58c18b5e Mon Sep 17 00:00:00 2001 From: Ekaterina Tuzova Date: Thu, 6 Nov 2014 16:57:57 +0300 Subject: [PATCH 08/34] speed up python class rename (restricted search scope for __init__) --- .../python/refactoring/rename/RenamePyClassProcessor.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/python/src/com/jetbrains/python/refactoring/rename/RenamePyClassProcessor.java b/python/src/com/jetbrains/python/refactoring/rename/RenamePyClassProcessor.java index b4917dd0767c..3f11c0505ee5 100644 --- a/python/src/com/jetbrains/python/refactoring/rename/RenamePyClassProcessor.java +++ b/python/src/com/jetbrains/python/refactoring/rename/RenamePyClassProcessor.java @@ -17,6 +17,7 @@ package com.jetbrains.python.refactoring.rename; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiReference; +import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.searches.ReferencesSearch; import com.intellij.util.Processor; import com.jetbrains.python.PyNames; @@ -67,7 +68,7 @@ public class RenamePyClassProcessor extends RenamePyElementProcessor { if (initMethod != null) { final List allRefs = Collections.synchronizedList(new ArrayList()); allRefs.addAll(super.findReferences(element)); - ReferencesSearch.search(initMethod).forEach(new Processor() { + ReferencesSearch.search(initMethod, GlobalSearchScope.projectScope(element.getProject())).forEach(new Processor() { @Override public boolean process(PsiReference psiReference) { if (psiReference.getCanonicalText().equals(((PyClass)element).getName())) { From 20a75c4842f3a1e32c67173d3dc14d8121772b88 Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Thu, 6 Nov 2014 17:07:05 +0300 Subject: [PATCH 09/34] Fixed completion for 'from .' (PY-6477) --- .../python/psi/impl/PyReferenceExpressionImpl.java | 7 +++---- .../fromQualifiedNamespacePackageImport/a.after.py | 1 + .../completion/fromQualifiedNamespacePackageImport/a.py | 1 + .../fromQualifiedNamespacePackageImport/nspkg1/bar.py | 0 .../fromQualifiedNamespacePackageImport/nspkg1/foo.py | 0 python/testSrc/com/jetbrains/python/Py3CompletionTest.java | 5 +++++ 6 files changed, 10 insertions(+), 4 deletions(-) create mode 100644 python/testData/completion/fromQualifiedNamespacePackageImport/a.after.py create mode 100644 python/testData/completion/fromQualifiedNamespacePackageImport/a.py create mode 100644 python/testData/completion/fromQualifiedNamespacePackageImport/nspkg1/bar.py create mode 100644 python/testData/completion/fromQualifiedNamespacePackageImport/nspkg1/foo.py diff --git a/python/src/com/jetbrains/python/psi/impl/PyReferenceExpressionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyReferenceExpressionImpl.java index a4ba8f8ead5d..fd1126e64a2f 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyReferenceExpressionImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyReferenceExpressionImpl.java @@ -379,12 +379,11 @@ public class PyReferenceExpressionImpl extends PyElementImpl implements PyRefere if (file != null) { return getTypeFromTarget(file, context, anchor); } - if (context.maySwitchToAST(anchor) && PyUtil.isPackage(dir, anchor)) { - final PyImportElement importElement = PsiTreeUtil.getParentOfType(anchor, PyImportElement.class); + if (PyUtil.isPackage(dir, anchor)) { final PsiFile containingFile = anchor.getContainingFile(); - if (importElement != null && containingFile instanceof PyFile) { + if (containingFile instanceof PyFile) { final QualifiedName qualifiedName = QualifiedName.fromComponents(dir.getName()); - final PyImportedModule module = new PyImportedModule(importElement, (PyFile)containingFile, qualifiedName); + final PyImportedModule module = new PyImportedModule(null, (PyFile)containingFile, qualifiedName); return new PyImportedModuleType(module); } } diff --git a/python/testData/completion/fromQualifiedNamespacePackageImport/a.after.py b/python/testData/completion/fromQualifiedNamespacePackageImport/a.after.py new file mode 100644 index 000000000000..08b9946188ab --- /dev/null +++ b/python/testData/completion/fromQualifiedNamespacePackageImport/a.after.py @@ -0,0 +1 @@ +from nspkg1.foo import diff --git a/python/testData/completion/fromQualifiedNamespacePackageImport/a.py b/python/testData/completion/fromQualifiedNamespacePackageImport/a.py new file mode 100644 index 000000000000..dc6e9e115236 --- /dev/null +++ b/python/testData/completion/fromQualifiedNamespacePackageImport/a.py @@ -0,0 +1 @@ +from nspkg1.f diff --git a/python/testData/completion/fromQualifiedNamespacePackageImport/nspkg1/bar.py b/python/testData/completion/fromQualifiedNamespacePackageImport/nspkg1/bar.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testData/completion/fromQualifiedNamespacePackageImport/nspkg1/foo.py b/python/testData/completion/fromQualifiedNamespacePackageImport/nspkg1/foo.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testSrc/com/jetbrains/python/Py3CompletionTest.java b/python/testSrc/com/jetbrains/python/Py3CompletionTest.java index 96ce44eeb467..9c87e473dd56 100644 --- a/python/testSrc/com/jetbrains/python/Py3CompletionTest.java +++ b/python/testSrc/com/jetbrains/python/Py3CompletionTest.java @@ -110,4 +110,9 @@ public class Py3CompletionTest extends PyTestCase { public void testImportQualifiedNamespacePackage() { doMultiFileTest(); } + + // PY-6477 + public void testFromQualifiedNamespacePackageImport() { + doMultiFileTest(); + } } From b42c4c7b125dc56249833b220a2053010e05aaba Mon Sep 17 00:00:00 2001 From: "Vladimir.Orlov" Date: Thu, 6 Nov 2014 17:08:01 +0300 Subject: [PATCH 10/34] added artifact without jdk bundled for Mac for PyCharm EDU. --- python/edu/build/pycharm_edu_build.gant | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/python/edu/build/pycharm_edu_build.gant b/python/edu/build/pycharm_edu_build.gant index 356df8c7d4c7..85889184ab09 100644 --- a/python/edu/build/pycharm_edu_build.gant +++ b/python/edu/build/pycharm_edu_build.gant @@ -144,8 +144,11 @@ target('default': "Build artifacts") { layoutEducational("${paths.sandbox}/classes/production", usedJars) - def extraArgs = ["build.code": "pycharm${buildName}", "build.number": "PE-$buildNumber", "artifacts.path": "${paths.artifacts}"] + signMacZip("pycharm", extraArgs) + notifyArtifactBuilt("${paths.artifacts}/pycharm${buildName}.sit") + buildDmg("pycharm", "${pythonEduHome}/build/DMG_background.png", extraArgs) + signMacZip("pycharm", extraArgs + ["sitFileName": "pycharm${buildName}-jdk-bundled", "jdk_archive_name": "jdk_mac_redist_for_${buildNumber}.tar"]) buildDmg("pycharm", "${pythonEduHome}/build/DMG_background.png", extraArgs + ["sitFileName": "pycharm${buildName}-jdk-bundled", "jdk_archive_name": "jdk_mac_redist_for_${buildNumber}.tar"]) @@ -206,7 +209,7 @@ public layoutEducational(String classesPath, Set usedJars) { String macAppRoot = isEap() ? "PyCharm Educational ${p("component.version.major")}.${p("component.version.minor")} EAP.app/Contents" : "PyCharm Educational.app/Contents" buildMacZip(macAppRoot, "${paths.artifacts}/pycharm${buildName}.sit", [paths.distAll], paths.distMac) ant.copy(file: "${paths.artifacts}/pycharm${buildName}.sit", tofile: "${paths.artifacts}/pycharm${buildName}-jdk-bundled.sit") - ant.delete(file: "${paths.artifacts}/pycharm${buildName}.sit") + //ant.delete(file: "${paths.artifacts}/pycharm${buildName}.sit") } private layoutPlugins(layouts) { From 4e66e187f821a19f2f5540fca0cd258bd5c1de61 Mon Sep 17 00:00:00 2001 From: Konstantin Bulenkov Date: Thu, 6 Nov 2014 15:13:07 +0100 Subject: [PATCH 11/34] Rollback JBColor wraps --- .../util/src/com/intellij/ui/JBColor.java | 16 ++- .../util/src/com/intellij/util/ui/UIUtil.java | 104 ++++++++---------- 2 files changed, 60 insertions(+), 60 deletions(-) diff --git a/platform/util/src/com/intellij/ui/JBColor.java b/platform/util/src/com/intellij/ui/JBColor.java index cd204b3c00d8..3669e725610d 100644 --- a/platform/util/src/com/intellij/ui/JBColor.java +++ b/platform/util/src/com/intellij/ui/JBColor.java @@ -250,11 +250,23 @@ public class JBColor extends Color { public static final Color CYAN = cyan; public static Color foreground() { - return UIUtil.getLabelForeground(); + return new JBColor(new NotNullProducer() { + @NotNull + @Override + public Color produce() { + return UIUtil.getLabelForeground(); + } + }); } public static Color background() { - return UIUtil.getListBackground(); + return new JBColor(new NotNullProducer() { + @NotNull + @Override + public Color produce() { + return UIUtil.getListBackground(); + } + }); } public static Color border() { diff --git a/platform/util/src/com/intellij/util/ui/UIUtil.java b/platform/util/src/com/intellij/util/ui/UIUtil.java index 893eb1d636b3..97352ca3ef1a 100644 --- a/platform/util/src/com/intellij/util/ui/UIUtil.java +++ b/platform/util/src/com/intellij/util/ui/UIUtil.java @@ -25,7 +25,7 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.CharsetToolkit; import com.intellij.ui.*; import com.intellij.util.*; -import com.intellij.util.containers.*; +import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.WeakHashMap; import org.intellij.lang.annotations.Language; import org.jetbrains.annotations.NonNls; @@ -75,7 +75,6 @@ import java.lang.reflect.Method; import java.net.URL; import java.text.NumberFormat; import java.util.*; -import java.util.HashMap; import java.util.List; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; @@ -680,11 +679,11 @@ public class UIUtil { } public static Color getLabelBackground() { - return getColor("Label.background"); + return UIManager.getColor("Label.background"); } public static Color getLabelForeground() { - return getColor("Label.foreground"); + return UIManager.getColor("Label.foreground"); } public static Color getLabelDisabledForeground() { @@ -734,11 +733,11 @@ public class UIUtil { } public static Color getTableHeaderBackground() { - return getColor("TableHeader.background"); + return UIManager.getColor("TableHeader.background"); } public static Color getTreeTextForeground() { - return getColor("Tree.textForeground"); + return UIManager.getColor("Tree.textForeground"); } public static Color getTreeSelectionBackground() { @@ -748,22 +747,23 @@ public class UIUtil { color = UIManager.getColor("nimbusSelectionBackground"); if (color != null) return color; } - return getColor("Tree.selectionBackground"); + return UIManager.getColor("Tree.selectionBackground"); } public static Color getTreeTextBackground() { - return getColor("Tree.textBackground"); + return UIManager.getColor("Tree.textBackground"); } public static Color getListSelectionForeground() { - if (isUnderNimbusLookAndFeel()) { + final Color color = UIManager.getColor("List.selectionForeground"); + if (color == null) { return UIManager.getColor("List[Selected].textForeground"); // Nimbus } - return getColor("List.selectionForeground"); + return color; } public static Color getFieldForegroundColor() { - return getColor("field.foreground"); + return UIManager.getColor("field.foreground"); } public static Color getTableSelectionBackground() { @@ -773,23 +773,11 @@ public class UIUtil { color = UIManager.getColor("nimbusSelectionBackground"); if (color != null) return color; } - return getColor("Table.selectionBackground"); + return UIManager.getColor("Table.selectionBackground"); } public static Color getActiveTextColor() { - return getColor("textActiveText"); - } - - @NotNull - private static Color getColor(final String property) { - return new JBColor(new NotNullProducer() { - @NotNull - @Override - public Color produce() { - final Color color = UIManager.getColor(property); - return color == null ? Gray.TRANSPARENT : color; - } - }); + return UIManager.getColor("textActiveText"); } public static Color getInactiveTextColor() { @@ -809,7 +797,7 @@ public class UIUtil { } public static Color getInactiveTextFieldBackgroundColor() { - return getColor("TextField.inactiveBackground"); + return UIManager.getColor("TextField.inactiveBackground"); } public static Font getTreeFont() { @@ -821,7 +809,7 @@ public class UIUtil { } public static Color getTreeSelectionForeground() { - return getColor("Tree.selectionForeground"); + return UIManager.getColor("Tree.selectionForeground"); } /** @@ -840,7 +828,7 @@ public class UIUtil { } public static Color getTreeSelectionBorderColor() { - return getColor("Tree.selectionBorderColor"); + return UIManager.getColor("Tree.selectionBorderColor"); } public static int getTreeRightChildIndent() { @@ -852,23 +840,23 @@ public class UIUtil { } public static Color getToolTipBackground() { - return getColor("ToolTip.background"); + return UIManager.getColor("ToolTip.background"); } public static Color getToolTipForeground() { - return getColor("ToolTip.foreground"); + return UIManager.getColor("ToolTip.foreground"); } public static Color getComboBoxDisabledForeground() { - return getColor("ComboBox.disabledForeground"); + return UIManager.getColor("ComboBox.disabledForeground"); } public static Color getComboBoxDisabledBackground() { - return getColor("ComboBox.disabledBackground"); + return UIManager.getColor("ComboBox.disabledBackground"); } public static Color getButtonSelectColor() { - return getColor("Button.select"); + return UIManager.getColor("Button.select"); } public static Integer getPropertyMaxGutterIconWidth(final String propertyPrefix) { @@ -876,7 +864,7 @@ public class UIUtil { } public static Color getMenuItemDisabledForeground() { - return getColor("MenuItem.disabledForeground"); + return UIManager.getColor("MenuItem.disabledForeground"); } public static Object getMenuItemDisabledForegroundObject() { @@ -893,7 +881,7 @@ public class UIUtil { public static Color getTableBackground() { // Under GTK+ L&F "Table.background" often has main panel color, which looks ugly - return isUnderGTKLookAndFeel() ? getTreeTextBackground() : getColor("Table.background"); + return isUnderGTKLookAndFeel() ? getTreeTextBackground() : UIManager.getColor("Table.background"); } public static Color getTableBackground(final boolean isSelected) { @@ -904,11 +892,11 @@ public class UIUtil { if (isUnderNimbusLookAndFeel()) { return UIManager.getColor("Table[Enabled+Selected].textForeground"); } - return getColor("Table.selectionForeground"); + return UIManager.getColor("Table.selectionForeground"); } public static Color getTableForeground() { - return getColor("Table.foreground"); + return UIManager.getColor("Table.foreground"); } public static Color getTableForeground(final boolean isSelected) { @@ -916,7 +904,7 @@ public class UIUtil { } public static Color getTableGridColor() { - return getColor("Table.gridColor"); + return UIManager.getColor("Table.gridColor"); } public static Color getListBackground() { @@ -926,7 +914,7 @@ public class UIUtil { return new Color(color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha()); } // Under GTK+ L&F "Table.background" often has main panel color, which looks ugly - return isUnderGTKLookAndFeel() ? getTreeTextBackground() : getColor("List.background"); + return isUnderGTKLookAndFeel() ? getTreeTextBackground() : UIManager.getColor("List.background"); } public static Color getListBackground(boolean isSelected) { @@ -934,7 +922,7 @@ public class UIUtil { } public static Color getListForeground() { - return getColor("List.foreground"); + return UIManager.getColor("List.foreground"); } public static Color getListForeground(boolean isSelected) { @@ -942,26 +930,26 @@ public class UIUtil { } public static Color getPanelBackground() { - return getColor("Panel.background"); + return UIManager.getColor("Panel.background"); } public static Color getTreeBackground() { - return getColor("Tree.background"); + return UIManager.getColor("Tree.background"); } public static Color getTreeForeground() { - return getColor("Tree.foreground"); + return UIManager.getColor("Tree.foreground"); } public static Color getTableFocusCellBackground() { - return getColor(TABLE_FOCUS_CELL_BACKGROUND_PROPERTY); + return UIManager.getColor(TABLE_FOCUS_CELL_BACKGROUND_PROPERTY); } public static Color getListSelectionBackground() { if (isUnderNimbusLookAndFeel()) { return UIManager.getColor("List[Selected].textBackground"); // Nimbus } - return getColor("List.selectionBackground"); + return UIManager.getColor("List.selectionBackground"); } public static Color getListUnfocusedSelectionBackground() { @@ -978,11 +966,11 @@ public class UIUtil { } public static Color getTextFieldForeground() { - return getColor("TextField.foreground"); + return UIManager.getColor("TextField.foreground"); } public static Color getTextFieldBackground() { - return isUnderGTKLookAndFeel() ? UIManager.getColor("EditorPane.background") : getColor("TextField.background"); + return isUnderGTKLookAndFeel() ? UIManager.getColor("EditorPane.background") : UIManager.getColor("TextField.background"); } public static Font getButtonFont() { @@ -994,7 +982,7 @@ public class UIUtil { } public static Color getTabbedPaneBackground() { - return getColor("TabbedPane.background"); + return UIManager.getColor("TabbedPane.background"); } public static void setSliderIsFilled(final JSlider slider, final boolean value) { @@ -1002,11 +990,11 @@ public class UIUtil { } public static Color getLabelTextForeground() { - return getColor("Label.textForeground"); + return UIManager.getColor("Label.textForeground"); } public static Color getControlColor() { - return getColor("control"); + return UIManager.getColor("control"); } public static Font getOptionPaneMessageFont() { @@ -1018,19 +1006,19 @@ public class UIUtil { } public static Color getSeparatorForeground() { - return getColor("Separator.foreground"); + return UIManager.getColor("Separator.foreground"); } public static Color getSeparatorBackground() { - return getColor("Separator.background"); + return UIManager.getColor("Separator.background"); } public static Color getSeparatorShadow() { - return getColor("Separator.shadow"); + return UIManager.getColor("Separator.shadow"); } public static Color getSeparatorHighlight() { - return getColor("Separator.highlight"); + return UIManager.getColor("Separator.highlight"); } public static Color getSeparatorColorUnderNimbus() { @@ -1065,7 +1053,7 @@ public class UIUtil { } public static Color getTableFocusCellForeground() { - return getColor("Table.focusCellForeground"); + return UIManager.getColor("Table.focusCellForeground"); } /** @@ -1160,15 +1148,15 @@ public class UIUtil { } public static Color getWindowColor() { - return getColor("window"); + return UIManager.getColor("window"); } public static Color getTextAreaForeground() { - return getColor("TextArea.foreground"); + return UIManager.getColor("TextArea.foreground"); } public static Color getOptionPaneBackground() { - return getColor("OptionPane.background"); + return UIManager.getColor("OptionPane.background"); } @SuppressWarnings({"HardCodedStringLiteral"}) From 267153f4e3b56ffe138752ea4bdb228895d2c9ac Mon Sep 17 00:00:00 2001 From: Sergey Simonchik Date: Thu, 6 Nov 2014 17:22:42 +0300 Subject: [PATCH 12/34] json: don't warn about comments in .eslintrc files (compliance level for JSON can be configured now) --- .../JsonStandardComplianceInspection.java | 4 +- .../JsonStandardComplianceProvider.java | 44 +++++++++++++++++++ .../src/META-INF/JsonPlugin.xml | 6 +++ 3 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 json/src/com/intellij/json/codeinsight/JsonStandardComplianceProvider.java diff --git a/json/src/com/intellij/json/codeinsight/JsonStandardComplianceInspection.java b/json/src/com/intellij/json/codeinsight/JsonStandardComplianceInspection.java index 8c17715d696c..d1c83ec03952 100644 --- a/json/src/com/intellij/json/codeinsight/JsonStandardComplianceInspection.java +++ b/json/src/com/intellij/json/codeinsight/JsonStandardComplianceInspection.java @@ -54,7 +54,9 @@ public class JsonStandardComplianceInspection extends LocalInspectionTool { @Override public void visitComment(PsiComment comment) { if (myWarnAboutComments) { - holder.registerProblem(comment, JsonBundle.message("msg.compliance.problem.comments"), ProblemHighlightType.WEAK_WARNING); + if (JsonStandardComplianceProvider.shouldWarnAboutComment(comment)) { + holder.registerProblem(comment, JsonBundle.message("msg.compliance.problem.comments"), ProblemHighlightType.WEAK_WARNING); + } } } diff --git a/json/src/com/intellij/json/codeinsight/JsonStandardComplianceProvider.java b/json/src/com/intellij/json/codeinsight/JsonStandardComplianceProvider.java new file mode 100644 index 000000000000..996cc82a6867 --- /dev/null +++ b/json/src/com/intellij/json/codeinsight/JsonStandardComplianceProvider.java @@ -0,0 +1,44 @@ +/* + * 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.json.codeinsight; + +import com.intellij.openapi.extensions.ExtensionPointName; +import com.intellij.psi.PsiComment; +import org.jetbrains.annotations.NotNull; + +/** + * Allows to configure a compliance level for JSON. + * For example, some tools ignore comments in JSON silently when parsing, so there is no need to warn users about it. + */ +public abstract class JsonStandardComplianceProvider { + public static final ExtensionPointName EP_NAME = + ExtensionPointName.create("com.intellij.json.jsonStandardComplianceProvider"); + + public abstract boolean isCommentAllowed(@NotNull PsiComment comment); + + public static boolean shouldWarnAboutComment(@NotNull PsiComment comment) { + JsonStandardComplianceProvider[] providers = EP_NAME.getExtensions(); + if (providers.length == 0) { + return true; + } + for (JsonStandardComplianceProvider provider : providers) { + if (provider.isCommentAllowed(comment)) { + return false; + } + } + return true; + } +} diff --git a/platform/platform-resources/src/META-INF/JsonPlugin.xml b/platform/platform-resources/src/META-INF/JsonPlugin.xml index deeec3ad3fa2..c3d643a5d1da 100644 --- a/platform/platform-resources/src/META-INF/JsonPlugin.xml +++ b/platform/platform-resources/src/META-INF/JsonPlugin.xml @@ -58,4 +58,10 @@ implementationClass="com.intellij.json.psi.JsonStringLiteralManipulator"/> + + + + + \ No newline at end of file From a1c6a7e8611efb041660521d851012a158c6f8ef Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Thu, 6 Nov 2014 14:29:11 +0100 Subject: [PATCH 13/34] show definition optimization: do not load psi for anonymouses when possible --- .../hint/ImplementationViewComponent.java | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInsight/hint/ImplementationViewComponent.java b/platform/lang-impl/src/com/intellij/codeInsight/hint/ImplementationViewComponent.java index b83d832f8348..38063e097f0d 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/hint/ImplementationViewComponent.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/hint/ImplementationViewComponent.java @@ -39,6 +39,7 @@ import com.intellij.openapi.util.Comparing; import com.intellij.openapi.vcs.FileStatusManager; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; +import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtilCore; import com.intellij.ui.IdeBorderFactory; import com.intellij.ui.ListCellRendererWrapper; @@ -329,12 +330,26 @@ public class ImplementationViewComponent extends JPanel { if (element instanceof PsiNamedElement) { names.add(((PsiNamedElement)element).getName()); } + if (names.size() > 1) { + break; + } } + for (PsiElement element : elements) { PsiFile file = getContainingFile(element); if (file == null) continue; - final PsiElement parent = element.getParent(); - files.add(new FileDescriptor(file, names.size() > 1 || parent == file ? element : parent)); + if (names.size() > 1) { + files.add(new FileDescriptor(file, element)); + } + else { + final PsiElement parent = PsiTreeUtil.getStubOrPsiParent(element); + if (parent == file) { + files.add(new FileDescriptor(file, element)); + } + else { + files.add(new FileDescriptor(file, parent)); + } + } candidates.add(element); } From 237f36c3ede475b70adf16bd4f7665e6520f1833 Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Thu, 6 Nov 2014 15:26:59 +0100 Subject: [PATCH 14/34] functional expressions search: process all files with ->/:: as there are about 400 methods in jdk with type parameter as parameter type which all should be processed on each functional expression search (IDEA-132407) --- .../cache/impl/idCache/JavaFilterLexer.java | 4 +- .../index/JavaMethodParameterTypesIndex.java | 50 ------ .../JavaFunctionalExpressionSearcher.java | 157 ++++++++---------- .../java/stubs/JavaMethodElementType.java | 31 ---- .../java/stubs/index/JavaStubIndexKeys.java | 1 - .../psi/impl/source/JavaFileElementType.java | 2 +- .../psi/impl/cache/impl/id/IdIndex.java | 2 +- resources/src/META-INF/IdeaPlugin.xml | 1 - 8 files changed, 71 insertions(+), 177 deletions(-) delete mode 100644 java/java-indexing-impl/src/com/intellij/psi/impl/java/stubs/index/JavaMethodParameterTypesIndex.java diff --git a/java/java-impl/src/com/intellij/psi/impl/cache/impl/idCache/JavaFilterLexer.java b/java/java-impl/src/com/intellij/psi/impl/cache/impl/idCache/JavaFilterLexer.java index 44207d32b640..8ea446e46786 100644 --- a/java/java-impl/src/com/intellij/psi/impl/cache/impl/idCache/JavaFilterLexer.java +++ b/java/java-impl/src/com/intellij/psi/impl/cache/impl/idCache/JavaFilterLexer.java @@ -58,7 +58,9 @@ public class JavaFilterLexer extends BaseFilterLexer { if (tokenType == JavaTokenType.IDENTIFIER || tokenType == JavaTokenType.LONG_LITERAL || tokenType == JavaTokenType.INTEGER_LITERAL - || tokenType == JavaTokenType.CHARACTER_LITERAL) { + || tokenType == JavaTokenType.CHARACTER_LITERAL + || tokenType == JavaTokenType.ARROW + || tokenType == JavaTokenType.DOUBLE_COLON) { addOccurrenceInToken(UsageSearchContext.IN_CODE); } else if (tokenType == JavaTokenType.STRING_LITERAL) { diff --git a/java/java-indexing-impl/src/com/intellij/psi/impl/java/stubs/index/JavaMethodParameterTypesIndex.java b/java/java-indexing-impl/src/com/intellij/psi/impl/java/stubs/index/JavaMethodParameterTypesIndex.java deleted file mode 100644 index 23f4ffac729e..000000000000 --- a/java/java-indexing-impl/src/com/intellij/psi/impl/java/stubs/index/JavaMethodParameterTypesIndex.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2000-2014 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * @author max - */ -package com.intellij.psi.impl.java.stubs.index; - -import com.intellij.openapi.project.Project; -import com.intellij.psi.PsiMethod; -import com.intellij.psi.impl.search.JavaSourceFilterScope; -import com.intellij.psi.search.GlobalSearchScope; -import com.intellij.psi.stubs.StringStubIndexExtension; -import com.intellij.psi.stubs.StubIndex; -import com.intellij.psi.stubs.StubIndexKey; -import org.jetbrains.annotations.NotNull; - -import java.util.Collection; - -public class JavaMethodParameterTypesIndex extends StringStubIndexExtension { - - private static final JavaMethodParameterTypesIndex ourInstance = new JavaMethodParameterTypesIndex(); - public static JavaMethodParameterTypesIndex getInstance() { - return ourInstance; - } - - @NotNull - @Override - public StubIndexKey getKey() { - return JavaStubIndexKeys.METHOD_TYPES; - } - - @Override - public Collection get(@NotNull final String s, @NotNull final Project project, @NotNull final GlobalSearchScope scope) { - return StubIndex.getElements(getKey(), s, project, new JavaSourceFilterScope(scope), PsiMethod.class); - } -} \ No newline at end of file diff --git a/java/java-indexing-impl/src/com/intellij/psi/impl/search/JavaFunctionalExpressionSearcher.java b/java/java-indexing-impl/src/com/intellij/psi/impl/search/JavaFunctionalExpressionSearcher.java index cb5d6be103fd..2652cb3aa51d 100644 --- a/java/java-indexing-impl/src/com/intellij/psi/impl/search/JavaFunctionalExpressionSearcher.java +++ b/java/java-indexing-impl/src/com/intellij/psi/impl/search/JavaFunctionalExpressionSearcher.java @@ -15,37 +15,39 @@ */ package com.intellij.psi.impl.search; +import com.intellij.ide.highlighter.JavaFileType; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleManager; import com.intellij.openapi.module.impl.scopes.ModulesScope; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.LanguageLevelModuleExtension; import com.intellij.openapi.roots.ModuleRootManager; +import com.intellij.openapi.roots.ProjectFileIndex; +import com.intellij.openapi.roots.ProjectRootManager; import com.intellij.openapi.util.Computable; +import com.intellij.openapi.util.Ref; +import com.intellij.openapi.vfs.VirtualFile; import com.intellij.pom.java.LanguageLevel; import com.intellij.psi.*; -import com.intellij.psi.impl.java.stubs.JavaMethodElementType; -import com.intellij.psi.impl.java.stubs.index.JavaMethodParameterTypesIndex; -import com.intellij.psi.search.EverythingGlobalScope; -import com.intellij.psi.search.GlobalSearchScope; -import com.intellij.psi.search.SearchScope; +import com.intellij.psi.search.*; import com.intellij.psi.search.searches.FunctionalExpressionSearch; -import com.intellij.psi.search.searches.MethodReferencesSearch; -import com.intellij.psi.search.searches.ReferencesSearch; import com.intellij.psi.util.PsiUtil; import com.intellij.psi.util.PsiUtilCore; +import com.intellij.util.CommonProcessors; import com.intellij.util.Processor; import com.intellij.util.QueryExecutor; import com.intellij.util.containers.HashSet; import org.jetbrains.annotations.NotNull; import java.util.Collection; -import java.util.LinkedHashSet; import java.util.Set; public class JavaFunctionalExpressionSearcher implements QueryExecutor { + private static final Logger LOG = Logger.getInstance("#" + JavaFunctionalExpressionSearcher.class.getName()); + @Override public boolean execute(@NotNull final FunctionalExpressionSearch.SearchParameters queryParameters, @NotNull final Processor consumer) { @@ -98,102 +100,75 @@ public class JavaFunctionalExpressionSearcher implements QueryExecutor lambdaCandidates = ApplicationManager.getApplication().runReadAction(new Computable>() { + + final ProjectFileIndex index = ProjectRootManager.getInstance(project).getFileIndex(); + CommonProcessors.CollectProcessor processor = new CommonProcessors.CollectProcessor() { @Override - public Collection compute() { - final String functionalInterfaceName = aClass.getName(); - final GlobalSearchScope useClassScope = classScope instanceof GlobalSearchScope ? (GlobalSearchScope)classScope : scope; - JavaMethodParameterTypesIndex parameterTypesIndex = JavaMethodParameterTypesIndex.getInstance(); - LinkedHashSet methods = new LinkedHashSet(parameterTypesIndex.get(functionalInterfaceName, project, useClassScope)); - methods.addAll(parameterTypesIndex.get(JavaMethodElementType.TYPE_PARAMETER_PSEUDO_NAME, project, - GlobalSearchScope.allScope(project))); - return methods; + protected boolean accept(VirtualFile virtualFile) { + return scope.contains(virtualFile) && virtualFile.getFileType() == JavaFileType.INSTANCE && index.isInSource(virtualFile); } - }); - for (PsiMethod psiMethod : lambdaCandidates) { - for (final PsiReference ref : MethodReferencesSearch.search(psiMethod, scope, false)) { - boolean accepted = ApplicationManager.getApplication().runReadAction(new Computable() { - @Override - public Boolean compute() { - final PsiElement refElement = ref.getElement(); - if (refElement != null) { - final PsiElement candidateElement = refElement.getParent(); - if (candidateElement instanceof PsiCallExpression) { - final PsiExpressionList argumentList = ((PsiCallExpression)candidateElement).getArgumentList(); - if (argumentList != null) { - final PsiExpression[] args = argumentList.getExpressions(); - for (PsiExpression arg : args) { - if (arg instanceof PsiFunctionalExpression) { - final PsiFunctionalExpression functionalExpression = (PsiFunctionalExpression)arg; - final PsiType functionalType = functionalExpression.getFunctionalInterfaceType(); - if (PsiUtil.resolveClassInType(functionalType) == aClass) { - if (!consumer.process(functionalExpression)) return false; - } - } - } - } - } - } - return true; - } - }); - if (!accepted) return false; - } - } + }; - for (final PsiReference reference : ReferencesSearch.search(aClass, scope)) { - boolean accepted = ApplicationManager.getApplication().runReadAction(new Computable() { + final PsiSearchHelperImpl helper = (PsiSearchHelperImpl)PsiSearchHelper.SERVICE.getInstance(project); + helper.processFilesWithText(scope, UsageSearchContext.IN_CODE, true, "::", processor); + helper.processFilesWithText(scope, UsageSearchContext.IN_CODE, true, "->", processor); + + Collection files = processor.getResults(); + LOG.info("#files: " + files.size()); + + final PsiManager psiManager = PsiManager.getInstance(project); + for (final VirtualFile file : files) { + if (!ApplicationManager.getApplication().runReadAction(new Computable() { @Override public Boolean compute() { - final PsiElement element = reference.getElement(); - if (element != null) { - final PsiElement parent = element.getParent(); - if (parent instanceof PsiTypeElement) { - final PsiElement gParent = parent.getParent(); - if (gParent instanceof PsiVariable) { - final PsiExpression initializer = PsiUtil.skipParenthesizedExprDown(((PsiVariable)gParent).getInitializer()); - if (initializer instanceof PsiFunctionalExpression) { - if (!consumer.process((PsiFunctionalExpression)initializer)) return false; - } - for (PsiReference varRef : ReferencesSearch.search(parent, scope)) { - final PsiElement varElement = varRef.getElement(); - if (varElement != null) { - final PsiElement varElementParent = varElement.getParent(); - if (varElementParent instanceof PsiAssignmentExpression && - ((PsiAssignmentExpression)varElementParent).getLExpression() == varElement) { - final PsiExpression rExpression = PsiUtil.skipParenthesizedExprDown(((PsiAssignmentExpression)varElementParent).getRExpression()); - if (rExpression instanceof PsiFunctionalExpression) { - if (!consumer.process((PsiFunctionalExpression)rExpression)) return false; - } - } - } - } - } else if (gParent instanceof PsiMethod) { - final PsiReturnStatement[] returnStatements = ApplicationManager.getApplication().runReadAction( - new Computable() { - @Override - public PsiReturnStatement[] compute() { - return PsiUtil.findReturnStatements((PsiMethod)gParent); - } - }); - for (PsiReturnStatement returnStatement : returnStatements) { - final PsiExpression returnValue = returnStatement.getReturnValue(); - if (returnValue instanceof PsiFunctionalExpression) { - if (!consumer.process((PsiFunctionalExpression)returnValue)) return false; - } - } - } + return processFileWithFunctionalInterfaces(aClass, consumer, psiManager, file); + } + })) return false; + } + return true; + } + + private static boolean processFileWithFunctionalInterfaces(final PsiClass aClass, + final Processor consumer, + final PsiManager psiManager, VirtualFile file) { + final PsiFile psiFile = psiManager.findFile(file); + if (psiFile != null) { + final Ref ref = new Ref(true); + psiFile.accept(new JavaRecursiveElementWalkingVisitor() { + @Override + public void visitElement(PsiElement element) { + if (!ref.get()) { + return; + } + super.visitElement(element); + } + + private void visitFunctionalExpression(PsiFunctionalExpression expression) { + PsiType functionalInterfaceType = expression.getFunctionalInterfaceType(); + if (psiManager.areElementsEquivalent(PsiUtil.resolveClassInType(functionalInterfaceType), aClass)) { + if (!consumer.process(expression)) { + ref.set(false); } } + } - return true; + @Override + public void visitLambdaExpression(PsiLambdaExpression expression) { + super.visitLambdaExpression(expression); + visitFunctionalExpression(expression); + } + + @Override + public void visitMethodReferenceExpression(PsiMethodReferenceExpression expression) { + super.visitMethodReferenceExpression(expression); + visitFunctionalExpression(expression); } }); - if (!accepted) return false; - + if (!ref.get()) return false; } return true; } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/JavaMethodElementType.java b/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/JavaMethodElementType.java index 53033115a85c..06369c9f7379 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/JavaMethodElementType.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/JavaMethodElementType.java @@ -50,7 +50,6 @@ import java.util.Set; * @author max */ public abstract class JavaMethodElementType extends JavaStubElementType { - public static final String TYPE_PARAMETER_PSEUDO_NAME = "$TYPE_PARAMETER$"; public JavaMethodElementType(@NonNls final String name) { super(name); } @@ -150,35 +149,5 @@ public abstract class JavaMethodElementType extends JavaStubElementType methodTypeParams = null; - for (StubElement stubElement : stub.getChildrenStubs()) { - if (stubElement instanceof PsiTypeParameterListStub) { - for (Object tStub : stubElement.getChildrenStubs()) { - if (tStub instanceof PsiTypeParameterStub) { - if (methodTypeParams == null) { - methodTypeParams = new HashSet(); - } - methodTypeParams.add(((PsiTypeParameterStub)tStub).getName()); - } - } - } - else if (stubElement instanceof PsiParameterListStub) { - for (StubElement paramStub : ((PsiParameterListStub)stubElement).getChildrenStubs()) { - if (paramStub instanceof PsiParameterStub) { - TypeInfo type = ((PsiParameterStub)paramStub).getType(false); - if (type.arrayCount > 0) continue; - String typeName = type.getShortTypeText(); - if (TypeConversionUtil.isPrimitive(typeName) || TypeConversionUtil.isPrimitiveWrapper(typeName)) continue; - sink.occurrence(JavaStubIndexKeys.METHOD_TYPES, typeName); - if (methodTypeParams != null && methodTypeParams.contains(typeName)) { - sink.occurrence(JavaStubIndexKeys.METHOD_TYPES, TYPE_PARAMETER_PSEUDO_NAME); - methodTypeParams = null; - } - } - } - break; - } - } } } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/index/JavaStubIndexKeys.java b/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/index/JavaStubIndexKeys.java index a3e247f73de8..e8760f5f95fa 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/index/JavaStubIndexKeys.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/index/JavaStubIndexKeys.java @@ -29,7 +29,6 @@ public class JavaStubIndexKeys { public static final StubIndexKey JVM_STATIC_MEMBERS_NAMES = StubIndexKey.createIndexKey("jvm.static.member.name"); public static final StubIndexKey JVM_STATIC_MEMBERS_TYPES = StubIndexKey.createIndexKey("jvm.static.member.type"); public static final StubIndexKey ANONYMOUS_BASEREF = StubIndexKey.createIndexKey("java.anonymous.baseref"); - public static final StubIndexKey METHOD_TYPES = StubIndexKey.createIndexKey("java.method.parameter.types"); public static final StubIndexKey CLASS_SHORT_NAMES = StubIndexKey.createIndexKey("java.class.shortname"); public static final StubIndexKey CLASS_FQN = StubIndexKey.createIndexKey("java.class.fqn"); diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/JavaFileElementType.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/JavaFileElementType.java index eedf4abf13cb..cec30eb3c8af 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/JavaFileElementType.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/JavaFileElementType.java @@ -38,7 +38,7 @@ import java.io.IOException; * @author max */ public class JavaFileElementType extends ILightStubFileElementType { - public static final int STUB_VERSION = 18; + public static final int STUB_VERSION = 19; public JavaFileElementType() { super("java.FILE", JavaLanguage.INSTANCE); diff --git a/platform/indexing-impl/src/com/intellij/psi/impl/cache/impl/id/IdIndex.java b/platform/indexing-impl/src/com/intellij/psi/impl/cache/impl/id/IdIndex.java index af193348c71b..aed1ccf7277f 100644 --- a/platform/indexing-impl/src/com/intellij/psi/impl/cache/impl/id/IdIndex.java +++ b/platform/indexing-impl/src/com/intellij/psi/impl/cache/impl/id/IdIndex.java @@ -91,7 +91,7 @@ public class IdIndex extends FileBasedIndexExtension { @Override public int getVersion() { - return 13 + (ourSnapshotMappingsEnabled ? 0xFF:0); // TODO: version should enumerate all word scanner versions and build version upon that set + return 14 + (ourSnapshotMappingsEnabled ? 0xFF:0); // TODO: version should enumerate all word scanner versions and build version upon that set } @Override diff --git a/resources/src/META-INF/IdeaPlugin.xml b/resources/src/META-INF/IdeaPlugin.xml index 4a9f2b5fe5cb..bae70d18ab02 100644 --- a/resources/src/META-INF/IdeaPlugin.xml +++ b/resources/src/META-INF/IdeaPlugin.xml @@ -1375,7 +1375,6 @@ - From 3957c0168fbe8497fc03fd00cba14252973655fe Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Thu, 6 Nov 2014 16:51:51 +0300 Subject: [PATCH 15/34] diff: gutter - allow to specify border color * unify default and 'smart' painting * fix NPE: color could be null (checkbox in config disabled -> null) --- .../openapi/editor/colors/EditorColors.java | 2 + .../colors/pages/GeneralColorsPage.java | 1 + .../src/messages/OptionsBundle.properties | 9 +- .../vcs/ex/LineStatusTrackerDrawing.java | 86 +++++++++++-------- 4 files changed, 59 insertions(+), 39 deletions(-) diff --git a/platform/editor-ui-api/src/com/intellij/openapi/editor/colors/EditorColors.java b/platform/editor-ui-api/src/com/intellij/openapi/editor/colors/EditorColors.java index ff563a51b97e..17a4ea41eb30 100644 --- a/platform/editor-ui-api/src/com/intellij/openapi/editor/colors/EditorColors.java +++ b/platform/editor-ui-api/src/com/intellij/openapi/editor/colors/EditorColors.java @@ -61,5 +61,7 @@ public interface EditorColors { ColorKey MODIFIED_LINES_COLOR = ColorKey.createColorKey("MODIFIED_LINES_COLOR"); ColorKey DELETED_LINES_COLOR = ColorKey.createColorKey("DELETED_LINES_COLOR"); ColorKey WHITESPACES_MODIFIED_LINES_COLOR = ColorKey.createColorKey("WHITESPACES_MODIFIED_LINES_COLOR"); + ColorKey BORDER_LINES_COLOR = ColorKey.createColorKey("BORDER_LINES_COLOR"); + TextAttributesKey INJECTED_LANGUAGE_FRAGMENT = TextAttributesKey.createTextAttributesKey("INJECTED_LANGUAGE_FRAGMENT"); } diff --git a/platform/lang-impl/src/com/intellij/openapi/options/colors/pages/GeneralColorsPage.java b/platform/lang-impl/src/com/intellij/openapi/options/colors/pages/GeneralColorsPage.java index 8ab353f7bc14..c0dd305dfb16 100644 --- a/platform/lang-impl/src/com/intellij/openapi/options/colors/pages/GeneralColorsPage.java +++ b/platform/lang-impl/src/com/intellij/openapi/options/colors/pages/GeneralColorsPage.java @@ -122,6 +122,7 @@ public class GeneralColorsPage implements ColorSettingsPage, InspectionColorSett new ColorDescriptor(OptionsBundle.message("options.general.color.descriptor.modified.lines"), EditorColors.MODIFIED_LINES_COLOR, ColorDescriptor.Kind.BACKGROUND), new ColorDescriptor(OptionsBundle.message("options.general.color.descriptor.deleted.lines"), EditorColors.DELETED_LINES_COLOR, ColorDescriptor.Kind.BACKGROUND), new ColorDescriptor(OptionsBundle.message("options.general.color.descriptor.whitespaces.modified.lines"), EditorColors.WHITESPACES_MODIFIED_LINES_COLOR, ColorDescriptor.Kind.BACKGROUND), + new ColorDescriptor(OptionsBundle.message("options.general.color.descriptor.border.lines"), EditorColors.BORDER_LINES_COLOR, ColorDescriptor.Kind.BACKGROUND), new ColorDescriptor(OptionsBundle.message("options.java.color.descriptor.method.separator.color"), CodeInsightColors.METHOD_SEPARATORS_COLOR, ColorDescriptor.Kind.FOREGROUND), new ColorDescriptor(OptionsBundle.message("options.general.color.soft.wrap.sign"), EditorColors.SOFT_WRAP_SIGN_COLOR, ColorDescriptor.Kind.FOREGROUND), }; diff --git a/platform/platform-resources-en/src/messages/OptionsBundle.properties b/platform/platform-resources-en/src/messages/OptionsBundle.properties index 1906440c7ecc..e2475e4e5b8b 100644 --- a/platform/platform-resources-en/src/messages/OptionsBundle.properties +++ b/platform/platform-resources-en/src/messages/OptionsBundle.properties @@ -126,10 +126,11 @@ options.general.color.descriptor.vcs.annotations=VCS annotations options.general.color.descriptor.vcs.annotations.merged=VCS annotations (merged from) options.general.color.descriptor.tearline=Tear line options.general.color.descriptor.tearline.selected=Selected tear line -options.general.color.descriptor.added.lines=Added lines -options.general.color.descriptor.modified.lines=Modified lines -options.general.color.descriptor.deleted.lines=Deleted lines -options.general.color.descriptor.whitespaces.modified.lines=Minor modified lines +options.general.color.descriptor.added.lines=Added lines in gutter +options.general.color.descriptor.modified.lines=Modified lines in gutter +options.general.color.descriptor.deleted.lines=Deleted lines in gutter +options.general.color.descriptor.whitespaces.modified.lines=Minor modified lines in gutter +options.general.color.descriptor.border.lines=Border for changed lines in gutter options.general.color.descriptor.console.background=Console background options.general.color.descriptor.console.stdout=Console standard output options.general.color.descriptor.console.stderr=Console error output diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTrackerDrawing.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTrackerDrawing.java index ccf0a1560c8c..af016745218b 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTrackerDrawing.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTrackerDrawing.java @@ -46,6 +46,7 @@ import com.intellij.ui.HintListener; import com.intellij.ui.LightweightHint; import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.awt.*; @@ -70,43 +71,27 @@ public class LineStatusTrackerDrawing { private static void paintGutterFragment(final Editor editor, final Graphics g, final Rectangle r, final Range range) { final EditorGutterComponentEx gutter = ((EditorEx)editor).getGutterComponentEx(); - Color stripeColor = getDiffGutterColor(range); + Color gutterColor = getDiffGutterColor(range); + Color borderColor = getDiffGutterBorderColor(); + + final int x = r.x + r.width - 3; + final int endX = gutter.getWhitespaceSeparatorOffset(); - int triangle = 4; if (range.getInnerRanges() == null) { // actual painter - g.setColor(stripeColor); - - final int endX = gutter.getWhitespaceSeparatorOffset(); - final int x = r.x + r.width - 3; - final int width = endX - x; if (r.height > 0) { - g.fillRect(x, r.y, width, r.height); + paintRect(g, gutterColor, borderColor, x, r.y, endX, r.y + r.height); } else { - final int[] xPoints = new int[]{x, x, endX}; - final int[] yPoints = new int[]{r.y - triangle, r.y + triangle, r.y}; - g.fillPolygon(xPoints, yPoints, 3); + paintTriangle(g, gutterColor, borderColor, x, endX, r.y); } } else { // registry: diff.status.tracker.smart - final int x = gutter.getLineMarkerAreaOffset() + gutter.getIconsAreaWidth() + 1; - final int endX = gutter.getWhitespaceSeparatorOffset(); - final int width = endX - x; - if (range.getType() == Range.DELETED) { final int y = lineToY(editor, range.getLine1()); - - final int[] xPoints = new int[]{x, x, endX + 1}; - final int[] yPoints = new int[]{y - triangle, y + triangle, y}; - - g.setColor(stripeColor); - g.fillPolygon(xPoints, yPoints, 3); - - g.setColor(gutter.getOutlineColor(false)); - g.drawPolygon(xPoints, yPoints, 3); + paintTriangle(g, gutterColor, borderColor, x, endX, y); } else { - int y = lineToY(editor, range.getLine1()); + final int y = lineToY(editor, range.getLine1()); int endY = lineToY(editor, range.getLine2()); List innerRanges = range.getInnerRanges(); @@ -116,8 +101,7 @@ public class LineStatusTrackerDrawing { int start = lineToY(editor, innerRange.getLine1()); int end = lineToY(editor, innerRange.getLine2()); - g.setColor(getDiffColor(innerRange)); - g.fillRect(x, start, width, end - start); + paintRect(g, getDiffColor(innerRange), null, x, start, endX, end); } for (int i = 0; i < innerRanges.size(); i++) { @@ -140,14 +124,10 @@ public class LineStatusTrackerDrawing { end = lineToY(editor, innerRange.getLine2()) + 3; } - g.setColor(getDiffColor(innerRange)); - g.fillRect(x, start, width, end - start); + paintRect(g, getDiffColor(innerRange), null, x, start, endX, end); } - g.setColor(gutter.getOutlineColor(false)); - UIUtil.drawLine(g, x, y, endX - 1, y); - UIUtil.drawLine(g, x, y, x, endY - 1); - UIUtil.drawLine(g, x, endY - 1, endX - 1, endY - 1); + paintRect(g, null, borderColor, x, y, endX, endY); } } } @@ -161,6 +141,35 @@ public class LineStatusTrackerDrawing { return editor.logicalPositionToXY(editor.offsetToLogicalPosition(document.getLineStartOffset(line))).y; } + private static void paintRect(@NotNull Graphics g, @Nullable Color color, @Nullable Color borderColor, int x1, int y1, int x2, int y2) { + if (color != null) { + g.setColor(color); + g.fillRect(x1, y1, x2 - x1, y2 - y1); + } + if (borderColor != null) { + g.setColor(borderColor); + UIUtil.drawLine(g, x1, y1, x2 - 1, y1); + UIUtil.drawLine(g, x1, y1, x1, y2 - 1); + UIUtil.drawLine(g, x1, y2 - 1, x2 - 1, y2 - 1); + } + } + + private static void paintTriangle(@NotNull Graphics g, @Nullable Color color, @Nullable Color borderColor, int x1, int x2, int y) { + int size = 4; + + final int[] xPoints = new int[]{x1, x1, x2}; + final int[] yPoints = new int[]{y - size, y + size, y}; + + if (color != null) { + g.setColor(color); + g.fillPolygon(xPoints, yPoints, xPoints.length); + } + if (borderColor != null) { + g.setColor(borderColor); + g.drawPolygon(xPoints, yPoints, xPoints.length); + } + } + public static LineMarkerRenderer createRenderer(final Range range, final LineStatusTracker tracker) { return new ActiveGutterRenderer() { public void paint(final Editor editor, final Graphics g, final Rectangle r) { @@ -307,8 +316,9 @@ public class LineStatusTrackerDrawing { }); } - @NotNull + @Nullable private static Color getDiffColor(@NotNull Range.InnerRange range) { + // TODO: we should move color settings from Colors-General to Colors-Diff final EditorColorsScheme globalScheme = EditorColorsManager.getInstance().getGlobalScheme(); switch (range.getType()) { case Range.INSERTED: @@ -341,7 +351,7 @@ public class LineStatusTrackerDrawing { } } - @NotNull + @Nullable private static Color getDiffGutterColor(@NotNull Range range) { final EditorColorsScheme globalScheme = EditorColorsManager.getInstance().getGlobalScheme(); switch (range.getType()) { @@ -356,4 +366,10 @@ public class LineStatusTrackerDrawing { return null; } } + + @Nullable + private static Color getDiffGutterBorderColor() { + final EditorColorsScheme globalScheme = EditorColorsManager.getInstance().getGlobalScheme(); + return globalScheme.getColor(EditorColors.BORDER_LINES_COLOR); + } } From d8407af5daa0f3ca607fed46e2ab056fb4f5b055 Mon Sep 17 00:00:00 2001 From: Dmitry Trofimov Date: Thu, 6 Nov 2014 15:55:48 +0100 Subject: [PATCH 16/34] Fix reslice and reformat on enter. --- .../python/debugger/array/ArrayTableForm.java | 27 +++++++++-- .../debugger/array/NumpyArrayTable.java | 45 +++++++------------ 2 files changed, 40 insertions(+), 32 deletions(-) diff --git a/python/src/com/jetbrains/python/debugger/array/ArrayTableForm.java b/python/src/com/jetbrains/python/debugger/array/ArrayTableForm.java index 90b6d1c1b75c..f50f0161034f 100644 --- a/python/src/com/jetbrains/python/debugger/array/ArrayTableForm.java +++ b/python/src/com/jetbrains/python/debugger/array/ArrayTableForm.java @@ -15,6 +15,8 @@ */ package com.jetbrains.python.debugger.array; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.editor.ex.EditorEx; import com.intellij.openapi.project.Project; import com.intellij.ui.EditorTextField; import com.intellij.ui.components.JBScrollPane; @@ -31,6 +33,7 @@ import javax.swing.table.DefaultTableCellRenderer; import javax.swing.table.DefaultTableModel; import javax.swing.table.JTableHeader; import java.awt.*; +import java.awt.event.KeyListener; /** * @author amarch @@ -46,23 +49,41 @@ public class ArrayTableForm { private JTable myTable; private JBTable myBusyTable; private final Project myProject; + private KeyListener myResliceCallback; + private KeyListener myReformatCallback; private static final String DATA_LOADING_IN_PROCESS = "Please wait, load array data."; private static final String NOT_APPLICABLE = "View not applicable for "; - public ArrayTableForm(@NotNull Project project) { + public ArrayTableForm(@NotNull Project project, KeyListener resliceCallback, KeyListener reformatCallback) { myProject = project; + myResliceCallback = resliceCallback; + myReformatCallback = reformatCallback; } private void createUIComponents() { - mySliceTextField = new EditorTextField("", myProject, PythonFileType.INSTANCE); + mySliceTextField = new EditorTextField("", myProject, PythonFileType.INSTANCE) { + @Override + protected EditorEx createEditor() { + EditorEx editor = super.createEditor(); + editor.getContentComponent().addKeyListener(myResliceCallback); + return editor; + } + }; myTable = new JBTableWithRowHeaders(); myScrollPane = ((JBTableWithRowHeaders)myTable).getScrollPane(); - myFormatTextField = new EditorTextField("", myProject, PythonFileType.INSTANCE); + myFormatTextField = new EditorTextField("", myProject, PythonFileType.INSTANCE) { + @Override + protected EditorEx createEditor() { + EditorEx editor = super.createEditor(); + editor.getContentComponent().addKeyListener(myReformatCallback); + return editor; + } + }; myBusyTable = new JBTable(new DefaultTableModel()); myBusyTable.getEmptyText().setText(""); diff --git a/python/src/com/jetbrains/python/debugger/array/NumpyArrayTable.java b/python/src/com/jetbrains/python/debugger/array/NumpyArrayTable.java index 230e8c058974..dacf3d51a770 100644 --- a/python/src/com/jetbrains/python/debugger/array/NumpyArrayTable.java +++ b/python/src/com/jetbrains/python/debugger/array/NumpyArrayTable.java @@ -19,6 +19,7 @@ import com.intellij.codeInsight.hint.HintManager; import com.intellij.openapi.application.Result; import com.intellij.openapi.command.WriteCommandAction; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.RangeMarker; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Pair; @@ -76,7 +77,21 @@ public class NumpyArrayTable { @NotNull PyViewArrayAction.ViewArrayDialog dialog, @NotNull PyDebugValue value) { myValue = value; myDialog = dialog; - myComponent = new ArrayTableForm(project); + myComponent = new ArrayTableForm(project, new KeyAdapter() { + @Override + public void keyPressed(KeyEvent e) { + if (e.getKeyCode() == KeyEvent.VK_ENTER) { + doReslice(getSliceText(), null); + } + } + }, new KeyAdapter() { + @Override + public void keyPressed(KeyEvent e) { + if (e.getKeyCode() == KeyEvent.VK_ENTER) { + doApplyFormat(); + } + } + }); myTable = myComponent.getTable(); myProject = project; myEvaluator = new PyDebuggerEvaluator(project, getDebugValue().getFrameAccessor()); @@ -127,9 +142,6 @@ public class NumpyArrayTable { }); } - // add slice actions - initSliceFieldActions(); - //make value name read-only myComponent.getSliceTextField().addFocusListener(new FocusListener() { @Override @@ -145,9 +157,6 @@ public class NumpyArrayTable { } } }); - - //add format actions - initFormatFieldActions(); } public void disableColor() { @@ -166,28 +175,6 @@ public class NumpyArrayTable { }); } - private void initSliceFieldActions() { - myComponent.getSliceTextField().addKeyListener(new KeyAdapter() { - @Override - public void keyPressed(KeyEvent e) { - if (e.getKeyCode() == KeyEvent.VK_ENTER) { - doReslice(getSliceText(), null); - } - } - }); - } - - private void initFormatFieldActions() { - myComponent.getFormatTextField().addKeyListener(new KeyAdapter() { - @Override - public void keyPressed(KeyEvent e) { - if (e.getKeyCode() == KeyEvent.VK_ENTER) { - doApplyFormat(); - } - } - }); - } - public PyDebugValue getDebugValue() { return myValue; } From 251687c3a0e5ab6c72388bb5b0c6560f13206fe6 Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Thu, 6 Nov 2014 15:24:48 +0300 Subject: [PATCH 17/34] [git] don't take write action for saveAllDocuments: it is taken inside --- .../src/git4idea/actions/GitRepositoryAction.java | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/plugins/git4idea/src/git4idea/actions/GitRepositoryAction.java b/plugins/git4idea/src/git4idea/actions/GitRepositoryAction.java index 7ee419e6ae9d..eb30f463ac7c 100644 --- a/plugins/git4idea/src/git4idea/actions/GitRepositoryAction.java +++ b/plugins/git4idea/src/git4idea/actions/GitRepositoryAction.java @@ -19,8 +19,6 @@ import com.intellij.openapi.actionSystem.ActionPlaces; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.CommonDataKeys; import com.intellij.openapi.actionSystem.DataContext; -import com.intellij.openapi.actionSystem.PlatformDataKeys; -import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.project.DumbAwareAction; import com.intellij.openapi.project.Project; @@ -53,16 +51,9 @@ public abstract class GitRepositoryAction extends DumbAwareAction { */ final List myDelayedTasks = new ArrayList(); - /** - * {@inheritDoc} - */ - public void actionPerformed(final AnActionEvent e) { + public void actionPerformed(@NotNull final AnActionEvent e) { myDelayedTasks.clear(); - ApplicationManager.getApplication().runWriteAction(new Runnable() { - public void run() { - FileDocumentManager.getInstance().saveAllDocuments(); - } - }); + FileDocumentManager.getInstance().saveAllDocuments(); DataContext dataContext = e.getDataContext(); final Project project = CommonDataKeys.PROJECT.getData(dataContext); if (project == null) { From af18624b898fc0cd69354e0bc1a73ce30353091e Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Thu, 6 Nov 2014 15:26:37 +0300 Subject: [PATCH 18/34] [git] cleanup --- .../src/git4idea/actions/GitRepositoryAction.java | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/plugins/git4idea/src/git4idea/actions/GitRepositoryAction.java b/plugins/git4idea/src/git4idea/actions/GitRepositoryAction.java index eb30f463ac7c..042b651c6840 100644 --- a/plugins/git4idea/src/git4idea/actions/GitRepositoryAction.java +++ b/plugins/git4idea/src/git4idea/actions/GitRepositoryAction.java @@ -18,7 +18,6 @@ package git4idea.actions; import com.intellij.openapi.actionSystem.ActionPlaces; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.CommonDataKeys; -import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.project.DumbAwareAction; import com.intellij.openapi.project.Project; @@ -54,11 +53,7 @@ public abstract class GitRepositoryAction extends DumbAwareAction { public void actionPerformed(@NotNull final AnActionEvent e) { myDelayedTasks.clear(); FileDocumentManager.getInstance().saveAllDocuments(); - DataContext dataContext = e.getDataContext(); - final Project project = CommonDataKeys.PROJECT.getData(dataContext); - if (project == null) { - return; - } + final Project project = e.getRequiredData(CommonDataKeys.PROJECT); GitVcs vcs = GitVcs.getInstance(project); final List roots = getGitRoots(project, vcs); if (roots == null) return; @@ -187,9 +182,6 @@ public abstract class GitRepositoryAction extends DumbAwareAction { final Set affectedRoots, List exceptions) throws VcsException; - /** - * {@inheritDoc} - */ @Override public void update(final AnActionEvent e) { super.update(e); From 30f65070cb278b67c43182b2baa3dadc7e0e0c4e Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Thu, 6 Nov 2014 16:01:39 +0300 Subject: [PATCH 19/34] [git] Don't spam "Couldn't find branch with name" & simplify Although it might indicate an inconsistency in our data structures, it can also be a valid situation, e.g. when branch was removes, but the record from .git/config wasn't removed. --- .../src/git4idea/branch/GitBranchUtil.java | 51 ++----------------- .../git4idea/src/git4idea/repo/GitConfig.java | 40 ++++++++------- .../ui/branch/GitMultiRootBranchConfig.java | 2 +- 3 files changed, 28 insertions(+), 65 deletions(-) diff --git a/plugins/git4idea/src/git4idea/branch/GitBranchUtil.java b/plugins/git4idea/src/git4idea/branch/GitBranchUtil.java index 4cc356e27df8..6dfa3f23dd36 100644 --- a/plugins/git4idea/src/git4idea/branch/GitBranchUtil.java +++ b/plugins/git4idea/src/git4idea/branch/GitBranchUtil.java @@ -16,10 +16,8 @@ package git4idea.branch; import com.google.common.base.Function; -import com.google.common.base.Optional; import com.google.common.base.Predicate; import com.google.common.collect.Collections2; -import com.google.common.collect.Iterables; import com.intellij.dvcs.DvcsUtil; import com.intellij.dvcs.repo.RepositoryUtil; import com.intellij.openapi.diagnostic.Logger; @@ -47,7 +45,10 @@ import org.jetbrains.annotations.Nullable; import java.io.File; import java.io.IOException; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; /** * @author Kirill Likhodedov @@ -262,50 +263,6 @@ public class GitBranchUtil { }); } - /** - * @deprecated Don't use names, use {@link GitLocalBranch} objects. - */ - @Deprecated - @Nullable - public static GitLocalBranch findLocalBranchByName(@NotNull GitRepository repository, @NotNull final String branchName) { - Optional optional = Iterables.tryFind(repository.getBranches().getLocalBranches(), new Predicate() { - @Override - public boolean apply(@Nullable GitLocalBranch input) { - assert input != null; - return input.getName().equals(branchName); - } - }); - if (optional.isPresent()) { - return optional.get(); - } - LOG.info(String.format("Couldn't find branch with name %s in %s", branchName, repository)); - return null; - - } - - /** - * Looks through the remote branches in the given repository and tries to find the one from the given remote, - * which the given name. - * @return remote branch or null if such branch couldn't be found. - */ - @Nullable - public static GitRemoteBranch findRemoteBranchByName(@NotNull String remoteBranchName, @NotNull final String remoteName, - @NotNull final Collection remoteBranches) { - final String branchName = stripRefsPrefix(remoteBranchName); - Optional optional = Iterables.tryFind(remoteBranches, new Predicate() { - @Override - public boolean apply(@Nullable GitRemoteBranch input) { - assert input != null; - return input.getNameForRemoteOperations().equals(branchName) && input.getRemote().getName().equals(remoteName); - } - }); - if (optional.isPresent()) { - return optional.get(); - } - LOG.info(String.format("Couldn't find branch with name %s", branchName)); - return null; - } - @NotNull public static String stripRefsPrefix(@NotNull String branchName) { if (branchName.startsWith(GitBranch.REFS_HEADS_PREFIX)) { diff --git a/plugins/git4idea/src/git4idea/repo/GitConfig.java b/plugins/git4idea/src/git4idea/repo/GitConfig.java index 4b0bdeadc8f9..aeb0bf8eb55c 100644 --- a/plugins/git4idea/src/git4idea/repo/GitConfig.java +++ b/plugins/git4idea/src/git4idea/repo/GitConfig.java @@ -158,7 +158,7 @@ public class GitConfig { Pair, Collection> remotesAndUrls = parseRemotes(ini, classLoader); Collection trackedInfos = parseTrackedInfos(ini, classLoader); - + return new GitConfig(remotesAndUrls.getFirst(), remotesAndUrls.getSecond(), trackedInfos); } @@ -201,12 +201,12 @@ public class GitConfig { boolean merge = mergeName != null; final String remoteBranchName = (merge ? mergeName : rebaseName); - assert remoteName != null; - assert remoteBranchName != null; GitLocalBranch localBranch = findLocalBranch(branchName, localBranches); - GitRemoteBranch remoteBranch = GitBranchUtil.findRemoteBranchByName(remoteBranchName, remoteName, remoteBranches); + GitRemoteBranch remoteBranch = findRemoteBranch(remoteBranchName, remoteName, remoteBranches); if (localBranch == null || remoteBranch == null) { + // obsolete record in .git/config: local or remote branch doesn't exist, but the tracking information wasn't removed + LOG.debug("localBranch: " + localBranch + ", remoteBranch: " + remoteBranch); return null; } return new GitBranchTrackInfo(localBranch, remoteBranch, merge); @@ -215,19 +215,25 @@ public class GitConfig { @Nullable private static GitLocalBranch findLocalBranch(@NotNull String branchName, @NotNull Collection localBranches) { final String name = GitBranchUtil.stripRefsPrefix(branchName); - try { - return ContainerUtil.find(localBranches, new Condition() { - @Override - public boolean value(@Nullable GitLocalBranch input) { - assert input != null; - return input.getName().equals(name); - } - }); - } - catch (NoSuchElementException e) { - LOG.info("Couldn't find branch with name " + name); - return null; - } + return ContainerUtil.find(localBranches, new Condition() { + @Override + public boolean value(@Nullable GitLocalBranch input) { + assert input != null; + return input.getName().equals(name); + } + }); + } + + @Nullable + public static GitRemoteBranch findRemoteBranch(@NotNull String remoteBranchName, @NotNull final String remoteName, + @NotNull final Collection remoteBranches) { + final String branchName = GitBranchUtil.stripRefsPrefix(remoteBranchName); + return ContainerUtil.find(remoteBranches, new Condition() { + @Override + public boolean value(GitRemoteBranch branch) { + return branch.getNameForRemoteOperations().equals(branchName) && branch.getRemote().getName().equals(remoteName); + } + }); } @Nullable diff --git a/plugins/git4idea/src/git4idea/ui/branch/GitMultiRootBranchConfig.java b/plugins/git4idea/src/git4idea/ui/branch/GitMultiRootBranchConfig.java index 18076a1b9a61..360cf56fe505 100644 --- a/plugins/git4idea/src/git4idea/ui/branch/GitMultiRootBranchConfig.java +++ b/plugins/git4idea/src/git4idea/ui/branch/GitMultiRootBranchConfig.java @@ -103,7 +103,7 @@ public class GitMultiRootBranchConfig extends DvcsMultiRootBranchConfig Date: Thu, 6 Nov 2014 16:31:19 +0300 Subject: [PATCH 20/34] [git] IDEA-130702 Don't spam "No remote found with name" & simplify --- plugins/git4idea/src/git4idea/GitUtil.java | 9 +++- .../src/git4idea/branch/GitBranchUtil.java | 41 ------------------- .../git4idea/repo/GitRepositoryReader.java | 33 ++++++++++++--- 3 files changed, 35 insertions(+), 48 deletions(-) diff --git a/plugins/git4idea/src/git4idea/GitUtil.java b/plugins/git4idea/src/git4idea/GitUtil.java index ffa394211faf..eca2b0f14503 100644 --- a/plugins/git4idea/src/git4idea/GitUtil.java +++ b/plugins/git4idea/src/git4idea/GitUtil.java @@ -687,8 +687,13 @@ public class GitUtil { @Nullable - public static GitRemote findRemoteByName(@NotNull GitRepository repository, @Nullable final String name) { - return ContainerUtil.find(repository.getRemotes(), new Condition() { + public static GitRemote findRemoteByName(@NotNull GitRepository repository, @NotNull final String name) { + return findRemoteByName(repository.getRemotes(), name); + } + + @Nullable + public static GitRemote findRemoteByName(Collection remotes, @NotNull final String name) { + return ContainerUtil.find(remotes, new Condition() { @Override public boolean value(GitRemote remote) { return remote.getName().equals(name); diff --git a/plugins/git4idea/src/git4idea/branch/GitBranchUtil.java b/plugins/git4idea/src/git4idea/branch/GitBranchUtil.java index 6dfa3f23dd36..b996dea69e5f 100644 --- a/plugins/git4idea/src/git4idea/branch/GitBranchUtil.java +++ b/plugins/git4idea/src/git4idea/branch/GitBranchUtil.java @@ -30,7 +30,6 @@ import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.containers.ContainerUtil; -import com.intellij.vcs.log.Hash; import com.intellij.vcsUtil.VcsUtil; import git4idea.*; import git4idea.commands.GitCommand; @@ -209,46 +208,6 @@ public class GitBranchUtil { return remote; } - /** - * - * @return {@link git4idea.GitStandardRemoteBranch} or {@link GitSvnRemoteBranch}, or null in case of an error. The error is logged in this method. - * @deprecated Should be used only in the GitRepositoryReader, i. e. moved there once all other usages are removed. - */ - @Deprecated - @Nullable - public static GitRemoteBranch parseRemoteBranch(@NotNull String fullBranchName, @NotNull Hash hash, - @NotNull Collection remotes) { - String stdName = stripRefsPrefix(fullBranchName); - - int slash = stdName.indexOf('/'); - if (slash == -1) { // .git/refs/remotes/my_branch => git-svn - return new GitSvnRemoteBranch(fullBranchName, hash); - } - else { - String remoteName = stdName.substring(0, slash); - String branchName = stdName.substring(slash + 1); - GitRemote remote = findRemoteByName(remoteName, remotes); - if (remote == null) { - // user may remove the remote section from .git/config, but leave remote refs untouched in .git/refs/remotes - LOG.info(String.format("No remote found with the name [%s]. All remotes: %s", remoteName, remotes)); - GitRemote fakeRemote = new GitRemote(remoteName, ContainerUtil.emptyList(), Collections.emptyList(), - Collections.emptyList(), Collections.emptyList()); - return new GitStandardRemoteBranch(fakeRemote, branchName, hash); - } - return new GitStandardRemoteBranch(remote, branchName, hash); - } - } - - @Nullable - private static GitRemote findRemoteByName(@NotNull String remoteName, @NotNull Collection remotes) { - for (GitRemote remote : remotes) { - if (remote.getName().equals(remoteName)) { - return remote; - } - } - return null; - } - /** * Convert {@link git4idea.GitRemoteBranch GitRemoteBranches} to their names, and remove remote HEAD pointers: origin/HEAD. */ diff --git a/plugins/git4idea/src/git4idea/repo/GitRepositoryReader.java b/plugins/git4idea/src/git4idea/repo/GitRepositoryReader.java index 576f326a8ea3..66ce94172794 100644 --- a/plugins/git4idea/src/git4idea/repo/GitRepositoryReader.java +++ b/plugins/git4idea/src/git4idea/repo/GitRepositoryReader.java @@ -25,9 +25,7 @@ import com.intellij.util.Processor; import com.intellij.util.containers.ContainerUtil; import com.intellij.vcs.log.Hash; import com.intellij.vcs.log.impl.HashImpl; -import git4idea.GitBranch; -import git4idea.GitLocalBranch; -import git4idea.GitRemoteBranch; +import git4idea.*; import git4idea.branch.GitBranchUtil; import git4idea.branch.GitBranchesCollection; import org.jetbrains.annotations.NonNls; @@ -349,7 +347,7 @@ class GitRepositoryReader { String hash = loadHashFromBranchFile(file); Hash h = createHash(hash); if (h != null) { - GitRemoteBranch remoteBranch = GitBranchUtil.parseRemoteBranch(branchName, h, remotes); + GitRemoteBranch remoteBranch = parseRemoteBranch(branchName, h, remotes); if (remoteBranch != null) { branches.add(remoteBranch); } @@ -386,7 +384,7 @@ class GitRepositoryReader { localBranches.add(new GitLocalBranch(branchName, hash)); } else if (branchName.startsWith(REFS_REMOTES_PREFIX)) { - GitRemoteBranch remoteBranch = GitBranchUtil.parseRemoteBranch(branchName, hash, remotes); + GitRemoteBranch remoteBranch = parseRemoteBranch(branchName, hash, remotes); if (remoteBranch != null) { remoteBranches.add(remoteBranch); } @@ -395,6 +393,31 @@ class GitRepositoryReader { return new GitBranchesCollection(localBranches, remoteBranches); } + @Nullable + private static GitRemoteBranch parseRemoteBranch(@NotNull String fullBranchName, + @NotNull Hash hash, + @NotNull Collection remotes) { + String stdName = GitBranchUtil.stripRefsPrefix(fullBranchName); + + int slash = stdName.indexOf('/'); + if (slash == -1) { // .git/refs/remotes/my_branch => git-svn + return new GitSvnRemoteBranch(fullBranchName, hash); + } + else { + String remoteName = stdName.substring(0, slash); + String branchName = stdName.substring(slash + 1); + GitRemote remote = GitUtil.findRemoteByName(remotes, remoteName); + if (remote == null) { + // user may remove the remote section from .git/config, but leave remote refs untouched in .git/refs/remotes + LOG.debug(String.format("No remote found with the name [%s]. All remotes: %s", remoteName, remotes)); + GitRemote fakeRemote = new GitRemote(remoteName, ContainerUtil.emptyList(), Collections.emptyList(), + Collections.emptyList(), Collections.emptyList()); + return new GitStandardRemoteBranch(fakeRemote, branchName, hash); + } + return new GitStandardRemoteBranch(remote, branchName, hash); + } + } + @NotNull private static String readBranchFile(@NotNull File branchFile) { return RepositoryUtil.tryLoadFile(branchFile); From 4e197ef308cc4cdcc746693a73c05e437e403e26 Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Thu, 6 Nov 2014 17:32:33 +0300 Subject: [PATCH 21/34] cleanup: remove unused methods --- plugins/git4idea/src/git4idea/GitUtil.java | 62 ---------------------- 1 file changed, 62 deletions(-) diff --git a/plugins/git4idea/src/git4idea/GitUtil.java b/plugins/git4idea/src/git4idea/GitUtil.java index eca2b0f14503..3fce39e477f9 100644 --- a/plugins/git4idea/src/git4idea/GitUtil.java +++ b/plugins/git4idea/src/git4idea/GitUtil.java @@ -15,7 +15,6 @@ */ package git4idea; -import com.google.common.base.Predicate; import com.google.common.base.Predicates; import com.google.common.collect.Collections2; import com.intellij.openapi.components.ServiceManager; @@ -26,7 +25,6 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.DialogBuilder; import com.intellij.openapi.ui.ex.MultiLineLabel; import com.intellij.openapi.util.Condition; -import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vcs.AbstractVcsHelper; @@ -101,13 +99,6 @@ public class GitUtil { private final static Logger LOG = Logger.getInstance(GitUtil.class); - public static final Predicate NOT_NULL_PREDICATE = new Predicate() { - @Override - public boolean apply(@Nullable GitBranchTrackInfo input) { - return input != null; - } - }; - /** * A private constructor to suppress instance creation */ @@ -226,22 +217,6 @@ public class GitUtil { return sortFilePathsByGitRoot(files, false); } - /** - * Sort files by vcs root - * - * @param files files to sort. - * @return the map from root to the files under the root - */ - public static Map> sortGitFilePathsByGitRoot(Collection files) { - try { - return sortFilePathsByGitRoot(files, true); - } - catch (VcsException e) { - throw new RuntimeException("Unexpected exception:", e); - } - } - - /** * Sort files by vcs root * @@ -714,39 +689,6 @@ public class GitUtil { }); } - /** - * @deprecated Calls Git for tracked info, use {@link GitRepository#getBranchTrackInfos()} instead. - */ - @Nullable - @Deprecated - public static Pair findMatchingRemoteBranch(GitRepository repository, GitLocalBranch branch) - throws VcsException { - /* - from man git-push: - git push - Works like git push , where is the current branch's remote (or origin, if no - remote is configured for the current branch). - - */ - String remoteName = GitBranchUtil.getTrackedRemoteName(repository.getProject(), repository.getRoot(), branch.getName()); - GitRemote remote; - if (remoteName == null) { - remote = findOrigin(repository.getRemotes()); - } else { - remote = findRemoteByName(repository, remoteName); - } - if (remote == null) { - return null; - } - - for (GitRemoteBranch remoteBranch : repository.getBranches().getRemoteBranches()) { - if (remoteBranch.getName().equals(remote.getName() + "/" + branch.getName())) { - return Pair.create(remote, remoteBranch); - } - } - return null; - } - @Nullable private static GitRemote findOrigin(Collection remotes) { for (GitRemote remote : remotes) { @@ -757,10 +699,6 @@ public class GitUtil { return null; } - public static boolean repoContainsRemoteBranch(@NotNull GitRepository repository, @NotNull GitRemoteBranch dest) { - return repository.getBranches().getRemoteBranches().contains(dest); - } - @NotNull public static Collection getRootsFromRepositories(@NotNull Collection repositories) { Collection roots = new ArrayList(repositories.size()); From 6f93511ef8531e5e390b359e6fbdd06eb658b233 Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Thu, 6 Nov 2014 17:52:57 +0300 Subject: [PATCH 22/34] [git] IDEA-132492 Don't show origin/HEAD in log + test + add a test for this to GitRepositoryReaderTest, although GitRepositoryReader behaves correctly. --- plugins/git4idea/src/git4idea/GitUtil.java | 2 ++ .../src/git4idea/history/GitHistoryUtils.java | 2 +- .../repo/example1/dot_git/refs/remotes/origin/HEAD | 1 + .../tests/git4idea/log/GitLogProviderTest.java | 14 ++++++++++++++ 4 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 plugins/git4idea/testData/repo/example1/dot_git/refs/remotes/origin/HEAD diff --git a/plugins/git4idea/src/git4idea/GitUtil.java b/plugins/git4idea/src/git4idea/GitUtil.java index 3fce39e477f9..c0790eb6496b 100644 --- a/plugins/git4idea/src/git4idea/GitUtil.java +++ b/plugins/git4idea/src/git4idea/GitUtil.java @@ -97,6 +97,8 @@ public class GitUtil { public static final Charset UTF8_CHARSET = Charset.forName(UTF8_ENCODING); public static final String DOT_GIT = ".git"; + public static final String ORIGIN_HEAD = "origin/HEAD"; + private final static Logger LOG = Logger.getInstance(GitUtil.class); /** diff --git a/plugins/git4idea/src/git4idea/history/GitHistoryUtils.java b/plugins/git4idea/src/git4idea/history/GitHistoryUtils.java index 1c310492059d..f50604bcf6d3 100644 --- a/plugins/git4idea/src/git4idea/history/GitHistoryUtils.java +++ b/plugins/git4idea/src/git4idea/history/GitHistoryUtils.java @@ -585,7 +585,7 @@ public class GitHistoryUtils { public VcsRef fun(String refName) { VcsRefType type = GitRefManager.getRefType(refName); refName = GitBranchUtil.stripRefsPrefix(refName); - return factory.createRef(hash, refName, type, root); + return refName.equals(GitUtil.ORIGIN_HEAD) ? null : factory.createRef(hash, refName, type, root); } }); } diff --git a/plugins/git4idea/testData/repo/example1/dot_git/refs/remotes/origin/HEAD b/plugins/git4idea/testData/repo/example1/dot_git/refs/remotes/origin/HEAD new file mode 100644 index 000000000000..6ed00ab3d0ea --- /dev/null +++ b/plugins/git4idea/testData/repo/example1/dot_git/refs/remotes/origin/HEAD @@ -0,0 +1 @@ + ref: refs/remotes/origin/master \ No newline at end of file diff --git a/plugins/git4idea/tests/git4idea/log/GitLogProviderTest.java b/plugins/git4idea/tests/git4idea/log/GitLogProviderTest.java index 313852f118b0..584f78bbe4dd 100644 --- a/plugins/git4idea/tests/git4idea/log/GitLogProviderTest.java +++ b/plugins/git4idea/tests/git4idea/log/GitLogProviderTest.java @@ -131,6 +131,20 @@ public class GitLogProviderTest extends GitSingleRepoTest { assertEquals("User email is incorrect", expected.getEmail(), user.getEmail()); } + public void test_dont_report_origin_HEAD() throws Exception { + prepareSomeHistory(); + git("update-ref refs/remotes/origin/HEAD master"); + + VcsLogProvider.DetailedLogData block = myLogProvider.readFirstBlock(myProjectRoot, + new RequirementsImpl(1000, false, Collections.emptySet())); + assertFalse("origin/HEAD should be ignored", ContainerUtil.exists(block.getRefs(), new Condition() { + @Override + public boolean value(VcsRef ref) { + return ref.getName().equals("origin/HEAD"); + } + })); + } + private static void prepareSomeHistory() { tac("a.txt"); git("tag ATAG"); From 74568115d07cc6884c2783359e39f5417a150a44 Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Thu, 6 Nov 2014 18:01:09 +0300 Subject: [PATCH 23/34] [git] IDEA-132502 Set all elements at once to avoid too many table change events --- .../git4idea/src/git4idea/merge/GitPullDialog.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/plugins/git4idea/src/git4idea/merge/GitPullDialog.java b/plugins/git4idea/src/git4idea/merge/GitPullDialog.java index ee8ddf33e582..eaf372e5f4f7 100644 --- a/plugins/git4idea/src/git4idea/merge/GitPullDialog.java +++ b/plugins/git4idea/src/git4idea/merge/GitPullDialog.java @@ -22,6 +22,8 @@ import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.ui.ListCellRendererWrapper; +import com.intellij.util.Function; +import com.intellij.util.containers.ContainerUtil; import git4idea.GitBranch; import git4idea.GitRemoteBranch; import git4idea.GitUtil; @@ -170,11 +172,13 @@ public class GitPullDialog extends DialogWrapper { String currentRemoteBranch = trackInfo == null ? null : trackInfo.getRemoteBranch().getNameForLocalOperations(); List remoteBranches = new ArrayList(repository.getBranches().getRemoteBranches()); Collections.sort(remoteBranches); - for (GitBranch remoteBranch : remoteBranches) { - if (belongsToRemote(remoteBranch, selectedRemote)) { - myBranchChooser.addElement(remoteBranch.getName(), remoteBranch.getName().equals(currentRemoteBranch)); + myBranchChooser.setElements(ContainerUtil.map(remoteBranches, new Function() { + @Override + public String fun(GitRemoteBranch branch) { + return branch.getName(); } - } + }), false); + myBranchChooser.setElementMarked(currentRemoteBranch, true); validateDialog(); } From e0987e23792f0e625d86ec4266ef7bb70caba064 Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Thu, 6 Nov 2014 18:16:38 +0300 Subject: [PATCH 24/34] Revert "[git] IDEA-132265 Don't send update event on repository initialization" This breaks GitBranchWidget, because it doesn't update its state on start. There is no good enough fix for the problem until the GitRepositoryManager is fixed and become more synchonous in terms of getting repository for root (IDEA-132330) --- plugins/git4idea/src/git4idea/repo/GitRepositoryImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/git4idea/src/git4idea/repo/GitRepositoryImpl.java b/plugins/git4idea/src/git4idea/repo/GitRepositoryImpl.java index 3f6f25f1dc46..30951670e079 100644 --- a/plugins/git4idea/src/git4idea/repo/GitRepositoryImpl.java +++ b/plugins/git4idea/src/git4idea/repo/GitRepositoryImpl.java @@ -217,7 +217,7 @@ public class GitRepositoryImpl extends RepositoryImpl implements GitRepository { if (Disposer.isDisposed(repository.getProject())) { return; } - if (previousInfo != null && !info.equals(previousInfo)) { + if (!info.equals(previousInfo)) { repository.getProject().getMessageBus().syncPublisher(GIT_REPO_CHANGE).repositoryChanged(repository); } } From 83bf1e448b374a8019d3820d7d88f31062a27483 Mon Sep 17 00:00:00 2001 From: Dmitry Avdeev Date: Wed, 5 Nov 2014 16:22:17 +0300 Subject: [PATCH 25/34] typo --- .../src/com/intellij/tasks/actions/TaskItemProvider.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/TaskItemProvider.java b/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/TaskItemProvider.java index 63bff938a26f..0e39cbb93a8f 100644 --- a/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/TaskItemProvider.java +++ b/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/TaskItemProvider.java @@ -76,10 +76,10 @@ class TaskItemProvider implements ChooseByNameItemProvider, Disposable { }); // Newer request always wins - Future> oldFeature = myFutureReference.getAndSet(future); - if (oldFeature != null) { + Future> oldFuture = myFutureReference.getAndSet(future); + if (oldFuture != null) { LOG.debug("Cancelling existing task"); - oldFeature.cancel(true); + oldFuture.cancel(true); } if (myAlarm.isDisposed()) { From 683301ebafd94c03bd8e3ab5647588e4d4f20535 Mon Sep 17 00:00:00 2001 From: Dmitry Avdeev Date: Thu, 6 Nov 2014 18:44:48 +0300 Subject: [PATCH 26/34] IDEA-132332 Open Task Hangs if submitted too quickly --- .../ide/util/gotoByName/ChooseByNameBase.java | 4 ++++ .../intellij/tasks/actions/GotoTaskAction.java | 1 - .../tasks/actions/TaskItemProvider.java | 18 +++++++++++++++--- 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ChooseByNameBase.java b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ChooseByNameBase.java index 9b354805211b..f5c06224f8c7 100644 --- a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ChooseByNameBase.java +++ b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ChooseByNameBase.java @@ -1192,6 +1192,10 @@ public abstract class ChooseByNameBase { myPostponedOkAction = null; } + public boolean hasPostponedAction() { + return myPostponedOkAction != null; + } + protected abstract void showList(); protected abstract void hideList(); diff --git a/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/GotoTaskAction.java b/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/GotoTaskAction.java index 6174054be32f..40a9cf04afbc 100644 --- a/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/GotoTaskAction.java +++ b/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/GotoTaskAction.java @@ -54,7 +54,6 @@ public class GotoTaskAction extends GotoActionBase implements DumbAware { popup.setShowListForEmptyPattern(true); popup.setSearchInAnyPlace(true); - popup.setFixLostTyping(false); popup.setAlwaysHasMore(true); popup.setAdText("Press SHIFT to merge with current context
" + "Pressing " + diff --git a/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/TaskItemProvider.java b/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/TaskItemProvider.java index 0e39cbb93a8f..0bd5835cd1a6 100644 --- a/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/TaskItemProvider.java +++ b/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/TaskItemProvider.java @@ -26,7 +26,7 @@ import java.util.concurrent.atomic.AtomicReference; class TaskItemProvider implements ChooseByNameItemProvider, Disposable { private static final Logger LOG = Logger.getInstance(TaskItemProvider.class); - private static final int DELAY_PERIOD = 1000; // ms + private static final int DELAY_PERIOD = 200; // ms private final Project myProject; @@ -85,10 +85,22 @@ class TaskItemProvider implements ChooseByNameItemProvider, Disposable { if (myAlarm.isDisposed()) { return false; } - myAlarm.addRequest(future, DELAY_PERIOD); + myAlarm.addRequest(future, oldFuture == null && pattern.length() > 5 ? 0 : DELAY_PERIOD); try { - List tasks = future.get(); + List tasks; + while (true) { + try { + tasks = future.get(10, TimeUnit.MILLISECONDS); + break; + } + catch (TimeoutException ignore) { + } + if (base.hasPostponedAction()) { + future.cancel(true); + return true; + } + } myFutureReference.compareAndSet(future, null); // Exclude *all* cached and local issues, not only those returned by TaskSearchSupport.getLocalAndCachedTasks(). From 8c373fae7677fdb111d13dfa69ab41996c595af0 Mon Sep 17 00:00:00 2001 From: Alexander Marchuk Date: Thu, 6 Nov 2014 19:03:37 +0300 Subject: [PATCH 27/34] fix slicing for 1d --- python/helpers/pydev/pydevd_vars.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/python/helpers/pydev/pydevd_vars.py b/python/helpers/pydev/pydevd_vars.py index d9e1d28c37c5..db297f991928 100644 --- a/python/helpers/pydev/pydevd_vars.py +++ b/python/helpers/pydev/pydevd_vars.py @@ -399,16 +399,17 @@ def array_to_xml(array, roffset, coffset, rows, cols, format): cols = 1 elif rows == 1 or cols == 1: is_row = True if (rows == 1) else False - pure_1d = False if (len(array) == 1) else True + if is_row: + array = array[roffset:] + else: + array = array[coffset:] - if not pure_1d: + if len(array) == 1: array = array[0] if is_row: - array = array[coffset:] cols = min(cols, len(array)) else: - array = array[roffset:] rows = min(rows, len(array)) else: array = array[roffset:, coffset:] From ad398fa2287f1e04666e54f39a627730c73807e3 Mon Sep 17 00:00:00 2001 From: peter Date: Thu, 6 Nov 2014 13:07:48 +0100 Subject: [PATCH 28/34] FileIndex.*source* javadoc should say that it accounts for both production and tests --- .../src/com/intellij/openapi/roots/FileIndex.java | 1 + .../src/com/intellij/openapi/roots/ProjectFileIndex.java | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/platform/projectModel-api/src/com/intellij/openapi/roots/FileIndex.java b/platform/projectModel-api/src/com/intellij/openapi/roots/FileIndex.java index 64558ddc5889..99eec952f1d9 100644 --- a/platform/projectModel-api/src/com/intellij/openapi/roots/FileIndex.java +++ b/platform/projectModel-api/src/com/intellij/openapi/roots/FileIndex.java @@ -57,6 +57,7 @@ public interface FileIndex { /** * Returns true if file is a source file which belongs to sources of the content. + * (Returns true for both source and test source).

* Note that sometimes a file can belong to the content and be a source file but not belong to sources of the content. * This happens if sources of some library are located under the content (so they belong to the project content but not as sources). * diff --git a/platform/projectModel-api/src/com/intellij/openapi/roots/ProjectFileIndex.java b/platform/projectModel-api/src/com/intellij/openapi/roots/ProjectFileIndex.java index fdae3317e74e..d47f640926d5 100644 --- a/platform/projectModel-api/src/com/intellij/openapi/roots/ProjectFileIndex.java +++ b/platform/projectModel-api/src/com/intellij/openapi/roots/ProjectFileIndex.java @@ -125,7 +125,7 @@ public interface ProjectFileIndex extends FileIndex { boolean isLibraryClassFile(@NotNull VirtualFile file); /** - * Returns true if fileOrDir is a file or directory from the content source or library sources. + * Returns true if fileOrDir is a file or directory from the content production/test source or library source. * * @param fileOrDir the file or directory to check. * @return true if the file or directory belongs to project or library sources, false otherwise. From 03d208ed88e3ac64c42d448292c7b99eccd7abce Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Thu, 6 Nov 2014 15:30:43 +0100 Subject: [PATCH 29/34] use SmartList/THashMap by default --- .../intellij/util/containers/MultiMap.java | 26 +++---------------- 1 file changed, 4 insertions(+), 22 deletions(-) diff --git a/platform/util/src/com/intellij/util/containers/MultiMap.java b/platform/util/src/com/intellij/util/containers/MultiMap.java index acd97a51268a..0ee1b4ee5e64 100644 --- a/platform/util/src/com/intellij/util/containers/MultiMap.java +++ b/platform/util/src/com/intellij/util/containers/MultiMap.java @@ -53,17 +53,17 @@ public class MultiMap implements Serializable { @NotNull protected Map> createMap() { - return new HashMap>(); + return new THashMap>(); } @NotNull protected Map> createMap(int initialCapacity, float loadFactor) { - return new HashMap>(initialCapacity, loadFactor); + return new THashMap>(initialCapacity, loadFactor); } @NotNull protected Collection createCollection() { - return new ArrayList(); + return new SmartList(); } @NotNull @@ -261,12 +261,6 @@ public class MultiMap implements Serializable { protected Map> createMap() { return new THashMap>(strategy); } - - @NotNull - @Override - protected Collection createCollection() { - return new SmartList(); - } }; } @@ -288,19 +282,7 @@ public class MultiMap implements Serializable { @NotNull public static MultiMap createSmartList() { - return new MultiMap() { - @NotNull - @Override - protected Collection createCollection() { - return new SmartList(); - } - - @NotNull - @Override - protected Map> createMap() { - return new THashMap>(); - } - }; + return new MultiMap(); } @NotNull From 05688e0d4d5798a10f268c9e2d72457c5fa04d56 Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Thu, 6 Nov 2014 16:31:57 +0100 Subject: [PATCH 30/34] revert "use THashMap by default" --- .../src/com/intellij/util/containers/MultiMap.java | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/platform/util/src/com/intellij/util/containers/MultiMap.java b/platform/util/src/com/intellij/util/containers/MultiMap.java index 0ee1b4ee5e64..f14303607c26 100644 --- a/platform/util/src/com/intellij/util/containers/MultiMap.java +++ b/platform/util/src/com/intellij/util/containers/MultiMap.java @@ -53,12 +53,12 @@ public class MultiMap implements Serializable { @NotNull protected Map> createMap() { - return new THashMap>(); + return new HashMap>(); } @NotNull protected Map> createMap(int initialCapacity, float loadFactor) { - return new THashMap>(initialCapacity, loadFactor); + return new HashMap>(initialCapacity, loadFactor); } @NotNull @@ -282,7 +282,13 @@ public class MultiMap implements Serializable { @NotNull public static MultiMap createSmartList() { - return new MultiMap(); + return new MultiMap() { + @NotNull + @Override + protected Map> createMap() { + return new THashMap>(); + } + }; } @NotNull From 0b30ac5a87f75f62cfb403534c2ea7641f6eaa69 Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Thu, 6 Nov 2014 16:51:36 +0100 Subject: [PATCH 31/34] add toString to simplify debug --- .../util/src/com/intellij/util/xmlb/AttributeBinding.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/platform/util/src/com/intellij/util/xmlb/AttributeBinding.java b/platform/util/src/com/intellij/util/xmlb/AttributeBinding.java index 578b9e12eb7b..c3cbeae595f3 100644 --- a/platform/util/src/com/intellij/util/xmlb/AttributeBinding.java +++ b/platform/util/src/com/intellij/util/xmlb/AttributeBinding.java @@ -86,4 +86,8 @@ public class AttributeBinding extends BasePrimitiveBinding { throw new XmlSerializationException("Can't use attribute binding for non-text content: " + myAccessor); } } + + public String toString() { + return "AttributeBinding[" + myName + ", binding=" + myBinding + "]"; + } } From 521d9ce235a78708e58ef0e9b61a3e2beaf6cff7 Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Thu, 6 Nov 2014 16:52:09 +0100 Subject: [PATCH 32/34] cleanup --- .../util/containers/LinkedMultiMap.java | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/platform/util/src/com/intellij/util/containers/LinkedMultiMap.java b/platform/util/src/com/intellij/util/containers/LinkedMultiMap.java index 9c780bc804fc..b778e4c63f2b 100644 --- a/platform/util/src/com/intellij/util/containers/LinkedMultiMap.java +++ b/platform/util/src/com/intellij/util/containers/LinkedMultiMap.java @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.intellij.util.containers; import com.intellij.util.containers.hash.LinkedHashMap; @@ -26,15 +25,15 @@ import java.util.Map; * @author Evgeny Gerashchenko */ public class LinkedMultiMap extends MultiMap { - @NotNull - @Override - protected Map> createMap() { - return new LinkedHashMap>(); - } + @NotNull + @Override + protected Map> createMap() { + return new LinkedHashMap>(); + } - @NotNull - @Override - protected Map> createMap(int initialCapacity, float loadFactor) { - return new LinkedHashMap>(initialCapacity, loadFactor); - } + @NotNull + @Override + protected Map> createMap(int initialCapacity, float loadFactor) { + return new LinkedHashMap>(initialCapacity, loadFactor); + } } From 0443b40293719e104f716b523810e8fd030edb3f Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Thu, 6 Nov 2014 17:10:06 +0100 Subject: [PATCH 33/34] =?UTF-8?q?AppletConfiguration=20=E2=80=94=20don't?= =?UTF-8?q?=20save=20defaults=20=E2=80=94=20get=20rid=20of=20"module"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../execution/applet/AppletConfiguration.java | 22 +++-- .../util/SimpleModificationTracker.java | 4 +- .../ModuleBasedConfiguration.java | 4 + .../RunConfigurationModule.java | 8 ++ .../src/com/intellij/util/xmlb/Accessor.java | 2 + .../util/xmlb/AccessorBindingWrapper.java | 12 ++- .../com/intellij/util/xmlb/BeanBinding.java | 89 ++++++++++++++----- .../com/intellij/util/xmlb/FieldAccessor.java | 6 ++ .../util/xmlb/PrimitiveValueBinding.java | 6 +- .../intellij/util/xmlb/PropertyAccessor.java | 5 ++ .../xmlb/SkipEmptySerializationFilter.java | 4 +- .../intellij/util/xmlb/SmartSerializer.java | 19 ++-- .../com/intellij/util/xmlb/TagBinding.java | 37 +++++--- .../intellij/util/xmlb/XmlSerializerImpl.java | 14 ++- .../intellij/util/xmlb/XmlSerializerTest.java | 34 +++++++ 15 files changed, 207 insertions(+), 59 deletions(-) diff --git a/java/execution/impl/src/com/intellij/execution/applet/AppletConfiguration.java b/java/execution/impl/src/com/intellij/execution/applet/AppletConfiguration.java index 9d00cad60172..f69ad997c8dc 100644 --- a/java/execution/impl/src/com/intellij/execution/applet/AppletConfiguration.java +++ b/java/execution/impl/src/com/intellij/execution/applet/AppletConfiguration.java @@ -35,6 +35,7 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiClass; import com.intellij.psi.PsiElement; import com.intellij.refactoring.listeners.RefactoringElementListener; +import com.intellij.util.SmartList; import com.intellij.util.xmlb.SmartSerializer; import com.intellij.util.xmlb.annotations.Transient; import org.jdom.Element; @@ -46,7 +47,6 @@ import java.io.FileWriter; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; -import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -74,7 +74,7 @@ public class AppletConfiguration extends ModuleBasedConfiguration parameters = new ArrayList(); - for (final Element element : parentNode.getChildren(PARAMETER_ELEMENT_NAME)) { - parameters.add(new AppletParameter(element.getAttributeValue(NAME_ATTR), element.getAttributeValue(VALUE_ATTR))); + + List paramList = parentNode.getChildren(PARAMETER_ELEMENT_NAME); + if (paramList.isEmpty()) { + myAppletParameters = null; + } + else { + List parameters = new SmartList(); + for (Element element : paramList) { + parameters.add(new AppletParameter(element.getAttributeValue(NAME_ATTR), element.getAttributeValue(VALUE_ATTR))); + } + myAppletParameters = parameters.toArray(new AppletParameter[parameters.size()]); } - myAppletParameters = parameters.toArray(new AppletParameter[parameters.size()]); } @Override @@ -208,7 +214,6 @@ public class AppletConfiguration extends ModuleBasedConfiguration extends LocatableConfigurationBase implements Cloneable, ModuleRunConfiguration { private static final Logger LOG = Logger.getInstance("#com.intellij.execution.configurations.ModuleBasedConfiguration"); + + @Property(surroundWithTag = false) private final ConfigurationModule myModule; + @NonNls protected static final String TO_CLONE_ELEMENT_NAME = "toClone"; diff --git a/platform/lang-api/src/com/intellij/execution/configurations/RunConfigurationModule.java b/platform/lang-api/src/com/intellij/execution/configurations/RunConfigurationModule.java index 189696892b66..21292428f11d 100644 --- a/platform/lang-api/src/com/intellij/execution/configurations/RunConfigurationModule.java +++ b/platform/lang-api/src/com/intellij/execution/configurations/RunConfigurationModule.java @@ -26,6 +26,9 @@ import com.intellij.openapi.roots.ModuleRootManager; import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.JDOMExternalizable; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.util.xmlb.annotations.Attribute; +import com.intellij.util.xmlb.annotations.Tag; +import com.intellij.util.xmlb.annotations.Transient; import org.jdom.Element; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -33,6 +36,7 @@ import org.jetbrains.annotations.Nullable; import java.util.List; +@Tag("module") public class RunConfigurationModule implements JDOMExternalizable { private static final Logger LOG = Logger.getInstance(RunConfigurationModule.class); @@ -40,7 +44,10 @@ public class RunConfigurationModule implements JDOMExternalizable { @NonNls private static final String ATTRIBUTE = "name"; private Module myModule = null; + + @Attribute("name") private String myModuleName; + private final Project myProject; public RunConfigurationModule(@NotNull Project project) { @@ -81,6 +88,7 @@ public class RunConfigurationModule implements JDOMExternalizable { } @Nullable + @Transient public Module getModule() { if (myModuleName != null) { //caching myModule = findModule(myModuleName); diff --git a/platform/util/src/com/intellij/util/xmlb/Accessor.java b/platform/util/src/com/intellij/util/xmlb/Accessor.java index 02c007ffb85a..7e364b9b6105 100644 --- a/platform/util/src/com/intellij/util/xmlb/Accessor.java +++ b/platform/util/src/com/intellij/util/xmlb/Accessor.java @@ -39,4 +39,6 @@ public interface Accessor { Class getValueClass(); Type getGenericType(); + + boolean isFinal(); } diff --git a/platform/util/src/com/intellij/util/xmlb/AccessorBindingWrapper.java b/platform/util/src/com/intellij/util/xmlb/AccessorBindingWrapper.java index e071b6b915ec..c5be1e8f7e31 100644 --- a/platform/util/src/com/intellij/util/xmlb/AccessorBindingWrapper.java +++ b/platform/util/src/com/intellij/util/xmlb/AccessorBindingWrapper.java @@ -15,6 +15,7 @@ */ package com.intellij.util.xmlb; +import org.jdom.Element; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -41,9 +42,14 @@ class AccessorBindingWrapper implements Binding { @Nullable public Object deserialize(Object context, @NotNull Object... nodes) { Object currentValue = myAccessor.read(context); - Object deserializedValue = myBinding.deserialize(currentValue, nodes); - if (currentValue != deserializedValue) { - myAccessor.write(context, deserializedValue); + if (myBinding instanceof BeanBinding && myAccessor.isFinal()) { + ((BeanBinding)myBinding).deserializeInto(currentValue, (Element)nodes[0], null); + } + else { + Object deserializedValue = myBinding.deserialize(currentValue, nodes); + if (currentValue != deserializedValue) { + myAccessor.write(context, deserializedValue); + } } return context; } diff --git a/platform/util/src/com/intellij/util/xmlb/BeanBinding.java b/platform/util/src/com/intellij/util/xmlb/BeanBinding.java index c9078e63b009..7f7022e48c0e 100644 --- a/platform/util/src/com/intellij/util/xmlb/BeanBinding.java +++ b/platform/util/src/com/intellij/util/xmlb/BeanBinding.java @@ -28,6 +28,7 @@ import com.intellij.util.containers.ContainerUtilRt; import com.intellij.util.containers.MultiMap; import com.intellij.util.containers.hash.LinkedHashMap; import com.intellij.util.xmlb.annotations.*; +import gnu.trove.TObjectDoubleHashMap; import org.jdom.Element; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -37,9 +38,8 @@ import java.beans.Introspector; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; +import java.util.*; import java.util.List; -import java.util.Map; -import java.util.Set; class BeanBinding implements Binding { private static final Logger LOG = Logger.getInstance(BeanBinding.class); @@ -81,23 +81,26 @@ class BeanBinding implements Binding { @Nullable public Element serializeInto(@NotNull Object o, @Nullable Element element, @NotNull SerializationFilter filter) { - for (Binding binding : myPropertyBindings.keySet()) { + return serializeInto(o, element, filter, myPropertyBindings.keySet()); + } + + @Nullable + Element serializeInto(@NotNull Object o, @Nullable Element element, @NotNull SerializationFilter filter, @Nullable Collection bindings) { + for (Binding binding : (bindings == null ? myPropertyBindings.keySet() : bindings)) { Accessor accessor = myPropertyBindings.get(binding); + if (accessor == null) { + LOG.warn("Illegal state: accessor null, " + binding.toString()); + continue; + } if (!filter.accepts(accessor, o)) { continue; } //todo: optimize. Cache it. Property property = accessor.getAnnotation(Property.class); - if (property != null && property.filter() != SerializationFilter.class) { - try { - if (!ReflectionUtil.newInstance(property.filter()).accepts(accessor, o)) { - continue; - } - } - catch (RuntimeException e) { - throw new XmlSerializationException(e); - } + if (property != null && property.filter() != SerializationFilter.class && + !ReflectionUtil.newInstance(property.filter()).accepts(accessor, o)) { + continue; } if (element == null) { @@ -130,14 +133,48 @@ class BeanBinding implements Binding { if (element == null) { return o; } - Object instance = XmlSerializerImpl.newInstance(myBeanClass); + Object instance = ReflectionUtil.newInstance(myBeanClass); deserializeInto(instance, element, null); return instance; } + @NotNull + List computeOrderedBindings(@NotNull LinkedHashSet accessorNameTracker) { + final TObjectDoubleHashMap weights = new TObjectDoubleHashMap(accessorNameTracker.size()); + double weight = 0; + double step = (double)myPropertyBindings.size() / (double)accessorNameTracker.size(); + for (String name : accessorNameTracker) { + weights.put(name, weight); + weight += step; + } + + weight = 0; + for (Accessor accessor : myPropertyBindings.values()) { + String name = accessor.getName(); + if (!weights.containsKey(name)) { + weights.put(name, weight); + } + + weight++; + } + + Binding[] result = myPropertyBindings.keySet().toArray(new Binding[myPropertyBindings.size()]); + Arrays.sort(result, new Comparator() { + @Override + public int compare(@NotNull Binding o1, @NotNull Binding o2) { + String n1 = myPropertyBindings.get(o1).getName(); + String n2 = myPropertyBindings.get(o2).getName(); + double w1 = weights.get(n1); + double w2 = weights.get(n2); + return (int)(w1 - w2); + } + }); + return Arrays.asList(result); + } + public void deserializeInto(@NotNull Object result, @NotNull Element element, @Nullable Set accessorNameTracker) { Set bindings = myPropertyBindings.keySet(); - MultiMap data = MultiMap.createSmartList(); + MultiMap data = MultiMap.createLinked(); nextNode: for (Object child : ContainerUtil.concat(element.getContent(), element.getAttributes())) { if (XmlSerializerImpl.isIgnoredNode(child)) { @@ -244,15 +281,25 @@ class BeanBinding implements Binding { } } - private static void collectFieldAccessors(Class aClass, List accessors) { - for (Field field : aClass.getFields()) { - final int modifiers = field.getModifiers(); - if (Modifier.isPublic(modifiers) && !Modifier.isStatic(modifiers) && - !Modifier.isFinal(modifiers) && !Modifier.isTransient(modifiers) && - field.getAnnotation(Transient.class) == null) { - accessors.add(new FieldAccessor(field)); + private static void collectFieldAccessors(@NotNull Class aClass, @NotNull List accessors) { + Class currentClass = aClass; + do { + for (Field field : currentClass.getDeclaredFields()) { + int modifiers = field.getModifiers(); + if (!Modifier.isStatic(modifiers) && + (field.getAnnotation(OptionTag.class) != null || + field.getAnnotation(Tag.class) != null || + field.getAnnotation(Attribute.class) != null || + field.getAnnotation(Property.class) != null || + (Modifier.isPublic(modifiers) && + !Modifier.isFinal(modifiers) && + !Modifier.isTransient(modifiers) && + field.getAnnotation(Transient.class) == null))) { + accessors.add(new FieldAccessor(field)); + } } } + while ((currentClass = currentClass.getSuperclass()) != null && currentClass.getAnnotation(Transient.class) == null); } @Nullable diff --git a/platform/util/src/com/intellij/util/xmlb/FieldAccessor.java b/platform/util/src/com/intellij/util/xmlb/FieldAccessor.java index 172b5e364825..c7fd18abad65 100644 --- a/platform/util/src/com/intellij/util/xmlb/FieldAccessor.java +++ b/platform/util/src/com/intellij/util/xmlb/FieldAccessor.java @@ -21,6 +21,7 @@ import org.jetbrains.annotations.NotNull; import java.lang.annotation.Annotation; import java.lang.reflect.Field; +import java.lang.reflect.Modifier; import java.lang.reflect.Type; class FieldAccessor implements Accessor { @@ -81,6 +82,11 @@ class FieldAccessor implements Accessor { return myField.getGenericType(); } + @Override + public boolean isFinal() { + return Modifier.isFinal(myField.getModifiers()); + } + @NonNls public String toString() { return "FieldAccessor[" + myField.getDeclaringClass() + "." + myField.getName() + "]"; diff --git a/platform/util/src/com/intellij/util/xmlb/PrimitiveValueBinding.java b/platform/util/src/com/intellij/util/xmlb/PrimitiveValueBinding.java index 3c303b07b410..84e94ef4c216 100644 --- a/platform/util/src/com/intellij/util/xmlb/PrimitiveValueBinding.java +++ b/platform/util/src/com/intellij/util/xmlb/PrimitiveValueBinding.java @@ -16,6 +16,8 @@ package com.intellij.util.xmlb; import com.intellij.openapi.util.JDOMUtil; +import org.jdom.Attribute; +import org.jdom.Content; import org.jdom.Text; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -44,8 +46,8 @@ class PrimitiveValueBinding implements Binding { value = JDOMUtil.concatTextNodesValues(nodes); } else { - assert nodes[0] != null; - value = JDOMUtil.getValue(nodes[0]); + Object node = nodes[0]; + value = node instanceof Attribute ? ((Attribute)node).getValue() : ((Content)node).getValue(); } return convertString(value); } diff --git a/platform/util/src/com/intellij/util/xmlb/PropertyAccessor.java b/platform/util/src/com/intellij/util/xmlb/PropertyAccessor.java index 9bef1ab7bf8a..9780e683154d 100644 --- a/platform/util/src/com/intellij/util/xmlb/PropertyAccessor.java +++ b/platform/util/src/com/intellij/util/xmlb/PropertyAccessor.java @@ -110,6 +110,11 @@ class PropertyAccessor implements Accessor { return myGenericType; } + @Override + public boolean isFinal() { + return false; + } + @NonNls public String toString() { return "PropertyAccessor[" + myReadMethod.getDeclaringClass().getName() + "." + getName() +"]"; diff --git a/platform/util/src/com/intellij/util/xmlb/SkipEmptySerializationFilter.java b/platform/util/src/com/intellij/util/xmlb/SkipEmptySerializationFilter.java index 4a98cf7a5cb8..aec1ab68e74a 100644 --- a/platform/util/src/com/intellij/util/xmlb/SkipEmptySerializationFilter.java +++ b/platform/util/src/com/intellij/util/xmlb/SkipEmptySerializationFilter.java @@ -36,8 +36,8 @@ public class SkipEmptySerializationFilter extends SerializationFilterBase { if (Boolean.FALSE.equals(beanValue) || (beanValue instanceof String && ((String)beanValue).isEmpty()) || - (beanValue instanceof Map && ((Map)beanValue).isEmpty()) || - (beanValue instanceof Collection && ((Collection)beanValue).isEmpty())) { + beanValue instanceof Collection && ((Collection)beanValue).isEmpty() || + (beanValue instanceof Map && ((Map)beanValue).isEmpty())) { return false; } diff --git a/platform/util/src/com/intellij/util/xmlb/SmartSerializer.java b/platform/util/src/com/intellij/util/xmlb/SmartSerializer.java index dd6a7cb916d3..805934e3c76e 100644 --- a/platform/util/src/com/intellij/util/xmlb/SmartSerializer.java +++ b/platform/util/src/com/intellij/util/xmlb/SmartSerializer.java @@ -16,19 +16,20 @@ package com.intellij.util.xmlb; import com.intellij.util.ThreeState; -import gnu.trove.THashSet; import org.jdom.Element; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.Set; +import java.util.LinkedHashSet; +import java.util.List; public final class SmartSerializer { - private final Set mySerializedAccessorNameTracker; + private final LinkedHashSet mySerializedAccessorNameTracker; + private List myOrderedBindings; private final SerializationFilter mySerializationFilter; public SmartSerializer(boolean trackSerializedNames, boolean useSkipEmptySerializationFilter) { - mySerializedAccessorNameTracker = trackSerializedNames ? new THashSet() : null; + mySerializedAccessorNameTracker = trackSerializedNames ? new LinkedHashSet() : null; mySerializationFilter = useSkipEmptySerializationFilter ? new SkipEmptySerializationFilter() { @@ -56,10 +57,16 @@ public final class SmartSerializer { if (mySerializedAccessorNameTracker != null) { mySerializedAccessorNameTracker.clear(); } - XmlSerializer.deserializeInto(bean, element, mySerializedAccessorNameTracker); + + BeanBinding beanBinding = (BeanBinding)XmlSerializerImpl.getBinding(bean.getClass()); + beanBinding.deserializeInto(bean, element, mySerializedAccessorNameTracker); + + if (mySerializedAccessorNameTracker != null) { + myOrderedBindings = beanBinding.computeOrderedBindings(mySerializedAccessorNameTracker); + } } public void writeExternal(@NotNull Object bean, @NotNull Element element) { - XmlSerializer.serializeInto(bean, element, mySerializationFilter); + ((BeanBinding)XmlSerializerImpl.getBinding(bean.getClass())).serializeInto(bean, element, mySerializationFilter, myOrderedBindings); } } \ No newline at end of file diff --git a/platform/util/src/com/intellij/util/xmlb/TagBinding.java b/platform/util/src/com/intellij/util/xmlb/TagBinding.java index 78336be646fe..37b013b5333d 100644 --- a/platform/util/src/com/intellij/util/xmlb/TagBinding.java +++ b/platform/util/src/com/intellij/util/xmlb/TagBinding.java @@ -16,6 +16,7 @@ package com.intellij.util.xmlb; import com.intellij.openapi.util.JDOMUtil; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.ArrayUtil; import com.intellij.util.SmartList; import com.intellij.util.xmlb.annotations.Tag; @@ -25,6 +26,7 @@ import org.jdom.Text; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.Collections; import java.util.List; class TagBinding extends BasePrimitiveBinding { @@ -33,7 +35,7 @@ class TagBinding extends BasePrimitiveBinding { public TagBinding(@NotNull Accessor accessor, @NotNull Tag tagAnnotation) { super(accessor, tagAnnotation.value(), null); - myTextIfEmpty = tagAnnotation.textIfEmpty(); + myTextIfEmpty = StringUtil.nullize(tagAnnotation.textIfEmpty()); } @Nullable @@ -57,28 +59,35 @@ class TagBinding extends BasePrimitiveBinding { @Nullable public Object deserialize(Object o, @NotNull Object... nodes) { assert nodes.length > 0; - Object[] children; + List children; + boolean isBeanBinding = myBinding instanceof BeanBinding; if (nodes.length == 1) { - children = JDOMUtil.getContent((Element)nodes[0]); + Element node = (Element)nodes[0]; + children = isBeanBinding ? node.getChildren() : node.getContent(); } else { String name = ((Element)nodes[0]).getName(); - List childrenList = new SmartList(); + children = new SmartList(); for (Object node : nodes) { - assert ((Element)node).getName().equals(name); - childrenList.addAll(((Element)node).getContent()); + Element element = (Element)node; + assert element.getName().equals(name); + //noinspection unchecked + children.addAll(((List)(isBeanBinding ? element.getChildren() : element.getContent()))); } - children = ArrayUtil.toObjectArray(childrenList); - } - - if (children.length == 0) { - children = new Object[] {new Text(myTextIfEmpty)}; } assert myBinding != null; - Object v = myBinding.deserialize(myAccessor.read(o), children); - Object value = XmlSerializerImpl.convert(v, myAccessor.getValueClass()); - myAccessor.write(o, value); + if (isBeanBinding && myAccessor.isFinal()) { + ((BeanBinding)myBinding).deserializeInto(o, (Element)children.get(0), null); + } + else { + if (children.isEmpty() && myTextIfEmpty != null) { + children = Collections.singletonList(new Text(myTextIfEmpty)); + } + + Object v = myBinding.deserialize(myAccessor.read(o), ArrayUtil.toObjectArray(children)); + myAccessor.write(o, XmlSerializerImpl.convert(v, myAccessor.getValueClass())); + } return o; } diff --git a/platform/util/src/com/intellij/util/xmlb/XmlSerializerImpl.java b/platform/util/src/com/intellij/util/xmlb/XmlSerializerImpl.java index ee16d1270500..fafaaaa93442 100644 --- a/platform/util/src/com/intellij/util/xmlb/XmlSerializerImpl.java +++ b/platform/util/src/com/intellij/util/xmlb/XmlSerializerImpl.java @@ -26,6 +26,7 @@ import java.lang.annotation.Annotation; import java.lang.ref.SoftReference; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; +import java.lang.reflect.TypeVariable; import java.util.*; import java.util.concurrent.ConcurrentHashMap; @@ -72,7 +73,18 @@ class XmlSerializerImpl { } static Binding getTypeBinding(@NotNull Type type, @Nullable Accessor accessor) { - return _getClassBinding(type instanceof Class ? (Class)type : (Class)((ParameterizedType)type).getRawType(), type, accessor); + Class aClass; + if (type instanceof Class) { + aClass = (Class)type; + } + else if (type instanceof TypeVariable) { + Type bound = ((TypeVariable)type).getBounds()[0]; + aClass = bound instanceof Class ? (Class)bound : (Class)((ParameterizedType)bound).getRawType(); + } + else { + aClass = (Class)((ParameterizedType)type).getRawType(); + } + return _getClassBinding(aClass, type, accessor); } private static synchronized Binding _getClassBinding(@NotNull Class aClass, @NotNull Type originalType, @Nullable Accessor accessor) { diff --git a/platform/util/testSrc/com/intellij/util/xmlb/XmlSerializerTest.java b/platform/util/testSrc/com/intellij/util/xmlb/XmlSerializerTest.java index 0f7217c5241e..a5b8edc491aa 100644 --- a/platform/util/testSrc/com/intellij/util/xmlb/XmlSerializerTest.java +++ b/platform/util/testSrc/com/intellij/util/xmlb/XmlSerializerTest.java @@ -24,9 +24,11 @@ import junit.framework.AssertionFailedError; import junit.framework.TestCase; import org.intellij.lang.annotations.Language; import org.jdom.Element; +import org.jdom.JDOMException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.io.IOException; import java.util.*; import java.util.concurrent.atomic.AtomicReference; @@ -1219,6 +1221,37 @@ public class XmlSerializerTest extends TestCase { doSerializerTest("", bean); } + static class Bean2 { + @Attribute + public String ab; + + @Attribute + public String module; + + @Attribute + public String ac; + } + + public void testOrdered() throws IOException, JDOMException { + Bean2 bean = new Bean2(); + bean.module = "module"; + bean.ab = "ab"; + doSerializerTest("", bean); + + checkSmartSerialization(new Bean2(), ""); + checkSmartSerialization(new Bean2(), ""); + checkSmartSerialization(new Bean2(), ""); + checkSmartSerialization(new Bean2(), ""); + } + + private static void checkSmartSerialization(@NotNull Bean2 bean, @NotNull String serialized) throws IOException, JDOMException { + SmartSerializer serializer = new SmartSerializer(); + serializer.readExternal(bean, JDOMUtil.loadDocument(serialized).getRootElement()); + Element serializedState = new Element("Bean2"); + serializer.writeExternal(bean, serializedState); + assertEquals(serialized, JDOMUtil.writeElement(serializedState)); + } + //--------------------------------------------------------------------------------------------------- private static Element assertSerializer(Object bean, String expected, SerializationFilter filter) { return assertSerializer(bean, expected, "Serialization failure", filter); @@ -1232,6 +1265,7 @@ public class XmlSerializerTest extends TestCase { Element element = assertSerializer(bean, expectedText, filter); //test deserializer + @SuppressWarnings("unchecked") Class aClass = (Class)bean.getClass(); T o = XmlSerializer.deserialize(element, aClass); assertSerializer(o, expectedText, "Deserialization failure", filter); From 111e2b3915d4051014821ef1f44605a26e2e7492 Mon Sep 17 00:00:00 2001 From: nik Date: Thu, 6 Nov 2014 16:19:26 +0300 Subject: [PATCH 34/34] external build: tolerate invalid run configurations produced by 'gradle idea' task (IDEA-132120) --- .../runConfigurations/JpsRunConfigurationSerializer.java | 8 +++++++- .../.idea/runConfigurations/invalid.xml | 4 ++++ .../testData/run-configurations/run-configurations.ipr | 2 ++ 3 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 jps/model-serialization/testData/run-configurations-dir/.idea/runConfigurations/invalid.xml diff --git a/jps/model-serialization/src/org/jetbrains/jps/model/serialization/runConfigurations/JpsRunConfigurationSerializer.java b/jps/model-serialization/src/org/jetbrains/jps/model/serialization/runConfigurations/JpsRunConfigurationSerializer.java index b20ddf0ff9ae..796ad663129a 100644 --- a/jps/model-serialization/src/org/jetbrains/jps/model/serialization/runConfigurations/JpsRunConfigurationSerializer.java +++ b/jps/model-serialization/src/org/jetbrains/jps/model/serialization/runConfigurations/JpsRunConfigurationSerializer.java @@ -15,6 +15,7 @@ */ package org.jetbrains.jps.model.serialization.runConfigurations; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.JDOMUtil; import com.intellij.util.containers.hash.HashMap; import org.jdom.Element; @@ -31,6 +32,8 @@ import java.util.Map; * @author nik */ public class JpsRunConfigurationSerializer { + private static final Logger LOG = Logger.getInstance(JpsRunConfigurationSerializer.class); + public static void loadRunConfigurations(@NotNull JpsProject project, @Nullable Element runManagerTag) { Map> serializers = new HashMap>(); for (JpsModelSerializerExtension extension : JpsModelSerializerExtension.getExtensions()) { @@ -50,9 +53,12 @@ public class JpsRunConfigurationSerializer { if (serializer != null) { loadRunConfiguration(name, configurationTag, serializer, project); } - else { + else if (typeId != null) { project.addRunConfiguration(name, new JpsUnknownRunConfigurationType(typeId), JpsElementFactory.getInstance().createDummyElement()); } + else { + LOG.info("Run configuration '" + name + "' wasn't loaded because 'type' attribute is missing"); + } } } diff --git a/jps/model-serialization/testData/run-configurations-dir/.idea/runConfigurations/invalid.xml b/jps/model-serialization/testData/run-configurations-dir/.idea/runConfigurations/invalid.xml new file mode 100644 index 000000000000..7e0f311245cf --- /dev/null +++ b/jps/model-serialization/testData/run-configurations-dir/.idea/runConfigurations/invalid.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/jps/model-serialization/testData/run-configurations/run-configurations.ipr b/jps/model-serialization/testData/run-configurations/run-configurations.ipr index 93c6bd97232b..e20908c8a349 100644 --- a/jps/model-serialization/testData/run-configurations/run-configurations.ipr +++ b/jps/model-serialization/testData/run-configurations/run-configurations.ipr @@ -45,6 +45,8 @@ + +