From 7d8033950329ef6b335db6a2c51b894d3bdc6746 Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Thu, 6 Nov 2014 15:15:11 +0300 Subject: [PATCH 01/84] 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/84] 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/84] 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/84] 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/84] 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 20a75c4842f3a1e32c67173d3dc14d8121772b88 Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Thu, 6 Nov 2014 17:07:05 +0300 Subject: [PATCH 06/84] 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 07/84] 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 08/84] 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 09/84] 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 10/84] 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 11/84] 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 12/84] 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 13/84] 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 14/84] [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 15/84] [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 16/84] [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 17/84] [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 18/84] 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 19/84] [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 20/84] [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 21/84] 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 7f5aff2c9babbd3c6720b2aee392ccd38f54934d Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Thu, 6 Nov 2014 16:36:28 +0100 Subject: [PATCH 22/84] IDEA-132440 (tests updated) --- .../{defaultFile/src/x => }/X.java | 5 ++- .../{defaultFile/src/x => }/X2.java | 4 +-- .../{defaultFile/src/x => }/X3.java | 2 +- .../defaultFile/expected.xml | 17 --------- .../DefaultFileTemplateInspectionTest.java | 30 ---------------- ...efaultFileTemplateUsageInspectionTest.java | 36 +++++++++++++++++++ 6 files changed, 41 insertions(+), 53 deletions(-) rename java/java-tests/testData/inspection/defaultFileTemplateUsage/{defaultFile/src/x => }/X.java (95%) rename java/java-tests/testData/inspection/defaultFileTemplateUsage/{defaultFile/src/x => }/X2.java (60%) rename java/java-tests/testData/inspection/defaultFileTemplateUsage/{defaultFile/src/x => }/X3.java (87%) delete mode 100644 java/java-tests/testData/inspection/defaultFileTemplateUsage/defaultFile/expected.xml delete mode 100644 java/java-tests/testSrc/com/intellij/codeInspection/DefaultFileTemplateInspectionTest.java create mode 100644 java/java-tests/testSrc/com/intellij/codeInspection/DefaultFileTemplateUsageInspectionTest.java diff --git a/java/java-tests/testData/inspection/defaultFileTemplateUsage/defaultFile/src/x/X.java b/java/java-tests/testData/inspection/defaultFileTemplateUsage/X.java similarity index 95% rename from java/java-tests/testData/inspection/defaultFileTemplateUsage/defaultFile/src/x/X.java rename to java/java-tests/testData/inspection/defaultFileTemplateUsage/X.java index c77b8f372e74..a9e7bf01f025 100644 --- a/java/java-tests/testData/inspection/defaultFileTemplateUsage/defaultFile/src/x/X.java +++ b/java/java-tests/testData/inspection/defaultFileTemplateUsage/X.java @@ -1,9 +1,9 @@ package x; import java.io.*; -/** +/** * Created by Alexey on 02.12.2005. - */ + */ public class X implements Runnable{ File f; //kkj lkkl jjkuufdffffjkkjjh kjh kjhj kkjh kjh i k kj kj klj lkj lkj lkjl kj klkl kl { @@ -60,4 +60,3 @@ public class X implements Runnable{ } } } - diff --git a/java/java-tests/testData/inspection/defaultFileTemplateUsage/defaultFile/src/x/X2.java b/java/java-tests/testData/inspection/defaultFileTemplateUsage/X2.java similarity index 60% rename from java/java-tests/testData/inspection/defaultFileTemplateUsage/defaultFile/src/x/X2.java rename to java/java-tests/testData/inspection/defaultFileTemplateUsage/X2.java index 89efeb89d00b..545b6c0de29a 100644 --- a/java/java-tests/testData/inspection/defaultFileTemplateUsage/defaultFile/src/x/X2.java +++ b/java/java-tests/testData/inspection/defaultFileTemplateUsage/X2.java @@ -1,8 +1,8 @@ package x; import java.io.*; -/** +/** * Created by Alexey on 02.12.2005. - */ + */ public class X2 { } diff --git a/java/java-tests/testData/inspection/defaultFileTemplateUsage/defaultFile/src/x/X3.java b/java/java-tests/testData/inspection/defaultFileTemplateUsage/X3.java similarity index 87% rename from java/java-tests/testData/inspection/defaultFileTemplateUsage/defaultFile/src/x/X3.java rename to java/java-tests/testData/inspection/defaultFileTemplateUsage/X3.java index c50dafa29576..a9f45957e068 100644 --- a/java/java-tests/testData/inspection/defaultFileTemplateUsage/defaultFile/src/x/X3.java +++ b/java/java-tests/testData/inspection/defaultFileTemplateUsage/X3.java @@ -5,5 +5,5 @@ import java.io.*; * Created by Alexey on 02.12.2005. * This class represents something important. */ -public class X2 { +public class X3 { } diff --git a/java/java-tests/testData/inspection/defaultFileTemplateUsage/defaultFile/expected.xml b/java/java-tests/testData/inspection/defaultFileTemplateUsage/defaultFile/expected.xml deleted file mode 100644 index 46addf64a834..000000000000 --- a/java/java-tests/testData/inspection/defaultFileTemplateUsage/defaultFile/expected.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - X.java - 4 - Default File Template Usage - Default File template - - - - X2.java - 4 - Default File Template Usage - Default File template - - \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/DefaultFileTemplateInspectionTest.java b/java/java-tests/testSrc/com/intellij/codeInspection/DefaultFileTemplateInspectionTest.java deleted file mode 100644 index 0bfd7e0021d5..000000000000 --- a/java/java-tests/testSrc/com/intellij/codeInspection/DefaultFileTemplateInspectionTest.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.intellij.codeInspection; - -import com.intellij.JavaTestUtil; -import com.intellij.codeInspection.defaultFileTemplateUsage.DefaultFileTemplateUsageInspection; -import com.intellij.openapi.projectRoots.Sdk; -import com.intellij.openapi.roots.LanguageLevelProjectExtension; -import com.intellij.pom.java.LanguageLevel; -import com.intellij.testFramework.InspectionTestCase; - -public class DefaultFileTemplateInspectionTest extends InspectionTestCase { - @Override - protected Sdk getTestProjectSdk() { - final Sdk sdk = super.getTestProjectSdk(); - LanguageLevelProjectExtension.getInstance(getProject()).setLanguageLevel(LanguageLevel.JDK_1_7); - return sdk; - } - - @Override - protected String getTestDataPath() { - return JavaTestUtil.getJavaTestDataPath() + "/inspection"; - } - - private void doTest() throws Exception { - doTest("defaultFileTemplateUsage/" + getTestName(true), new DefaultFileTemplateUsageInspection()); - } - - public void testDefaultFile() throws Exception{ - doTest(); - } -} diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/DefaultFileTemplateUsageInspectionTest.java b/java/java-tests/testSrc/com/intellij/codeInspection/DefaultFileTemplateUsageInspectionTest.java new file mode 100644 index 000000000000..71b416383de2 --- /dev/null +++ b/java/java-tests/testSrc/com/intellij/codeInspection/DefaultFileTemplateUsageInspectionTest.java @@ -0,0 +1,36 @@ +/* + * 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.codeInspection; + +import com.intellij.JavaTestUtil; +import com.intellij.codeInspection.defaultFileTemplateUsage.DefaultFileTemplateUsageInspection; +import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase; + +public class DefaultFileTemplateUsageInspectionTest extends LightCodeInsightFixtureTestCase { + @Override + protected String getTestDataPath() { + return JavaTestUtil.getJavaTestDataPath() + "/inspection/defaultFileTemplateUsage"; + } + + public void testX() { doTest(); } + public void testX2() { doTest(); } + public void testX3() { doTest(); } + + public void doTest() { + myFixture.enableInspections(new DefaultFileTemplateUsageInspection()); + myFixture.testHighlighting(true, false, true, getTestName(false) + ".java"); + } +} From 83bf1e448b374a8019d3820d7d88f31062a27483 Mon Sep 17 00:00:00 2001 From: Dmitry Avdeev Date: Wed, 5 Nov 2014 16:22:17 +0300 Subject: [PATCH 23/84] 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 24/84] 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 25/84] 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 26/84] 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 27/84] 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 28/84] 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 29/84] 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 30/84] 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 31/84] =?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 72093f557ce0ab1dfd83aee7d70bad3b7be1973e Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Thu, 6 Nov 2014 17:11:57 +0100 Subject: [PATCH 32/84] IDEA-132440 (quick fix corrected; cleanup) --- .../DefaultFileTemplateUsageInspection.java | 39 +---- .../FileHeaderChecker.java | 153 ++++++++---------- 2 files changed, 75 insertions(+), 117 deletions(-) diff --git a/java/java-impl/src/com/intellij/codeInspection/defaultFileTemplateUsage/DefaultFileTemplateUsageInspection.java b/java/java-impl/src/com/intellij/codeInspection/defaultFileTemplateUsage/DefaultFileTemplateUsageInspection.java index 9835c6864ad5..150cbe05b980 100644 --- a/java/java-impl/src/com/intellij/codeInspection/defaultFileTemplateUsage/DefaultFileTemplateUsageInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/defaultFileTemplateUsage/DefaultFileTemplateUsageInspection.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,17 +18,15 @@ package com.intellij.codeInspection.defaultFileTemplateUsage; import com.intellij.codeInspection.*; import com.intellij.ide.fileTemplates.FileTemplate; import com.intellij.ide.fileTemplates.impl.FileTemplateConfigurable; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.command.WriteCommandAction; import com.intellij.openapi.options.ShowSettingsUtil; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Pair; -import com.intellij.psi.*; +import com.intellij.psi.PsiFile; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import javax.swing.*; - /** * @author cdr */ @@ -60,26 +58,6 @@ public class DefaultFileTemplateUsageInspection extends BaseJavaLocalInspectionT return "DefaultFileTemplate"; } - static Pair getInteriorRange(PsiCodeBlock codeBlock) { - PsiElement[] children = codeBlock.getChildren(); - if (children.length == 0) return Pair.create(codeBlock, codeBlock); - int start; - for (start=0; start start;end--) { - PsiElement child = children[end]; - if (child instanceof PsiWhiteSpace) continue; - if (child instanceof PsiJavaToken && ((PsiJavaToken)child).getTokenType() == JavaTokenType.RBRACE) continue; - break; - } - return Pair.create(children[start], children[end]); - } - @Override @Nullable public ProblemDescriptor[] checkFile(@NotNull PsiFile file, @NotNull InspectionManager manager, boolean isOnTheFly) { @@ -92,15 +70,15 @@ public class DefaultFileTemplateUsageInspection extends BaseJavaLocalInspectionT return true; } - public static LocalQuickFix createEditFileTemplateFix(final FileTemplate templateToEdit, final ReplaceWithFileTemplateFix replaceTemplateFix) { - return new MyLocalQuickFix(templateToEdit, replaceTemplateFix); + public static LocalQuickFix createEditFileTemplateFix(FileTemplate templateToEdit, ReplaceWithFileTemplateFix replaceTemplateFix) { + return new EditFileTemplateFix(templateToEdit, replaceTemplateFix); } - private static class MyLocalQuickFix implements LocalQuickFix { + private static class EditFileTemplateFix implements LocalQuickFix { private final FileTemplate myTemplateToEdit; private final ReplaceWithFileTemplateFix myReplaceTemplateFix; - public MyLocalQuickFix(FileTemplate templateToEdit, ReplaceWithFileTemplateFix replaceTemplateFix) { + public EditFileTemplateFix(FileTemplate templateToEdit, ReplaceWithFileTemplateFix replaceTemplateFix) { myTemplateToEdit = templateToEdit; myReplaceTemplateFix = replaceTemplateFix; } @@ -120,11 +98,10 @@ public class DefaultFileTemplateUsageInspection extends BaseJavaLocalInspectionT @Override public void applyFix(@NotNull final Project project, @NotNull final ProblemDescriptor descriptor) { final FileTemplateConfigurable configurable = new FileTemplateConfigurable(); - SwingUtilities.invokeLater(new Runnable(){ + ApplicationManager.getApplication().invokeLater(new Runnable() { @Override public void run() { configurable.setTemplate(myTemplateToEdit, null); - boolean ok = ShowSettingsUtil.getInstance().editConfigurable(project, configurable); if (ok) { WriteCommandAction.runWriteCommandAction(project, new Runnable() { diff --git a/java/java-impl/src/com/intellij/codeInspection/defaultFileTemplateUsage/FileHeaderChecker.java b/java/java-impl/src/com/intellij/codeInspection/defaultFileTemplateUsage/FileHeaderChecker.java index a3db2c3d31f8..86cd33ba5434 100644 --- a/java/java-impl/src/com/intellij/codeInspection/defaultFileTemplateUsage/FileHeaderChecker.java +++ b/java/java-impl/src/com/intellij/codeInspection/defaultFileTemplateUsage/FileHeaderChecker.java @@ -20,97 +20,97 @@ import com.intellij.codeInspection.*; import com.intellij.ide.fileTemplates.FileTemplate; import com.intellij.ide.fileTemplates.FileTemplateManager; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.editor.Document; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.text.StringUtil; -import com.intellij.psi.JavaRecursiveElementWalkingVisitor; -import com.intellij.psi.PsiDocumentManager; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiFile; +import com.intellij.psi.*; import com.intellij.psi.javadoc.PsiDocComment; -import com.intellij.util.IncorrectOperationException; +import com.intellij.util.containers.ContainerUtil; import gnu.trove.TIntObjectHashMap; -import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import java.io.IOException; -import java.util.ArrayList; import java.util.Arrays; -import java.util.Collection; +import java.util.List; import java.util.Properties; import java.util.regex.Matcher; import java.util.regex.Pattern; /** - * @author Alexey + * @author cdr */ public class FileHeaderChecker { private static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.defaultFileTemplateUsage.FileHeaderChecker"); - static ProblemDescriptor checkFileHeader(@NotNull final PsiFile file, @NotNull InspectionManager manager, boolean onTheFly) { + static ProblemDescriptor checkFileHeader(@NotNull PsiFile file, @NotNull InspectionManager manager, boolean onTheFly) { TIntObjectHashMap offsetToProperty = new TIntObjectHashMap(); FileTemplate defaultTemplate = FileTemplateManager.getInstance().getDefaultTemplate(FileTemplateManager.FILE_HEADER_TEMPLATE_NAME); Pattern pattern = getTemplatePattern(defaultTemplate, file.getProject(), offsetToProperty); Matcher matcher = pattern.matcher(file.getViewProvider().getContents()); - if (matcher.matches()) { - final int startOffset = matcher.start(1); - final int endOffset = matcher.end(1); - final Ref docComment = new Ref(); - file.accept(new JavaRecursiveElementWalkingVisitor(){ - @Override public void visitElement(PsiElement element) { - if (docComment.get() != null) return; - TextRange range = element.getTextRange(); - if (!range.contains(startOffset) && !range.contains(endOffset)) return; - super.visitElement(element); - } - @Override public void visitDocComment(PsiDocComment comment) { - docComment.set(comment); - } - }); - PsiDocComment element = docComment.get(); - if (element == null) return null; - LocalQuickFix[] quickFix = createQuickFix(matcher, offsetToProperty); - final String description = InspectionsBundle.message("default.file.template.description"); - return manager.createProblemDescriptor(element, description, onTheFly, quickFix, ProblemHighlightType.GENERIC_ERROR_OR_WARNING); - } - return null; + if (!matcher.matches()) return null; + + final int startOffset = matcher.start(1); + final int endOffset = matcher.end(1); + final Ref docComment = new Ref(); + file.accept(new JavaRecursiveElementWalkingVisitor() { + @Override + public void visitElement(PsiElement element) { + if (docComment.get() != null) return; + TextRange range = element.getTextRange(); + if (!range.contains(startOffset) && !range.contains(endOffset)) return; + super.visitElement(element); + } + + @Override + public void visitDocComment(PsiDocComment comment) { + docComment.set(comment); + } + }); + PsiDocComment element = docComment.get(); + if (element == null) return null; + + LocalQuickFix[] fixes = createQuickFix(matcher, offsetToProperty); + String description = InspectionsBundle.message("default.file.template.description"); + return manager.createProblemDescriptor(element, description, onTheFly, fixes, ProblemHighlightType.GENERIC_ERROR_OR_WARNING); } - public static Pattern getTemplatePattern(@NotNull FileTemplate template, @NotNull Project project, @NotNull TIntObjectHashMap offsetToProperty) { + public static Pattern getTemplatePattern(@NotNull FileTemplate template, + @NotNull Project project, + @NotNull TIntObjectHashMap offsetToProperty) { String templateText = template.getText().trim(); String regex = templateToRegex(templateText, offsetToProperty, project); regex = StringUtil.replace(regex, "with", "(?:with|by)"); - regex = ".*("+regex+").*"; + regex = ".*(" + regex + ").*"; return Pattern.compile(regex, Pattern.DOTALL); } private static Properties computeProperties(final Matcher matcher, final TIntObjectHashMap offsetToProperty) { Properties properties = new Properties(FileTemplateManager.getInstance().getDefaultProperties()); + int[] offsets = offsetToProperty.keys(); Arrays.sort(offsets); - for (int i = 0; i < offsets.length; i++) { final int offset = offsets[i]; String propName = offsetToProperty.get(offset); int groupNum = i + 2; // first group is whole doc comment String propValue = matcher.group(groupNum); - properties.put(propName, propValue); + properties.setProperty(propName, propValue); } + return properties; } - private static LocalQuickFix[] createQuickFix(final Matcher matcher, - final TIntObjectHashMap offsetToProperty) { + private static LocalQuickFix[] createQuickFix(final Matcher matcher, final TIntObjectHashMap offsetToProperty) { final FileTemplate template = FileTemplateManager.getInstance().getPattern(FileTemplateManager.FILE_HEADER_TEMPLATE_NAME); - final ReplaceWithFileTemplateFix replaceTemplateFix = new ReplaceWithFileTemplateFix() { + ReplaceWithFileTemplateFix replaceTemplateFix = new ReplaceWithFileTemplateFix() { @Override - public void applyFix(@NotNull final Project project, @NotNull final ProblemDescriptor descriptor) { + public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) { PsiElement element = descriptor.getPsiElement(); if (element == null || !element.isValid()) return; if (!CodeInsightUtil.preparePsiElementsForWrite(element)) return; + String newText; try { newText = template.getText(computeProperties(matcher, offsetToProperty)); @@ -119,49 +119,30 @@ public class FileHeaderChecker { LOG.error(e); return; } - try { - int offset = element.getTextRange().getStartOffset(); - PsiFile psiFile = element.getContainingFile(); - if (psiFile == null) return; - PsiDocumentManager documentManager = PsiDocumentManager.getInstance(psiFile.getProject()); - Document document = documentManager.getDocument(psiFile); - if (document == null) return; - element.delete(); - documentManager.doPostponedOperationsAndUnblockDocument(document); - documentManager.commitDocument(document); - - document.insertString(offset, newText); - } - catch (IncorrectOperationException e) { - LOG.error(e); - } - catch (IllegalStateException e) { - LOG.error("Cannot create doc comment from text: '" + newText + "'", e); - } + PsiDocComment newComment = JavaPsiFacade.getElementFactory(project).createDocCommentFromText(newText); + element.replace(newComment); } }; - final LocalQuickFix editFileTemplateFix = DefaultFileTemplateUsageInspection.createEditFileTemplateFix(template, replaceTemplateFix); - if (template.isDefault()) { - return new LocalQuickFix[]{editFileTemplateFix}; - } - return new LocalQuickFix[]{replaceTemplateFix,editFileTemplateFix}; + + LocalQuickFix editFileTemplateFix = DefaultFileTemplateUsageInspection.createEditFileTemplateFix(template, replaceTemplateFix); + return template.isDefault() ? new LocalQuickFix[]{editFileTemplateFix} : new LocalQuickFix[]{replaceTemplateFix, editFileTemplateFix}; } - private static String templateToRegex(@NotNull String text, @NotNull TIntObjectHashMap offsetToProperty, @NotNull Project project) { - String regex = text; - @NonNls Collection properties = new ArrayList((Collection)FileTemplateManager.getInstance().getDefaultProperties(project).keySet()); + private static String templateToRegex(String text, TIntObjectHashMap offsetToProperty, Project project) { + List properties = ContainerUtil.newArrayList(FileTemplateManager.getInstance().getDefaultProperties(project).keySet()); properties.add("PACKAGE_NAME"); - regex = escapeRegexChars(regex); + String regex = escapeRegexChars(text); // first group is a whole file header int groupNumber = 1; - for (String name : properties) { - String escaped = escapeRegexChars("${"+name+"}"); + for (Object property : properties) { + String name = property.toString(); + String escaped = escapeRegexChars("${" + name + "}"); boolean first = true; - for (int i = regex.indexOf(escaped); i!=-1 && i i) { @@ -170,7 +151,7 @@ public class FileHeaderChecker { } } offsetToProperty.put(i, name); - regex = regex.substring(0,i) + replacement + regex.substring(i+escaped.length()); + regex = regex.substring(0, i) + replacement + regex.substring(i + escaped.length()); if (first) { groupNumber++; first = false; @@ -181,18 +162,18 @@ public class FileHeaderChecker { } private static String escapeRegexChars(String regex) { - regex = StringUtil.replace(regex,"|", "\\|"); - regex = StringUtil.replace(regex,".", "\\."); - regex = StringUtil.replace(regex,"*", "\\*"); - regex = StringUtil.replace(regex,"+", "\\+"); - regex = StringUtil.replace(regex,"?", "\\?"); - regex = StringUtil.replace(regex,"$", "\\$"); - regex = StringUtil.replace(regex,"(", "\\("); - regex = StringUtil.replace(regex,")", "\\)"); - regex = StringUtil.replace(regex,"[", "\\["); - regex = StringUtil.replace(regex,"]", "\\]"); - regex = StringUtil.replace(regex,"{", "\\{"); - regex = StringUtil.replace(regex,"}", "\\}"); + regex = StringUtil.replace(regex, "|", "\\|"); + regex = StringUtil.replace(regex, ".", "\\."); + regex = StringUtil.replace(regex, "*", "\\*"); + regex = StringUtil.replace(regex, "+", "\\+"); + regex = StringUtil.replace(regex, "?", "\\?"); + regex = StringUtil.replace(regex, "$", "\\$"); + regex = StringUtil.replace(regex, "(", "\\("); + regex = StringUtil.replace(regex, ")", "\\)"); + regex = StringUtil.replace(regex, "[", "\\["); + regex = StringUtil.replace(regex, "]", "\\]"); + regex = StringUtil.replace(regex, "{", "\\{"); + regex = StringUtil.replace(regex, "}", "\\}"); return regex; } } From 111e2b3915d4051014821ef1f44605a26e2e7492 Mon Sep 17 00:00:00 2001 From: nik Date: Thu, 6 Nov 2014 16:19:26 +0300 Subject: [PATCH 33/84] 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 @@ + + From 4e851eaffba79106a20a89347a7722b46037aa05 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Thu, 6 Nov 2014 18:00:38 +0100 Subject: [PATCH 34/84] IDEA-132440 (more straightforward element lookup) --- .../FileHeaderChecker.java | 36 ++++++++----------- .../defaultFileTemplateUsage/Range.java | 10 ++++++ ...efaultFileTemplateUsageInspectionTest.java | 1 + 3 files changed, 25 insertions(+), 22 deletions(-) create mode 100644 java/java-tests/testData/inspection/defaultFileTemplateUsage/Range.java diff --git a/java/java-impl/src/com/intellij/codeInspection/defaultFileTemplateUsage/FileHeaderChecker.java b/java/java-impl/src/com/intellij/codeInspection/defaultFileTemplateUsage/FileHeaderChecker.java index 86cd33ba5434..e7e6bbe24a5f 100644 --- a/java/java-impl/src/com/intellij/codeInspection/defaultFileTemplateUsage/FileHeaderChecker.java +++ b/java/java-impl/src/com/intellij/codeInspection/defaultFileTemplateUsage/FileHeaderChecker.java @@ -21,11 +21,14 @@ import com.intellij.ide.fileTemplates.FileTemplate; import com.intellij.ide.fileTemplates.FileTemplateManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.text.StringUtil; -import com.intellij.psi.*; +import com.intellij.psi.JavaPsiFacade; +import com.intellij.psi.PsiComment; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; import com.intellij.psi.javadoc.PsiDocComment; +import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.containers.ContainerUtil; import gnu.trove.TIntObjectHashMap; import org.jetbrains.annotations.NotNull; @@ -48,27 +51,16 @@ public class FileHeaderChecker { FileTemplate defaultTemplate = FileTemplateManager.getInstance().getDefaultTemplate(FileTemplateManager.FILE_HEADER_TEMPLATE_NAME); Pattern pattern = getTemplatePattern(defaultTemplate, file.getProject(), offsetToProperty); Matcher matcher = pattern.matcher(file.getViewProvider().getContents()); - if (!matcher.matches()) return null; + if (!matcher.matches()) { + return null; + } - final int startOffset = matcher.start(1); - final int endOffset = matcher.end(1); - final Ref docComment = new Ref(); - file.accept(new JavaRecursiveElementWalkingVisitor() { - @Override - public void visitElement(PsiElement element) { - if (docComment.get() != null) return; - TextRange range = element.getTextRange(); - if (!range.contains(startOffset) && !range.contains(endOffset)) return; - super.visitElement(element); - } - - @Override - public void visitDocComment(PsiDocComment comment) { - docComment.set(comment); - } - }); - PsiDocComment element = docComment.get(); - if (element == null) return null; + int startOffset = matcher.start(1); + int endOffset = matcher.end(1); + PsiComment element = PsiTreeUtil.getParentOfType(file.findElementAt(startOffset), PsiComment.class); + if (element == null || !element.getTextRange().equals(new TextRange(startOffset, endOffset))) { + return null; + } LocalQuickFix[] fixes = createQuickFix(matcher, offsetToProperty); String description = InspectionsBundle.message("default.file.template.description"); diff --git a/java/java-tests/testData/inspection/defaultFileTemplateUsage/Range.java b/java/java-tests/testData/inspection/defaultFileTemplateUsage/Range.java new file mode 100644 index 000000000000..2a36f0341190 --- /dev/null +++ b/java/java-tests/testData/inspection/defaultFileTemplateUsage/Range.java @@ -0,0 +1,10 @@ +package mylibs.aspectjlibs.lib2; + +/** + * Created by irina on 11/6/2014. + */ +class Range { + /** + * for all public methods with name == foo* and String type + */ +} diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/DefaultFileTemplateUsageInspectionTest.java b/java/java-tests/testSrc/com/intellij/codeInspection/DefaultFileTemplateUsageInspectionTest.java index 71b416383de2..3230fa6f1483 100644 --- a/java/java-tests/testSrc/com/intellij/codeInspection/DefaultFileTemplateUsageInspectionTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInspection/DefaultFileTemplateUsageInspectionTest.java @@ -28,6 +28,7 @@ public class DefaultFileTemplateUsageInspectionTest extends LightCodeInsightFixt public void testX() { doTest(); } public void testX2() { doTest(); } public void testX3() { doTest(); } + public void testRange() { doTest(); } public void doTest() { myFixture.enableInspections(new DefaultFileTemplateUsageInspection()); From 24256c47eccfcd7a57cd5d315a8a8181ff55073a Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Thu, 6 Nov 2014 18:45:33 +0100 Subject: [PATCH 35/84] IDEA-CR-880 (utility method used) --- .../defaultFileTemplateUsage/FileHeaderChecker.java | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/java/java-impl/src/com/intellij/codeInspection/defaultFileTemplateUsage/FileHeaderChecker.java b/java/java-impl/src/com/intellij/codeInspection/defaultFileTemplateUsage/FileHeaderChecker.java index e7e6bbe24a5f..0b40ae38b1d0 100644 --- a/java/java-impl/src/com/intellij/codeInspection/defaultFileTemplateUsage/FileHeaderChecker.java +++ b/java/java-impl/src/com/intellij/codeInspection/defaultFileTemplateUsage/FileHeaderChecker.java @@ -21,7 +21,6 @@ import com.intellij.ide.fileTemplates.FileTemplate; import com.intellij.ide.fileTemplates.FileTemplateManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.JavaPsiFacade; import com.intellij.psi.PsiComment; @@ -55,10 +54,8 @@ public class FileHeaderChecker { return null; } - int startOffset = matcher.start(1); - int endOffset = matcher.end(1); - PsiComment element = PsiTreeUtil.getParentOfType(file.findElementAt(startOffset), PsiComment.class); - if (element == null || !element.getTextRange().equals(new TextRange(startOffset, endOffset))) { + PsiComment element = PsiTreeUtil.findElementOfClassAtRange(file, matcher.start(1), matcher.end(1), PsiComment.class); + if (element == null) { return null; } From 628862ec4fc9c5c1682560665db5f3af246d5291 Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Thu, 6 Nov 2014 17:16:14 +0100 Subject: [PATCH 36/84] notnull --- .../editor-ui-api/src/com/intellij/ide/ui/UISettings.java | 2 +- .../impl/source/codeStyle/PersistableCodeStyleSchemes.java | 2 +- .../src/com/intellij/util/xmlb/SerializationFilter.java | 7 ++++--- .../com/intellij/util/xmlb/SerializationFilterBase.java | 2 +- .../util/src/com/intellij/util/xmlb/XmlSerializer.java | 2 +- .../testSrc/com/intellij/util/xmlb/XmlSerializerTest.java | 4 ++-- .../tasks/context/XDebuggerBreakpointsContextProvider.java | 2 +- .../intellij/tasks/context/XDebuggerWatchesProvider.java | 2 +- 8 files changed, 12 insertions(+), 11 deletions(-) diff --git a/platform/editor-ui-api/src/com/intellij/ide/ui/UISettings.java b/platform/editor-ui-api/src/com/intellij/ide/ui/UISettings.java index 4a390bc1383b..a366c5bff330 100644 --- a/platform/editor-ui-api/src/com/intellij/ide/ui/UISettings.java +++ b/platform/editor-ui-api/src/com/intellij/ide/ui/UISettings.java @@ -186,7 +186,7 @@ public class UISettings extends SimpleModificationTracker implements PersistentS public static class FontFilter implements SerializationFilter { @Override - public boolean accepts(Accessor accessor, Object bean) { + public boolean accepts(@NotNull Accessor accessor, Object bean) { UISettings settings = (UISettings)bean; return !hasDefaultFontSetting(settings); } diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/PersistableCodeStyleSchemes.java b/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/PersistableCodeStyleSchemes.java index e3f4fb760fbf..d04cc68967bc 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/PersistableCodeStyleSchemes.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/PersistableCodeStyleSchemes.java @@ -52,7 +52,7 @@ public class PersistableCodeStyleSchemes extends CodeStyleSchemesImpl implements public Element getState() { return XmlSerializer.serialize(this, new SerializationFilter() { @Override - public boolean accepts(Accessor accessor, Object bean) { + public boolean accepts(@NotNull Accessor accessor, Object bean) { return accessor.getValueClass().equals(String.class); } }); diff --git a/platform/util/src/com/intellij/util/xmlb/SerializationFilter.java b/platform/util/src/com/intellij/util/xmlb/SerializationFilter.java index 4c0d2a81ff62..01f6f68f4fd1 100644 --- a/platform/util/src/com/intellij/util/xmlb/SerializationFilter.java +++ b/platform/util/src/com/intellij/util/xmlb/SerializationFilter.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,9 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.intellij.util.xmlb; +import org.jetbrains.annotations.NotNull; + public interface SerializationFilter { - boolean accepts(Accessor accessor, Object bean); + boolean accepts(@NotNull Accessor accessor, Object bean); } diff --git a/platform/util/src/com/intellij/util/xmlb/SerializationFilterBase.java b/platform/util/src/com/intellij/util/xmlb/SerializationFilterBase.java index 3fab01c85af6..7c1cb2b51795 100644 --- a/platform/util/src/com/intellij/util/xmlb/SerializationFilterBase.java +++ b/platform/util/src/com/intellij/util/xmlb/SerializationFilterBase.java @@ -20,7 +20,7 @@ import org.jetbrains.annotations.Nullable; public abstract class SerializationFilterBase implements SerializationFilter { @Override - public final boolean accepts(Accessor accessor, Object bean) { + public final boolean accepts(@NotNull Accessor accessor, Object bean) { if (bean == null) { return true; } diff --git a/platform/util/src/com/intellij/util/xmlb/XmlSerializer.java b/platform/util/src/com/intellij/util/xmlb/XmlSerializer.java index 76fa9d08c0e1..97e4a35276a5 100644 --- a/platform/util/src/com/intellij/util/xmlb/XmlSerializer.java +++ b/platform/util/src/com/intellij/util/xmlb/XmlSerializer.java @@ -31,7 +31,7 @@ import java.util.Set; public class XmlSerializer { private static final SerializationFilter TRUE_FILTER = new SerializationFilter() { @Override - public boolean accepts(Accessor accessor, Object bean) { + public boolean accepts(@NotNull Accessor accessor, Object bean) { return true; } }; diff --git a/platform/util/testSrc/com/intellij/util/xmlb/XmlSerializerTest.java b/platform/util/testSrc/com/intellij/util/xmlb/XmlSerializerTest.java index a5b8edc491aa..69cc37512462 100644 --- a/platform/util/testSrc/com/intellij/util/xmlb/XmlSerializerTest.java +++ b/platform/util/testSrc/com/intellij/util/xmlb/XmlSerializerTest.java @@ -537,7 +537,7 @@ public class XmlSerializerTest extends TestCase { "", new SerializationFilter() { @Override - public boolean accepts(Accessor accessor, Object bean) { + public boolean accepts(@NotNull Accessor accessor, Object bean) { return accessor.getName().startsWith("I"); } }); @@ -850,7 +850,7 @@ public class XmlSerializerTest extends TestCase { } public static class PropertyFilterTest implements SerializationFilter { @Override - public boolean accepts(Accessor accessor, Object bean) { + public boolean accepts(@NotNull Accessor accessor, Object bean) { return !accessor.read(bean).equals("skip"); } } diff --git a/plugins/tasks/tasks-core/src/com/intellij/tasks/context/XDebuggerBreakpointsContextProvider.java b/plugins/tasks/tasks-core/src/com/intellij/tasks/context/XDebuggerBreakpointsContextProvider.java index 2e8d5df8c823..ec4d81f86d2c 100644 --- a/plugins/tasks/tasks-core/src/com/intellij/tasks/context/XDebuggerBreakpointsContextProvider.java +++ b/plugins/tasks/tasks-core/src/com/intellij/tasks/context/XDebuggerBreakpointsContextProvider.java @@ -56,7 +56,7 @@ public class XDebuggerBreakpointsContextProvider extends WorkingContextProvider XBreakpointManagerImpl.BreakpointManagerState state = myBreakpointManager.getState(); Element serialize = XmlSerializer.serialize(state, new SerializationFilter() { @Override - public boolean accepts(Accessor accessor, Object bean) { + public boolean accepts(@NotNull Accessor accessor, Object bean) { return accessor.read(bean) != null; } }); diff --git a/plugins/tasks/tasks-core/src/com/intellij/tasks/context/XDebuggerWatchesProvider.java b/plugins/tasks/tasks-core/src/com/intellij/tasks/context/XDebuggerWatchesProvider.java index 62b26995daf2..2b39f86d30b8 100644 --- a/plugins/tasks/tasks-core/src/com/intellij/tasks/context/XDebuggerWatchesProvider.java +++ b/plugins/tasks/tasks-core/src/com/intellij/tasks/context/XDebuggerWatchesProvider.java @@ -54,7 +54,7 @@ public class XDebuggerWatchesProvider extends WorkingContextProvider { XDebuggerWatchesManager.WatchesManagerState state = myWatchesManager.getState(); Element serialize = XmlSerializer.serialize(state, new SerializationFilter() { @Override - public boolean accepts(Accessor accessor, Object bean) { + public boolean accepts(@NotNull Accessor accessor, Object bean) { return accessor.read(bean) != null; } }); From f004dd5116de3682b087c179bcef8636831221c8 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Thu, 6 Nov 2014 19:03:48 +0100 Subject: [PATCH 37/84] IDEA-132508 (typo in action description) --- .../src/com/intellij/ide/actions/GoToLinkTargetAction.java | 7 ++++--- .../src/messages/ActionsBundle.properties | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/ide/actions/GoToLinkTargetAction.java b/platform/lang-impl/src/com/intellij/ide/actions/GoToLinkTargetAction.java index 951ff97fb40b..138a102e2dad 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/GoToLinkTargetAction.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/GoToLinkTargetAction.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,17 +24,18 @@ import com.intellij.openapi.vfs.VFileProperty; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiFileSystemItem; import com.intellij.psi.PsiManager; +import org.jetbrains.annotations.NotNull; public class GoToLinkTargetAction extends DumbAwareAction { @Override - public void update(AnActionEvent e) { + public void update(@NotNull AnActionEvent e) { Project project = getEventProject(e); VirtualFile file = CommonDataKeys.VIRTUAL_FILE.getData(e.getDataContext()); e.getPresentation().setEnabledAndVisible(project != null && file != null && file.is(VFileProperty.SYMLINK)); } @Override - public void actionPerformed(AnActionEvent e) { + public void actionPerformed(@NotNull AnActionEvent e) { Project project = getEventProject(e); VirtualFile file = CommonDataKeys.VIRTUAL_FILE.getData(e.getDataContext()); if (project != null && file != null && file.is(VFileProperty.SYMLINK)) { diff --git a/platform/platform-resources-en/src/messages/ActionsBundle.properties b/platform/platform-resources-en/src/messages/ActionsBundle.properties index ad2a2098d8f7..1125e69f3b16 100644 --- a/platform/platform-resources-en/src/messages/ActionsBundle.properties +++ b/platform/platform-resources-en/src/messages/ActionsBundle.properties @@ -1401,7 +1401,7 @@ action.Console.History.Browse.text=Browse History action.Console.History.Browse.description=Browse console history action.RevealIn.description=Highlights the file in platform's file manager action.GoToLinkTarget.text=Go to Link Target -action.GoToLinkTarget.description=Opens a target ot this symlink in the Project View +action.GoToLinkTarget.description=Opens a target of this symlink in the Project View action.Images.EditExternally.text=Jump to External Editor action.Images.EditExternally.description=Open image in external editor From 51262ecf745e6f1fc77cf3b2a77d3171ac9e48f9 Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Thu, 6 Nov 2014 16:03:40 +0100 Subject: [PATCH 38/84] fix empty dialog --- .../openapi/updateSettings/impl/AbstractUpdateDialog.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/AbstractUpdateDialog.java b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/AbstractUpdateDialog.java index 7d5456dd53b3..fb3f69fc9c77 100644 --- a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/AbstractUpdateDialog.java +++ b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/AbstractUpdateDialog.java @@ -102,7 +102,7 @@ public abstract class AbstractUpdateDialog extends DialogWrapper { protected void configureMessageArea(@NotNull JEditorPane area) { - configureMessageArea(area, IdeBundle.message("updates.configure.label", ShowSettingsUtil.getSettingsMenuName()), null, null); + configureMessageArea(area, myEnableLink ? IdeBundle.message("updates.configure.label", ShowSettingsUtil.getSettingsMenuName()) : "", null, null); } protected void configureMessageArea(final @NotNull JEditorPane area, @@ -113,7 +113,7 @@ public abstract class AbstractUpdateDialog extends DialogWrapper { UIUtil.getCssFontDeclaration(UIUtil.getLabelFont(), fontColor, null, null) + "" + "" + - (myEnableLink ? messageBody : "") + + messageBody + ""; area.setBackground(UIUtil.getPanelBackground()); From bba30278f93adbaaf02c501e367b1f6ce2ec8f65 Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Thu, 6 Nov 2014 16:56:50 +0100 Subject: [PATCH 39/84] method refs: fix variable initializing order (IDEA-132445) --- ...ethodReferenceCompatibilityConstraint.java | 6 +++--- .../newMethodRef/TypeParametersInitOrder.java | 21 +++++++++++++++++++ .../lambda/NewMethodRefHighlightingTest.java | 4 ++++ 3 files changed, 28 insertions(+), 3 deletions(-) create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newMethodRef/TypeParametersInitOrder.java diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/PsiMethodReferenceCompatibilityConstraint.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/PsiMethodReferenceCompatibilityConstraint.java index b5e4188e1644..45018296d888 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/PsiMethodReferenceCompatibilityConstraint.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/PsiMethodReferenceCompatibilityConstraint.java @@ -169,13 +169,13 @@ public class PsiMethodReferenceCompatibilityConstraint implements ConstraintForm } LOG.assertTrue(referencedMethodReturnType != null, method); - session.initBounds(myExpression, method.getTypeParameters()); - - if (!PsiTreeUtil.isContextAncestor(containingClass, myExpression, false) || + if (!PsiTreeUtil.isContextAncestor(containingClass, myExpression, false) || PsiUtil.getEnclosingStaticElement(myExpression, containingClass) != null) { session.initBounds(myExpression, containingClass.getTypeParameters()); } + session.initBounds(myExpression, method.getTypeParameters()); + //if i) the method reference elides NonWildTypeArguments, // ii) the compile-time declaration is a generic method, and // iii) the return type of the compile-time declaration mentions at least one of the method's type parameters; diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newMethodRef/TypeParametersInitOrder.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newMethodRef/TypeParametersInitOrder.java new file mode 100644 index 000000000000..966b0137f7b6 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newMethodRef/TypeParametersInitOrder.java @@ -0,0 +1,21 @@ +import java.util.function.Function; + +interface Repository { + S save(S s); +} + +interface Builder { + + T build(); + + default Builder map(Function fx) { + return () -> fx.apply(this.build()); + } +} + +class Usage { + void test(Repository repository, Builder sample) { + sample.map(repository::save).build(); + sample.map((s) -> repository.save(s)).build(); + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/NewMethodRefHighlightingTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/NewMethodRefHighlightingTest.java index 281cefa64109..57629d86b601 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/NewMethodRefHighlightingTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/NewMethodRefHighlightingTest.java @@ -318,6 +318,10 @@ public class NewMethodRefHighlightingTest extends LightDaemonAnalyzerTestCase { doTest(); } + public void testTypeParametersInitOrder() throws Exception { + doTest(); + } + private void doTest() { doTest(false); } From e29cd563db83f952ac81cb67456ebb4718c717f9 Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Thu, 6 Nov 2014 17:09:53 +0100 Subject: [PATCH 40/84] NPE (IDEA-132409) --- .../daemon/impl/analysis/HighlightVisitorImpl.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java index 095912a20094..936516efc083 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java @@ -617,9 +617,10 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh myHolder.add(HighlightMethodUtil.checkConstructorName(method)); } myHolder.add(HighlightNamesUtil.highlightMethodName(method, identifier, true, colorsScheme)); - myHolder.add(GenericsHighlightUtil.checkDefaultMethodOverrideEquivalentToObjectNonPrivate(myLanguageLevel, - method.getContainingClass(), method, - identifier)); + final PsiClass aClass = method.getContainingClass(); + if (aClass != null) { + myHolder.add(GenericsHighlightUtil.checkDefaultMethodOverrideEquivalentToObjectNonPrivate(myLanguageLevel, aClass, method, identifier)); + } } super.visitIdentifier(identifier); From 668ccc7dd073a839bbc25752871de06a92f29e91 Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Thu, 6 Nov 2014 19:02:56 +0100 Subject: [PATCH 41/84] new inference: site substitution from remembered properties (IDEA-132417) --- .../ExpressionCompatibilityConstraint.java | 2 +- ...opertiesInsteadOfSiteSubstitutorIfAny.java | 51 +++++++++++++++++++ .../lambda/NewLambdaHighlightingTest.java | 4 ++ 3 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/PropertiesInsteadOfSiteSubstitutorIfAny.java diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/ExpressionCompatibilityConstraint.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/ExpressionCompatibilityConstraint.java index f7b73ba5eee2..95baff29ef69 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/ExpressionCompatibilityConstraint.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/ExpressionCompatibilityConstraint.java @@ -105,7 +105,7 @@ public class ExpressionCompatibilityConstraint extends InputOutputConstraintForm if (typeParams != null) { PsiSubstitutor siteSubstitutor = - resolveResult instanceof MethodCandidateInfo && method != null && !method.isConstructor() ? ((MethodCandidateInfo)resolveResult).getSiteSubstitutor() : PsiSubstitutor.EMPTY; + resolveResult instanceof MethodCandidateInfo && method != null && !method.isConstructor() ? ((MethodCandidateInfo)resolveResult).getSiteSubstitutor() : candidateProperties != null ? candidateProperties.getSubstitutor() : PsiSubstitutor.EMPTY; final InferenceSession callSession = new InferenceSession(typeParams, siteSubstitutor, myExpression.getManager(), myExpression); callSession.propagateVariables(session.getInferenceVariables()); if (method != null) { diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/PropertiesInsteadOfSiteSubstitutorIfAny.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/PropertiesInsteadOfSiteSubstitutorIfAny.java new file mode 100644 index 000000000000..ddc4008f666a --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/PropertiesInsteadOfSiteSubstitutorIfAny.java @@ -0,0 +1,51 @@ + +import java.util.List; +import java.util.Optional; +import java.util.function.Function; +import java.util.function.Supplier; +import java.util.stream.Stream; + +class Test { + public static class Thing { + public Integer toPresenter() { + return 1; + } + } + + public void map1(Function mapper) {} + + private void getPresentersFailure( final Stream stream) { + map1((roles) -> { + return stream.map(Thing::toPresenter); + }); + } + +} + +class Test1 { + public interface Convertable { + ThingPresenter toPresenter(); + } + + public static class Thing implements Convertable { + @Override + public ThingPresenter toPresenter() { + return new ThingPresenter("thing"); + } + } + + public static class ThingPresenter { + public String value; + public ThingPresenter(String value) { this.value = value; } + } + + private static Stream getPresentersFailure(Supplier>> thingSupplier) { + Optional> personRoles = thingSupplier.get(); + return personRoles.map(roles -> roles.stream().map(Thing::toPresenter)).get(); + } + + private static Stream getPresentersWorking(Supplier>> thingSupplier) { + Optional> personRoles = thingSupplier.get(); + return personRoles.map(roles -> roles.stream().map(t -> t.toPresenter())).get(); + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/NewLambdaHighlightingTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/NewLambdaHighlightingTest.java index 5f606082970e..416f07e77b22 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/NewLambdaHighlightingTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/NewLambdaHighlightingTest.java @@ -156,6 +156,10 @@ public class NewLambdaHighlightingTest extends LightDaemonAnalyzerTestCase { doTest(); } + public void testPropertiesInsteadOfSiteSubstitutorIfAny() throws Exception { + doTest(); + } + private void doTest() { doTest(false); } From 216f253d0f62b9c1367778a35ec0fd4cf98b3c02 Mon Sep 17 00:00:00 2001 From: Konstantin Bulenkov Date: Thu, 6 Nov 2014 19:55:35 +0100 Subject: [PATCH 42/84] invisible go to class on gnome 3.14 (cherry picked from commit 6e6d7e5dd5acd7aeb7766cd56f85c6b5eeafcfa7) --- .../com/intellij/ui/popup/PopupComponent.java | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/ui/popup/PopupComponent.java b/platform/platform-impl/src/com/intellij/ui/popup/PopupComponent.java index 1670491b91bf..aa2f1745b03b 100644 --- a/platform/platform-impl/src/com/intellij/ui/popup/PopupComponent.java +++ b/platform/platform-impl/src/com/intellij/ui/popup/PopupComponent.java @@ -140,23 +140,10 @@ public interface PopupComponent { myDialog.setFocusableWindowState(false); } - try { - if (UIUtil.isUnderDarcula()) { - AWTUtilities.setWindowOpaque(myDialog, false); - } - } - catch (Exception ignore) { - } - + AwtPopupWrapper.fixFlickering(myDialog, false); myDialog.setVisible(true); + AwtPopupWrapper.fixFlickering(myDialog, true); - try { - if (UIUtil.isUnderDarcula()) { - AWTUtilities.setWindowOpaque(myDialog, true); - } - } - catch (Exception ignore) { - } SwingUtilities.invokeLater(new Runnable() { public void run() { myDialog.setFocusableWindowState(true); From 1b93351cf68aaaecf18dce956cf69f91ffae2ed6 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Thu, 6 Nov 2014 20:22:12 +0100 Subject: [PATCH 43/84] IDEA-128713 (option to prevent file chooser from peeking inside non-user directories) --- bin/idea.properties | 9 ++++++++- .../OpenProjectFileChooserDescriptor.java | 17 +++++++++-------- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/bin/idea.properties b/bin/idea.properties index be34798ed34e..a9cd05389fd5 100644 --- a/bin/idea.properties +++ b/bin/idea.properties @@ -99,4 +99,11 @@ sun.java2d.pmoffscreen=false # Maximum size (kilobytes) IDEA will load for showing past file contents - # in Show Diff or when calculating Digest Diff #--------------------------------------------------------------------- -#idea.max.vcs.loaded.size.kb=20480 \ No newline at end of file +#idea.max.vcs.loaded.size.kb=20480 + +#--------------------------------------------------------------------- +# IDEA file chooser peeks inside directories to detect whether they contain a valid project +# (to mark such directories with a corresponding icon). +# Uncommenting the option prevents this behavior outside of user home directory. +#--------------------------------------------------------------------- +#idea.chooser.lookup.for.project.dirs=false diff --git a/platform/platform-impl/src/com/intellij/ide/actions/OpenProjectFileChooserDescriptor.java b/platform/platform-impl/src/com/intellij/ide/actions/OpenProjectFileChooserDescriptor.java index b462fcbc11ad..b5cecc222169 100644 --- a/platform/platform-impl/src/com/intellij/ide/actions/OpenProjectFileChooserDescriptor.java +++ b/platform/platform-impl/src/com/intellij/ide/actions/OpenProjectFileChooserDescriptor.java @@ -24,6 +24,7 @@ import com.intellij.openapi.vfs.VfsUtil; import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.projectImport.ProjectOpenProcessor; +import com.intellij.util.SystemProperties; import org.jetbrains.annotations.NotNull; import javax.swing.*; @@ -34,6 +35,7 @@ import javax.swing.*; */ public class OpenProjectFileChooserDescriptor extends FileChooserDescriptor { private static final Icon ourProjectIcon = IconLoader.getIcon(ApplicationInfoEx.getInstanceEx().getSmallIconUrl()); + private static final boolean ourCanInspectDirs = SystemProperties.getBooleanProperty("idea.chooser.lookup.for.project.dirs", true); public OpenProjectFileChooserDescriptor(boolean chooseFiles) { super(chooseFiles, true, chooseFiles, chooseFiles, false, false); @@ -64,15 +66,14 @@ public class OpenProjectFileChooserDescriptor extends FileChooserDescriptor { } private static boolean canInspectDirectory(VirtualFile file) { - if (file.getParent() == null) return false; - VirtualFile home = VfsUtil.getUserHomeDir(); - if (home == null) return false; // unnatural situation - VirtualFile homes = home.getParent(); - if (homes == null) return false; // another one - if (homes.equals(file.getParent()) || VfsUtilCore.isAncestor(file, homes, false)) return false; - - return true; + if (home == null || VfsUtilCore.isAncestor(file, home, false)) { + return false; + } + if (ourCanInspectDirs || VfsUtilCore.isAncestor(home, file, true)) { + return true; + } + return false; } private static Icon getImporterIcon(VirtualFile file) { From 8fb15f4de87fdf9c2ee38b0c7947bb0ed6837a98 Mon Sep 17 00:00:00 2001 From: Alexander Zolotov Date: Thu, 6 Nov 2014 14:01:38 +0300 Subject: [PATCH 44/84] Block support: extract retrieving reparseable element --- .../impl/source/text/BlockSupportImpl.java | 56 +++++++++++-------- 1 file changed, 34 insertions(+), 22 deletions(-) diff --git a/platform/core-impl/src/com/intellij/psi/impl/source/text/BlockSupportImpl.java b/platform/core-impl/src/com/intellij/psi/impl/source/text/BlockSupportImpl.java index 80d62f72d72b..13d25c14c982 100644 --- a/platform/core-impl/src/com/intellij/psi/impl/source/text/BlockSupportImpl.java +++ b/platform/core-impl/src/com/intellij/psi/impl/source/text/BlockSupportImpl.java @@ -27,6 +27,7 @@ import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.fileTypes.PlainTextLanguage; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Couple; import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.TextRange; import com.intellij.psi.*; @@ -58,7 +59,7 @@ public class BlockSupportImpl extends BlockSupport { project.getMessageBus().connect().subscribe(DocumentBulkUpdateListener.TOPIC, new DocumentBulkUpdateListener.Adapter() { @Override public void updateStarted(@NotNull final Document doc) { - doc.putUserData(DO_NOT_REPARSE_INCREMENTALLY, Boolean.TRUE); + doc.putUserData(DO_NOT_REPARSE_INCREMENTALLY, Boolean.TRUE); } }); } @@ -80,22 +81,34 @@ public class BlockSupportImpl extends BlockSupport { @NotNull final CharSequence newFileText, @NotNull final ProgressIndicator indicator) { final PsiFileImpl fileImpl = (PsiFileImpl)file; - Project project = fileImpl.getProject(); - final FileElement treeFileElement = fileImpl.getTreeElement(); - final CharTable charTable = treeFileElement.getCharTable(); + + final Couple reparseableRoots = findReparseableRoots(fileImpl, changedPsiRange, newFileText); + return reparseableRoots != null + ? mergeTrees(fileImpl, reparseableRoots.first, reparseableRoots.second, indicator) + : makeFullParse(fileImpl.getTreeElement(), newFileText, newFileText.length(), fileImpl, indicator); + } + /** + * This method searches ast node that could be reparsed incrementally and returns pair of target reparseable node and new replacement node. + * Returns null if there is no any chance to make incremental parsing. + */ + @Nullable + public Couple findReparseableRoots(@NotNull PsiFileImpl file, + @NotNull TextRange changedPsiRange, + @NotNull CharSequence newFileText) { + Project project = file.getProject(); + final FileElement fileElement = file.getTreeElement(); + final CharTable charTable = fileElement.getCharTable(); + int lengthShift = newFileText.length() - fileElement.getTextLength(); - final int textLength = newFileText.length(); - int lengthShift = textLength - treeFileElement.getTextLength(); - - if (treeFileElement.getElementType() instanceof ITemplateDataElementType || isTooDeep(file)) { + if (fileElement.getElementType() instanceof ITemplateDataElementType || isTooDeep(file)) { // unable to perform incremental reparse for template data in JSP, or in exceptionally deep trees - return makeFullParse(treeFileElement, newFileText, textLength, fileImpl, indicator); + return null; } - final ASTNode leafAtStart = treeFileElement.findLeafElementAt(Math.max(0, changedPsiRange.getStartOffset() - 1)); - final ASTNode leafAtEnd = treeFileElement.findLeafElementAt(changedPsiRange.getEndOffset()); - ASTNode node = leafAtStart != null && leafAtEnd != null ? TreeUtil.findCommonParent(leafAtStart, leafAtEnd) : treeFileElement; + final ASTNode leafAtStart = fileElement.findLeafElementAt(Math.max(0, changedPsiRange.getStartOffset() - 1)); + final ASTNode leafAtEnd = fileElement.findLeafElementAt(changedPsiRange.getEndOffset()); + ASTNode node = leafAtStart != null && leafAtEnd != null ? TreeUtil.findCommonParent(leafAtStart, leafAtEnd) : fileElement; Language baseLanguage = file.getViewProvider().getBaseLanguage(); while (node != null && !(node instanceof FileElement)) { @@ -117,25 +130,24 @@ public class BlockSupportImpl extends BlockSupport { if (reparseable.isParsable(node.getTreeParent(), newTextStr, baseLanguage, project)) { ASTNode chameleon = reparseable.createNode(newTextStr); if (chameleon != null) { - DummyHolder holder = DummyHolderFactory.createHolder(fileImpl.getManager(), null, node.getPsi(), charTable); + DummyHolder holder = DummyHolderFactory.createHolder(file.getManager(), null, node.getPsi(), charTable); holder.getTreeElement().rawAddChildren((TreeElement)chameleon); if (holder.getTextLength() != newTextStr.length()) { String details = ApplicationManager.getApplication().isInternal() - ? "text=" + newTextStr + "; treeText=" + holder.getText() + ";" - : ""; + ? "text=" + newTextStr + "; treeText=" + holder.getText() + ";" + : ""; LOG.error("Inconsistent reparse: " + details + " type=" + elementType); } - return mergeTrees(fileImpl, node, chameleon, indicator); + return Couple.of(node, chameleon); } } } } node = node.getTreeParent(); } - - return makeFullParse(node, newFileText, textLength, fileImpl, indicator); + return null; } private static void reportInconsistentLength(PsiFile file, CharSequence newFileText, ASTNode node, int start, int end) { @@ -288,7 +300,7 @@ public class BlockSupportImpl extends BlockSupport { }; } - private static boolean isReplaceWholeNode(@NotNull PsiFileImpl fileImpl, @NotNull ASTNode newRoot) throws ReparsedSuccessfullyException{ + private static boolean isReplaceWholeNode(@NotNull PsiFileImpl fileImpl, @NotNull ASTNode newRoot) throws ReparsedSuccessfullyException { final Boolean data = fileImpl.getUserData(DO_NOT_REPARSE_INCREMENTALLY); if (data != null) fileImpl.putUserData(DO_NOT_REPARSE_INCREMENTALLY, null); @@ -308,7 +320,7 @@ public class BlockSupportImpl extends BlockSupport { } public static void sendBeforeChildrenChangeEvent(@NotNull PsiManagerImpl manager, @NotNull PsiElement scope, boolean isGenericChange) { - if(!scope.isPhysical()) { + if (!scope.isPhysical()) { manager.beforeChange(false); return; } @@ -318,7 +330,7 @@ public class BlockSupportImpl extends BlockSupport { TextRange range = scope.getTextRange(); event.setOffset(range == null ? 0 : range.getStartOffset()); event.setOldLength(scope.getTextLength()); - // the "generic" event is being sent on every PSI change. It does not carry any specific info except the fact that "something has changed" + // the "generic" event is being sent on every PSI change. It does not carry any specific info except the fact that "something has changed" event.setGenericChange(isGenericChange); manager.beforeChildrenChange(event); } @@ -327,7 +339,7 @@ public class BlockSupportImpl extends BlockSupport { @NotNull PsiFile scope, int oldLength, boolean isGenericChange) { - if(!scope.isPhysical()) { + if (!scope.isPhysical()) { manager.afterChange(false); return; } From 4630a6c6ee5cdc27ae8a1b9f5f0fae7c298c1577 Mon Sep 17 00:00:00 2001 From: Alexander Zolotov Date: Thu, 6 Nov 2014 14:31:12 +0300 Subject: [PATCH 45/84] Block support: fix retrieving reparseable node on change at the end of file --- .../src/com/intellij/psi/impl/source/text/BlockSupportImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/core-impl/src/com/intellij/psi/impl/source/text/BlockSupportImpl.java b/platform/core-impl/src/com/intellij/psi/impl/source/text/BlockSupportImpl.java index 13d25c14c982..708a4e2ac1d4 100644 --- a/platform/core-impl/src/com/intellij/psi/impl/source/text/BlockSupportImpl.java +++ b/platform/core-impl/src/com/intellij/psi/impl/source/text/BlockSupportImpl.java @@ -107,7 +107,7 @@ public class BlockSupportImpl extends BlockSupport { } final ASTNode leafAtStart = fileElement.findLeafElementAt(Math.max(0, changedPsiRange.getStartOffset() - 1)); - final ASTNode leafAtEnd = fileElement.findLeafElementAt(changedPsiRange.getEndOffset()); + final ASTNode leafAtEnd = fileElement.findLeafElementAt(Math.min(changedPsiRange.getEndOffset(), fileElement.getTextLength() - 1)); ASTNode node = leafAtStart != null && leafAtEnd != null ? TreeUtil.findCommonParent(leafAtStart, leafAtEnd) : fileElement; Language baseLanguage = file.getViewProvider().getBaseLanguage(); From d804506bf7489fad90e150da75f52dad7a5e9021 Mon Sep 17 00:00:00 2001 From: Konstantin Bulenkov Date: Thu, 6 Nov 2014 21:35:11 +0100 Subject: [PATCH 46/84] change invokeLater to invokeLaterIfNeeded --- .../src/com/intellij/ide/actions/SearchEverywhereAction.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java b/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java index c5a1db15c2e4..0e595a8d9027 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java @@ -443,7 +443,7 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA private ActionCallback onFocusLost() { final ActionCallback result = new ActionCallback(); //noinspection SSBasedInspection - SwingUtilities.invokeLater(new Runnable() { + UIUtil.invokeLaterIfNeeded(new Runnable() { @Override public void run() { try { From a2b8c73c928c70f1d4069138b9f7c6c9da17177e Mon Sep 17 00:00:00 2001 From: Konstantin Bulenkov Date: Thu, 6 Nov 2014 21:47:38 +0100 Subject: [PATCH 47/84] IDEA-127185 Switcher throws exception and stops working --- .../ide/actions/SwitcherToolWindowsListRenderer.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/ide/actions/SwitcherToolWindowsListRenderer.java b/platform/platform-impl/src/com/intellij/ide/actions/SwitcherToolWindowsListRenderer.java index 52aada754cba..7aed887c254b 100644 --- a/platform/platform-impl/src/com/intellij/ide/actions/SwitcherToolWindowsListRenderer.java +++ b/platform/platform-impl/src/com/intellij/ide/actions/SwitcherToolWindowsListRenderer.java @@ -53,11 +53,11 @@ class SwitcherToolWindowsListRenderer extends ColoredListCellRenderer { final String name; String stripeTitle = tw.getStripeTitle(); - if (myPinned) { + String shortcut = shortcuts.get(tw); + if (myPinned || shortcut == null) { name = stripeTitle; - } - else { - append(shortcuts.get(tw), new SimpleTextAttributes(SimpleTextAttributes.STYLE_UNDERLINE, null)); + } else { + append(shortcut, new SimpleTextAttributes(SimpleTextAttributes.STYLE_UNDERLINE, null)); name = ": " + stripeTitle; } From 8d4fd2ee02c9678a966171a39e0310063d412fa3 Mon Sep 17 00:00:00 2001 From: Konstantin Bulenkov Date: Thu, 6 Nov 2014 22:37:29 +0100 Subject: [PATCH 48/84] IDEA-132363 NPE invoking recent searches with Darcula --- .../intellij/ide/ui/laf/darcula/ui/DarculaTextFieldUI.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaTextFieldUI.java b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaTextFieldUI.java index 7cffd25ae46c..9b522b676377 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaTextFieldUI.java +++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaTextFieldUI.java @@ -97,7 +97,7 @@ public class DarculaTextFieldUI extends BasicTextFieldUI { } protected void showSearchPopup() { - final Object value = getComponent().getClientProperty("JTextField.Search.FindPopup"); + final Object value = myTextField.getClientProperty("JTextField.Search.FindPopup"); if (value instanceof JPopupMenu) { final JPopupMenu popup = (JPopupMenu)value; popup.show(getComponent(), getSearchIconCoord().x, getComponent().getHeight()); @@ -168,7 +168,7 @@ public class DarculaTextFieldUI extends BasicTextFieldUI { } } Point p = getSearchIconCoord(); - Icon searchIcon = getComponent().getClientProperty("JTextField.Search.FindPopup") instanceof JPopupMenu ? UIManager.getIcon("TextField.darcula.searchWithHistory.icon") : UIManager.getIcon("TextField.darcula.search.icon"); + Icon searchIcon = myTextField.getClientProperty("JTextField.Search.FindPopup") instanceof JPopupMenu ? UIManager.getIcon("TextField.darcula.searchWithHistory.icon") : UIManager.getIcon("TextField.darcula.search.icon"); if (searchIcon == null) { searchIcon = IconLoader.findIcon("/com/intellij/ide/ui/laf/icons/search.png", DarculaTextFieldUI.class, true); } From 396bb2b5d02c9965ee5d965b7f7dc62a87ffbd7e Mon Sep 17 00:00:00 2001 From: "Maxim.Mossienko" Date: Thu, 6 Nov 2014 23:40:14 +0100 Subject: [PATCH 49/84] proper synchronization in write --- .../history/core/changes/ChangeSet.java | 23 +++++++++++++++---- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/platform/lvcs-impl/src/com/intellij/history/core/changes/ChangeSet.java b/platform/lvcs-impl/src/com/intellij/history/core/changes/ChangeSet.java index b6da7fb9d6a6..c9a75530871b 100644 --- a/platform/lvcs-impl/src/com/intellij/history/core/changes/ChangeSet.java +++ b/platform/lvcs-impl/src/com/intellij/history/core/changes/ChangeSet.java @@ -19,6 +19,7 @@ package com.intellij.history.core.changes; import com.intellij.history.core.Content; import com.intellij.history.core.StreamUtil; import com.intellij.history.utils.LocalHistoryLog; +import com.intellij.openapi.util.Ref; import com.intellij.util.Producer; import com.intellij.util.SmartList; import com.intellij.util.containers.ContainerUtil; @@ -60,15 +61,27 @@ public class ChangeSet { isLocked = true; } - public void write(DataOutput out) throws IOException { + public void write(final DataOutput out) throws IOException { out.writeLong(myId); StreamUtil.writeStringOrNull(out, myName); out.writeLong(myTimestamp); - out.writeInt(myChanges.size()); - for (Change c : myChanges) { - StreamUtil.writeChange(out, c); - } + final Ref ref = new Ref(); + accessChanges(new Runnable() { + @Override + public void run() { + try { + out.writeInt(myChanges.size()); + for (Change c : myChanges) { + StreamUtil.writeChange(out, c); + } + } + catch (IOException e) { + ref.set(e); + } + } + }); + if (ref.get() != null) throw ref.get(); } public void setName(@Nullable String name) { From 4277ef15f740dc177098da34288990de7323f5d6 Mon Sep 17 00:00:00 2001 From: "Maxim.Mossienko" Date: Thu, 6 Nov 2014 23:43:12 +0100 Subject: [PATCH 50/84] separate stacks for undo / redo for light virtual files (potentially they can have no document) --- .../DocumentReferenceByLightVirtualFile.java | 49 +++++++++++++++ .../impl/DocumentReferenceByVirtualFile.java | 3 +- .../impl/DocumentReferenceManagerImpl.java | 12 +++- .../command/impl/UndoRedoStacksHolder.java | 61 +++++++++++++------ 4 files changed, 103 insertions(+), 22 deletions(-) create mode 100644 platform/platform-impl/src/com/intellij/openapi/command/impl/DocumentReferenceByLightVirtualFile.java diff --git a/platform/platform-impl/src/com/intellij/openapi/command/impl/DocumentReferenceByLightVirtualFile.java b/platform/platform-impl/src/com/intellij/openapi/command/impl/DocumentReferenceByLightVirtualFile.java new file mode 100644 index 000000000000..d1dde6a49acd --- /dev/null +++ b/platform/platform-impl/src/com/intellij/openapi/command/impl/DocumentReferenceByLightVirtualFile.java @@ -0,0 +1,49 @@ +/* + * 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.openapi.command.impl; + +import com.intellij.openapi.command.undo.DocumentReference; +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.fileEditor.FileDocumentManager; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.testFramework.LightVirtualFile; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +class DocumentReferenceByLightVirtualFile implements DocumentReference { + private LightVirtualFile myFile; + + DocumentReferenceByLightVirtualFile(@NotNull LightVirtualFile file) { + myFile = file; + } + + @Override + @Nullable + public Document getDocument() { + return FileDocumentManager.getInstance().getDocument(myFile); + } + + @Override + @NotNull + public VirtualFile getFile() { + return myFile; + } + + @Override + public String toString() { + return myFile.toString(); + } +} diff --git a/platform/platform-impl/src/com/intellij/openapi/command/impl/DocumentReferenceByVirtualFile.java b/platform/platform-impl/src/com/intellij/openapi/command/impl/DocumentReferenceByVirtualFile.java index db56ab7a8fdb..271bf8f84c12 100644 --- a/platform/platform-impl/src/com/intellij/openapi/command/impl/DocumentReferenceByVirtualFile.java +++ b/platform/platform-impl/src/com/intellij/openapi/command/impl/DocumentReferenceByVirtualFile.java @@ -19,7 +19,6 @@ import com.intellij.openapi.command.undo.DocumentReference; import com.intellij.openapi.editor.Document; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.testFramework.LightVirtualFile; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -33,7 +32,7 @@ public class DocumentReferenceByVirtualFile implements DocumentReference { @Override @Nullable public Document getDocument() { - assert myFile.isValid() || myFile instanceof LightVirtualFile : "should not be called on references to deleted file: " + myFile; + assert myFile.isValid() : "should not be called on references to deleted file: " + myFile; return FileDocumentManager.getInstance().getDocument(myFile); } diff --git a/platform/platform-impl/src/com/intellij/openapi/command/impl/DocumentReferenceManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/command/impl/DocumentReferenceManagerImpl.java index 5f226ed07608..020ed90d9ad8 100644 --- a/platform/platform-impl/src/com/intellij/openapi/command/impl/DocumentReferenceManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/command/impl/DocumentReferenceManagerImpl.java @@ -46,6 +46,7 @@ public class DocumentReferenceManagerImpl extends DocumentReferenceManager imple private final Map myDocToRef = new WeakKeyWeakValueHashMap(); private static final Key> FILE_TO_REF_KEY = Key.create("FILE_TO_REF_KEY"); + private static final Key FILE_TO_STRONG_REF_KEY = Key.create("FILE_TO_STRONG_REF_KEY"); private final Map myDeletedFilePathToRef = new WeakValueHashMap(); @Override @@ -132,7 +133,16 @@ public class DocumentReferenceManagerImpl extends DocumentReferenceManager imple @Override public DocumentReference create(@NotNull VirtualFile file) { assertInDispatchThread(); - assert file.isValid() || file instanceof LightVirtualFile : "file is invalid: " + file; + + if (file instanceof LightVirtualFile) { + DocumentReference reference = file.getUserData(FILE_TO_STRONG_REF_KEY); + if (reference == null) { + file.putUserData(FILE_TO_STRONG_REF_KEY, reference = new DocumentReferenceByLightVirtualFile((LightVirtualFile)file)); + } + return reference; + } + + assert file.isValid() : "file is invalid: " + file; DocumentReference result = SoftReference.dereference(file.getUserData(FILE_TO_REF_KEY)); if (result == null) { diff --git a/platform/platform-impl/src/com/intellij/openapi/command/impl/UndoRedoStacksHolder.java b/platform/platform-impl/src/com/intellij/openapi/command/impl/UndoRedoStacksHolder.java index 529fddd24a5d..742e3cb9cb23 100644 --- a/platform/platform-impl/src/com/intellij/openapi/command/impl/UndoRedoStacksHolder.java +++ b/platform/platform-impl/src/com/intellij/openapi/command/impl/UndoRedoStacksHolder.java @@ -19,6 +19,7 @@ import com.intellij.openapi.command.undo.DocumentReference; import com.intellij.openapi.command.undo.DocumentReferenceManager; import com.intellij.openapi.editor.Document; import com.intellij.openapi.util.Key; +import com.intellij.openapi.util.UserDataHolder; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.testFramework.LightVirtualFile; import com.intellij.util.containers.HashMap; @@ -35,7 +36,8 @@ class UndoRedoStacksHolder { private final LinkedList myGlobalStack = new LinkedList(); private final Map> myDocumentStacks = new HashMap>(); - private final List myDocumentsWithStacks = new WeakList(); + private final WeakList myDocumentsWithStacks = new WeakList(); + private final WeakList myLightVirtualFilesWithStacks = new WeakList(); public UndoRedoStacksHolder(boolean isUndo) { myUndo = isUndo; @@ -43,17 +45,25 @@ class UndoRedoStacksHolder { @NotNull LinkedList getStack(@NotNull DocumentReference r) { - VirtualFile file = r.getFile(); - return file != null && !(file instanceof LightVirtualFile) ? doGetStackForFile(r) : doGetStackForDocument(r); + return r.getFile() != null ? doGetStackForFile(r) : doGetStackForDocument(r); } @NotNull private LinkedList doGetStackForFile(@NotNull DocumentReference r) { - LinkedList result = myDocumentStacks.get(r); - if (result == null) { - result = new LinkedList(); - myDocumentStacks.put(r, result); + LinkedList result; + VirtualFile file = r.getFile(); + + if (file instanceof LightVirtualFile) { + result = addWeaklyTrackedEmptyStack((LightVirtualFile)file, myLightVirtualFilesWithStacks); } + else { + result = myDocumentStacks.get(r); + if (result == null) { + result = new LinkedList(); + myDocumentStacks.put(r, result); + } + } + return result; } @@ -63,12 +73,15 @@ class UndoRedoStacksHolder { // itself to avoid memory leaks caused by holding stacks of all documents, ever created, here. // And to know, what documents do exist now, we have to maintain weak reference list of them. - Document d = r.getDocument(); - LinkedList result = d.getUserData(STACK_IN_DOCUMENT_KEY); + return addWeaklyTrackedEmptyStack(r.getDocument(), myDocumentsWithStacks); + } + + private LinkedList addWeaklyTrackedEmptyStack(T holder, WeakList allHolders) { + LinkedList result; + result = holder.getUserData(STACK_IN_DOCUMENT_KEY); if (result == null) { - result = new LinkedList(); - d.putUserData(STACK_IN_DOCUMENT_KEY, result); - myDocumentsWithStacks.add(d); + holder.putUserData(STACK_IN_DOCUMENT_KEY, result = new LinkedList()); + allHolders.add(holder); } return result; } @@ -164,15 +177,20 @@ class UndoRedoStacksHolder { } - Set docsToDrop = new THashSet(); - for (Document each : myDocumentsWithStacks) { - LinkedList stack = each.getUserData(STACK_IN_DOCUMENT_KEY); + cleanWeaklyTrackedEmptyStacks(myDocumentsWithStacks); + cleanWeaklyTrackedEmptyStacks(myLightVirtualFilesWithStacks); + } + + private void cleanWeaklyTrackedEmptyStacks(WeakList stackHolders) { + Set holdersToDrop = new THashSet(); + for (T holder : stackHolders) { + LinkedList stack = holder.getUserData(STACK_IN_DOCUMENT_KEY); if (stack != null && stack.isEmpty()) { - each.putUserData(STACK_IN_DOCUMENT_KEY, null); - docsToDrop.add(each); + holder.putUserData(STACK_IN_DOCUMENT_KEY, null); + holdersToDrop.add(holder); } } - myDocumentsWithStacks.removeAll(docsToDrop); + stackHolders.removeAll(holdersToDrop); } private void clearStacksFrom(@NotNull UndoableGroup from) { @@ -217,8 +235,13 @@ class UndoRedoStacksHolder { private void collectLocalAffectedDocuments(@NotNull Collection result) { result.addAll(myDocumentStacks.keySet()); + DocumentReferenceManager documentReferenceManager = DocumentReferenceManager.getInstance(); + for (Document each : myDocumentsWithStacks) { - result.add(DocumentReferenceManager.getInstance().create(each)); + result.add(documentReferenceManager.create(each)); + } + for (LightVirtualFile each : myLightVirtualFilesWithStacks) { + result.add(documentReferenceManager.create(each)); } } From 5c003f8a24de6893c4820f8a73ce788bc243c17e Mon Sep 17 00:00:00 2001 From: Sergey Ignatov Date: Fri, 7 Nov 2014 02:03:51 +0300 Subject: [PATCH 51/84] tweak transparent progress indicator position in case of tabbed editors --- .../intellij/openapi/wm/impl/status/InfoAndProgressPanel.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/status/InfoAndProgressPanel.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/status/InfoAndProgressPanel.java index 0aa196baedef..383b74acb4f2 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/status/InfoAndProgressPanel.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/status/InfoAndProgressPanel.java @@ -40,6 +40,7 @@ import com.intellij.openapi.wm.StatusBar; import com.intellij.openapi.wm.StatusBarWidget; import com.intellij.openapi.wm.ex.ProgressIndicatorEx; import com.intellij.ui.Gray; +import com.intellij.ui.TabbedPaneWrapper; import com.intellij.ui.awt.RelativePoint; import com.intellij.ui.components.labels.LinkLabel; import com.intellij.ui.components.labels.LinkListener; @@ -414,6 +415,8 @@ public class InfoAndProgressPanel extends JPanel implements CustomStatusBarWidge @NotNull private static Component getAnchor(@NotNull JRootPane pane) { + Component tabWrapper = UIUtil.findComponentOfType(pane, TabbedPaneWrapper.TabWrapper.class); + if (tabWrapper != null) return tabWrapper; Component splitters = UIUtil.findComponentOfType(pane, EditorsSplitters.class); if (splitters != null) return splitters; FileEditorManagerEx ex = FileEditorManagerEx.getInstanceEx(ProjectUtil.guessCurrentProject(pane)); From 4442fec5a6d6c82009049f0c4851a1bbcb3aa52d Mon Sep 17 00:00:00 2001 From: Konstantin Bulenkov Date: Fri, 7 Nov 2014 00:49:45 +0100 Subject: [PATCH 52/84] Progress indicator may call invokeLater too often when in Presentation Mode --- .../status/PresentationModeProgressPanel.java | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/status/PresentationModeProgressPanel.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/status/PresentationModeProgressPanel.java index f62910ffd556..d5cf0885b77d 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/status/PresentationModeProgressPanel.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/status/PresentationModeProgressPanel.java @@ -23,6 +23,8 @@ import com.intellij.ui.InplaceButton; import com.intellij.ui.TransparentPanel; import com.intellij.util.ui.EmptyIcon; import com.intellij.util.ui.UIUtil; +import com.intellij.util.ui.update.MergingUpdateQueue; +import com.intellij.util.ui.update.Update; import org.jetbrains.annotations.NotNull; import javax.swing.*; @@ -40,6 +42,8 @@ public class PresentationModeProgressPanel { private InplaceButton myCancelButton; private JLabel myText2; private JPanel myRootPanel; + private MergingUpdateQueue myUpdateQueue; + private Update myUpdate; public PresentationModeProgressPanel(InlineProgressIndicator progress) { myProgress = progress; @@ -48,15 +52,17 @@ public class PresentationModeProgressPanel { myText2.setFont(font); myText.setIcon(EmptyIcon.create(1, 16)); myText2.setIcon(EmptyIcon.create(1, 16)); - } - - public void update() { - UIUtil.invokeLaterIfNeeded(new Runnable() { + myUpdateQueue = new MergingUpdateQueue("Presentation Mode Progress", 100, true, null); + myUpdate = new Update("Update UI") { @Override public void run() { updateImpl(); } - }); + }; + } + + public void update() { + myUpdateQueue.queue(myUpdate); } @NotNull From 234488760bd7600c7096a67bb29c4d963d32d000 Mon Sep 17 00:00:00 2001 From: "Gregory.Shrago" Date: Thu, 6 Nov 2014 17:25:46 +0300 Subject: [PATCH 53/84] introduce installSimpleHintUpdateSupply() API --- .../intellij/ui/popup/HintUpdateSupply.java | 38 ++++++++++++++++--- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/platform/platform-api/src/com/intellij/ui/popup/HintUpdateSupply.java b/platform/platform-api/src/com/intellij/ui/popup/HintUpdateSupply.java index 54b071ab0b94..9f64f809af96 100644 --- a/platform/platform-api/src/com/intellij/ui/popup/HintUpdateSupply.java +++ b/platform/platform-api/src/com/intellij/ui/popup/HintUpdateSupply.java @@ -15,6 +15,8 @@ */ package com.intellij.ui.popup; +import com.intellij.ide.DataManager; +import com.intellij.openapi.actionSystem.CommonDataKeys; import com.intellij.openapi.ui.popup.JBPopup; import com.intellij.openapi.util.Key; import com.intellij.psi.PsiElement; @@ -55,12 +57,40 @@ public abstract class HintUpdateSupply { if (supply != null) supply.hideHint(); } + public static void installSimpleHintUpdateSupply(@NotNull final JComponent component) { + HintUpdateSupply supply = new HintUpdateSupply(component) { + @Nullable + @Override + protected PsiElement getPsiElementForHint(@Nullable Object selectedValue) { + return selectedValue instanceof PsiElement ? (PsiElement)selectedValue : + CommonDataKeys.PSI_ELEMENT.getData(DataManager.getInstance().getDataContext(component)); + } + }; + if (component instanceof JList) supply.installListListener((JList)component); + if (component instanceof JTree) supply.installTreeListener((JTree)component); + if (component instanceof JTable) supply.installTableListener((JTable)component); + } + protected HintUpdateSupply(@NotNull JComponent component) { installSupply(component); } - public HintUpdateSupply(@NotNull final JBTable table) { + public HintUpdateSupply(@NotNull JBTable table) { installSupply(table); + installTableListener(table); + } + + public HintUpdateSupply(@NotNull Tree tree) { + installSupply(tree); + installTreeListener(tree); + } + + public HintUpdateSupply(@NotNull JBList list) { + installSupply(list); + installListListener(list); + } + + protected void installTableListener(@NotNull final JTable table) { ListSelectionListener listener = new ListSelectionListener() { @Override public void valueChanged(final ListSelectionEvent e) { @@ -80,8 +110,7 @@ public abstract class HintUpdateSupply { table.getColumnModel().getSelectionModel().addListSelectionListener(listener); } - public HintUpdateSupply(@NotNull final Tree tree) { - installSupply(tree); + protected void installTreeListener(@NotNull final JTree tree) { tree.addTreeSelectionListener(new TreeSelectionListener() { @Override public void valueChanged(final TreeSelectionEvent e) { @@ -98,8 +127,7 @@ public abstract class HintUpdateSupply { }); } - public HintUpdateSupply(@NotNull final JBList list) { - installSupply(list); + protected void installListListener(@NotNull final JList list) { list.addListSelectionListener(new ListSelectionListener() { @Override public void valueChanged(final ListSelectionEvent e) { From 0989d07237604fd3f36f2291b05338f5ef71e752 Mon Sep 17 00:00:00 2001 From: "Gregory.Shrago" Date: Thu, 6 Nov 2014 18:53:20 +0300 Subject: [PATCH 54/84] UI: one simple way to control toolwindow toolbars visibility 5 --- .../hierarchy/HierarchyBrowserManager.java | 4 +- .../ide/impl/StructureViewWrapperImpl.java | 13 +- .../StructureViewComponent.java | 22 +-- .../usageView/impl/UsageViewManagerImpl.java | 4 +- .../openapi/ui/SimpleToolWindowPanel.java | 72 +-------- .../ide/actions/ToggleToolbarAction.java | 144 ++++++++++++++++++ .../changes/ui/ChangesViewContentManager.java | 4 +- .../vcs/impl/ProjectLevelVcsManagerImpl.java | 4 +- 8 files changed, 165 insertions(+), 102 deletions(-) create mode 100644 platform/platform-impl/src/com/intellij/ide/actions/ToggleToolbarAction.java diff --git a/platform/lang-impl/src/com/intellij/ide/hierarchy/HierarchyBrowserManager.java b/platform/lang-impl/src/com/intellij/ide/hierarchy/HierarchyBrowserManager.java index 595907aa5720..905e8a96ceb9 100644 --- a/platform/lang-impl/src/com/intellij/ide/hierarchy/HierarchyBrowserManager.java +++ b/platform/lang-impl/src/com/intellij/ide/hierarchy/HierarchyBrowserManager.java @@ -17,11 +17,11 @@ package com.intellij.ide.hierarchy; import com.intellij.icons.AllIcons; +import com.intellij.ide.actions.ToggleToolbarAction; import com.intellij.ide.impl.ContentManagerWatcher; import com.intellij.openapi.actionSystem.DefaultActionGroup; import com.intellij.openapi.components.*; import com.intellij.openapi.project.Project; -import com.intellij.openapi.ui.SimpleToolWindowPanel; import com.intellij.openapi.wm.ToolWindow; import com.intellij.openapi.wm.ToolWindowAnchor; import com.intellij.openapi.wm.ToolWindowId; @@ -52,7 +52,7 @@ public final class HierarchyBrowserManager implements PersistentStateComponent iterateToolbars(JComponent root) { + return JBSwingUtilities.uiTraverser().preOrderTraversal(root).filter(ActionToolbar.class); + } + + private static class ToolbarTogglesGroup extends ActionGroup { + + private final ToolWindow myToolWindow; + + public ToolbarTogglesGroup(ToolWindow toolWindow) { + super("View Options", true); + myToolWindow = toolWindow; + } + + @Override + public boolean isPopup() { + return getChildren(null).length > 3; + } + + @Override + public void update(AnActionEvent e) { + e.getPresentation().setVisible(!ActionGroupUtil.isGroupEmpty(this, e)); + } + + @NotNull + @Override + public AnAction[] getChildren(@Nullable AnActionEvent e) { + ContentManager contentManager = myToolWindow.getContentManager(); + Content selectedContent = contentManager.getSelectedContent(); + JComponent contentComponent = selectedContent != null ? selectedContent.getComponent() : null; + if (contentComponent == null) return EMPTY_ARRAY; + List result = ContainerUtil.newSmartList(); + for (final ActionToolbar toolbar : iterateToolbars(contentComponent)) { + JComponent c = toolbar.getComponent(); + if (c.isVisible() || !c.isValid()) continue; + List actions = toolbar.getActions(false); + for (AnAction action : actions) { + if (!(action instanceof ToggleAction || action instanceof Separator)) continue; + result.add(action); + } + } + return result.toArray(new AnAction[result.size()]); + } + } +} diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesViewContentManager.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesViewContentManager.java index 7801b7f80b45..2fc08b1d2f8a 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesViewContentManager.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesViewContentManager.java @@ -17,6 +17,7 @@ package com.intellij.openapi.vcs.changes.ui; import com.intellij.icons.AllIcons; +import com.intellij.ide.actions.ToggleToolbarAction; import com.intellij.lifecycle.PeriodicalTasksCloser; import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.DefaultActionGroup; @@ -27,7 +28,6 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.DumbAwareRunnable; import com.intellij.openapi.project.Project; import com.intellij.openapi.startup.StartupManager; -import com.intellij.openapi.ui.SimpleToolWindowPanel; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.Key; @@ -87,7 +87,7 @@ public class ChangesViewContentManager extends AbstractProjectComponent implemen myToolWindow = toolWindowManager.registerToolWindow(TOOLWINDOW_ID, true, ToolWindowAnchor.BOTTOM, myProject, true); myToolWindow.setIcon(AllIcons.Toolwindows.ToolWindowChanges); DefaultActionGroup gearActions = new DefaultActionGroup(); - gearActions.addAction(SimpleToolWindowPanel.createToggleToolbarAction(myProject, myToolWindow)).setAsSecondary(true); + gearActions.addAction(ToggleToolbarAction.createToggleToolbarGroup(myProject, myToolWindow)).setAsSecondary(true); ((ToolWindowEx)myToolWindow).setAdditionalGearActions(gearActions); updateToolWindowAvailability(); diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/ProjectLevelVcsManagerImpl.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/ProjectLevelVcsManagerImpl.java index 6886dd5098d8..1e0ab57f5c52 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/ProjectLevelVcsManagerImpl.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/ProjectLevelVcsManagerImpl.java @@ -16,6 +16,7 @@ package com.intellij.openapi.vcs.impl; import com.intellij.icons.AllIcons; +import com.intellij.ide.actions.ToggleToolbarAction; import com.intellij.openapi.actionSystem.DefaultActionGroup; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ModalityState; @@ -34,7 +35,6 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ex.ProjectEx; import com.intellij.openapi.roots.FileIndexFacade; import com.intellij.openapi.startup.StartupManager; -import com.intellij.openapi.ui.SimpleToolWindowPanel; import com.intellij.openapi.util.*; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.registry.Registry; @@ -242,7 +242,7 @@ public class ProjectLevelVcsManagerImpl extends ProjectLevelVcsManagerEx impleme myContentManager = toolWindow.getContentManager(); toolWindow.setIcon(AllIcons.Toolwindows.VcsSmallTab); DefaultActionGroup gearActions = new DefaultActionGroup(); - gearActions.addAction(SimpleToolWindowPanel.createToggleToolbarAction(myProject, toolWindow)).setAsSecondary(true); + gearActions.addAction(ToggleToolbarAction.createToggleToolbarGroup(myProject, toolWindow)).setAsSecondary(true); ((ToolWindowEx)toolWindow).setAdditionalGearActions(gearActions); toolWindow.installWatcher(myContentManager); } From b47f906df0707b505c58ff0c261cf9b2ae323450 Mon Sep 17 00:00:00 2001 From: "Gregory.Shrago" Date: Thu, 6 Nov 2014 19:41:47 +0300 Subject: [PATCH 55/84] UI: introduce ActionPlaces.TOOLWINDOW_TITLE --- .../src/com/intellij/openapi/actionSystem/ActionPlaces.java | 1 + .../src/com/intellij/openapi/wm/impl/ToolWindowHeader.java | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/platform/platform-api/src/com/intellij/openapi/actionSystem/ActionPlaces.java b/platform/platform-api/src/com/intellij/openapi/actionSystem/ActionPlaces.java index aa1248775a21..7c0006c9a3e7 100644 --- a/platform/platform-api/src/com/intellij/openapi/actionSystem/ActionPlaces.java +++ b/platform/platform-api/src/com/intellij/openapi/actionSystem/ActionPlaces.java @@ -38,6 +38,7 @@ public abstract class ActionPlaces { public static final String COMMANDER_POPUP = "CommanderPopup"; public static final String COMMANDER_TOOLBAR = "CommanderToolbar"; public static final String CONTEXT_TOOLBAR = "ContextToolbar"; + public static final String TOOLWINDOW_TITLE = "ToolwindowTitle"; public static final String PROJECT_VIEW_POPUP = "ProjectViewPopup"; public static final String PROJECT_VIEW_TOOLBAR = "ProjectViewToolbar"; diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowHeader.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowHeader.java index e84028ead618..6587a398e26a 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowHeader.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowHeader.java @@ -484,7 +484,7 @@ public abstract class ToolWindowHeader extends JPanel implements Disposable, UIS final ActionManagerEx actionManager = ActionManagerEx.getInstanceEx(); InputEvent inputEvent = e.getSource() instanceof InputEvent ? (InputEvent) e.getSource() : null; final AnActionEvent event = - new AnActionEvent(inputEvent, dataContext, ActionPlaces.UNKNOWN, action.getTemplatePresentation(), + new AnActionEvent(inputEvent, dataContext, ActionPlaces.TOOLWINDOW_TITLE, action.getTemplatePresentation(), ActionManager.getInstance(), 0); actionManager.fireBeforeActionPerformed(action, dataContext, event); From 37793568c65f8f028d66d769344c8b7beaa2c3d7 Mon Sep 17 00:00:00 2001 From: "Gregory.Shrago" Date: Fri, 7 Nov 2014 01:09:14 +0300 Subject: [PATCH 56/84] ActionToolbar: extract ToolbarUpdater & run update on title actions --- .../actionSystem/impl/ActionToolbarImpl.java | 223 ++++++------------ .../actionSystem/impl/ToolbarUpdater.java | 174 ++++++++++++++ .../openapi/wm/impl/InternalDecorator.java | 41 +--- .../openapi/wm/impl/ToolWindowHeader.java | 100 +++++--- 4 files changed, 318 insertions(+), 220 deletions(-) create mode 100644 platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ToolbarUpdater.java diff --git a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionToolbarImpl.java b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionToolbarImpl.java index 529d5ba1c62f..e65c6dd0cfe5 100644 --- a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionToolbarImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionToolbarImpl.java @@ -24,31 +24,26 @@ import com.intellij.openapi.actionSystem.ex.ActionButtonLook; import com.intellij.openapi.actionSystem.ex.ActionManagerEx; import com.intellij.openapi.actionSystem.ex.AnActionListener; import com.intellij.openapi.actionSystem.ex.CustomComponentAction; -import com.intellij.openapi.application.Application; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.keymap.Keymap; -import com.intellij.openapi.keymap.KeymapManagerListener; import com.intellij.openapi.keymap.ex.KeymapManagerEx; import com.intellij.openapi.project.DumbAwareRunnable; import com.intellij.openapi.ui.popup.*; import com.intellij.openapi.util.ActionCallback; import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.Disposer; -import com.intellij.openapi.util.IdRunnable; import com.intellij.openapi.wm.IdeFocusManager; import com.intellij.openapi.wm.WindowManager; import com.intellij.openapi.wm.ex.WindowManagerEx; import com.intellij.ui.ColorUtil; import com.intellij.ui.Gray; import com.intellij.ui.JBColor; -import com.intellij.ui.ScreenUtil; import com.intellij.ui.awt.RelativePoint; import com.intellij.ui.awt.RelativeRectangle; import com.intellij.ui.switcher.SwitchTarget; +import com.intellij.util.containers.ContainerUtil; import com.intellij.util.ui.UIUtil; -import com.intellij.util.ui.update.UiNotifyConnector; import org.jetbrains.annotations.NotNull; import javax.swing.*; @@ -96,11 +91,12 @@ public class ActionToolbarImpl extends JPanel implements ActionToolbar { private int myOrientation; private final ActionGroup myActionGroup; private final String myPlace; - private final MyKeymapManagerListener myKeymapManagerListener; - private List myNewVisibleActions; protected List myVisibleActions; - private final PresentationFactory myPresentationFactory; + private final PresentationFactory myPresentationFactory = new PresentationFactory(); private final boolean myDecorateButtons; + + private final ToolbarUpdater myUpdater; + /** * @see ActionToolbar#adjustTheSameSize(boolean) */ @@ -109,7 +105,7 @@ public class ActionToolbarImpl extends JPanel implements ActionToolbar { private final ActionButtonLook myButtonLook = null; private final ActionButtonLook myMinimalButtonLook = new InplaceActionButtonLook(); private final DataManager myDataManager; - @NotNull protected final ActionManagerEx myActionManager; + protected final ActionManagerEx myActionManager; private Rectangle myAutoPopupRec; @@ -122,7 +118,6 @@ public class ActionToolbarImpl extends JPanel implements ActionToolbar { } private ActionButton mySecondaryActionsButton; - private final KeymapManagerEx myKeymapManager; private int myFirstOutsideIndex = -1; private JBPopup myPopup; @@ -131,45 +126,46 @@ public class ActionToolbarImpl extends JPanel implements ActionToolbar { private boolean myReservePlaceAutoPopupIcon = true; private boolean myAddSeparatorFirst; - private final WeakTimerListener myWeakTimerListener; - @SuppressWarnings({"FieldCanBeLocal"}) private final ActionToolbarImpl.MyTimerListener myTimerListener; - public ActionToolbarImpl(final String place, + public ActionToolbarImpl(String place, @NotNull final ActionGroup actionGroup, - final boolean horizontal, - DataManager dataManager, + boolean horizontal, + @NotNull DataManager dataManager, @NotNull ActionManagerEx actionManager, - KeymapManagerEx keymapManager) { + @NotNull KeymapManagerEx keymapManager) { this(place, actionGroup, horizontal, false, dataManager, actionManager, keymapManager, false); } - public ActionToolbarImpl(final String place, - @NotNull final ActionGroup actionGroup, - final boolean horizontal, - final boolean decorateButtons, - DataManager dataManager, + + public ActionToolbarImpl(String place, + @NotNull ActionGroup actionGroup, + boolean horizontal, + boolean decorateButtons, + @NotNull DataManager dataManager, @NotNull ActionManagerEx actionManager, - KeymapManagerEx keymapManager) { + @NotNull KeymapManagerEx keymapManager) { this(place, actionGroup, horizontal, decorateButtons, dataManager, actionManager, keymapManager, false); } - public ActionToolbarImpl(final String place, - @NotNull final ActionGroup actionGroup, + public ActionToolbarImpl(String place, + @NotNull ActionGroup actionGroup, final boolean horizontal, final boolean decorateButtons, - DataManager dataManager, + @NotNull DataManager dataManager, @NotNull ActionManagerEx actionManager, - KeymapManagerEx keymapManager, + @NotNull KeymapManagerEx keymapManager, boolean updateActionsNow) { super(null); myActionManager = actionManager; - myKeymapManager = keymapManager; myPlace = place; myActionGroup = actionGroup; - myPresentationFactory = new PresentationFactory(); - myKeymapManagerListener = new MyKeymapManagerListener(); myVisibleActions = new ArrayList(); - myNewVisibleActions = new ArrayList(); myDataManager = dataManager; myDecorateButtons = decorateButtons; + myUpdater = new ToolbarUpdater(actionManager, keymapManager, this) { + @Override + protected void updateActionsImpl(boolean transparentOnly, boolean forced) { + ActionToolbarImpl.this.updateActionsImpl(transparentOnly, forced); + } + }; setLayout(new BorderLayout()); setOrientation(horizontal ? SwingConstants.HORIZONTAL : SwingConstants.VERTICAL); @@ -177,12 +173,8 @@ public class ActionToolbarImpl extends JPanel implements ActionToolbar { mySecondaryActions.getTemplatePresentation().setIcon(AllIcons.General.SecondaryGroup); mySecondaryActions.setPopup(true); - updateActions(updateActionsNow, false, false); + myUpdater.updateActions(updateActionsNow, false); - // - keymapManager.addWeakListener(myKeymapManagerListener); - myTimerListener = new MyTimerListener(); - myWeakTimerListener = new WeakTimerListener(actionManager, myTimerListener); // If the panel doesn't handle mouse event then it will be passed to its parent. // It means that if the panel is in sliding mode then the focus goes to the editor // and panel will be automatically hidden. @@ -202,9 +194,7 @@ public class ActionToolbarImpl extends JPanel implements ActionToolbar { public void addNotify() { super.addNotify(); ourToolbars.add(this); - myActionManager.addTimerListener(500, myWeakTimerListener); - myActionManager.addTransparentTimerListener(500, myWeakTimerListener); - + // should update action right on the showing, otherwise toolbar may not be displayed at all, // since by default all updates are postponed until frame gets focused. updateActionsImmediately(); @@ -226,10 +216,6 @@ public class ActionToolbarImpl extends JPanel implements ActionToolbar { public void removeNotify() { super.removeNotify(); ourToolbars.remove(this); - myActionManager.removeTimerListener(myWeakTimerListener); - myActionManager.removeTransparentTimerListener(myWeakTimerListener); - if (ScreenUtil.isStandardAddRemoveNotify(this)) - myKeymapManager.removeWeakListener(myKeymapManagerListener); } @Override @@ -373,7 +359,11 @@ public class ActionToolbarImpl extends JPanel implements ActionToolbar { } private ActionButton createToolbarButton(final AnAction action) { - return createToolbarButton(action, myMinimalMode ? myMinimalButtonLook : myDecorateButtons ? new MacToolbarDecoratorButtonLook() : myButtonLook, myPlace, myPresentationFactory.getPresentation(action), myMinimumButtonSize); + return createToolbarButton( + action, + myMinimalMode ? myMinimalButtonLook : myDecorateButtons ? new MacToolbarDecoratorButtonLook() : myButtonLook, + myPlace, myPresentationFactory.getPresentation(action), + myMinimumButtonSize); } @Override @@ -847,53 +837,6 @@ public class ActionToolbarImpl extends JPanel implements ActionToolbar { } } - private final class MyKeymapManagerListener implements KeymapManagerListener { - @Override - public void activeKeymapChanged(final Keymap keymap) { - final int componentCount = getComponentCount(); - for (int i = 0; i < componentCount; i++) { - final Component component = getComponent(i); - if (component instanceof ActionButton) { - ((ActionButton)component).updateToolTipText(); - } - } - } - } - - private final class MyTimerListener implements TimerListener { - - @Override - public ModalityState getModalityState() { - return ModalityState.stateForComponent(ActionToolbarImpl.this); - } - - @Override - public void run() { - if (!isShowing()) { - return; - } - - // do not update when a popup menu is shown (if popup menu contains action which is also in the toolbar, it should not be enabled/disabled) - final MenuSelectionManager menuSelectionManager = MenuSelectionManager.defaultManager(); - final MenuElement[] selectedPath = menuSelectionManager.getSelectedPath(); - if (selectedPath.length > 0) { - return; - } - - // don't update toolbar if there is currently active modal dialog - - final Window window = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusedWindow(); - if (window instanceof Dialog) { - final Dialog dialog = (Dialog)window; - if (dialog.isModal() && !SwingUtilities.isDescendingFrom(ActionToolbarImpl.this, dialog)) { - return; - } - } - - updateActions(false, myActionManager.isTransparentOnlyActionsUpdateNow(), false); - } - } - @Override public void adjustTheSameSize(final boolean value) { if (myAdjustTheSameSize == value) { @@ -927,79 +870,47 @@ public class ActionToolbarImpl extends JPanel implements ActionToolbar { @Override public void updateActionsImmediately() { ApplicationManager.getApplication().assertIsDispatchThread(); - updateActions(true, false, false); + myUpdater.updateActions(true, false); } - private void updateActions(boolean now, final boolean transparentOnly, final boolean forced) { - final IdRunnable updateRunnable = new IdRunnable(this) { - @Override - public void run() { - if (!isVisible()) { - return; - } + private void updateActionsImpl(boolean transparentOnly, boolean forced) { + List newVisibleActions = ContainerUtil.newArrayListWithCapacity(myVisibleActions.size()); + DataContext dataContext = getDataContext(); - myNewVisibleActions.clear(); - final DataContext dataContext = getDataContext(); + Utils.expandActionGroup(myActionGroup, newVisibleActions, myPresentationFactory, dataContext, + myPlace, myActionManager, transparentOnly); - Utils.expandActionGroup(myActionGroup, myNewVisibleActions, myPresentationFactory, dataContext, myPlace, myActionManager, transparentOnly); + if (forced || !newVisibleActions.equals(myVisibleActions)) { + boolean shouldRebuildUI = newVisibleActions.isEmpty() || myVisibleActions.isEmpty(); + myVisibleActions = newVisibleActions; - if (forced || !myNewVisibleActions.equals(myVisibleActions)) { - // should rebuild UI + Dimension oldSize = getPreferredSize(); - final boolean changeBarVisibility = myNewVisibleActions.isEmpty() || myVisibleActions.isEmpty(); + removeAll(); + mySecondaryActions.removeAll(); + mySecondaryActionsButton = null; + fillToolBar(myVisibleActions, getLayoutPolicy() == AUTO_LAYOUT_POLICY && myOrientation == SwingConstants.HORIZONTAL); - final List temp = myVisibleActions; - myVisibleActions = myNewVisibleActions; - myNewVisibleActions = temp; + Dimension newSize = getPreferredSize(); - Dimension oldSize = getPreferredSize(); + ((WindowManagerEx)WindowManager.getInstance()).adjustContainerWindow(this, oldSize, newSize); - removeAll(); - mySecondaryActions.removeAll(); - mySecondaryActionsButton = null; - fillToolBar(myVisibleActions, getLayoutPolicy() == AUTO_LAYOUT_POLICY && myOrientation == SwingConstants.HORIZONTAL); - - Dimension newSize = getPreferredSize(); - - if (changeBarVisibility) { - revalidate(); - } - else { - final Container parent = getParent(); - if (parent != null) { - parent.invalidate(); - parent.validate(); - } - } - - ((WindowManagerEx)WindowManager.getInstance()).adjustContainerWindow(ActionToolbarImpl.this, oldSize, newSize); - - repaint(); + if (shouldRebuildUI) { + revalidate(); + } + else { + Container parent = getParent(); + if (parent != null) { + parent.invalidate(); + parent.validate(); } } - }; - if (now) { - updateRunnable.run(); - } else { - final Application app = ApplicationManager.getApplication(); - final IdeFocusManager fm = IdeFocusManager.getInstance(null); - - if (!app.isUnitTestMode() && !app.isHeadlessEnvironment()) { - if (app.isDispatchThread()) { - fm.doWhenFocusSettlesDown(updateRunnable); - } else { - UiNotifyConnector.doWhenFirstShown(this, new Runnable() { - @Override - public void run() { - fm.doWhenFocusSettlesDown(updateRunnable); - } - }); - } - } + repaint(); } } + @Override public boolean hasVisibleActions() { return !myVisibleActions.isEmpty(); @@ -1013,7 +924,7 @@ public class ActionToolbarImpl extends JPanel implements ActionToolbar { ApplicationManager.getApplication().invokeLater(new DumbAwareRunnable() { @Override public void run() { - updateActions(false, false, false); + myUpdater.updateActions(false, false); } }, ModalityState.stateForComponent(myTargetComponent)); } @@ -1060,7 +971,7 @@ public class ActionToolbarImpl extends JPanel implements ActionToolbar { group = outside; } - PopupToolbar popupToolbar = new PopupToolbar(myPlace, group, true, myDataManager, myActionManager, myKeymapManager, this) { + PopupToolbar popupToolbar = new PopupToolbar(myPlace, group, true, myDataManager, myActionManager, myUpdater.getKeymapManager(), this) { @Override protected void onOtherActionPerformed() { hidePopup(); @@ -1094,7 +1005,7 @@ public class ActionToolbarImpl extends JPanel implements ActionToolbar { public Boolean compute() { final boolean toClose = myActionManager.isActionPopupStackEmpty(); if (toClose) { - updateActions(false, false, true); + myUpdater.updateActions(false, true); } return toClose; } @@ -1191,7 +1102,7 @@ public class ActionToolbarImpl extends JPanel implements ActionToolbar { Disposer.dispose(myPopup); myPopup = null; - updateActions(false, false, false); + myUpdater.updateActions(false, false); } abstract static class PopupToolbar extends ActionToolbarImpl implements AnActionListener, Disposable { @@ -1264,7 +1175,7 @@ public class ActionToolbarImpl extends JPanel implements ActionToolbar { return result; } - private class ActionTarget implements SwitchTarget { + private static class ActionTarget implements SwitchTarget { private final ActionButton myButton; private ActionTarget(ActionButton button) { @@ -1350,11 +1261,11 @@ public class ActionToolbarImpl extends JPanel implements ActionToolbar { setLayoutPolicy(AUTO_LAYOUT_POLICY); } - updateActions(false, false, true); + myUpdater.updateActions(false, true); } public void setAddSeparatorFirst(boolean addSeparatorFirst) { myAddSeparatorFirst = addSeparatorFirst; - updateActions(false, false, true); + myUpdater.updateActions(false, true); } } diff --git a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ToolbarUpdater.java b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ToolbarUpdater.java new file mode 100644 index 000000000000..2d219251d549 --- /dev/null +++ b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ToolbarUpdater.java @@ -0,0 +1,174 @@ +/* + * 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.openapi.actionSystem.impl; + +import com.intellij.openapi.actionSystem.TimerListener; +import com.intellij.openapi.actionSystem.ex.ActionManagerEx; +import com.intellij.openapi.application.Application; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ModalityState; +import com.intellij.openapi.keymap.Keymap; +import com.intellij.openapi.keymap.KeymapManagerListener; +import com.intellij.openapi.keymap.ex.KeymapManagerEx; +import com.intellij.openapi.util.IdRunnable; +import com.intellij.openapi.wm.IdeFocusManager; +import com.intellij.ui.ScreenUtil; +import com.intellij.util.ui.JBSwingUtilities; +import com.intellij.util.ui.update.Activatable; +import com.intellij.util.ui.update.UiNotifyConnector; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; +import java.awt.*; + +/** + * @author Konstantin Bulenkov + */ +public abstract class ToolbarUpdater implements Activatable { + private final KeymapManagerListener myKeymapManagerListener; + private final WeakTimerListener myWeakTimerListener; + /** @noinspection FieldCanBeLocal*/ + private final TimerListener myTimerListener; + private final ActionManagerEx myActionManager; + private final KeymapManagerEx myKeymapManager; + private final JComponent myComponent; + + public ToolbarUpdater(@NotNull JComponent component) { + this(ActionManagerEx.getInstanceEx(), KeymapManagerEx.getInstanceEx(), component); + } + + public ToolbarUpdater(@NotNull ActionManagerEx actionManager, @NotNull KeymapManagerEx keymapManager, @NotNull JComponent component) { + new UiNotifyConnector(component, this); + myActionManager = actionManager; + myKeymapManager = keymapManager; + myComponent = component; + myKeymapManagerListener = new MyKeymapManagerListener(); + keymapManager.addWeakListener(myKeymapManagerListener); + myTimerListener = new MyTimerListener(); + myWeakTimerListener = new WeakTimerListener(actionManager, myTimerListener); + } + + @Override + public void showNotify() { + myActionManager.addTimerListener(500, myWeakTimerListener); + myActionManager.addTransparentTimerListener(500, myWeakTimerListener); + } + + @Override + public void hideNotify() { + //noinspection ConstantConditions + if (myActionManager == null) return; // not yet initialized + myActionManager.removeTimerListener(myWeakTimerListener); + myActionManager.removeTransparentTimerListener(myWeakTimerListener); + if (ScreenUtil.isStandardAddRemoveNotify(myComponent)) { + myKeymapManager.removeWeakListener(myKeymapManagerListener); + } + } + + @NotNull + public KeymapManagerEx getKeymapManager() { + return myKeymapManager; + } + + @NotNull + public ActionManagerEx getActionManager() { + return myActionManager; + } + + public void updateActions(boolean now, boolean forced) { + updateActions(now, false, forced); + } + + private void updateActions(boolean now, final boolean transparentOnly, final boolean forced) { + final IdRunnable updateRunnable = new IdRunnable(this) { + @Override + public void run() { + if (!myComponent.isVisible()) { + return; + } + + updateActionsImpl(transparentOnly, forced); + } + }; + + if (now) { + updateRunnable.run(); + } + else { + final Application app = ApplicationManager.getApplication(); + final IdeFocusManager fm = IdeFocusManager.getInstance(null); + + if (!app.isUnitTestMode() && !app.isHeadlessEnvironment()) { + if (app.isDispatchThread()) { + fm.doWhenFocusSettlesDown(updateRunnable); + } + else { + UiNotifyConnector.doWhenFirstShown(myComponent, new Runnable() { + @Override + public void run() { + fm.doWhenFocusSettlesDown(updateRunnable); + } + }); + } + } + } + } + + protected abstract void updateActionsImpl(boolean transparentOnly, boolean forced); + + protected void updateActionTooltips() { + for (ActionButton actionButton : JBSwingUtilities.uiTraverser().preOrderTraversal(myComponent).filter(ActionButton.class)) { + actionButton.updateToolTipText(); + } + } + + private final class MyKeymapManagerListener implements KeymapManagerListener { + @Override + public void activeKeymapChanged(Keymap keymap) { + updateActionTooltips(); + } + } + + private final class MyTimerListener implements TimerListener { + + @Override + public ModalityState getModalityState() { + return ModalityState.stateForComponent(myComponent); + } + + @Override + public void run() { + if (!myComponent.isShowing()) { + return; + } + + // do not update when a popup menu is shown (if popup menu contains action which is also in the toolbar, it should not be enabled/disabled) + MenuSelectionManager menuSelectionManager = MenuSelectionManager.defaultManager(); + MenuElement[] selectedPath = menuSelectionManager.getSelectedPath(); + if (selectedPath.length > 0) { + return; + } + + // don't update toolbar if there is currently active modal dialog + Window window = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusedWindow(); + if (window instanceof Dialog && ((Dialog)window).isModal() && !SwingUtilities.isDescendingFrom(myComponent, window)) { + return; + } + + updateActions(false, myActionManager.isTransparentOnlyActionsUpdateNow(), false); + } + } +} diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/InternalDecorator.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/InternalDecorator.java index dbee99dd8035..29f9b96aeb28 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/InternalDecorator.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/InternalDecorator.java @@ -19,9 +19,6 @@ import com.intellij.ide.actions.ResizeToolWindowAction; import com.intellij.idea.ActionsBundle; import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.*; -import com.intellij.openapi.keymap.Keymap; -import com.intellij.openapi.keymap.KeymapManagerListener; -import com.intellij.openapi.keymap.ex.KeymapManagerEx; import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.Queryable; @@ -54,7 +51,7 @@ import java.util.Map; * @author Eugene Belyaev * @author Vladimir Kondratyev */ -public final class InternalDecorator extends JPanel implements Queryable, TypeSafeDataProvider { +public final class InternalDecorator extends JPanel implements Queryable, DataProvider { private Project myProject; private WindowInfoImpl myInfo; @@ -74,7 +71,6 @@ public final class InternalDecorator extends JPanel implements Queryable, TypeSa /** * Catches all event from tool window and modifies decorator's appearance. */ - private final MyKeymapManagerListener myWeakKeymapManagerListener; @NonNls private static final String HIDE_ACTIVE_WINDOW_ACTION_ID = "HideActiveWindow"; @NonNls public static final String TOGGLE_PINNED_MODE_ACTION_ID = "TogglePinnedMode"; @NonNls public static final String TOGGLE_DOCK_MODE_ACTION_ID = "ToggleDockMode"; @@ -124,11 +120,6 @@ public final class InternalDecorator extends JPanel implements Queryable, TypeSa } }; - MyKeymapManagerListener keymapManagerListener = new MyKeymapManagerListener(); - final KeymapManagerEx keymapManager = KeymapManagerEx.getInstanceEx(); - myWeakKeymapManagerListener = keymapManagerListener; - keymapManager.addWeakListener(keymapManagerListener); - init(); apply(info); @@ -192,11 +183,13 @@ public final class InternalDecorator extends JPanel implements Queryable, TypeSa setBorder(new InnerPanelBorder(myToolWindow)); } + @Nullable @Override - public void calcData(DataKey key, DataSink sink) { - if (PlatformDataKeys.TOOL_WINDOW.equals(key)) { - sink.put(PlatformDataKeys.TOOL_WINDOW, myToolWindow); + public Object getData(@NonNls String dataId) { + if (PlatformDataKeys.TOOL_WINDOW.is(dataId)) { + return myToolWindow; } + return null; } final void addInternalDecoratorListener(InternalDecoratorListener l) { @@ -209,7 +202,6 @@ public final class InternalDecorator extends JPanel implements Queryable, TypeSa final void dispose() { removeAll(); - KeymapManagerEx.getInstanceEx().removeWeakListener(myWeakKeymapManagerListener); Disposer.dispose(myHeader); myHeader = null; @@ -502,7 +494,7 @@ public final class InternalDecorator extends JPanel implements Queryable, TypeSa } @Override - public final void actionPerformed(final AnActionEvent e) { + public final void actionPerformed(@NotNull final AnActionEvent e) { fireAnchorChanged(myAnchor); } } @@ -581,7 +573,7 @@ public final class InternalDecorator extends JPanel implements Queryable, TypeSa } @Override - public void update(final AnActionEvent e) { + public void update(@NotNull final AnActionEvent e) { super.update(e); } } @@ -595,12 +587,12 @@ public final class InternalDecorator extends JPanel implements Queryable, TypeSa } @Override - public final void actionPerformed(final AnActionEvent e) { + public final void actionPerformed(@NotNull final AnActionEvent e) { fireHidden(); } @Override - public final void update(final AnActionEvent event) { + public final void update(@NotNull final AnActionEvent event) { final Presentation presentation = event.getPresentation(); presentation.setEnabled(myInfo.isVisible()); } @@ -714,6 +706,7 @@ public final class InternalDecorator extends JPanel implements Queryable, TypeSa } } + @NotNull @Override public Cursor getCursor() { final boolean isVerticalCursor = myInfo.isDocked() ? myInfo.getAnchor().isSplitVertically() : myInfo.getAnchor().isHorizontal(); @@ -721,18 +714,6 @@ public final class InternalDecorator extends JPanel implements Queryable, TypeSa } } - /** - * Updates tooltips. - */ - private final class MyKeymapManagerListener implements KeymapManagerListener { - @Override - public final void activeKeymapChanged(final Keymap keymap) { - if (myHeader != null) { - myHeader.updateTooltips(); - } - } - } - @Override public void putInfo(@NotNull Map info) { info.put("toolWindowTitle", myToolWindow.getTitle()); diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowHeader.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowHeader.java index 6587a398e26a..101d3ab2762b 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowHeader.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowHeader.java @@ -22,8 +22,7 @@ import com.intellij.ide.ui.UISettingsListener; import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.actionSystem.ex.ActionManagerEx; -import com.intellij.openapi.actionSystem.impl.ActionManagerImpl; -import com.intellij.openapi.actionSystem.impl.MenuItemPresentationFactory; +import com.intellij.openapi.actionSystem.impl.*; import com.intellij.openapi.keymap.KeymapUtil; import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.util.SystemInfo; @@ -37,7 +36,9 @@ import com.intellij.ui.UIBundle; import com.intellij.ui.components.panels.Wrapper; import com.intellij.ui.tabs.TabsUtil; import com.intellij.util.Producer; +import com.intellij.util.containers.ContainerUtil; import com.intellij.util.ui.EmptyIcon; +import com.intellij.util.ui.JBSwingUtilities; import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -49,6 +50,7 @@ import java.awt.event.*; import java.awt.image.BufferedImage; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; +import java.util.List; /** * @author pegov @@ -66,6 +68,11 @@ public abstract class ToolWindowHeader extends JPanel implements Disposable, UIS private final JPanel myButtonPanel; private final ToolWindowHeader.ActionButton myGearButton; + private final PresentationFactory myPresentationFactory = new PresentationFactory(); + private final ToolbarUpdater myUpdater; + private final DefaultActionGroup myActionGroup = new DefaultActionGroup(); + private List myVisibleActions = ContainerUtil.newArrayListWithCapacity(2); + public ToolWindowHeader(final ToolWindowImpl toolWindow, @NotNull WindowInfoImpl info, @NotNull final Producer gearProducer) { setLayout(new BorderLayout()); @@ -103,7 +110,7 @@ public abstract class ToolWindowHeader extends JPanel implements Disposable, UIS myGearButton = new ActionButton(new AnAction() { @Override - public void actionPerformed(AnActionEvent e) { + public void actionPerformed(@NotNull AnActionEvent e) { final InputEvent inputEvent = e.getInputEvent(); final ActionPopupMenu popupMenu = ((ActionManagerImpl)ActionManager.getInstance()) @@ -127,17 +134,15 @@ public abstract class ToolWindowHeader extends JPanel implements Disposable, UIS myHideButton = new ActionButton(new HideAction() { @Override - public void actionPerformed(AnActionEvent e) { + public void actionPerformed(@NotNull AnActionEvent e) { hideToolWindow(); } }, new HideSideAction() { @Override - public void actionPerformed(AnActionEvent e) { + public void actionPerformed(@NotNull AnActionEvent e) { sideHidden(); } - }, - AllIcons.General.HideLeft, null, null - ) { + }, AllIcons.General.HideLeft, null, null) { @Override protected Icon getActiveIcon() { return getHideToolWindowIcon(myToolWindow); @@ -190,6 +195,19 @@ public abstract class ToolWindowHeader extends JPanel implements Disposable, UIS setBorder(BorderFactory.createEmptyBorder(TabsUtil.TABS_BORDER, 1, TabsUtil.TABS_BORDER, 1)); UISettings.getInstance().addUISettingsListener(this, toolWindow.getContentUI()); + myUpdater = new ToolbarUpdater(this) { + @Override + protected void updateActionsImpl(boolean transparentOnly, boolean forced) { + ToolWindowHeader.this.updateActionsImpl(transparentOnly, forced); + } + + @Override + protected void updateActionTooltips() { + for (ActionButton actionButton : JBSwingUtilities.uiTraverser().preOrderTraversal(myButtonPanel).filter(ActionButton.class)) { + actionButton.updateTooltip(); + } + } + }; } @Override @@ -211,32 +229,46 @@ public abstract class ToolWindowHeader extends JPanel implements Disposable, UIS myInfo = null; } - public void updateTooltips() { - if (myHideButton != null) { - myHideButton.updateTooltip(); - } + public void setAdditionalTitleActions(AnAction[] actions) { + myActionGroup.removeAll(); + myActionGroup.addAll(actions); + myUpdater.updateActions(false, true); } - public void setAdditionalTitleActions(AnAction[] actions) { - myButtonPanel.removeAll(); - boolean actionAdded = false; - for (final AnAction action : actions) { - if (action == null) continue; - myButtonPanel.add(new ActionButton(action, action.getTemplatePresentation().getIcon()) { - @Override - protected Icon getActiveHoveredIcon() { - final Icon icon = action.getTemplatePresentation().getHoveredIcon(); - return icon != null ? icon : super.getActiveHoveredIcon(); - } - }); - myButtonPanel.add(Box.createHorizontalStrut(9)); - actionAdded = true; + private void updateActionsImpl(boolean transparentOnly, boolean forced) { + List newVisibleActions = ContainerUtil.newArrayListWithCapacity(myVisibleActions.size()); + DataContext dataContext = DataManager.getInstance().getDataContext(this); + + Utils.expandActionGroup(myActionGroup, newVisibleActions, myPresentationFactory, dataContext, + ActionPlaces.TOOLWINDOW_TITLE, myUpdater.getActionManager(), transparentOnly); + + if (forced || !newVisibleActions.equals(myVisibleActions)) { + myVisibleActions = newVisibleActions; + + myButtonPanel.removeAll(); + boolean actionAdded = false; + for (final AnAction action : newVisibleActions) { + if (action == null) continue; + final Presentation presentation = myPresentationFactory.getPresentation(action); + myButtonPanel.add(new ActionButton(action, presentation.getIcon()) { + @Override + protected Icon getActiveHoveredIcon() { + Icon icon = presentation.getHoveredIcon(); + return icon != null ? icon : super.getActiveHoveredIcon(); + } + }); + myButtonPanel.add(Box.createHorizontalStrut(9)); + actionAdded = true; + } + if (actionAdded) { + myButtonPanel.add(new JLabel(AllIcons.General.Divider)); + myButtonPanel.add(Box.createHorizontalStrut(6)); + } + addDefaultActions(myButtonPanel); + + revalidate(); + repaint(); } - if (actionAdded) { - myButtonPanel.add(new JLabel(AllIcons.General.Divider)); - myButtonPanel.add(Box.createHorizontalStrut(6)); - } - addDefaultActions(myButtonPanel); } private static Icon getHideToolWindowIcon(ToolWindow toolWindow) { @@ -542,9 +574,9 @@ public abstract class ToolWindowHeader extends JPanel implements Disposable, UIS getTemplatePresentation().setText(UIBundle.message("tool.window.hideSide.action.name")); } - public abstract void actionPerformed(final AnActionEvent e); + public abstract void actionPerformed(@NotNull final AnActionEvent e); - public final void update(final AnActionEvent event) { + public final void update(@NotNull final AnActionEvent event) { final Presentation presentation = event.getPresentation(); presentation.setEnabled(myInfo.isVisible()); } @@ -558,7 +590,7 @@ public abstract class ToolWindowHeader extends JPanel implements Disposable, UIS getTemplatePresentation().setText(UIBundle.message("tool.window.hide.action.name")); } - public final void update(final AnActionEvent event) { + public final void update(@NotNull final AnActionEvent event) { final Presentation presentation = event.getPresentation(); presentation.setEnabled(myInfo.isVisible()); } From 119cc4b0b7b156bfd9483f5ab02897d74314c341 Mon Sep 17 00:00:00 2001 From: "Gregory.Shrago" Date: Fri, 7 Nov 2014 10:23:52 +0300 Subject: [PATCH 57/84] toolbar toggles: improve isPopup() calculation --- .../ide/actions/ToggleToolbarAction.java | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/ide/actions/ToggleToolbarAction.java b/platform/platform-impl/src/com/intellij/ide/actions/ToggleToolbarAction.java index 29c0676518a5..f2ca56055989 100644 --- a/platform/platform-impl/src/com/intellij/ide/actions/ToggleToolbarAction.java +++ b/platform/platform-impl/src/com/intellij/ide/actions/ToggleToolbarAction.java @@ -39,7 +39,7 @@ public class ToggleToolbarAction extends ToggleAction implements DumbAware { @NotNull public static ActionGroup createToggleToolbarGroup(@NotNull Project project, @NotNull ToolWindow toolWindow) { - return new DefaultActionGroup(new ToolbarTogglesGroup(toolWindow), + return new DefaultActionGroup(new OptionsGroup(toolWindow), new ToggleToolbarAction(toolWindow, PropertiesComponent.getInstance(project))); } @@ -102,18 +102,19 @@ public class ToggleToolbarAction extends ToggleAction implements DumbAware { return JBSwingUtilities.uiTraverser().preOrderTraversal(root).filter(ActionToolbar.class); } - private static class ToolbarTogglesGroup extends ActionGroup { + private static class OptionsGroup extends ActionGroup { private final ToolWindow myToolWindow; - public ToolbarTogglesGroup(ToolWindow toolWindow) { + public OptionsGroup(ToolWindow toolWindow) { super("View Options", true); myToolWindow = toolWindow; } @Override public boolean isPopup() { - return getChildren(null).length > 3; + // configured in getChildren() + return super.isPopup(); } @Override @@ -129,15 +130,21 @@ public class ToggleToolbarAction extends ToggleAction implements DumbAware { JComponent contentComponent = selectedContent != null ? selectedContent.getComponent() : null; if (contentComponent == null) return EMPTY_ARRAY; List result = ContainerUtil.newSmartList(); + boolean addSeparator = false; for (final ActionToolbar toolbar : iterateToolbars(contentComponent)) { JComponent c = toolbar.getComponent(); if (c.isVisible() || !c.isValid()) continue; List actions = toolbar.getActions(false); for (AnAction action : actions) { - if (!(action instanceof ToggleAction || action instanceof Separator)) continue; + if (action instanceof Separator && (addSeparator = true) || !(action instanceof ToggleAction)) continue; + if (addSeparator && !result.isEmpty()) result.add(Separator.getInstance()); result.add(action); + addSeparator = false; } } + boolean popup = result.size() > 3; + setPopup(popup); + if (!popup && !result.isEmpty()) result.add(Separator.getInstance()); return result.toArray(new AnAction[result.size()]); } } From ca4e20bc835f9f7e9da1fe906596f7e2f9645e7b Mon Sep 17 00:00:00 2001 From: Mikhail Golubev Date: Fri, 7 Nov 2014 01:00:13 +0300 Subject: [PATCH 58/84] PY-14261 Do not copy indentation, adjust offset for insertion instead See review IDEA-COMMUNITY-CR-900. --- .../lang/folding/CustomFoldingSurroundDescriptor.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/platform/lang-api/src/com/intellij/lang/folding/CustomFoldingSurroundDescriptor.java b/platform/lang-api/src/com/intellij/lang/folding/CustomFoldingSurroundDescriptor.java index 17da710c06c5..4062cb45beef 100644 --- a/platform/lang-api/src/com/intellij/lang/folding/CustomFoldingSurroundDescriptor.java +++ b/platform/lang-api/src/com/intellij/lang/folding/CustomFoldingSurroundDescriptor.java @@ -200,8 +200,6 @@ public class CustomFoldingSurroundDescriptor implements SurroundDescriptor { int prefixLength = linePrefix.length(); int startOffset = firstElement.getTextRange().getStartOffset(); final Document document = editor.getDocument(); - final int startLineNumber = document.getLineNumber(startOffset); - final String startIndent = document.getText(new TextRange(document.getLineStartOffset(startLineNumber), startOffset)); int endOffset = lastElement.getTextRange().getEndOffset(); int delta = 0; TextRange rangeToSelect = new TextRange(startOffset, startOffset); @@ -211,11 +209,12 @@ public class CustomFoldingSurroundDescriptor implements SurroundDescriptor { startText = startText.replace("?", DEFAULT_DESC_TEXT); rangeToSelect = new TextRange(startOffset + descPos, startOffset + descPos + DEFAULT_DESC_TEXT.length()); } - String startString = linePrefix + startText + "\n" + startIndent; + String startString = linePrefix + startText + "\n"; String endString = "\n" + linePrefix + myProvider.getEndString(); document.insertString(endOffset, endString); delta += endString.length(); - document.insertString(startOffset, startString); + final int startCommentInsertionOffset = document.getLineStartOffset(document.getLineNumber(startOffset)); + document.insertString(startCommentInsertionOffset, startString); delta += startString.length(); rangeToSelect = rangeToSelect.shiftRight(prefixLength); PsiDocumentManager documentManager = PsiDocumentManager.getInstance(project); @@ -223,7 +222,7 @@ public class CustomFoldingSurroundDescriptor implements SurroundDescriptor { adjustLineIndent(project, psiFile, language, new TextRange(endOffset + delta - endString.length(), endOffset + delta)); adjustLineIndent(project, psiFile, language, - new TextRange(startOffset, startOffset + startString.length())); + new TextRange(startCommentInsertionOffset, startCommentInsertionOffset + startString.length())); return rangeToSelect; } From 16df7cd4e95204d0a796914af747f764a072e917 Mon Sep 17 00:00:00 2001 From: Mikhail Golubev Date: Fri, 7 Nov 2014 01:24:31 +0300 Subject: [PATCH 59/84] Clean up in PyPropertyDefinitionInspection * Got rid of snake_case names * Removed highlighted constant condition * Reformatted entire file --- .../PyPropertyDefinitionInspection.java | 133 ++++++++++-------- 1 file changed, 71 insertions(+), 62 deletions(-) diff --git a/python/src/com/jetbrains/python/inspections/PyPropertyDefinitionInspection.java b/python/src/com/jetbrains/python/inspections/PyPropertyDefinitionInspection.java index e808a0d1dbdb..f1c950993ffa 100644 --- a/python/src/com/jetbrains/python/inspections/PyPropertyDefinitionInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyPropertyDefinitionInspection.java @@ -82,20 +82,20 @@ public class PyPropertyDefinitionInspection extends PyInspection { // save us continuous checks for level, module, stc myLevel = LanguageLevel.forElement(psiFile); // string classes - final List string_classes = new ArrayList(2); + final List stringClasses = new ArrayList(2); final PyBuiltinCache builtins = PyBuiltinCache.getInstance(psiFile); PyClass cls = builtins.getClass("str"); - if (cls != null) string_classes.add(cls); + if (cls != null) stringClasses.add(cls); cls = builtins.getClass("unicode"); - if (cls != null) string_classes.add(cls); - myStringClasses = string_classes; + if (cls != null) stringClasses.add(cls); + myStringClasses = stringClasses; // reference signatures - PyClass object_class = builtins.getClass("object"); - if (object_class != null) { - final PyFunction method_repr = object_class.findMethodByName("__repr__", false); - if (method_repr != null) myOneParamFunction = method_repr; - final PyFunction method_delattr = object_class.findMethodByName("__delattr__", false); - if (method_delattr != null) myTwoParamFunction = method_delattr; + PyClass objectClass = builtins.getClass("object"); + if (objectClass != null) { + final PyFunction methodRepr = objectClass.findMethodByName("__repr__", false); + if (methodRepr != null) myOneParamFunction = methodRepr; + final PyFunction methodDelattr = objectClass.findMethodByName("__delattr__", false); + if (methodDelattr != null) myTwoParamFunction = methodDelattr; } } @@ -121,10 +121,10 @@ public class PyPropertyDefinitionInspection extends PyInspection { assert arglist != null : "Property call has null arglist"; CallArgumentsMapping analysis = arglist.analyzeCall(getResolveContext()); // we assume fget, fset, fdel, doc names - for (Map.Entry entry: analysis.getPlainMappedParams().entrySet()) { - final String param_name = entry.getValue().getName(); + for (Map.Entry entry : analysis.getPlainMappedParams().entrySet()) { + final String paramName = entry.getValue().getName(); PyExpression argument = PyUtil.peelArgument(entry.getKey()); - checkPropertyCallArgument(param_name, argument, node.getContainingFile()); + checkPropertyCallArgument(paramName, argument, node.getContainingFile()); } } else { @@ -137,40 +137,45 @@ public class PyPropertyDefinitionInspection extends PyInspection { } return false; // always want more } - }, false); } - private void checkPropertyCallArgument(String param_name, PyExpression argument, PsiFile containingFile) { + private void checkPropertyCallArgument(String paramName, PyExpression argument, PsiFile containingFile) { assert argument != null : "Parameter mapped to null argument"; Callable callable = null; if (argument instanceof PyReferenceExpression) { final PsiPolyVariantReference reference = ((PyReferenceExpression)argument).getReference(getResolveContext()); - if (reference != null) { - PsiElement resolved = reference.resolve(); - if (resolved instanceof Callable) { - callable = (Callable)resolved; - } - else { - reportNonCallableArg(resolved, argument); - return; - } + PsiElement resolved = reference.resolve(); + if (resolved instanceof Callable) { + callable = (Callable)resolved; + } + else { + reportNonCallableArg(resolved, argument); + return; } } - else if (argument instanceof PyLambdaExpression) callable = (PyLambdaExpression)argument; - else if (! "doc".equals(param_name)) { + else if (argument instanceof PyLambdaExpression) { + callable = (PyLambdaExpression)argument; + } + else if (!"doc".equals(paramName)) { reportNonCallableArg(argument, argument); return; } if (callable != null && callable.getContainingFile() != containingFile) { return; } - if ("fget".equals(param_name)) checkGetter(callable, argument); - else if ("fset".equals(param_name)) checkSetter(callable, argument); - else if ("fdel".equals(param_name)) checkDeleter(callable, argument); - else if ("doc".equals(param_name)) { + if ("fget".equals(paramName)) { + checkGetter(callable, argument); + } + else if ("fset".equals(paramName)) { + checkSetter(callable, argument); + } + else if ("fdel".equals(paramName)) { + checkDeleter(callable, argument); + } + else if ("doc".equals(paramName)) { PyType type = myTypeEvalContext.getType(argument); - if (! (type instanceof PyClassType && myStringClasses.contains(((PyClassType)type).getPyClass()))) { + if (!(type instanceof PyClassType && myStringClasses.contains(((PyClassType)type).getPyClass()))) { registerProblem(argument, PyBundle.message("INSP.doc.param.should.be.str")); } } @@ -203,17 +208,21 @@ public class PyPropertyDefinitionInspection extends PyInspection { if (decos != null) { String name = node.getName(); for (PyDecorator deco : decos.getDecorators()) { - final QualifiedName q_name = deco.getQualifiedName(); - if (q_name != null) { - List name_parts = q_name.getComponents(); - if (name_parts.size() == 2) { - final int suffix_index = SUFFIXES.indexOf(name_parts.get(1)); - if (suffix_index >= 0) { - if (Comparing.equal(name, name_parts.get(0))) { + final QualifiedName qName = deco.getQualifiedName(); + if (qName != null) { + List nameParts = qName.getComponents(); + if (nameParts.size() == 2) { + final int suffixIndex = SUFFIXES.indexOf(nameParts.get(1)); + if (suffixIndex >= 0) { + if (Comparing.equal(name, nameParts.get(0))) { // names are ok, what about signatures? PsiElement markable = getFunctionMarkingElement(node); - if (suffix_index == 0) checkSetter(node, markable); - else checkDeleter(node, markable); + if (suffixIndex == 0) { + checkSetter(node, markable); + } + else { + checkDeleter(node, markable); + } } else { registerProblem(deco, PyBundle.message("INSP.func.property.name.mismatch")); @@ -230,37 +239,37 @@ public class PyPropertyDefinitionInspection extends PyInspection { @Nullable private static PsiElement getFunctionMarkingElement(PyFunction node) { if (node == null) return null; - final ASTNode name_node = node.getNameNode(); + final ASTNode nameNode = node.getNameNode(); PsiElement markable = node; - if (name_node != null) markable = name_node.getPsi(); + if (nameNode != null) markable = nameNode.getPsi(); return markable; } - private void checkGetter(Callable callable, PsiElement being_checked) { + private void checkGetter(Callable callable, PsiElement beingChecked) { if (callable != null) { - checkOneParameter(callable, being_checked, true); - checkReturnValueAllowed(callable, being_checked, true, PyBundle.message("INSP.getter.return.smth")); + checkOneParameter(callable, beingChecked, true); + checkReturnValueAllowed(callable, beingChecked, true, PyBundle.message("INSP.getter.return.smth")); } } - private void checkSetter(Callable callable, PsiElement being_checked) { + private void checkSetter(Callable callable, PsiElement beingChecked) { if (callable != null) { // signature: at least two params, more optionals ok; first arg 'self' - final PyParameterList param_list = callable.getParameterList(); + final PyParameterList paramList = callable.getParameterList(); if (myTwoParamFunction != null && !PyUtil.isSignatureCompatibleTo(callable, myTwoParamFunction, myTypeEvalContext)) { - registerProblem(being_checked, PyBundle.message("INSP.setter.signature.advice"), new PyUpdatePropertySignatureQuickFix(true)); + registerProblem(beingChecked, PyBundle.message("INSP.setter.signature.advice"), new PyUpdatePropertySignatureQuickFix(true)); } - checkForSelf(param_list); + checkForSelf(paramList); // no explicit return type - checkReturnValueAllowed(callable, being_checked, false, PyBundle.message("INSP.setter.should.not.return")); + checkReturnValueAllowed(callable, beingChecked, false, PyBundle.message("INSP.setter.should.not.return")); } } - private void checkDeleter(Callable callable, PsiElement being_checked) { + private void checkDeleter(Callable callable, PsiElement beingChecked) { if (callable != null) { - checkOneParameter(callable, being_checked, false); - checkReturnValueAllowed(callable, being_checked, false, PyBundle.message("INSP.deleter.should.not.return")); + checkOneParameter(callable, beingChecked, false); + checkReturnValueAllowed(callable, beingChecked, false, PyBundle.message("INSP.deleter.should.not.return")); } } @@ -278,25 +287,26 @@ public class PyPropertyDefinitionInspection extends PyInspection { checkForSelf(parameterList); } - private void checkForSelf(PyParameterList param_list) { - PyParameter[] parameters = param_list.getParameters(); - final PyClass cls = PsiTreeUtil.getParentOfType(param_list, PyClass.class); + private void checkForSelf(PyParameterList paramList) { + PyParameter[] parameters = paramList.getParameters(); + final PyClass cls = PsiTreeUtil.getParentOfType(paramList, PyClass.class); if (cls != null && cls.isSubclass("type")) return; - if (parameters.length > 0 && ! PyNames.CANONICAL_SELF.equals(parameters[0].getName())) { + if (parameters.length > 0 && !PyNames.CANONICAL_SELF.equals(parameters[0].getName())) { registerProblem( - parameters[0], PyBundle.message("INSP.accessor.first.param.is.$0", PyNames.CANONICAL_SELF), ProblemHighlightType.WEAK_WARNING, null, + parameters[0], PyBundle.message("INSP.accessor.first.param.is.$0", PyNames.CANONICAL_SELF), ProblemHighlightType.WEAK_WARNING, + null, new RenameParameterQuickFix(PyNames.CANONICAL_SELF)); } } - private void checkReturnValueAllowed(Callable callable, PsiElement being_checked, boolean allowed, String message) { + private void checkReturnValueAllowed(Callable callable, PsiElement beingChecked, boolean allowed, String message) { // TODO: use a real flow analysis to check all exit points boolean hasReturns; if (callable instanceof PyFunction) { final PsiElement[] returnStatements = PsiTreeUtil.collectElements(callable, new PsiElementFilter() { @Override public boolean isAccepted(PsiElement element) { - return (element instanceof PyReturnStatement && ((PyReturnStatement) element).getExpression() != null) || + return (element instanceof PyReturnStatement && ((PyReturnStatement)element).getExpression() != null) || (element instanceof PyYieldExpression); } }); @@ -316,9 +326,8 @@ public class PyPropertyDefinitionInspection extends PyInspection { } } } - registerProblem(being_checked, message); + registerProblem(beingChecked, message); } } } - } From a32668ecd9c3306154d277753f800b96b6ff1ed9 Mon Sep 17 00:00:00 2001 From: Mikhail Golubev Date: Fri, 7 Nov 2014 02:07:07 +0300 Subject: [PATCH 60/84] PY-11426 Do not warn about missing return if property was decorated as @abstractmethod/@abstractproperty --- .../PyPropertyDefinitionInspection.java | 3 +++ .../src/prop_test.py | 5 +++++ .../PyPropertyDefinitionInspection33/expected.xml | 9 +++++++++ .../src/prop_test.py | 14 ++++++++++++++ .../jetbrains/python/PythonInspectionsTest.java | 5 +++++ 5 files changed, 36 insertions(+) create mode 100644 python/testData/inspections/PyPropertyDefinitionInspection33/expected.xml create mode 100644 python/testData/inspections/PyPropertyDefinitionInspection33/src/prop_test.py diff --git a/python/src/com/jetbrains/python/inspections/PyPropertyDefinitionInspection.java b/python/src/com/jetbrains/python/inspections/PyPropertyDefinitionInspection.java index f1c950993ffa..e52134dbfad9 100644 --- a/python/src/com/jetbrains/python/inspections/PyPropertyDefinitionInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyPropertyDefinitionInspection.java @@ -318,6 +318,9 @@ public class PyPropertyDefinitionInspection extends PyInspection { } if (allowed ^ hasReturns) { if (allowed && callable instanceof PyFunction) { + if (PyUtil.isDecoratedAsAbstract(((PyFunction)callable))) { + return; + } // one last chance: maybe there's no return but a 'raise' statement, see PY-4043, PY-5048 PyStatementList statementList = ((PyFunction)callable).getStatementList(); for (PyStatement stmt : statementList.getStatements()) { diff --git a/python/testData/inspections/PyPropertyDefinitionInspection26/src/prop_test.py b/python/testData/inspections/PyPropertyDefinitionInspection26/src/prop_test.py index 5823e797f197..f7b7d2065e45 100644 --- a/python/testData/inspections/PyPropertyDefinitionInspection26/src/prop_test.py +++ b/python/testData/inspections/PyPropertyDefinitionInspection26/src/prop_test.py @@ -63,3 +63,8 @@ class A(object): get_foo2 = lambda self: 'foo2' foo2 = property(get_foo2) + + @property + @abstractproperty + def abstract_property(self): + pass diff --git a/python/testData/inspections/PyPropertyDefinitionInspection33/expected.xml b/python/testData/inspections/PyPropertyDefinitionInspection33/expected.xml new file mode 100644 index 000000000000..d12754a111d5 --- /dev/null +++ b/python/testData/inspections/PyPropertyDefinitionInspection33/expected.xml @@ -0,0 +1,9 @@ + + + + prop_test.py + 3 + Getter should return or yield something + + + diff --git a/python/testData/inspections/PyPropertyDefinitionInspection33/src/prop_test.py b/python/testData/inspections/PyPropertyDefinitionInspection33/src/prop_test.py new file mode 100644 index 000000000000..516047992b8e --- /dev/null +++ b/python/testData/inspections/PyPropertyDefinitionInspection33/src/prop_test.py @@ -0,0 +1,14 @@ +class A: + @property + def normal_property(self): + pass + + @property + @abstractproperty + def abstract_property1(self): + pass + + @property + @abstractmethod + def abstract_property2(self): + pass diff --git a/python/testSrc/com/jetbrains/python/PythonInspectionsTest.java b/python/testSrc/com/jetbrains/python/PythonInspectionsTest.java index aeb4cfdccf84..7413026fdaf4 100644 --- a/python/testSrc/com/jetbrains/python/PythonInspectionsTest.java +++ b/python/testSrc/com/jetbrains/python/PythonInspectionsTest.java @@ -245,6 +245,11 @@ public class PythonInspectionsTest extends PyTestCase { doTestWithLanguageLevel(getTestName(false), new PyPropertyDefinitionInspection(), LanguageLevel.PYTHON26); } + // PY-11426 + public void testPyPropertyDefinitionInspection33() { + doTestWithLanguageLevel(getTestName(false), new PyPropertyDefinitionInspection(), LanguageLevel.PYTHON33); + } + public void testInconsistentIndentation() { doHighlightingTest(PyInconsistentIndentationInspection.class, LanguageLevel.PYTHON26); } From 000308c053f60f79e732505068cfdd6ea630c1d4 Mon Sep 17 00:00:00 2001 From: Dmitry Avdeev Date: Fri, 7 Nov 2014 11:58:47 +0300 Subject: [PATCH 61/84] cleanup --- .../config/TaskRepositoriesConfigurable.java | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/plugins/tasks/tasks-core/src/com/intellij/tasks/config/TaskRepositoriesConfigurable.java b/plugins/tasks/tasks-core/src/com/intellij/tasks/config/TaskRepositoriesConfigurable.java index 2ab1079ac56c..9262b81020e2 100644 --- a/plugins/tasks/tasks-core/src/com/intellij/tasks/config/TaskRepositoriesConfigurable.java +++ b/plugins/tasks/tasks-core/src/com/intellij/tasks/config/TaskRepositoriesConfigurable.java @@ -27,6 +27,7 @@ import com.intellij.util.containers.ConcurrentFactoryMap; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.FactoryMap; import org.jetbrains.annotations.Nls; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; @@ -89,7 +90,7 @@ public class TaskRepositoriesConfigurable extends BaseConfigurable implements Co String description = "New " + subtype.getName() + " server"; createActions.add(new IconWithTextAction(subtype.getName(), description, subtype.getIcon()) { @Override - public void actionPerformed(AnActionEvent e) { + public void actionPerformed(@NotNull AnActionEvent e) { TaskRepository repository = repositoryType.createRepository(subtype); addRepository(repository); } @@ -113,7 +114,7 @@ public class TaskRepositoriesConfigurable extends BaseConfigurable implements Co for (final TaskRepository repository : repositories) { group.add(new IconWithTextAction(repository.getUrl(), repository.getUrl(), repository.getIcon()) { @Override - public void actionPerformed(AnActionEvent e) { + public void actionPerformed(@NotNull AnActionEvent e) { addRepository(repository); } }); @@ -151,7 +152,7 @@ public class TaskRepositoriesConfigurable extends BaseConfigurable implements Co myServersPanel.add(toolbarDecorator.createPanel(), BorderLayout.CENTER); myRepositoriesList.getSelectionModel().addListSelectionListener(new ListSelectionListener() { - public void valueChanged(ListSelectionEvent e) { + public void valueChanged(@NotNull ListSelectionEvent e) { TaskRepository repository = getSelectedRepository(); if (repository != null) { String name = myRepoNames.get(repository); @@ -182,21 +183,17 @@ public class TaskRepositoriesConfigurable extends BaseConfigurable implements Co private void addRepository(TaskRepository repository) { myRepositories.add(repository); ((CollectionListModel)myRepositoriesList.getModel()).add(repository); - addRepositoryEditor(repository, true); + addRepositoryEditor(repository); myRepositoriesList.setSelectedIndex(myRepositoriesList.getModel().getSize() - 1); } - private void addRepositoryEditor(TaskRepository repository, boolean requestFocus) { + private void addRepositoryEditor(TaskRepository repository) { TaskRepositoryEditor editor = repository.getRepositoryType().createEditor(repository, myProject, myChangeListener); myEditors.add(editor); JComponent component = editor.createComponent(); String name = myRepoNames.get(repository); myRepositoryEditor.add(component, name); myRepositoryEditor.doLayout(); - JComponent preferred = editor.getPreferredFocusedComponent(); - if (preferred != null && requestFocus) { -// IdeFocusManager.getInstance(myProject).requestFocus(preferred, false); - } } @Nullable @@ -255,7 +252,7 @@ public class TaskRepositoriesConfigurable extends BaseConfigurable implements Co myRepositoriesList.setModel(listModel); for (TaskRepository clone : myRepositories) { - addRepositoryEditor(clone, false); + addRepositoryEditor(clone); } if (!myRepositories.isEmpty()) { From 70d68021e04ccd1a71cfecfa7c9d6bbe04c8bf99 Mon Sep 17 00:00:00 2001 From: Dmitry Avdeev Date: Fri, 7 Nov 2014 12:12:26 +0300 Subject: [PATCH 62/84] IDEA-132523 Task Management: 'Add server' action unavailable in dumb mode --- .../config/TaskRepositoriesConfigurable.java | 35 ++++++++++++++----- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/plugins/tasks/tasks-core/src/com/intellij/tasks/config/TaskRepositoriesConfigurable.java b/plugins/tasks/tasks-core/src/com/intellij/tasks/config/TaskRepositoriesConfigurable.java index 9262b81020e2..02b599ed1340 100644 --- a/plugins/tasks/tasks-core/src/com/intellij/tasks/config/TaskRepositoriesConfigurable.java +++ b/plugins/tasks/tasks-core/src/com/intellij/tasks/config/TaskRepositoriesConfigurable.java @@ -8,6 +8,7 @@ import com.intellij.openapi.actionSystem.Separator; import com.intellij.openapi.options.BaseConfigurable; import com.intellij.openapi.options.Configurable; import com.intellij.openapi.options.ConfigurationException; +import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.ui.configuration.actions.IconWithTextAction; import com.intellij.openapi.ui.Splitter; @@ -87,12 +88,10 @@ public class TaskRepositoriesConfigurable extends BaseConfigurable implements Co final List createActions = new ArrayList(); for (final TaskRepositoryType repositoryType : groups) { for (final TaskRepositorySubtype subtype : (List)repositoryType.getAvailableSubtypes()) { - String description = "New " + subtype.getName() + " server"; - createActions.add(new IconWithTextAction(subtype.getName(), description, subtype.getIcon()) { + createActions.add(new AddServerAction(subtype) { @Override - public void actionPerformed(@NotNull AnActionEvent e) { - TaskRepository repository = repositoryType.createRepository(subtype); - addRepository(repository); + protected TaskRepository getRepository() { + return repositoryType.createRepository(subtype); } }); } @@ -112,10 +111,10 @@ public class TaskRepositoriesConfigurable extends BaseConfigurable implements Co if (!repositories.isEmpty()) { group.add(Separator.getInstance()); for (final TaskRepository repository : repositories) { - group.add(new IconWithTextAction(repository.getUrl(), repository.getUrl(), repository.getIcon()) { + group.add(new AddServerAction(repository) { @Override - public void actionPerformed(@NotNull AnActionEvent e) { - addRepository(repository); + protected TaskRepository getRepository() { + return repository; } }); } @@ -123,7 +122,7 @@ public class TaskRepositoriesConfigurable extends BaseConfigurable implements Co JBPopupFactory.getInstance() .createActionGroupPopup("Add server", group, DataManager.getInstance().getDataContext(anActionButton.getContextComponent()), - JBPopupFactory.ActionSelectionAid.SPEEDSEARCH, false).show( + JBPopupFactory.ActionSelectionAid.SPEEDSEARCH, true).show( anActionButton.getPreferredPopupPoint()); } }); @@ -269,4 +268,22 @@ public class TaskRepositoriesConfigurable extends BaseConfigurable implements Co Disposer.dispose(editor); } } + + private abstract class AddServerAction extends IconWithTextAction implements DumbAware { + + public AddServerAction(TaskRepositorySubtype subtype) { + super(subtype.getName(), "New " + subtype.getName() + " server", subtype.getIcon()); + } + + public AddServerAction(TaskRepository repository) { + super(repository.getUrl(), repository.getUrl(), repository.getIcon()); + } + + protected abstract TaskRepository getRepository(); + + @Override + public void actionPerformed(@NotNull AnActionEvent e) { + addRepository(getRepository()); + } + } } From 9e8a4066cf2916a0021d47475aa8c8976ce847c6 Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Fri, 7 Nov 2014 10:36:54 +0100 Subject: [PATCH 63/84] =?UTF-8?q?use=20less=20memory=20and=20simplify=20?= =?UTF-8?q?=E2=80=94=20almost=20all=20bindings=20in=20any=20case=20store?= =?UTF-8?q?=20assessors?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../util/xmlb/AbstractCollectionBinding.java | 6 +- .../util/xmlb/AccessorBindingWrapper.java | 6 +- .../util/xmlb/BasePrimitiveBinding.java | 6 +- .../com/intellij/util/xmlb/BeanBinding.java | 67 +++++++++---------- .../src/com/intellij/util/xmlb/Binding.java | 26 +++++-- .../com/intellij/util/xmlb/DateBinding.java | 8 +-- .../util/xmlb/JDOMElementBinding.java | 6 +- .../com/intellij/util/xmlb/MapBinding.java | 14 ++-- .../util/xmlb/PrimitiveValueBinding.java | 6 +- .../intellij/util/xmlb/SmartSerializer.java | 4 +- .../intellij/util/xmlb/TagBindingWrapper.java | 14 ++-- .../com/intellij/util/xmlb/TextBinding.java | 10 ++- .../intellij/util/xmlb/XmlSerializerImpl.java | 39 ++++++++--- 13 files changed, 117 insertions(+), 95 deletions(-) diff --git a/platform/util/src/com/intellij/util/xmlb/AbstractCollectionBinding.java b/platform/util/src/com/intellij/util/xmlb/AbstractCollectionBinding.java index 77d39314073e..1252a271a34a 100644 --- a/platform/util/src/com/intellij/util/xmlb/AbstractCollectionBinding.java +++ b/platform/util/src/com/intellij/util/xmlb/AbstractCollectionBinding.java @@ -29,18 +29,18 @@ import java.util.Collection; import java.util.List; import java.util.Map; -abstract class AbstractCollectionBinding implements Binding { +abstract class AbstractCollectionBinding extends Binding { private Map myElementBindings; private final Class myElementType; private final String myTagName; - @Nullable protected final Accessor myAccessor; private final AbstractCollection myAnnotation; public AbstractCollectionBinding(Class elementType, String tagName, @Nullable Accessor accessor) { + super(accessor); + myElementType = elementType; myTagName = tagName; - myAccessor = accessor; myAnnotation = accessor == null ? null : accessor.getAnnotation(AbstractCollection.class); } diff --git a/platform/util/src/com/intellij/util/xmlb/AccessorBindingWrapper.java b/platform/util/src/com/intellij/util/xmlb/AccessorBindingWrapper.java index c5be1e8f7e31..266fdf8f926a 100644 --- a/platform/util/src/com/intellij/util/xmlb/AccessorBindingWrapper.java +++ b/platform/util/src/com/intellij/util/xmlb/AccessorBindingWrapper.java @@ -19,12 +19,12 @@ import org.jdom.Element; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -class AccessorBindingWrapper implements Binding { - private final Accessor myAccessor; +class AccessorBindingWrapper extends Binding { private final Binding myBinding; public AccessorBindingWrapper(@NotNull Accessor accessor, @NotNull Binding binding) { - myAccessor = accessor; + super(accessor); + myBinding = binding; } diff --git a/platform/util/src/com/intellij/util/xmlb/BasePrimitiveBinding.java b/platform/util/src/com/intellij/util/xmlb/BasePrimitiveBinding.java index 68c5e626a3ea..936c367f4404 100644 --- a/platform/util/src/com/intellij/util/xmlb/BasePrimitiveBinding.java +++ b/platform/util/src/com/intellij/util/xmlb/BasePrimitiveBinding.java @@ -20,15 +20,15 @@ import com.intellij.util.ReflectionUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -abstract class BasePrimitiveBinding implements Binding { - protected final Accessor myAccessor; +abstract class BasePrimitiveBinding extends Binding { protected final String myName; protected final @Nullable Converter myConverter; @Nullable protected Binding myBinding; protected BasePrimitiveBinding(@NotNull Accessor accessor, @Nullable String suggestedName, @Nullable Class converterClass) { - myAccessor = accessor; + super(accessor); + myName = StringUtil.isEmpty(suggestedName) ? myAccessor.getName() : suggestedName; if (converterClass == null || converterClass == Converter.class) { myConverter = null; diff --git a/platform/util/src/com/intellij/util/xmlb/BeanBinding.java b/platform/util/src/com/intellij/util/xmlb/BeanBinding.java index 7f7022e48c0e..78725e85378e 100644 --- a/platform/util/src/com/intellij/util/xmlb/BeanBinding.java +++ b/platform/util/src/com/intellij/util/xmlb/BeanBinding.java @@ -26,7 +26,6 @@ import com.intellij.util.containers.ConcurrentSoftValueHashMap; import com.intellij.util.containers.ContainerUtil; 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; @@ -41,16 +40,20 @@ import java.lang.reflect.Modifier; import java.util.*; import java.util.List; -class BeanBinding implements Binding { +class BeanBinding extends Binding { private static final Logger LOG = Logger.getInstance(BeanBinding.class); private static final Map> ourAccessorCache = new ConcurrentSoftValueHashMap>(); private final String myTagName; - private final LinkedHashMap myPropertyBindings = new LinkedHashMap(); + @SuppressWarnings("FieldAccessedSynchronizedAndUnsynchronized") + private Binding[] myBindings; + private final Class myBeanClass; - public BeanBinding(Class beanClass) { + public BeanBinding(@NotNull Class beanClass, @Nullable Accessor accessor) { + super(accessor); + assert !beanClass.isArray() : "Bean is an array: " + beanClass; assert !beanClass.isPrimitive() : "Bean is primitive type: " + beanClass; myBeanClass = beanClass; @@ -59,13 +62,15 @@ class BeanBinding implements Binding { } @Override - public void init() { - initPropertyBindings(myBeanClass); - } + public synchronized void init() { + assert myBindings == null; - private synchronized void initPropertyBindings(Class beanClass) { - for (Accessor accessor : getAccessors(beanClass)) { - myPropertyBindings.put(createBindingByAccessor(accessor), accessor); + List accessors = getAccessors(myBeanClass); + myBindings = new Binding[accessors.size()]; + for (int i = 0, size = accessors.size(); i < size; i++) { + Binding binding = createBinding(accessors.get(i)); + binding.init(); + myBindings[i] = binding; } } @@ -81,17 +86,13 @@ class BeanBinding implements Binding { @Nullable public Element serializeInto(@NotNull Object o, @Nullable Element element, @NotNull SerializationFilter filter) { - return serializeInto(o, element, filter, myPropertyBindings.keySet()); + return serializeInto(o, element, filter, myBindings); } @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; - } + public Element serializeInto(@NotNull Object o, @Nullable Element element, @NotNull SerializationFilter filter, @Nullable Binding[] bindings) { + for (Binding binding : bindings == null ? myBindings : bindings) { + Accessor accessor = binding.getAccessor(); if (!filter.accepts(accessor, o)) { continue; } @@ -139,18 +140,18 @@ class BeanBinding implements Binding { } @NotNull - List computeOrderedBindings(@NotNull LinkedHashSet accessorNameTracker) { + public Binding[] computeOrderedBindings(@NotNull LinkedHashSet accessorNameTracker) { final TObjectDoubleHashMap weights = new TObjectDoubleHashMap(accessorNameTracker.size()); double weight = 0; - double step = (double)myPropertyBindings.size() / (double)accessorNameTracker.size(); + double step = (double)myBindings.length / (double)accessorNameTracker.size(); for (String name : accessorNameTracker) { weights.put(name, weight); weight += step; } weight = 0; - for (Accessor accessor : myPropertyBindings.values()) { - String name = accessor.getName(); + for (Binding binding : myBindings) { + String name = binding.getAccessor().getName(); if (!weights.containsKey(name)) { weights.put(name, weight); } @@ -158,22 +159,21 @@ class BeanBinding implements Binding { weight++; } - Binding[] result = myPropertyBindings.keySet().toArray(new Binding[myPropertyBindings.size()]); + Binding[] result = Arrays.copyOf(myBindings, myBindings.length); 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(); + String n1 = o1.getAccessor().getName(); + String n2 = o2.getAccessor().getName(); double w1 = weights.get(n1); double w2 = weights.get(n2); return (int)(w1 - w2); } }); - return Arrays.asList(result); + return result; } public void deserializeInto(@NotNull Object result, @NotNull Element element, @Nullable Set accessorNameTracker) { - Set bindings = myPropertyBindings.keySet(); MultiMap data = MultiMap.createLinked(); nextNode: for (Object child : ContainerUtil.concat(element.getContent(), element.getAttributes())) { @@ -181,7 +181,7 @@ class BeanBinding implements Binding { continue; } - for (Binding binding : bindings) { + for (Binding binding : myBindings) { if (binding.isBoundTo(child)) { data.putValue(binding, child); continue nextNode; @@ -196,7 +196,7 @@ class BeanBinding implements Binding { for (Binding binding : data.keySet()) { if (accessorNameTracker != null) { - accessorNameTracker.add(myPropertyBindings.get(binding).getName()); + accessorNameTracker.add(binding.getAccessor().getName()); } binding.deserialize(result, ArrayUtil.toObjectArray(data.get(binding))); } @@ -323,13 +323,8 @@ class BeanBinding implements Binding { return "BeanBinding[" + myBeanClass.getName() + ", tagName=" + myTagName + "]"; } - private static Binding createBindingByAccessor(@NotNull Accessor accessor) { - final Binding binding = _createBinding(accessor); - binding.init(); - return binding; - } - - private static Binding _createBinding(@NotNull Accessor accessor) { + @NotNull + private static Binding createBinding(@NotNull Accessor accessor) { Binding binding = XmlSerializerImpl.getTypeBinding(accessor.getGenericType(), accessor); if (binding instanceof JDOMElementBinding) { return binding; diff --git a/platform/util/src/com/intellij/util/xmlb/Binding.java b/platform/util/src/com/intellij/util/xmlb/Binding.java index cc6cc168b43d..6bf6a4c6feb8 100644 --- a/platform/util/src/com/intellij/util/xmlb/Binding.java +++ b/platform/util/src/com/intellij/util/xmlb/Binding.java @@ -18,16 +18,28 @@ package com.intellij.util.xmlb; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -interface Binding { - @Nullable - Object serialize(Object o, @Nullable Object context, SerializationFilter filter); +abstract class Binding { + protected final Accessor myAccessor; + + protected Binding(Accessor accessor) { + myAccessor = accessor; + } + + @NotNull + public Accessor getAccessor() { + return myAccessor; + } @Nullable - Object deserialize(Object context, @NotNull Object... nodes); + public abstract Object serialize(Object o, @Nullable Object context, SerializationFilter filter); - boolean isBoundTo(Object node); + @Nullable + public abstract Object deserialize(Object context, @NotNull Object... nodes); - Class getBoundNodeType(); + public abstract boolean isBoundTo(Object node); - void init(); + public abstract Class getBoundNodeType(); + + public void init() { + } } diff --git a/platform/util/src/com/intellij/util/xmlb/DateBinding.java b/platform/util/src/com/intellij/util/xmlb/DateBinding.java index b3ae2634c03e..da3292932868 100644 --- a/platform/util/src/com/intellij/util/xmlb/DateBinding.java +++ b/platform/util/src/com/intellij/util/xmlb/DateBinding.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.intellij.util.xmlb; import org.jdom.Text; @@ -25,9 +24,8 @@ import java.util.Date; * @author Dmitry Avdeev */ public class DateBinding extends PrimitiveValueBinding { - - public DateBinding() { - super(Date.class); + public DateBinding(@Nullable Accessor accessor) { + super(Date.class, accessor); } @Nullable diff --git a/platform/util/src/com/intellij/util/xmlb/JDOMElementBinding.java b/platform/util/src/com/intellij/util/xmlb/JDOMElementBinding.java index 227f0fd4757c..8541b48eced3 100644 --- a/platform/util/src/com/intellij/util/xmlb/JDOMElementBinding.java +++ b/platform/util/src/com/intellij/util/xmlb/JDOMElementBinding.java @@ -23,12 +23,12 @@ import org.jetbrains.annotations.Nullable; import java.util.ArrayList; -class JDOMElementBinding implements Binding { - private final Accessor myAccessor; +class JDOMElementBinding extends Binding { private final String myTagName; public JDOMElementBinding(@NotNull Accessor accessor) { - myAccessor = accessor; + super(accessor); + Tag tag = myAccessor.getAnnotation(Tag.class); assert tag != null : "jdom.Element property without @Tag annotation: " + accessor; diff --git a/platform/util/src/com/intellij/util/xmlb/MapBinding.java b/platform/util/src/com/intellij/util/xmlb/MapBinding.java index a2490e39fdb2..144c71e1204b 100644 --- a/platform/util/src/com/intellij/util/xmlb/MapBinding.java +++ b/platform/util/src/com/intellij/util/xmlb/MapBinding.java @@ -34,7 +34,7 @@ import java.util.Map; import static com.intellij.util.xmlb.Constants.*; -class MapBinding implements Binding { +class MapBinding extends Binding { private static final Logger LOG = Logger.getInstance(MapBinding.class); private static final Comparator KEY_COMPARATOR = new Comparator() { @@ -54,7 +54,9 @@ class MapBinding implements Binding { private final Binding myValueBinding; private final MapAnnotation myMapAnnotation; - public MapBinding(ParameterizedType type, Accessor accessor) { + public MapBinding(ParameterizedType type, @NotNull Accessor accessor) { + super(accessor); + Type[] arguments = type.getActualTypeArguments(); Type keyType = arguments[0]; Type valueType = arguments[1]; @@ -64,6 +66,10 @@ class MapBinding implements Binding { myMapAnnotation = accessor.getAnnotation(MapAnnotation.class); } + @Override + public void init() { + } + @Nullable @Override public Object serialize(Object o, @Nullable Object context, SerializationFilter filter) { @@ -218,8 +224,4 @@ class MapBinding implements Binding { public Class getBoundNodeType() { return Element.class; } - - @Override - public void init() { - } } diff --git a/platform/util/src/com/intellij/util/xmlb/PrimitiveValueBinding.java b/platform/util/src/com/intellij/util/xmlb/PrimitiveValueBinding.java index 84e94ef4c216..22b5cb80549d 100644 --- a/platform/util/src/com/intellij/util/xmlb/PrimitiveValueBinding.java +++ b/platform/util/src/com/intellij/util/xmlb/PrimitiveValueBinding.java @@ -22,10 +22,12 @@ import org.jdom.Text; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -class PrimitiveValueBinding implements Binding { +class PrimitiveValueBinding extends Binding { private final Class myType; - public PrimitiveValueBinding(@NotNull Class myType) { + public PrimitiveValueBinding(@NotNull Class myType, @Nullable Accessor accessor) { + super(accessor); + this.myType = myType; } diff --git a/platform/util/src/com/intellij/util/xmlb/SmartSerializer.java b/platform/util/src/com/intellij/util/xmlb/SmartSerializer.java index 805934e3c76e..3a9ef3dc9ec2 100644 --- a/platform/util/src/com/intellij/util/xmlb/SmartSerializer.java +++ b/platform/util/src/com/intellij/util/xmlb/SmartSerializer.java @@ -21,11 +21,10 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.LinkedHashSet; -import java.util.List; public final class SmartSerializer { private final LinkedHashSet mySerializedAccessorNameTracker; - private List myOrderedBindings; + private Binding[] myOrderedBindings; private final SerializationFilter mySerializationFilter; public SmartSerializer(boolean trackSerializedNames, boolean useSkipEmptySerializationFilter) { @@ -56,6 +55,7 @@ public final class SmartSerializer { public void readExternal(@NotNull Object bean, @NotNull Element element) { if (mySerializedAccessorNameTracker != null) { mySerializedAccessorNameTracker.clear(); + myOrderedBindings = null; } BeanBinding beanBinding = (BeanBinding)XmlSerializerImpl.getBinding(bean.getClass()); diff --git a/platform/util/src/com/intellij/util/xmlb/TagBindingWrapper.java b/platform/util/src/com/intellij/util/xmlb/TagBindingWrapper.java index 389adca9cd18..59568dd60858 100644 --- a/platform/util/src/com/intellij/util/xmlb/TagBindingWrapper.java +++ b/platform/util/src/com/intellij/util/xmlb/TagBindingWrapper.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.intellij.util.xmlb; import com.intellij.openapi.util.JDOMUtil; @@ -24,14 +23,17 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; //todo: merge with option tag binding -class TagBindingWrapper implements Binding { +class TagBindingWrapper extends Binding { private final Binding binding; private final String myTagName; private final String myAttributeName; - public TagBindingWrapper(Binding binding, final String tagName, final String attributeName) { + public TagBindingWrapper(@NotNull Binding binding, final String tagName, final String attributeName) { + super(binding.myAccessor); + this.binding = binding; + //noinspection unchecked assert binding.getBoundNodeType().isAssignableFrom(Text.class); myTagName = tagName; myAttributeName = attributeName; @@ -81,8 +83,4 @@ class TagBindingWrapper implements Binding { public Class getBoundNodeType() { return Element.class; } - - @Override - public void init() { - } } diff --git a/platform/util/src/com/intellij/util/xmlb/TextBinding.java b/platform/util/src/com/intellij/util/xmlb/TextBinding.java index 5cfaad76594d..ae9192bb3a0c 100644 --- a/platform/util/src/com/intellij/util/xmlb/TextBinding.java +++ b/platform/util/src/com/intellij/util/xmlb/TextBinding.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.intellij.util.xmlb; import org.jdom.Content; @@ -21,12 +20,11 @@ import org.jdom.Text; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -public class TextBinding implements Binding { - private final Accessor myAccessor; +public class TextBinding extends Binding { private volatile Binding myBinding; - public TextBinding(final Accessor accessor) { - myAccessor = accessor; + public TextBinding(@NotNull Accessor accessor) { + super(accessor); } @Nullable diff --git a/platform/util/src/com/intellij/util/xmlb/XmlSerializerImpl.java b/platform/util/src/com/intellij/util/xmlb/XmlSerializerImpl.java index fafaaaa93442..0f7c1fc2ba4b 100644 --- a/platform/util/src/com/intellij/util/xmlb/XmlSerializerImpl.java +++ b/platform/util/src/com/intellij/util/xmlb/XmlSerializerImpl.java @@ -87,6 +87,7 @@ class XmlSerializerImpl { return _getClassBinding(aClass, type, accessor); } + @NotNull private static synchronized Binding _getClassBinding(@NotNull Class aClass, @NotNull Type originalType, @Nullable Accessor accessor) { Pair key = Pair.create(originalType, accessor); Map, Binding> map = getBindingCacheMap(); @@ -109,26 +110,42 @@ class XmlSerializerImpl { return map; } + @NotNull private static Binding _getNonCachedClassBinding(@NotNull Class aClass, @Nullable Accessor accessor, @NotNull Type originalType) { - if (aClass.isPrimitive()) return new PrimitiveValueBinding(aClass); + if (aClass.isPrimitive()) { + return new PrimitiveValueBinding(aClass, accessor); + } if (aClass.isArray()) { return Element.class.isAssignableFrom(aClass.getComponentType()) ? new JDOMElementBinding(accessor) : new ArrayBinding(aClass, accessor); } - if (Number.class.isAssignableFrom(aClass)) return new PrimitiveValueBinding(aClass); - if (Boolean.class.isAssignableFrom(aClass)) return new PrimitiveValueBinding(aClass); - if (String.class.isAssignableFrom(aClass)) return new PrimitiveValueBinding(aClass); + if (Number.class.isAssignableFrom(aClass)) { + return new PrimitiveValueBinding(aClass, accessor); + } + if (Boolean.class.isAssignableFrom(aClass)) { + return new PrimitiveValueBinding(aClass, accessor); + } + if (String.class.isAssignableFrom(aClass)) { + return new PrimitiveValueBinding(aClass, accessor); + } if (Collection.class.isAssignableFrom(aClass) && originalType instanceof ParameterizedType) { return new CollectionBinding((ParameterizedType)originalType, accessor); } - if (Map.class.isAssignableFrom(aClass) && originalType instanceof ParameterizedType) { - return new MapBinding((ParameterizedType)originalType, accessor); + if (accessor != null) { + if (Map.class.isAssignableFrom(aClass) && originalType instanceof ParameterizedType) { + return new MapBinding((ParameterizedType)originalType, accessor); + } + if (Element.class.isAssignableFrom(aClass)) { + return new JDOMElementBinding(accessor); + } } - if (Element.class.isAssignableFrom(aClass)) return new JDOMElementBinding(accessor); - if (Date.class.isAssignableFrom(aClass)) return new DateBinding(); - if (aClass.isEnum()) return new PrimitiveValueBinding(aClass); - - return new BeanBinding(aClass); + if (Date.class.isAssignableFrom(aClass)) { + return new DateBinding(accessor); + } + if (aClass.isEnum()) { + return new PrimitiveValueBinding(aClass, accessor); + } + return new BeanBinding(aClass, accessor); } @Nullable From 56120974c03f3a702d44e2cdccd20f8190dee02e Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Thu, 6 Nov 2014 14:15:14 +0300 Subject: [PATCH 64/84] IDEA-128150 When inspections are disabled for a file, the 'eye' is not updated - without any indication why (looks like a broken) --- .../options/colors/FontEditorPreview.java | 5 +- .../daemon/impl/TrafficLightRenderer.java | 244 ++++++++++++++---- .../daemon/impl/TrafficProgressPanel.java | 211 +++++++-------- .../impl/TrafficTooltipRendererImpl.java | 8 +- .../highlighting/DomElementsErrorPanel.java | 18 +- 5 files changed, 299 insertions(+), 187 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/application/options/colors/FontEditorPreview.java b/platform/lang-impl/src/com/intellij/application/options/colors/FontEditorPreview.java index ddd24150b395..c0587f1fea0a 100644 --- a/platform/lang-impl/src/com/intellij/application/options/colors/FontEditorPreview.java +++ b/platform/lang-impl/src/com/intellij/application/options/colors/FontEditorPreview.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -66,8 +66,9 @@ public class FontEditorPreview implements PreviewPanel{ static void installTrafficLights(@NotNull EditorEx editor) { TrafficLightRenderer renderer = new TrafficLightRenderer(null, null,null){ + @NotNull @Override - protected DaemonCodeAnalyzerStatus getDaemonCodeAnalyzerStatus(boolean fillErrorsCount, SeverityRegistrar severityRegistrar) { + protected DaemonCodeAnalyzerStatus getDaemonCodeAnalyzerStatus(@NotNull SeverityRegistrar severityRegistrar) { DaemonCodeAnalyzerStatus status = new DaemonCodeAnalyzerStatus(); status.errorAnalyzingFinished = true; status.errorCount = new int[]{1, 2}; diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/TrafficLightRenderer.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/TrafficLightRenderer.java index c67af24d8cdc..84255a5e8729 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/TrafficLightRenderer.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/TrafficLightRenderer.java @@ -18,9 +18,12 @@ package com.intellij.codeInsight.daemon.impl; import com.intellij.codeHighlighting.HighlightDisplayLevel; import com.intellij.codeHighlighting.TextEditorHighlightingPass; +import com.intellij.codeInsight.daemon.DaemonBundle; import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer; -import com.intellij.codeInsight.daemon.impl.analysis.HighlightingLevelManager; +import com.intellij.codeInsight.daemon.impl.analysis.FileHighlightingSetting; +import com.intellij.codeInsight.daemon.impl.analysis.HighlightingSettingsPerFile; import com.intellij.icons.AllIcons; +import com.intellij.ide.PowerSaveMode; import com.intellij.lang.Language; import com.intellij.lang.annotation.HighlightSeverity; import com.intellij.openapi.Disposable; @@ -35,14 +38,22 @@ import com.intellij.openapi.editor.impl.EditorMarkupModelImpl; import com.intellij.openapi.editor.impl.event.MarkupModelListener; import com.intellij.openapi.editor.markup.ErrorStripeRenderer; import com.intellij.openapi.editor.markup.RangeHighlighter; +import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Disposer; +import com.intellij.openapi.util.Pair; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.FileViewProvider; +import com.intellij.psi.PsiCompiledElement; import com.intellij.psi.PsiFile; import com.intellij.ui.LayeredIcon; import com.intellij.util.ArrayUtil; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.containers.HashMap; +import com.intellij.util.io.storage.HeavyProcessLatch; import com.intellij.util.ui.UIUtil; +import com.intellij.xml.util.XmlStringUtil; import gnu.trove.TIntArrayList; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -50,20 +61,27 @@ import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.awt.*; -import java.util.ArrayList; -import java.util.Collections; +import java.util.*; import java.util.List; -import java.util.Set; public class TrafficLightRenderer implements ErrorStripeRenderer, Disposable { private static final Icon NO_ANALYSIS_ICON = AllIcons.General.NoAnalysis; - private static final Icon STARING_EYE_ICON = AllIcons.General.InspectionInProgress; private final Project myProject; private final Document myDocument; private final PsiFile myFile; private final DaemonCodeAnalyzerImpl myDaemonCodeAnalyzer; private final SeverityRegistrar mySeverityRegistrar; + Icon icon; + String statistics; + String statusLabel; + String statusExtraLine; + boolean passStatusesVisible; + final Map> passes = ContainerUtil.newLinkedHashMap(); + final Map myProgressToText = new HashMap(); + static final int MAX = 100; + boolean progressBarsEnabled; + Boolean progressBarsCompleted; /** * array filled with number of highlighters with a given severity. @@ -131,8 +149,12 @@ public class TrafficLightRenderer implements ErrorStripeRenderer, Disposable { Disposer.dispose(tlr); } renderer = new TrafficLightRenderer(project, document, file); - Disposer.register(((EditorImpl)editorMarkupModel.getEditor()).getDisposable(), (Disposable)renderer); - editorMarkupModel.setErrorStripeRenderer(renderer); + EditorImpl editor = (EditorImpl)editorMarkupModel.getEditor(); + + if (!editor.isDisposed()) { + Disposer.register(editor.getDisposable(), (Disposable)renderer); + editorMarkupModel.setErrorStripeRenderer(renderer); + } } @Override @@ -153,10 +175,9 @@ public class TrafficLightRenderer implements ErrorStripeRenderer, Disposable { public static class DaemonCodeAnalyzerStatus { public boolean errorAnalyzingFinished; // all passes done public List passStati = Collections.emptyList(); - public String[/*rootsNumber*/] noHighlightingRoots; - public String[/*rootsNumber*/] noInspectionRoots; public int[] errorCount = ArrayUtil.EMPTY_INT_ARRAY; - public boolean enabled = true; + public String reasonWhyDisabled; + public String reasonWhySuspended; public int rootsNumber; @Override @@ -171,30 +192,65 @@ public class TrafficLightRenderer implements ErrorStripeRenderer, Disposable { } } - @Nullable - protected DaemonCodeAnalyzerStatus getDaemonCodeAnalyzerStatus(boolean fillErrorsCount, SeverityRegistrar severityRegistrar) { - if (myFile == null || myProject != null && myProject.isDisposed() || !myDaemonCodeAnalyzer.isHighlightingAvailable(myFile)) return null; + @NotNull + protected DaemonCodeAnalyzerStatus getDaemonCodeAnalyzerStatus(@NotNull SeverityRegistrar severityRegistrar) { + DaemonCodeAnalyzerStatus status = new DaemonCodeAnalyzerStatus(); + if (myFile == null) { + status.reasonWhyDisabled = "No file"; + status.errorAnalyzingFinished = true; + return status; + } + if (myProject != null && myProject.isDisposed()) { + status.reasonWhyDisabled = "Project is disposed"; + status.errorAnalyzingFinished = true; + return status; + } + if (!myDaemonCodeAnalyzer.isHighlightingAvailable(myFile)) { + if (!myFile.isPhysical()) { + status.reasonWhyDisabled = "File is generated"; + status.errorAnalyzingFinished = true; + return status; + } + else if (myFile instanceof PsiCompiledElement) { + status.reasonWhyDisabled = "File is decompiled"; + status.errorAnalyzingFinished = true; + return status; + } + final FileType fileType = myFile.getFileType(); + if (fileType.isBinary()) { + status.reasonWhyDisabled = "File is binary"; + status.errorAnalyzingFinished = true; + return status; + } + status.reasonWhyDisabled = "Highlighting is disabled for this file"; + status.errorAnalyzingFinished = true; + return status; + } - List noInspectionRoots = new ArrayList(); - List noHighlightingRoots = new ArrayList(); FileViewProvider provider = myFile.getViewProvider(); Set languages = provider.getLanguages(); + HighlightingSettingsPerFile levelSettings = HighlightingSettingsPerFile.getInstance(myProject); + boolean shouldHighlight = languages.isEmpty(); for (Language language : languages) { PsiFile root = provider.getPsi(language); - if (!HighlightingLevelManager.getInstance(myProject).shouldHighlight(root)) { - noHighlightingRoots.add(language.getID()); - } - else if (!HighlightingLevelManager.getInstance(myProject).shouldInspect(root)) { - noInspectionRoots.add(language.getID()); - } + FileHighlightingSetting level = levelSettings.getHighlightingSettingForRoot(root); + shouldHighlight |= level != FileHighlightingSetting.SKIP_HIGHLIGHTING; + } + if (!shouldHighlight) { + status.reasonWhyDisabled = "Highlighting level is None"; + status.errorAnalyzingFinished = true; + return status; + } + + if (HeavyProcessLatch.INSTANCE.isRunning()) { + status.reasonWhySuspended = StringUtil.defaultIfEmpty(HeavyProcessLatch.INSTANCE.getRunningOperationName(), "Heavy operation is running"); + status.errorAnalyzingFinished = true; + return status; } - DaemonCodeAnalyzerStatus status = new DaemonCodeAnalyzerStatus(); - status.noInspectionRoots = noInspectionRoots.isEmpty() ? null : ArrayUtil.toStringArray(noInspectionRoots); - status.noHighlightingRoots = noHighlightingRoots.isEmpty() ? null : ArrayUtil.toStringArray(noHighlightingRoots); status.errorCount = errorCount.clone(); status.rootsNumber = languages.size(); - fillDaemonCodeAnalyzerErrorsStatus(status, fillErrorsCount, severityRegistrar); + fillDaemonCodeAnalyzerErrorsStatus(status, severityRegistrar); List passes = myDaemonCodeAnalyzer.getPassesToShowProgressFor(myDocument); status.passStati = passes.isEmpty() ? Collections.emptyList() : new ArrayList(passes.size()); @@ -208,14 +264,13 @@ public class TrafficLightRenderer implements ErrorStripeRenderer, Disposable { status.passStati.add(pass); } status.errorAnalyzingFinished = myDaemonCodeAnalyzer.isAllAnalysisFinished(myFile); - status.enabled = myDaemonCodeAnalyzer.isUpdateByTimerEnabled(); + status.reasonWhySuspended = myDaemonCodeAnalyzer.isUpdateByTimerEnabled() ? null : "Highlighting is paused temporarily"; return status; } - protected void fillDaemonCodeAnalyzerErrorsStatus(final DaemonCodeAnalyzerStatus status, - final boolean fillErrorsCount, - final SeverityRegistrar severityRegistrar) { + protected void fillDaemonCodeAnalyzerErrorsStatus(@NotNull DaemonCodeAnalyzerStatus status, + @NotNull SeverityRegistrar severityRegistrar) { } public final Project getProject() { @@ -230,7 +285,7 @@ public class TrafficLightRenderer implements ErrorStripeRenderer, Disposable { @Override public void paint(Component c, Graphics g, Rectangle r) { - DaemonCodeAnalyzerStatus status = getDaemonCodeAnalyzerStatus(false, mySeverityRegistrar); + DaemonCodeAnalyzerStatus status = getDaemonCodeAnalyzerStatus(mySeverityRegistrar); Icon icon = getIcon(status); int height = icon.getIconHeight(); @@ -240,32 +295,17 @@ public class TrafficLightRenderer implements ErrorStripeRenderer, Disposable { icon.paintIcon(c, g, x, y); } + @NotNull private Icon getIcon(DaemonCodeAnalyzerStatus status) { - if (status == null || status.noHighlightingRoots != null && status.noHighlightingRoots.length == status.rootsNumber) { - return NO_ANALYSIS_ICON; - } - - Icon icon = HighlightDisplayLevel.DO_NOT_SHOW.getIcon(); - for (int i = status.errorCount.length - 1; i >= 0; i--) { - if (status.errorCount[i] != 0) { - icon = mySeverityRegistrar.getRendererIconByIndex(i); - break; - } - } - - if (status.errorAnalyzingFinished) { - if (myProject != null && DumbService.isDumb(myProject)) { - return new LayeredIcon(NO_ANALYSIS_ICON, icon, STARING_EYE_ICON); - } - + updatePanel(status, getProject()); + Icon icon = this.icon; + if (PowerSaveMode.isEnabled() || status.reasonWhySuspended != null || status.reasonWhyDisabled != null) { return icon; } - if (!status.enabled) return NO_ANALYSIS_ICON; - double progress = getOverallProgress(status); TruncatingIcon trunc = new TruncatingIcon(icon, icon.getIconWidth(), (int)(icon.getIconHeight() * progress)); - return new LayeredIcon(NO_ANALYSIS_ICON, trunc, STARING_EYE_ICON); + return new LayeredIcon(NO_ANALYSIS_ICON, trunc); } private static double getOverallProgress(DaemonCodeAnalyzerStatus status) { @@ -277,4 +317,108 @@ public class TrafficLightRenderer implements ErrorStripeRenderer, Disposable { } return limit == 0 ? status.errorAnalyzingFinished ? 1 : 0 : advancement * 1.0 / limit; } + + // return true if panel needs to be rebuilt + boolean updatePanel(@NotNull DaemonCodeAnalyzerStatus status, Project project) { + progressBarsEnabled = false; + progressBarsCompleted = null; + statistics = ""; + passStatusesVisible = (false); + statusLabel = null; + statusExtraLine = null; + + boolean result = false; + if (!status.passStati.equals(new ArrayList(passes.keySet()))) { + // passes set has changed + rebuildPassesMap(status); + result = true; + } + + if (PowerSaveMode.isEnabled()) { + statusLabel = "Code analysis is disabled in power save mode"; + status.errorAnalyzingFinished = true; + icon = AllIcons.Nodes.Plugin; + return result; + } + if (status.reasonWhyDisabled != null) { + statusLabel = "No analysis has been performed"; + statusExtraLine = "(" + status.reasonWhyDisabled + ")"; + passStatusesVisible = (true); + progressBarsCompleted = Boolean.FALSE; + icon = AllIcons.General.NoAnalysis; + return result; + } + if (status.reasonWhySuspended != null) { + statusLabel = "Code analysis has been suspended"; + statusExtraLine = "(" + status.reasonWhySuspended + ")"; + passStatusesVisible = (true); + progressBarsCompleted = Boolean.FALSE; + icon = AllIcons.Actions.Pause; + return result; + } + + Icon icon = HighlightDisplayLevel.DO_NOT_SHOW.getIcon(); + for (int i = status.errorCount.length - 1; i >= 0; i--) { + if (status.errorCount[i] != 0) { + icon = SeverityRegistrar.getSeverityRegistrar(project).getRendererIconByIndex(i); + break; + } + } + + if (status.errorAnalyzingFinished) { + boolean isDumb = DumbService.isDumb(project); + if (isDumb) { + statusLabel = "Shallow analysis completed"; + statusExtraLine = "Complete results will be available after indexing"; + } + else { + statusLabel = DaemonBundle.message("analysis.completed"); + } + progressBarsCompleted = Boolean.TRUE; + } + else { + statusLabel = DaemonBundle.message("performing.code.analysis"); + passStatusesVisible = true; + progressBarsEnabled = true; + progressBarsCompleted = null; + } + + int currentSeverityErrors = 0; + @org.intellij.lang.annotations.Language("HTML") + String text = ""; + for (int i = status.errorCount.length - 1; i >= 0; i--) { + if (status.errorCount[i] > 0) { + final HighlightSeverity severity = SeverityRegistrar.getSeverityRegistrar(project).getSeverityByIndex(i); + String name = + status.errorCount[i] > 1 ? StringUtil.pluralize(severity.getName().toLowerCase()) : severity.getName().toLowerCase(); + text += status.errorAnalyzingFinished + ? DaemonBundle.message("errors.found", status.errorCount[i], name) + : DaemonBundle.message("errors.found.so.far", status.errorCount[i], name); + text += "
"; + currentSeverityErrors += status.errorCount[i]; + } + } + if (currentSeverityErrors == 0) { + text += status.errorAnalyzingFinished + ? DaemonBundle.message("no.errors.or.warnings.found") + : DaemonBundle.message("no.errors.or.warnings.found.so.far") + "
"; + } + statistics = XmlStringUtil.wrapInHtml(text); + + this.icon = icon; + return result; + } + + private void rebuildPassesMap(@NotNull DaemonCodeAnalyzerStatus status) { + passes.clear(); + for (ProgressableTextEditorHighlightingPass pass : status.passStati) { + JProgressBar progressBar = new JProgressBar(0, MAX); + progressBar.setMaximum(TrafficLightRenderer.MAX); + progressBar.putClientProperty("JComponent.sizeVariant", "mini"); + JLabel percLabel = new JLabel(); + percLabel.setText(TrafficProgressPanel.MAX_TEXT); + passes.put(pass, Pair.create(progressBar, percLabel)); + myProgressToText.put(progressBar, percLabel); + } + } } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/TrafficProgressPanel.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/TrafficProgressPanel.java index 74cfdd9f434e..aec39b1fb83e 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/TrafficProgressPanel.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/TrafficProgressPanel.java @@ -16,11 +16,8 @@ package com.intellij.codeInsight.daemon.impl; import com.intellij.codeInsight.daemon.DaemonBundle; -import com.intellij.ide.PowerSaveMode; -import com.intellij.lang.annotation.HighlightSeverity; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.progress.ProgressIndicator; -import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.TextRange; @@ -32,10 +29,7 @@ import com.intellij.ui.components.panels.NonOpaquePanel; import com.intellij.ui.components.panels.VerticalBox; import com.intellij.ui.components.panels.Wrapper; import com.intellij.util.containers.HashMap; -import com.intellij.util.containers.hash.LinkedHashMap; import com.intellij.util.ui.AwtVisitor; -import com.intellij.xml.util.XmlStringUtil; -import org.intellij.lang.annotations.Language; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -48,16 +42,14 @@ import java.util.Map; * User: cdr */ public class TrafficProgressPanel extends JPanel { - private static final int MAX = 100; - private static final String MAX_TEXT = "100%"; + static final String MAX_TEXT = "100%"; private static final String MIN_TEXT = "0%"; private final JLabel statistics = new JLabel(); - private final Map> passes = new LinkedHashMap>(); private final Map myProgressToText = new HashMap(); private final JLabel statusLabel = new JLabel(); - private final JLabel dumbLabel = new JLabel("Complete results will be available after indexing"); + private final JLabel statusExtraLineLabel = new JLabel(); @NotNull private final TrafficLightRenderer myTrafficLightRenderer; private final JPanel myPassStatuses = new JPanel(); @@ -73,10 +65,10 @@ public class TrafficProgressPanel extends JPanel { setLayout(new BorderLayout()); VerticalBox center = new VerticalBox(); - add(center, BorderLayout.NORTH); + add(center, BorderLayout.NORTH); center.add(statusLabel); - center.add(dumbLabel); + center.add(statusExtraLineLabel); center.add(new Separator()); center.add(Box.createVerticalStrut(6)); @@ -98,19 +90,46 @@ public class TrafficProgressPanel extends JPanel { } }); } - rebuildPassesPanel(fakeStatusLargeEnough); - for (Pair pair : passes.values()) { - JProgressBar bar = pair.first; - bar.setMaximum(MAX); - JLabel label = pair.second; - label.setText(MAX_TEXT); - } center.add(myPassStatusesContainer); add(statistics, BorderLayout.SOUTH); updatePanel(fakeStatusLargeEnough, true); hintHint.initStyle(this, true); + statusLabel.setFont(statusLabel.getFont().deriveFont(Font.BOLD)); + } + + public int getMinWidth() { + return Math.max(Math.max(Math.max(getLabelMinWidth(statistics), getLabelMinWidth(statusExtraLineLabel)), getLabelMinWidth(statusLabel)), getLabelMinWidth(new JLabel("Slow inspections progress report long line"))); + } + + private int getLabelMinWidth(@NotNull JLabel label) { + String text = label.getText(); + Icon icon = label.isEnabled() ? label.getIcon() : label.getDisabledIcon(); + + if ((icon == null) && (StringUtil.isEmpty(text))) { + return 0; + } + + Rectangle paintIconR = new Rectangle(); + Rectangle paintTextR = new Rectangle(); + Rectangle paintViewR = new Rectangle(10000, 10000); + + SwingUtilities.layoutCompoundLabel( + label, + getFontMetrics(getFont()), + text, + icon, + label.getVerticalAlignment(), + label.getHorizontalAlignment(), + label.getVerticalTextPosition(), + label.getHorizontalTextPosition(), + paintViewR, + paintIconR, + paintTextR, + label.getIconTextGap()); + + return paintTextR.width; } private class Separator extends NonOpaquePanel { @@ -137,115 +156,34 @@ public class TrafficProgressPanel extends JPanel { } } - private void rebuildPassesPanel(@Nullable TrafficLightRenderer.DaemonCodeAnalyzerStatus status) { - myPassStatuses.removeAll(); - myPassStatuses.setLayout(new GridBagLayout()); - passes.clear(); - GridBagConstraints c = new GridBagConstraints(); - c.gridy = 0; - c.fill = GridBagConstraints.HORIZONTAL; - if (status != null) { - for (ProgressableTextEditorHighlightingPass pass : status.passStati) { - JLabel label = new JLabel(pass.getPresentableName() + ": "); - label.setHorizontalTextPosition(SwingConstants.RIGHT); - - JProgressBar progressBar = new JProgressBar(0, MAX); - progressBar.putClientProperty("JComponent.sizeVariant", "mini"); - JLabel percLabel = new JLabel(); - passes.put(pass, Pair.create(progressBar, percLabel)); - myProgressToText.put(progressBar, percLabel); - c.gridx = 0; - myPassStatuses.add(label, c); - c.gridx = 1; - myPassStatuses.add(progressBar, c); - c.gridx = 2; - c.weightx = 1; - myPassStatuses.add(percLabel, c); - - c.gridy++; - } - } - - myHintHint.initStyle(myPassStatuses, true); - statusLabel.setFont(statusLabel.getFont().deriveFont(Font.BOLD)); - } - - public void updatePanel(@Nullable TrafficLightRenderer.DaemonCodeAnalyzerStatus status, boolean isFake) { - boolean isDumb = DumbService.isDumb(myTrafficLightRenderer.getProject()); - dumbLabel.setVisible(isDumb); + public void updatePanel(@NotNull TrafficLightRenderer.DaemonCodeAnalyzerStatus status, boolean isFake) { try { - if (PowerSaveMode.isEnabled()) { - statusLabel.setText("Code analysis is disabled in power save mode"); - myPassStatuses.setVisible(false); - statistics.setText(""); - } - else if (status == null || status.noHighlightingRoots != null && status.noHighlightingRoots.length == status.rootsNumber) { - statusLabel.setText(DaemonBundle.message("analysis.hasnot.been.run")); - myPassStatuses.setVisible(true); - setPassesEnabled(false, Boolean.FALSE); - statistics.setText(""); - } - else if (status.errorAnalyzingFinished) { - if (isDumb) { - statusLabel.setText("Shallow analysis completed"); - } - else { - statusLabel.setText(DaemonBundle.message("analysis.completed")); - } - myPassStatuses.setVisible(true); - setPassesEnabled(false, Boolean.TRUE); - } - else if (!status.enabled) { - statusLabel.setText("Code analysis has been suspended"); - myPassStatuses.setVisible(true); - setPassesEnabled(false, Boolean.FALSE); - statistics.setText(""); + boolean needRebuild = myTrafficLightRenderer.updatePanel(status, myTrafficLightRenderer.getProject()); + statusLabel.setText(myTrafficLightRenderer.statusLabel); + if (myTrafficLightRenderer.statusExtraLine == null) { + statusExtraLineLabel.setVisible(false); } else { - statusLabel.setText(DaemonBundle.message("performing.code.analysis")); - myPassStatuses.setVisible(true); - setPassesEnabled(true, null); + statusExtraLineLabel.setText(myTrafficLightRenderer.statusExtraLine); + statusExtraLineLabel.setVisible(true); } + myPassStatuses.setVisible(myTrafficLightRenderer.passStatusesVisible); + statistics.setText(myTrafficLightRenderer.statistics); + resetProgressBars(myTrafficLightRenderer.progressBarsEnabled, myTrafficLightRenderer.progressBarsCompleted); - - if (status == null || - !status.passStati.equals(new ArrayList(passes.keySet()))) { + if (needRebuild) { // passes set has changed - rebuildPassesPanel(status); + rebuildPassesProgress(status); } - if (status != null) { - for (ProgressableTextEditorHighlightingPass pass : status.passStati) { - double progress = pass.getProgress(); - Pair pair = passes.get(pass); - JProgressBar progressBar = pair.first; - int percent = (int)Math.round(progress * MAX); - progressBar.setValue(percent); - JLabel percentage = pair.second; - percentage.setText(percent + "%"); - } - - int currentSeverityErrors = 0; - @Language("HTML") - String text = ""; - for (int i = status.errorCount.length - 1; i >= 0; i--) { - if (status.errorCount[i] > 0) { - final HighlightSeverity severity = SeverityRegistrar.getSeverityRegistrar(myTrafficLightRenderer.getProject()).getSeverityByIndex(i); - String name = - status.errorCount[i] > 1 ? StringUtil.pluralize(severity.getName().toLowerCase()) : severity.getName().toLowerCase(); - text += status.errorAnalyzingFinished - ? DaemonBundle.message("errors.found", status.errorCount[i], name) - : DaemonBundle.message("errors.found.so.far", status.errorCount[i], name); - text += "
"; - currentSeverityErrors += status.errorCount[i]; - } - } - if (currentSeverityErrors == 0) { - text += status.errorAnalyzingFinished - ? DaemonBundle.message("no.errors.or.warnings.found") - : DaemonBundle.message("no.errors.or.warnings.found.so.far") + "
"; - } - statistics.setText(XmlStringUtil.wrapInHtml(text)); + for (ProgressableTextEditorHighlightingPass pass : status.passStati) { + double progress = pass.getProgress(); + Pair pair = myTrafficLightRenderer.passes.get(pass); + JProgressBar progressBar = pair.first; + int percent = (int)Math.round(progress * TrafficLightRenderer.MAX); + progressBar.setValue(percent); + JLabel percentage = pair.second; + percentage.setText(percent + "%"); } } finally { @@ -259,7 +197,7 @@ public class TrafficProgressPanel extends JPanel { } } - private void setPassesEnabled(final boolean enabled, @Nullable final Boolean completed) { + private void resetProgressBars(final boolean enabled, @Nullable final Boolean completed) { new AwtVisitor(myPassStatuses) { @Override public boolean visit(Component component) { @@ -268,7 +206,7 @@ public class TrafficProgressPanel extends JPanel { progress.setEnabled(enabled); if (completed != null) { if (completed) { - progress.setValue(MAX); + progress.setValue(TrafficLightRenderer.MAX); myProgressToText.get(progress).setText(MAX_TEXT); } else { @@ -281,4 +219,33 @@ public class TrafficProgressPanel extends JPanel { } }; } + + private void rebuildPassesProgress(@NotNull TrafficLightRenderer.DaemonCodeAnalyzerStatus status) { + myPassStatuses.removeAll(); + myPassStatuses.setLayout(new GridBagLayout()); + GridBagConstraints c = new GridBagConstraints(); + c.gridy = 0; + c.fill = GridBagConstraints.HORIZONTAL; + for (ProgressableTextEditorHighlightingPass pass : status.passStati) { + JLabel label = new JLabel(pass.getPresentableName() + ": "); + label.setHorizontalTextPosition(SwingConstants.RIGHT); + + Pair pair = myTrafficLightRenderer.passes.get(pass); + JProgressBar progressBar = pair.getFirst(); + progressBar.putClientProperty("JComponent.sizeVariant", "mini"); + JLabel percLabel = pair.getSecond(); + myProgressToText.put(progressBar, percLabel); + c.gridx = 0; + myPassStatuses.add(label, c); + c.gridx = 1; + myPassStatuses.add(progressBar, c); + c.gridx = 2; + c.weightx = 1; + myPassStatuses.add(percLabel, c); + + c.gridy++; + } + + myHintHint.initStyle(myPassStatuses, true); + } } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/TrafficTooltipRendererImpl.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/TrafficTooltipRendererImpl.java index 22eebb5e880d..55bf221973df 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/TrafficTooltipRendererImpl.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/TrafficTooltipRendererImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2010 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -48,7 +48,7 @@ public class TrafficTooltipRendererImpl extends ComparableObject.Impl implements public void repaintTooltipWindow() { if (myPanel != null) { SeverityRegistrar severityRegistrar = SeverityRegistrar.getSeverityRegistrar(myTrafficLightRenderer.getProject()); - TrafficLightRenderer.DaemonCodeAnalyzerStatus status = myTrafficLightRenderer.getDaemonCodeAnalyzerStatus(true, severityRegistrar); + TrafficLightRenderer.DaemonCodeAnalyzerStatus status = myTrafficLightRenderer.getDaemonCodeAnalyzerStatus(severityRegistrar); myPanel.updatePanel(status, false); } } @@ -57,7 +57,8 @@ public class TrafficTooltipRendererImpl extends ComparableObject.Impl implements public LightweightHint show(@NotNull Editor editor, @NotNull Point p, boolean alignToRight, @NotNull TooltipGroup group, @NotNull HintHint hintHint) { myTrafficLightRenderer = (TrafficLightRenderer)((EditorMarkupModelImpl)editor.getMarkupModel()).getErrorStripeRenderer(); myPanel = new TrafficProgressPanel(myTrafficLightRenderer, editor, hintHint); - LineTooltipRenderer.correctLocation(editor, myPanel, p, alignToRight, false, -1); + repaintTooltipWindow(); + LineTooltipRenderer.correctLocation(editor, myPanel, p, alignToRight, true, myPanel.getMinWidth()); LightweightHint hint = new LightweightHint(myPanel); HintManagerImpl hintManager = (HintManagerImpl)HintManager.getInstance(); @@ -72,7 +73,6 @@ public class TrafficTooltipRendererImpl extends ComparableObject.Impl implements onHide.run(); } }); - repaintTooltipWindow(); return hint; } } diff --git a/xml/dom-impl/src/com/intellij/util/xml/highlighting/DomElementsErrorPanel.java b/xml/dom-impl/src/com/intellij/util/xml/highlighting/DomElementsErrorPanel.java index b4a3502f223a..c147324e75c6 100644 --- a/xml/dom-impl/src/com/intellij/util/xml/highlighting/DomElementsErrorPanel.java +++ b/xml/dom-impl/src/com/intellij/util/xml/highlighting/DomElementsErrorPanel.java @@ -25,7 +25,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.Disposer; import com.intellij.psi.PsiDocumentManager; -import com.intellij.psi.PsiFile; +import com.intellij.psi.xml.XmlFile; import com.intellij.util.Alarm; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.xml.DomChangeAdapter; @@ -34,6 +34,7 @@ import com.intellij.util.xml.DomManager; import com.intellij.util.xml.DomUtil; import com.intellij.util.xml.ui.CommittablePanel; import com.intellij.util.xml.ui.Highlightable; +import org.jetbrains.annotations.NotNull; import javax.swing.*; import java.awt.*; @@ -152,25 +153,24 @@ public class DomElementsErrorPanel extends JPanel implements CommittablePanel, H } private class DomElementsTrafficLightRenderer extends TrafficLightRenderer { - - public DomElementsTrafficLightRenderer(final PsiFile xmlFile) { + public DomElementsTrafficLightRenderer(@NotNull XmlFile xmlFile) { super(xmlFile.getProject(), PsiDocumentManager.getInstance(xmlFile.getProject()).getDocument(xmlFile), xmlFile); } + @NotNull @Override - protected DaemonCodeAnalyzerStatus getDaemonCodeAnalyzerStatus(boolean fillErrorsCount, SeverityRegistrar severityRegistrar) { - final DaemonCodeAnalyzerStatus status = super.getDaemonCodeAnalyzerStatus(fillErrorsCount, severityRegistrar); - if (status != null && isInspectionCompleted()) { + protected DaemonCodeAnalyzerStatus getDaemonCodeAnalyzerStatus(@NotNull SeverityRegistrar severityRegistrar) { + final DaemonCodeAnalyzerStatus status = super.getDaemonCodeAnalyzerStatus(severityRegistrar); + if (isInspectionCompleted()) { status.errorAnalyzingFinished = true; } return status; } @Override - protected void fillDaemonCodeAnalyzerErrorsStatus(DaemonCodeAnalyzerStatus status, - boolean fillErrorsCount, - SeverityRegistrar severityRegistrar) { + protected void fillDaemonCodeAnalyzerErrorsStatus(@NotNull DaemonCodeAnalyzerStatus status, + @NotNull SeverityRegistrar severityRegistrar) { for (int i = 0; i < status.errorCount.length; i++) { final HighlightSeverity minSeverity = severityRegistrar.getSeverityByIndex(i); if (minSeverity == null) { From e3c0f36f5f53a10319dd63fe9f573ee2cf3eeabf Mon Sep 17 00:00:00 2001 From: Nadya Zabrodina Date: Fri, 7 Nov 2014 12:45:51 +0300 Subject: [PATCH 65/84] IDEA-132467 apply target branch modification with Enter or mouse interruption * selection listener from WideSelectionTreeUi modified not to stop edit mode when mouse pressed/release, because BaseTreeUi managed this situation himself according to appropriate flags; (if mouse pressed, then BaseUi starts edit mode, and WideUi stops it immediately - this was strange) * validation added in editor listener --- .../src/com/intellij/dvcs/push/ui/PushLog.java | 12 +++++++++++- .../intellij/util/ui/tree/WideSelectionTreeUI.java | 5 ----- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/PushLog.java b/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/PushLog.java index b91aa17e04d5..2e1713e05c89 100644 --- a/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/PushLog.java +++ b/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/PushLog.java @@ -127,7 +127,15 @@ public class PushLog extends JPanel implements TypeSafeDataProvider { public void editingStopped(ChangeEvent e) { DefaultMutableTreeNode node = (DefaultMutableTreeNode)myTree.getLastSelectedPathComponent(); if (node != null && node instanceof EditableTreeNode) { - ((EditableTreeNode)node).fireOnChange(); + JComponent editedComponent = (JComponent)node.getUserObject(); + InputVerifier verifier = editedComponent.getInputVerifier(); + if (verifier != null && !verifier.verify(editedComponent)) { + // if invalid and interrupted, then revert + ((EditableTreeNode)node).fireOnCancel(); + } + else { + ((EditableTreeNode)node).fireOnChange(); + } } myTree.firePropertyChange(PushLogTreeUtil.EDIT_MODE_PROP, true, false); } @@ -141,6 +149,8 @@ public class PushLog extends JPanel implements TypeSafeDataProvider { myTree.firePropertyChange(PushLogTreeUtil.EDIT_MODE_PROP, true, false); } }); + // complete editing when interrupt + myTree.setInvokesStopCellEditing(true); myTree.setRootVisible(false); TreeUtil.collapseAll(myTree, 1); final VcsBranchEditorListener linkMouseListener = new VcsBranchEditorListener(myTreeCellRenderer); diff --git a/platform/util/src/com/intellij/util/ui/tree/WideSelectionTreeUI.java b/platform/util/src/com/intellij/util/ui/tree/WideSelectionTreeUI.java index 9775ddb01be1..93cdf6a01822 100644 --- a/platform/util/src/com/intellij/util/ui/tree/WideSelectionTreeUI.java +++ b/platform/util/src/com/intellij/util/ui/tree/WideSelectionTreeUI.java @@ -122,11 +122,6 @@ public class WideSelectionTreeUI extends BasicTreeUI { private void handle(MouseEvent e) { final JTree tree = (JTree)e.getSource(); if (SwingUtilities.isLeftMouseButton(e) && !e.isPopupTrigger()) { - // if we can't stop any ongoing editing, do nothing - if (isEditing(tree) && tree.getInvokesStopCellEditing() && !stopEditing(tree)) { - return; - } - final TreePath pressedPath = getClosestPathForLocation(tree, e.getX(), e.getY()); if (pressedPath != null) { Rectangle bounds = getPathBounds(tree, pressedPath); From bdac2ab0af9f82a71383700916667183cfd7bc8e Mon Sep 17 00:00:00 2001 From: Dmitry Avdeev Date: Fri, 7 Nov 2014 13:48:19 +0300 Subject: [PATCH 66/84] IDEA-132507 "Clear Read-Only Status" dialog too wide --- .../openapi/vcs/readOnlyHandler/ReadOnlyStatusDialog.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/vcs/readOnlyHandler/ReadOnlyStatusDialog.java b/platform/platform-impl/src/com/intellij/openapi/vcs/readOnlyHandler/ReadOnlyStatusDialog.java index 84c5d462b803..e5ad2a53fee7 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vcs/readOnlyHandler/ReadOnlyStatusDialog.java +++ b/platform/platform-impl/src/com/intellij/openapi/vcs/readOnlyHandler/ReadOnlyStatusDialog.java @@ -18,6 +18,7 @@ package com.intellij.openapi.vcs.readOnlyHandler; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.registry.Registry; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vcs.VcsBundle; import com.intellij.openapi.vfs.ReadonlyStatusHandler; import com.intellij.ui.CollectionComboBoxModel; @@ -107,11 +108,12 @@ public class ReadOnlyStatusDialog extends OptionsDialog { @Override protected void doCustomize(JList list, String value, int index, boolean selected, boolean hasFocus) { if (value == null) return; + String trimmed = StringUtil.first(value, 50, true); if (value.equals(defaultChangelist)) { - append(value, selected ? SELECTED_BOLD_ATTRIBUTES : BOLD_ATTRIBUTES); + append(trimmed, selected ? SELECTED_BOLD_ATTRIBUTES : BOLD_ATTRIBUTES); } else { - append(value, selected ? SimpleTextAttributes.SELECTED_SIMPLE_CELL_ATTRIBUTES : SimpleTextAttributes.SIMPLE_CELL_ATTRIBUTES); + append(trimmed, selected ? SimpleTextAttributes.SELECTED_SIMPLE_CELL_ATTRIBUTES : SimpleTextAttributes.SIMPLE_CELL_ATTRIBUTES); } } }); From cbd8be4b8eb3298d787af49580d2600639d9095c Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Fri, 7 Nov 2014 11:46:59 +0100 Subject: [PATCH 67/84] conflict resolution: missed null checks for diamonds non-physical static methods (IDEA-132534) --- .../JavaMethodsConflictResolver.java | 5 +++-- .../ResolveConflictDiamonds.java | 19 +++++++++++++++++++ .../daemon/LightAdvHighlightingJdk7Test.java | 1 + 3 files changed, 23 insertions(+), 2 deletions(-) create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/ResolveConflictDiamonds.java diff --git a/java/java-psi-impl/src/com/intellij/psi/scope/conflictResolvers/JavaMethodsConflictResolver.java b/java/java-psi-impl/src/com/intellij/psi/scope/conflictResolvers/JavaMethodsConflictResolver.java index 3318d15b747a..dd171de90d18 100644 --- a/java/java-psi-impl/src/com/intellij/psi/scope/conflictResolvers/JavaMethodsConflictResolver.java +++ b/java/java-psi-impl/src/com/intellij/psi/scope/conflictResolvers/JavaMethodsConflictResolver.java @@ -231,7 +231,8 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{ final PsiMethod method = ((MethodCandidateInfo)conflict).getElement(); for (HierarchicalMethodSignature methodSignature : method.getHierarchicalMethodSignature().getSuperSignatures()) { final PsiMethod superMethod = methodSignature.getMethod(); - if (!CommonClassNames.JAVA_LANG_OBJECT.equals(superMethod.getContainingClass().getQualifiedName())) { + final PsiClass aClass = superMethod.getContainingClass(); + if (aClass != null && !CommonClassNames.JAVA_LANG_OBJECT.equals(aClass.getQualifiedName())) { superMethods.add(superMethod); } } @@ -513,7 +514,7 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{ if (varargsPosition) { if (type1 instanceof PsiEllipsisType && type2 instanceof PsiEllipsisType && params1.length == params2.length && - (!JavaVersionService.getInstance().isAtLeast(class1, JavaSdkVersion.JDK_1_7) || ((PsiArrayType)type1).getComponentType().equalsToText(CommonClassNames.JAVA_LANG_OBJECT) || ((PsiArrayType)type2).getComponentType().equalsToText(CommonClassNames.JAVA_LANG_OBJECT))) { + class1 != null && (!JavaVersionService.getInstance().isAtLeast(class1, JavaSdkVersion.JDK_1_7) || ((PsiArrayType)type1).getComponentType().equalsToText(CommonClassNames.JAVA_LANG_OBJECT) || ((PsiArrayType)type2).getComponentType().equalsToText(CommonClassNames.JAVA_LANG_OBJECT))) { type1 = ((PsiEllipsisType)type1).toArrayType(); type2 = ((PsiEllipsisType)type2).toArrayType(); } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/ResolveConflictDiamonds.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/ResolveConflictDiamonds.java new file mode 100644 index 000000000000..a4949425dbd3 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/ResolveConflictDiamonds.java @@ -0,0 +1,19 @@ +class Test { + enum FooBar {Foo, Bar} + + void someMethod() { + new Infer<>((FooBar) null, FooBar.class); + new Infer( (FooBar) null, FooBar.class ); + } + + + public class Infer> { + @SafeVarargs + public Infer(T inst, Class tClass, T... excludes) { + } + + @SafeVarargs + public Infer(String inst, Class tClass, T... excludes) { + } + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/LightAdvHighlightingJdk7Test.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/LightAdvHighlightingJdk7Test.java index e7e236999426..36861062d1a0 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/LightAdvHighlightingJdk7Test.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/LightAdvHighlightingJdk7Test.java @@ -107,6 +107,7 @@ public class LightAdvHighlightingJdk7Test extends LightDaemonAnalyzerTestCase { public void testInnerInTypeArguments() { doTest(false, false); } public void testRawSubstitutor() { doTest(false, false); } public void testIncompleteDiamonds() { doTest(false, false); } + public void testResolveConflictDiamonds() { doTest(false, false); } public void testDynamicallyAddIgnoredAnnotations() { ExtensionPoint point = Extensions.getRootArea().getExtensionPoint(ToolExtensionPoints.DEAD_CODE_TOOL); From d5506ea9fc934ad49091e5676b30af7132eb669c Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Fri, 7 Nov 2014 11:53:47 +0100 Subject: [PATCH 68/84] functional expressions search: merge same files --- .../psi/impl/search/JavaFunctionalExpressionSearcher.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) 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 2652cb3aa51d..8fbe6ef11a5c 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 @@ -106,7 +106,8 @@ public class JavaFunctionalExpressionSearcher implements QueryExecutor processor = new CommonProcessors.CollectProcessor() { + final HashSet files = new HashSet(); + CommonProcessors.CollectProcessor processor = new CommonProcessors.CollectProcessor(files) { @Override protected boolean accept(VirtualFile virtualFile) { return scope.contains(virtualFile) && virtualFile.getFileType() == JavaFileType.INSTANCE && index.isInSource(virtualFile); @@ -116,8 +117,6 @@ public class JavaFunctionalExpressionSearcher implements QueryExecutor", processor); - - Collection files = processor.getResults(); LOG.info("#files: " + files.size()); final PsiManager psiManager = PsiManager.getInstance(project); From d10f2589ccaba11fe95324fd8addf9ddf8d3ed48 Mon Sep 17 00:00:00 2001 From: nik Date: Fri, 7 Nov 2014 14:03:51 +0300 Subject: [PATCH 69/84] size reduced for new icons --- platform/icons/src/Logo_welcomeScreen.png | Bin 2475 -> 2301 bytes platform/icons/src/Logo_welcomeScreen@2x.png | Bin 5145 -> 4623 bytes platform/icons/src/icons/ide/nextStep@2x.png | Bin 504 -> 448 bytes .../icons/src/icons/ide/nextStepGrayed@2x.png | Bin 249 -> 175 bytes .../src/icons/ide/nextStepInverted@2x.png | Bin 235 -> 167 bytes 5 files changed, 0 insertions(+), 0 deletions(-) diff --git a/platform/icons/src/Logo_welcomeScreen.png b/platform/icons/src/Logo_welcomeScreen.png index 9023c4285eba6c94f8b12cd20ecfea7f39451e60..c5dbabdd5f638282ad63c6cab564b36e302c9c8f 100644 GIT binary patch delta 2290 zcmV?a9Ah<}7Q?uko?3-q|ajM~%7 z!5;8Bcn5suQ7(Z5hpYsD1VQjI2!qRD92@}mx)z8ZF9m-BUluf-6WdyYqAD;hws&|F zJ7@I1KHkwE-l85k~vI6tJ_hYfof z7Xkw+eWQP;c7JGpf}|@6M8h9}Gqh*CF3zRE-;)$4+m{j#s0yquY#Kp1Pc9m^cTA`X zTnqkN85no8eSg5%egq_23Y3%TH9r!%Nd+D+K04|uMsf2f#rU(G!2L9I7n3{(0`H&$ z;&zwCu^r&|Gjx2g5;$CrBhXDM@V>l;VOE^{Mq@7AWq&2`@?sml4g|i)9bGj1v7II> zfkvq=HvDP=UoLGOW5wBq-(x$2Rsyg3sd3lTqQY;^Pj&+TQGuf=Cr+igqu#d?c)pw& z#KQtFS22r2#`%wxz_#M%;LR#9q+@i^G-o9+Gw0A*;ise)5mkx;sU0_#r9dh1r9vES z;sV_ZynhS)tGHzhKbT$=RCP`%3Y=ocvK1&LW`K{1FdtS?f*z+*Q6RPB#!?a}B_`69 zNnXP_QPMh&B;x`d3A{n%uV`MRn+)0YXGQMeVUgRQ2iiHM*f~|Sa~M>1C<^SDV#jhU z@CK2$$f~RWm6~{vBvN&As8AG0?YOaA3$zf+VSia>-I=(+xWEM#SV0mPlq(9PcHCHT zfpLLxf!`8XP7)YwQxr(;xUpOd4ELri1$p4t;5o1l>;j2#f!5+yf@W|f()TkF?OzX) zBpXDeZ?nL^T>!gDvKxWhNCJa0MS;|g8_SVE2zeY_jSZ|5;?&(><##fB@*YDh+MWlS z9e)e#m}XHHP!x!E+*ry2A)=9_keu%m_f290Yf0i&Q0hcr8A)JJswj}!abqb7gn&QL z5H-cDa71k2UXmCB89zvY=y)-R&YoQ5Sl-tX*O0`&E6j<8z*3UHphQt1wd2OJ6o?Kl z0dK_y62&Y;aFBE29wmW+X%;2ziUQG&8-L4AU|FPZBU>I3JGq(!UZkC3C$NMhFep|O zNbR_>>;!g2``6&Wu|f-U+JkN8{*VOzHP*jc%nq#3LbNZ51n#pFSlm9%Vr!e4Kx)U0 zWhd~9SU-kezfTL%zC;q(VJ~os#n!e-MS+v-Sat$Mtk0(nDR98%l{2xGBrqs41%G~G zCy?54W7!G(Jl2Z}?Dc6O+H0K7v|Ds)IaOd$+Z2m}7W17IJAs9*lk8Y_0^f@EtP;^4 zpB5q~){(%cEIPFztNyGmfq(OYz_v)w8WBD2(?a-!aTLz7=+yn$hlfQWh8BnXX5+Q9 zpq;>i)(LhjJAp;v6B|Y3n2%5QDu0sqwoRw@Z)qG6R2dxdj~D`9vlWO+<;GIEl$(fj zCyGd?k45;naV7GYO{WI)j*f`}B*r1P$#`?L(@x;eA&?tOMIhZYoe6iMf&xBw95W6c zZ-QH_4j}X;P(ce4W0KQgd{y*2TY=3J>{zOIWA=u-lf+D5rI=~=Iit%sb$|IBY_jRl z-kihd1XTr>tV6@pv2r_s`OV|(SWfN-J`ZMR0;|PLt51zCqw=nREjFFG6}+2=xho%4 z!3Eoj%FolR1s)yO5zEmX=^fycaMxNf(}rqn@qIV#t3|kb1IY`5wF>tEchk|ADuPSy zksx(yS|KI`j26fj^~BtZ3MhJgPoj$m%=qU<8D8#GNmJx5**+lFFWmG$~UBq}>E{vfrP(y5%K>0=cI=YVs=r&a` zc!E9wl_#@NstoF27Jqegj*xTTBM#31LONo*c}u?poTA}KKhCH-^M6ohXqaZ<+%BtO zWX{PnuY1Sk!O5XOetak2iL5X_Zy-rXIuljp1?1un87^L>3u%h4^rg~z@L>iGl|$#e zL!B{n>s-Ez7}Ao1!nbnEj0xIn^2~YfO~tE@1r>OThHW|y27jKxtUP+|o5Xk;%?R!f9ye71C?ZP}09;$}Bxz8gq6TgQ<1b6NT+ko+S9d~q@Z)(DcO$!K%1Bnso7%~|pK!8@FFnh6BNd(A zbYRdmMzxuHk1oXq!Nc=hao@)?ro>B~-&tLB;b6%s$ zl}9VO_-lU!{6@~L2_EAC@Bs-*x!ylnaW{;X55Pm*mCWyvt9p;gRlZ|#EzvLO@(8>~ z)hgGPISL*JsdAZ=1dnr@Jm>5Iqw;oHP(EwkNuwpcmVW$yM&NC}0`rZY%!H?nVHKYy|#65cMo_$KHEbgUHijft5_@Thx+Dm9NrCu6`p6_u>AF@$vekM&!EQp2F(>l1m1hK7Si1l*mNs7|@0?I4@24eMR9Z zS`X%WUo3#QL6qt>eWk)&HJaBhD7i&PrE@+MIB`MQ6`Sy_W*m5-C{@Kg7r`rm&WAy4 z>EUuuz*K7^`_K@;Gkai>=4e`lzV&g7%pp$|T}Nd3V{rhUAg;TSg8eiVzyCIU1__XHvx#b-f-RX?;e||cH>k@ z#d@0WE*YPwzBEy(N8ZnDp`_lN-Fn^vAh>WZvVXGe`zYpqYbv$+7jgY@tyC!p0aCI+X@*0>>z%Wxa9!SN46)T!$V+M>K~}qXSd(k zeSa%AQyiFsU_dTKxXXcE0J|bQt3^05fVJC}$-OH;%Oo@;Ux8lQy_j~b9NE05%Ylu7 zlQ(r&gDzsO4>Eg)jitg2#i8AcFCWH-TR^`8nDwp^c>}x)kv*mL#Fd4@YlDt+fV3V5 z9gJv<9A_Wsz;dN3x8vSj0Q0>qAuvlP!+$CUyo~^5E5PYjY9h9k;LJn7o{W!=0mM`1 z34YT92=J~}YVsNZg}IivcmZ1L(SCgRJwQBZUb-;=?<2^52mo8s8cJ1#8|CHm9RSgp zR~!iNBuMZR=r&C-7Ohso03YIif*79prUOrf$gW^j$sVc-IGDZ-F68;713$}LwSQ6* zQ(cV95`6l=eDVW7EFHJyFiBa49MP$}V>u&ZeMz4;GZ0WchNRQhYN|(N&Rth}Du4^x zFigEMzg1REO3V$~otm@nubIWn8WI0_n*6?Mti1s%ZVbgXFywk92 ziTf}%>^!}4Wb@-O^`EF@y>eE!DZr0j>$oFb_|iWfCN4ZmTnrnPfeg!%NmfiHH#k)Cd@dWCWNc9K_j$!}4V9e}5MhGae*bC+x(J4Gv<*=9vX1`UZJNGiJEJa+qD#nl-A@5z|H$X0->wBw{7plQhWJPDHzCE>uVbtMj{0z}bY z=WuD@6?V%K9cZi=Q~_#p0e`^jeMsiM0Pk;2y7GDL=wmrpa+^&n`F^mnVJL|eZig0( z4e0~KyGXXUy5;Y3@8BNpJ(8%{Pt?;FQfYv=|0ti!0}qnpenxZ}zHf~lgj2p32AHDP-lW@7E-qRJx8-cneOBgGCNLo4|NYf^=%yV2W=vlOZBSx3EEO18 z-``14VpecqhKRy-pc@_64QIZVxF8bW+dIX5GXbESudoGT`ze`mki~6e2HXddY2u@{ zqlS3^P@)KOn8OCvdVeA7NNg?kAhN!j+7Y?#B!KS#od^0FE42g`JKWu4x#d9+*7u&q zYc8HA$oo6}2Ak}2OBO(mYPC+KC z^w&rLbn0%$fWw$y&)eJF*LB|`xcqGkPtP2H0B$j|p8=G!Lw}A^&6_p@dr6Gv3D;fP zN^LWy0|B0FW%vtb3-1)*OuK4N@A%38ji4u5)tzk*XGMo9+e`#Jt^Y;#=Qsd=jgE}Z1au-!8sLGR z!WXB5z6zRbBa_P{b}`v0OH4&k^NXjYxdef(jF<_QTz%9>neP6 z;?z-XV}II&I$vc<|0+{6%lgBco6d!iZp0`(79Lb)kKsiD;PY(DJ2Ez>tL||GzAbhNr%<|@!dKjC(5ZDQiiLQherPioOf;noJ3SQvLF)a zPH~Y6S{Z3y)AnQJ(eCSk%hm?Ye#3L5i^$f4u7C7=Q<9^GgMz2}MSSR*=}=5nh1cS- z?*RP)v`t(j%2zrI^i%ZfUA~E46GYvS;Be>_uq+(70^r>pGh2$c>j3g-3M0~IPHh)@0G}u|V0j57%K!iX07*qoM6N<$f~Go^Z2$lO diff --git a/platform/icons/src/Logo_welcomeScreen@2x.png b/platform/icons/src/Logo_welcomeScreen@2x.png index 2ef76b6c829cc1ebfb75b74e974debdf7538da70..4b3b1d6e7eb3a4116ff42f3fe708fad6b2c42b3b 100644 GIT binary patch literal 4623 zcmZ8lWmJ?;+;tyzsTJu|q&uVqL|oFPmhSGA5|L679~zVf>2fJ4T|iKJkws!j=}?yZ zi_%I-z4+lh=RNO-nLFpqocaCkJ$L5AjWa;qr=nz|ymI9Vl@?On=n{+m4RX@U`PHzy z*p(}^lUnL3Cc(3t`A>XJCs=VpoWe_An_GDupc-5hkk8i~37^Z*4aVhxqe9L)-lYxf z8gq)TWg);!7aK**@>dV$YGN!Bm?3`&*JUS+H=t}Q$tPiT$#dIx4)acY0Hoh`(_!dg z+ji0dC(m~KN&fcXP~fn_#~4SJyDa>IpJ-T^k{uze(J&VaMD!aWVyx?MKvXDhA4f-g zRCMi#d53gNtYFLO$uB1f?3G}KV2WUlBZi}^M>O)}N|1Syk~_!OZoxJv24DryL=w{F zoCsy)6j>Ho>ks0&9my7Sh{_75fP)O@#WZ9XxucVJ(m+oiF5>K_Z+Rg-} z!(LS8B@E5E>e@71_cIgOa^#;URPT{G%Sq^bXI^`3)am1_8`@xt4+5>jX?C25k^wx< z<|fyT5sIzr3XBQyY9TZ`qDAwSqGsbPW0amP&kF^4%w*(fYuA;BZ$V;69xgGvi!Sit zou8<3IoLbIq`K8bx9Y*3j6$9a{ulNzSj>Un*F?6#!n9ug4GoqVt0(*M=x*~CD?3(} zpl9T-57jl_(*w@|IK43B)lPFULiv_(0*X!W2NpD^WIU#WmnD& z3O(4_`0k!A%f?eYxVza5W0*J$Mh9A^8&FJ}Cz`w&Hve^erXSH6*LuN&E46|~QZJxQ z7giHQwLd{y_4lXFUOI;O``c_-A&wj#Do9fof3wQqwE>olE4qT)s+XQFIQ7PT@x6-l z7a@ADDRJCx<6`g)TWBaWg@2Y;`LYXILv}6SNj6{;VHAbndtw9Del6&R#d5#=xfsVp zpgrPfrf@++~+S$R4NFhr~!k>@>>Qbo|%ZkP_XKywc8(n zm-l_fp5F-Z=WoHkTxBc=sTD< z1RZd?Z0cl}E!)$BB*|U-%|80w=Qt3+BYWIjRMoIdJU`4fgmn0FJ8(2%M|z{fv*Vau zl=!TZzzajbC|0ZHOJFmbTSRb~1vUmokpxa|Xo!+$0eLjfDY-iYnIsaS>2%7~Zj+XD zOcLafw6Njsx>JlIQxxovIYNlbr=EUp%dcMo`#he^C3AB^(1AWK>jSwUUr6sfyZInp z9T-L)J0>+8EA6-!$U3HTJ%M!x7Oz|>=~8JD zmeZLv)Az%xjS_&2+bOYqo{-JKJ>BCUTbtPYzB~;VM7M0wiSZs|u+&$XC!rDt%;t2Z z(;Gco(UF_*ymdBD+>N&oAv{Am=(wmV+c^Z(fufx7-v5O!g`k3gg^ILZF*w7?8I@&$ zU`mF$KrH_syae3T9AOD4NIe2UDOvk}u3)(bG@6vzLg&e=NgE;WA={9`D;$vbBrV`R zPKi?i4XO84LF05M1d0AM$*Q{T6y$XKq&}pLB;Met-T_Gm(EhI_TPB*wb&6B+;4yKN zUlCI*0+pn!o7Sme5X6hFqvxr((`Qnr7h#%nYgLO2Wz!m`482`eDtbQD1g8bZ08sc zwWjO!#dv^pH0G0k93jpI2;>F~QLnI>iquBnCBcQ)BxQz?cC64lP6^uh{EJ)kzm7i36yT*CaSH@12-j((v`EveIYAI&otF6@5uU ziw!ma{YOF*$HYa9pso90X2rAEcP%YI5{@*-xf$akEtqz=`5gHDXCvI4Qj{SAonW-8 zt`GFog4`mTTpj7;89v6&FJeiabsvQz5p{5#t#V>3lcI=C#>Cg zW^Hr&C`qBXsUjV!*QPyf_7OluLa3s$=E>!|7)@!&exHbo=LDowlPq=5jT~ZJ*;wclz$BL% zt2Nb5^yXf_UbHTf1nv17rrmz{sJrnM@8Vuf5Z1x>C&`IUm@)b;?09~a`q$f^Q%12m znIOsPdKqV@siux4{)O=0IsJj=KG#&KZh9K@9<~C5`}E@mQJEb`B)c>~>2LJ4d9JBM zK*s#4M2-&6xnTy>7JQ@KPDynVCejW4(|^|mdc)X3uhXOsEWekBuBeR4A>6v1qr?5( zm~zki!^*SCRdM+SU`;xuWMUulUOjAdly(OY1KvI0q|IdhkA%rmZ?U;5er+i>D4j}z z?B3epgool=zc(|dlL)a%#5roRu!m5D+HSSd^F!N*VTmk1cTT*hgQzca+DJp>sq?*Hhjrv1-muI?E|}Uj&I4 z22MAbQz?H@;fSMj#tehkW$=QqY605ZshD*8Yo~*i6>?W4bEfPb+_;63N@Uh-Mi~OJ zw@1)+3yWSqB5)pjCabf3NkP#K8BQq~)`SpC^W?)V2E;Zdg$Kdph*1 zZZcUG$JUyT$IcF+rq1#nA)>3-on#Yp5P^@63g_zb@I2p!6TNJKL_RuqgZDo_cMbGF zI-tURg4Fdo!9H!w=$fVZ6B8 zVP+G5mT(c=JjKNe$IY-CB$vOd?|GpCiyZRA43$tQGv#bze#oL~mz8i9bs0kCP za4#lIbV%cc@7GlFB-I?We2b8x1&rck&0u)rn)8zIuE=N=C0^$!+5NqnBQdb6ncyc3 zpS{m~ZO*)*1m-Hdad!LT&DSXm$(pUT+?)r$DL0qmtf)QG3`IQEB5Jk|C4Jk=0lGMa z0iZyn&~3v&fJJZ@%SymSM#rZRYG${UsR??Q4X;U1#KOrmfglq7ssy!K&VuAy3zcWe z&>?3?8zYTtGi4U3jmXsUAjBu*zXD=$`7>}8x4fsjvK+WL-W$mKXV=&NdZ4Dd{@tUv zo_j7roGG84Gx!Q(kwbm#zeJ5Q5sO7-^j{slnR(&|s%kluzY~}tarmtm@bLzHXJ9s} zY?gNzN*__@_*;gKo-u8sF;nLqwJj?b=j)?32H#k#jRzD09`7wO`cwc6Nz(o2Y^~i< z;Jx%`EX1XtFpI2 z0i-HIcy-YV@g(c;S>`#lnHC?F@Lyv;8DB`;^u@YvT!<}R_+a|tRT?7D1$I5N-= zNDWaO4;`prz3Ck|x55-wG=)m-&%O@nsidw)yQfnh3#FJYGr*L7s^d;fe&6x3lpTxv z<2n&|9IA%y7*OHjOz|^H;?5^OGMA=dNUlw5uT~q()c5K#6Dw`)lTut!$3=(|Sy!zU z!oQnM+%xXWt*QQ*PcFz`I7Z}-*LvC`oAfGf>$SK!Kx%8($hJcv0K7ad`B2)DRm#5N znK?)C)@QPVz#wrnUwW$nIuOLgDXk>D@F;V8Z$DyYjhJH6^leQY_i?wYYssS3ksZEE z-_-Z=uZmt=WiA4VyD9)|F#_UYue!Me3u`)p5L9l(O$YA zl4%S{o8TUouip2)CL>nzkQ5;fwF)1|-;7ZjNdb*MKdl#DpkPkWlaRA^Z0PS>eXJ^4 z=;Ue8)U}!wipSMJ-9YIcLcFD)xs4_dsuSO4Dq2pkwziG0n# zR|nr;2}8CyBb6Io?Ycge*|0yx2-Mju)N$a}-L%fB$MJ6cOYUlVPd_|BpswVG={V^s z-FbXA^lhiK{5yP86LHFCnya@vG@_OHv@Td4`&XxzjP={%gAPA;k^j!}5AmPAWyA@j zhn6Tds4WuSM&vIV#~$)ZD5CJjR}GR(+XnJ$*6#*ZdQ&LMmAO|*pJMeT{YUFpkSVay ziliW$f*;9j?n^UGsC=nk8e3RDVx387Jup!D;Z6W?3bJib zjL-M5GcS+q%J3IF)F?j*%`bO$?Ne*ih>`ZLz2J80@R{zDW#6j^**ASRZ_>RKu+sC> z)a@vu+s}V&b~^OWrn};y)#0vJpGT@9+W=}f$F%j}L8S5h!n>p)Iyb$BFwbR;SH8R6 zZ;~#rRUCiH(eIq~>`16+wo$?UCeHaS8?8pCJ(FC55cP&cwD!hD&3Qo`I_4;-qRvdG z-lH-9U@^oU3m@S;baEjL22`@v1r}hE7)eer^OVfP^V>N)E%t5VDwGj89nV9P55f17TF^D!5ebXrg-{jBBs siho}5ua?Ugr4@vSU1lklD`4?rmb^9I;vi||GU&OYrGZj^r|J;?KRC&Nl>h($ literal 5145 zcmV+!6z1!RP)005u}1^@s6i_d2*0000PbVXQnQ*UN; zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBU_yGcYrRCwC#T?vpJRT+M-yJz;uZW0m# zp~N7F+($ejLJF^dAXWk51qxP>fVX%Rlo&Ny@t`;?5Ii6p1s(w@0XZzdaLO%K6ajBB z9w1lF-OcVC?f<>^dZuU1&d&7obieNTKlrD2lSyCid*A>6@07mp3kD-CIQ$A2Oh5(` zkilRAGMIo2Mw0Ma{o=xvYg+l*5ZPPEUPrb!*-m8hndoifk7P$Bc)i`pjwCyTY%f!8 zgQna@$^L8Z>0z?l$R2O^0&ABq>5PEWs3>06sboix^)Y`s#z+F!D3X1E>=R_KnMPE0 zAlskp-DKyG{ekQvvdhWF5>db@@OH9qksT2HL0`cYMb8nQ;|SN0!Xaa{2DHgOziDd{ zmwFr7g=Bjw5>OcxJ(tRk%FT6zBc-7Kg;e(>M1?-e6<9DGBhn2Nb-7Ii6sJQ}q~cZI1;!>S zVsxS`#!Hn2^y^Q^jy4`}BnbjS?QS636=WOg_s9y&9{Yiq?s}tsVtAk+h9j06hzJ`Q zFN@7%B~kVL6GCz1OWn+Z7n9u!^1;>4o7vCg%LX7_*MfX-wpMwob*P3N3LTrlT6i0snXUGTz{ zYj!Z~R^*#KqfhV63y*~`YC}LLn8Hl`lCC^E{jtE zk#6sdL<8hwWGe2vRL6WpQSiFg91A6!HCPOOJ(p}=ECeL=J2sH-SxmmH;ge(w5U(c@ ztHV1&qzJRg&gz(eL_WCa^K`&j;3k%A0S(A!1Z9`lMF(ms_z|IdR60^X`19S+NI8SE z-K=3L*&L`}pH`(rfMleWoeb&VEvlQrsJ5?#Qp9pbh}^E zmU4!bK%?-1=nhSTfVw+YsqV|k4vwmThofD9)i0AcM!7>Ty+KID`n8XVO29+)iCiwu z>_K(6^`|HveFd-KUZM~XBOcV~2u7xW0y}7u3Zab z!Ts^Q6GnpA!ivd?k3wXQL4-?RjS+|od9Brw!N6o*NFr+REo9~aP9IX6Lh!+ zKaXxLF*~w@8I5IcH>Q)d3&^Tt<0VnyY?zTW0Z9d)5_;mX*fKiKZ;O$*0s(Fsve%STAIu34NpsQu5=Qff;i#2nA7v3Sn<&0|DDZX0C8 zoU*q7jPKu}Qmr2G(&kYyYiK|ec(AIC%`kQ}!NeE?20*h6hF9NMrHpv}rctqZWGl0V zkr)91q{7FMeI1nyNy!FM!>yd0FcKmlfBbuK*($Qb zjC($^>ifG?iHzDYm+gK7V?xZCIVe0E5~^;r!sMKQVYhs{F#zMg_7Qq*ko{u3PTat1 zOP}6Cp#!q|)CJJD^ITaV;ACJl^*tGQ{#hVkiHDqJDhXjQn1Bo>AcJ9T4466iIlG5E zcEvFmOh5(`kilRAGMIo224}&&mNjw~%wRA98B9P1!`2w^(fOxiHKaESz0U|%$HaQm z7se zo?`g-kI~^rWLFXy*RwXT0=7y#xbY7Oy@En*DOM>F}`7d(!R-(z))aC=}KU&)ZA{+^UEO z5=vP$Z^bvigP`N|{Vnv}4eAKO5@s4QKS}3*A8Q0BAybj>6Lffx>~&I>i9jPY(nYC$ zjx#~$*i7fxq{u1saQ@YFoh!%&xv1C$2gE~c_g%8nG;zii`Qie|3?f&n{i0IAJPnDM za$macQRI?eU=N(HB*ck8zSRNw;5OqVU!x*!HEO74)h!~skFGzDHKVs(@OQ}Gjr!$z z8KM*0A`EgzrfUeY3xODU<_-4avq$<^E7k8yKAW_(`jtf zbKDcg7&;iL^>VUxtS9-30k_xXZ11Y~k_hN)5#KH%0sF#qwxLSdc&@YvIBb73>o?wO z`{1>CEheBJ=uH0B4fuZo+ECAUk@7}h_{m)1+f2Y(?y)iA31&8)#y)B9Wd-~%2QVNEB3ivy+ zqt#dZ2|I6H^X7>TPO@`AKpUExLJIg|$LGq37jH(ud-b7UWkljTh2Y1#J2;J+NG~1h zT<}Y*fI{3)HtNg5pinCr*wr5Biy8rM@8C51t2o4Qtf*vuH9iH*{K^Q0WxvPB&l~i& z`YlU-3)+PES6!(i;lLUJt*BHr);z~ah{hG_#mJ&n35YLi72+yNK%z=BGGN``O$4;z z(W-R?{AU~jnE4UWq=LVs!(&2{r*;M`c_Q44>OmV5dY*DrV6>0x+Ok)$iUDhN>1mDu z>sUc{lMe!xqpkZA?;Y2ciTMGk-?JT@=?GN=UDuj;DHH>CPQbjZjzubXGaYUrKShN< zl&<=@R0$k40w2WtN+(gI(DPl?&hB=^6@HKfkC^A{2`Aj@;zU>p>k#4gZKpaJODRmx zbm&&S8NqKKBlYW~x8M-61rCufi2u??weEhOh(%3vl7s{*2$yh*dM>YDwZZwi(k5eA zY_(V$@NzMc@A?j(d#TQT?TP=Y)fxeRCwd4iw?CLdU#a|8-z@D46H#!Nu15*0RAjk> z?6Vy{GuE#@Udg{}PdB4qsS)tEA}$Hc$;t>}5`I~jHDYA{Od*S1jtNO=4pJD(f22V~8aXBBCHWy@QDO20ETBu#B(k%>fz1Ex%0w zw{siWm1y*)^Oa(LPAoBUl2X4y!7g#2N@?Ohgc$e6cG_MdV2Fqh(cvK?;>U#EbOsH+ z=v>g*D%)vt^H8Xr^tRyc0c{wZnbXDH^i0>B_6hoehy{7cae>Y9z$1BK_U}; z$|J_o1bpoeb>iXb%-6E%Vj=f?bKJ_B+blRkSV6V~s%KlX%OnEg<9gA9$TI;yK=#ET z?h_VHJPN7b-9pbo>^XQjeXe6_aUZ!}TLv6VMx{=`Yh%xCn1HF_Sh8#IY#^U&Vce%f zG++2S0U7HC0kaYZ=8b@80=gt1AF^Isiy-8FuM_A|>QM#EOALsLgvRU3!sN3Vp(&V` ziXKKD6!2waKM`g{*DR0^>Sx^VlVrbQ0%jLSldU3~ho%;(8k!yJLm$81_vk4v42z40xgL%J3{jl`Lce;BqR=`d%AoQTu50Whr zx?fijPa5K7Z57ARxW99R9+c7R{IiOHAlUwfY)ed5I~4q7n0Q%)iv9G|%jb;yWpt5% zAk!;^UVjfR6K`G`LgDXb8p8~=J;?Sl$G-4M)X*tM&)v;l-JUY`!xV#&1g_X~1O$oR zXVhyES^GR*c z)xI~_X$nj3Cc3${pVJZ1kT$H0aD^ftln#x+(qXb~3-vCy&x;;f^|V_G2=Za%#wnV* z4im2_`5NYWT*)t_a{_*?PCl38yy=uryFd)HUnY8J=cBF=aN)`|m{+UjSNMVIahx}0 z{wa0b=Ns~+GS|bF7;rk7a#|oC8jLSj=aQ0@Z@L#=kNeIQaZk0(AzBIIzDl-}>U-sw zuQ~bZtDN2~%sMoT4qPy)-%di0KoM%wLiW1TkWalJ>|KHdFw@CW->ZQ`GdNg5c_e9%eGxhXh`f?WZ$!@uzjmEuo8uU2i0Q< zX5eJk`PK`)#p`OzZ~M0vmfPb|6cB!U zmtGY>HP*IXir7F9bCmy@fm=tpJx%rsnQ~K%QNS&t$p(zg6!57)25i}PEGcsu$%i#) z7H5Qf0Uk)Z>_YArJ11145b(ZUbHR94&(Q=Fdhe2t3*Ei8C1a0r^K^xqU=vK!A!*HA zFm~S1dzG%mkB!{h@t8WN^bcDSajd(o$(Dj6|ADk~4R2eR@E~I*Eg`V@0 zm+ex~H+_slPg+U1>_WRyeSf;|P8TNph-{tH=$>*A=aFx6Yve<76Q)fr68YMz_jXjO zN!fhY5#kDz@4Ai%NNyMlDC*5#9GQ7{3s)N=9(oxu*X31Y=Nb2#C*YyKqzXB~vUBU| zhgp;poho3Uf_DYVkyXVjx(*Rf1_kpovIC6EeIduW6*ACYBvp2}hT$Lfk-n-W#hmU7 zq=G0gY<2nq3J^+|1-(=I!zowWK)jzDSNpDvCmHSFG$bY6E<2pxyk|6Doh(|M6Vp;t z5s~oULNC2G4vF=oovqWl>x@X}IApaKGH#No{e<4a>oL(=z$7W`n^);p*&)#hDeP&Y zjcEz(v{l||lw;gALA*`bEba$x)~jc>=()huNbFUN3F1$R-o-6sr-LqdS8=*yuaOHY zM4K!Bdl4Q4>jD0h)MajwE?lYliKqEG)6$DsPI{M{OvC3@ro!-W#yT!GNx^rCgh~ie zcGZYQhkx(Yy^L=v``K+1IKs8Dv-fMreoWV1>>;c4@i0`{T_B=bj6rCkZG&*YOQy-; zrwF)(-u#cTZD4UJ42}9R5oc$I$_{1LPTA>LQUt^Uo-;Aut&tQo;)9@<UnSsxk`VM>kK|>i=>+5At2optALD~IPM;!$PbCMCxK@R=$+WxG|_yD z%C6th`w!I0ZE~lBDw9yz7?cd5vF7!QkzIHP4+8ggiShX$;xf9q0}$xC@eN@>+Z+a1 zVmJ?aDjpn}oa9LMqg3H>E*6A~7arO7F)O=`?#Hq2aG zXzM|)(Ym(^r8?(`%_X9o9Oe3#)IafYJYZ}*(B*-x2k*zP{chhM4*;*6@hU*UfY3ma zTvcTQ+KfjKtHaih9K)hm40Fq4B06+lr%Y zHO3*)T>X5QC<++xq%jeB{%njxbljHpSrZVOP9V@nQ9E}?)y#(Y1p#UogVDpMZ;iYo zfeiW`DRix!p?}Fhy(78mnIQ3JK--D9~bY>Q;pYpDJAzm-?{SVd8X+-*rf>1BV4Cfw=buW2XulI8C7*YdqC zMp3edCf5M@8%U1-k9Gd5JBhD9f;GF(9AQox3;u%8&N{fj0r8fye68 R@q%p^Qun zmu;(8gi_51X$ubj=i%aD`0?{M!>2Fb89sda#_$#7o8Ny|1NGz_ZI66Kkq>~O!|{Op7O`FJ@I76NVj`3vHkPaxlX z{|Wcasjlc(WPkYJKf@m+4Dt;t8!IqwxEX|m_`tqmXJ-ZahVim#$r7BtVZkNw=l?&T z!T&H_#KOeD$;}R?Sy-7FK7ans`0d+IMv^V~`xof)zqoQa&^N5C47|KdYk={Qy{|6l z73n?zy8bs7A3(utP}na`v0Ftbl5tyr+Xrj@{ri`_Dp<{)sANh?9DrTDHr-(rDH#o? z1;C;KoRW}Ty)ny)U@>4^XU002ovPDHLkV1mEP>n{KR diff --git a/platform/icons/src/icons/ide/nextStepGrayed@2x.png b/platform/icons/src/icons/ide/nextStepGrayed@2x.png index 12f3ee9480c0be876532a0c5eda1320ae5403dd0..ff3d7277ed6b54eec38337c373c99693daaa8c14 100644 GIT binary patch delta 147 zcmV;E0BryH0j~j&B!6~EL_t(|+U?cB4S+BV1Hdc+o55(=0WujZ5iF$gDQZz0^XkLz zvuRbt-Gvz$Kr^7K8!{pCB`ts>2eL4MlpUFwKy^(7P+SuUysn7`vNbH=S;GWQWMu)y z`b2kY)*&0~nr5vd0b@NC#n!z*wRIOTewn`k7y9!p1xBd%HVgm&002ovPDHLkV1kx@ BJ1hVI delta 221 zcmV<303!dd0r>%tB!3xnMObuGZ)S9NVRB^vL1b@YWgtmyVP|DhWnpA_ami&o0001+ zNklhp7|JyU`8XjK3IwfL*P={+~CL_llmPY|mQ4Gwh8zOq9 ziA{Jb9i*dh+Wbj`!=(HZTN^U&2V^li-VZq36z(A7rp+C8S*zp2u314K#!R8NSw%V# rzN;5C>4XbsGu~V$x7LV#IxE9t0m+cVJlDk;fWXt$&xK{3Q$iB}#T_<; delta 207 zcmV;=05Jcj0qX&fB!3xnMObuGZ)S9NVRB^vL1b@YWgtmyVP|DhWnpA_ami&o0001u zNkl Date: Fri, 7 Nov 2014 12:28:49 +0400 Subject: [PATCH 70/84] Do not endlessly indent a block when it can't be aligned, report an error instead --- .../AbstractBlockAlignmentProcessor.java | 21 ++++++++++++++++--- .../formatting/BlockAlignmentProcessor.java | 5 ++++- .../intellij/formatting/FormatProcessor.java | 2 +- 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/formatting/AbstractBlockAlignmentProcessor.java b/platform/lang-impl/src/com/intellij/formatting/AbstractBlockAlignmentProcessor.java index 4cea2ab53d74..a66eceb51618 100644 --- a/platform/lang-impl/src/com/intellij/formatting/AbstractBlockAlignmentProcessor.java +++ b/platform/lang-impl/src/com/intellij/formatting/AbstractBlockAlignmentProcessor.java @@ -16,8 +16,9 @@ package com.intellij.formatting; import com.intellij.diagnostic.LogMessageEx; +import com.intellij.lang.ASTNode; +import com.intellij.lang.Language; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.util.TextRange; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -50,10 +51,16 @@ public abstract class AbstractBlockAlignmentProcessor implements BlockAlignmentP } if (diff > 0) { - whiteSpace.setSpaces(whiteSpace.getSpaces() + diff, whiteSpace.getIndentSpaces()); + int alignmentSpaces = whiteSpace.getSpaces() + diff; + if (alignmentSpaces > context.maxAlignmentSpaces) { + whiteSpace.setSpaces(1, whiteSpace.getIndentSpaces()); + reportAlignmentProcessingError(context); + return Result.RECURSION_DETECTED; + } + whiteSpace.setSpaces(alignmentSpaces, whiteSpace.getIndentSpaces()); - // Avoid tabulations usage for aligning blocks that are not the first blocks on a line. if (!whiteSpace.containsLineFeeds()) { + // Avoid tabulations usage for aligning blocks that are not the first blocks on a line. whiteSpace.setForceSkipTabulationsUsage(true); } return Result.TARGET_BLOCK_ALIGNED; @@ -127,4 +134,12 @@ public abstract class AbstractBlockAlignmentProcessor implements BlockAlignmentP * @return alignment anchor indent minus current target block indent */ protected abstract int getAlignmentIndentDiff(@NotNull IndentData alignmentAnchorIndent, @NotNull Context context); + + private static void reportAlignmentProcessingError(Context context) { + ASTNode node = context.targetBlock.getNode(); + Language language = node != null ? node.getPsi().getLanguage() : null; + LogMessageEx.error(LOG, + (language != null ? language.getDisplayName() + ": " : "") + + "Can't align block " + context.targetBlock, context.document.getText()); + } } diff --git a/platform/lang-impl/src/com/intellij/formatting/BlockAlignmentProcessor.java b/platform/lang-impl/src/com/intellij/formatting/BlockAlignmentProcessor.java index c1debaab6909..8ac3700f8b08 100644 --- a/platform/lang-impl/src/com/intellij/formatting/BlockAlignmentProcessor.java +++ b/platform/lang-impl/src/com/intellij/formatting/BlockAlignmentProcessor.java @@ -71,13 +71,15 @@ public interface BlockAlignmentProcessor { @NotNull public final Map> alignmentMappings; @NotNull public final Map> backwardShiftedAlignedBlocks; @NotNull public final CommonCodeStyleSettings.IndentOptions indentOptions; + public int maxAlignmentSpaces; public Context(@NotNull Document document, @NotNull AlignmentImpl alignment, @NotNull LeafBlockWrapper targetBlock, @NotNull Map> alignmentMappings, @NotNull Map> backwardShiftedAlignedBlocks, - @NotNull CommonCodeStyleSettings.IndentOptions indentOptions) + @NotNull CommonCodeStyleSettings.IndentOptions indentOptions, + int maxAlignmentSpaces) { this.document = document; this.alignment = alignment; @@ -85,6 +87,7 @@ public interface BlockAlignmentProcessor { this.alignmentMappings = alignmentMappings; this.backwardShiftedAlignedBlocks = backwardShiftedAlignedBlocks; this.indentOptions = indentOptions; + this.maxAlignmentSpaces = maxAlignmentSpaces; } } } diff --git a/platform/lang-impl/src/com/intellij/formatting/FormatProcessor.java b/platform/lang-impl/src/com/intellij/formatting/FormatProcessor.java index 73358455bdcd..d94fabf83baf 100644 --- a/platform/lang-impl/src/com/intellij/formatting/FormatProcessor.java +++ b/platform/lang-impl/src/com/intellij/formatting/FormatProcessor.java @@ -683,7 +683,7 @@ class FormatProcessor { BlockAlignmentProcessor.Context context = new BlockAlignmentProcessor.Context( myDocument, alignment, myCurrentBlock, myAlignmentMappings, myBackwardShiftedAlignedBlocks, - getIndentOptionsToUse(myCurrentBlock, myDefaultIndentOption) + getIndentOptionsToUse(myCurrentBlock, myDefaultIndentOption), myRightMargin ); BlockAlignmentProcessor.Result result = alignmentProcessor.applyAlignment(context); final LeafBlockWrapper offsetResponsibleBlock = alignment.getOffsetRespBlockBefore(myCurrentBlock); From 8cced4cec44a02f1e0486db12ffb215f146f490b Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Fri, 7 Nov 2014 10:57:52 +0100 Subject: [PATCH 71/84] make IG test light --- ...itiveArrayArgumentToVariableArgMethod.java | 2 +- .../siyeh/igtest/bugs/var_arg/expected.xml | 9 -------- ...mentToVariableArgMethodInspectionTest.java | 21 +++++++++++++++---- 3 files changed, 18 insertions(+), 14 deletions(-) delete mode 100644 plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/var_arg/expected.xml diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/var_arg/PrimitiveArrayArgumentToVariableArgMethod.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/var_arg/PrimitiveArrayArgumentToVariableArgMethod.java index aa8620ac34c1..09d6bb59a169 100644 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/var_arg/PrimitiveArrayArgumentToVariableArgMethod.java +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/var_arg/PrimitiveArrayArgumentToVariableArgMethod.java @@ -4,7 +4,7 @@ public class PrimitiveArrayArgumentToVariableArgMethod { public static void main(String[] arg) { - methodVarArgObject(new byte[3]); + methodVarArgObject(new byte[3]); methodVarArgByteArray(new byte[3]); } diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/var_arg/expected.xml b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/var_arg/expected.xml deleted file mode 100644 index cee36b29eb4e..000000000000 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/var_arg/expected.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - PrimitiveArrayArgumentToVariableArgMethod.java - 7 - Confusing primitive array argument to var-arg method - Confusing primitive array argument to var-arg method #loc - - \ No newline at end of file diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/bugs/PrimitiveArrayArgumentToVariableArgMethodInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/bugs/PrimitiveArrayArgumentToVariableArgMethodInspectionTest.java index 505385d32ca2..c88e008d377b 100644 --- a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/bugs/PrimitiveArrayArgumentToVariableArgMethodInspectionTest.java +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/bugs/PrimitiveArrayArgumentToVariableArgMethodInspectionTest.java @@ -1,10 +1,23 @@ package com.siyeh.ig.bugs; -import com.siyeh.ig.IGInspectionTestCase; +import com.intellij.codeInspection.InspectionProfileEntry; +import com.siyeh.ig.LightInspectionTestCase; +import org.jetbrains.annotations.Nullable; -public class PrimitiveArrayArgumentToVariableArgMethodInspectionTest extends IGInspectionTestCase { +public class PrimitiveArrayArgumentToVariableArgMethodInspectionTest extends LightInspectionTestCase { - public void test() throws Exception { - doTest("com/siyeh/igtest/bugs/var_arg", new PrimitiveArrayArgumentToVariableArgMethodInspection()); + public void testPrimitiveArrayArgumentToVariableArgMethod() throws Exception { + doTest(); + } + + @Nullable + @Override + protected InspectionProfileEntry getInspection() { + return new PrimitiveArrayArgumentToVariableArgMethodInspection(); + } + + @Override + protected String getBasePath() { + return "/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/var_arg"; } } \ No newline at end of file From 49d9433a9d22bf9d209e51a5132b8bd39e4b979b Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Fri, 7 Nov 2014 11:16:11 +0100 Subject: [PATCH 72/84] IDEA-132470 (Wrong code inspections on signature polymorphic method calls) --- ...rimitiveArrayArgumentToVariableArgMethodInspection.java | 7 +++++-- .../var_arg/PrimitiveArrayArgumentToVariableArgMethod.java | 6 +++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/PrimitiveArrayArgumentToVariableArgMethodInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/PrimitiveArrayArgumentToVariableArgMethodInspection.java index 90921cdb2cc1..f168f9d1f57c 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/PrimitiveArrayArgumentToVariableArgMethodInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/PrimitiveArrayArgumentToVariableArgMethodInspection.java @@ -1,5 +1,5 @@ /* - * Copyright 2006-2013 Dave Griffith, Bas Leijdekkers + * Copyright 2006-2014 Dave Griffith, Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,6 +15,7 @@ */ package com.siyeh.ig.bugs; +import com.intellij.codeInsight.AnnotationUtil; import com.intellij.psi.*; import com.intellij.psi.util.PsiUtil; import com.intellij.psi.util.TypeConversionUtil; @@ -23,6 +24,8 @@ import com.siyeh.ig.BaseInspection; import com.siyeh.ig.BaseInspectionVisitor; import org.jetbrains.annotations.NotNull; +import java.util.Arrays; + public class PrimitiveArrayArgumentToVariableArgMethodInspection extends BaseInspection { @Override @@ -67,7 +70,7 @@ public class PrimitiveArrayArgumentToVariableArgMethodInspection extends BaseIns } final JavaResolveResult result = call.resolveMethodGenerics(); final PsiMethod method = (PsiMethod)result.getElement(); - if (method == null) { + if (method == null || AnnotationUtil.isAnnotated(method, Arrays.asList("java.lang.invoke.MethodHandle.PolymorphicSignature"))) { return; } final PsiParameterList parameterList = method.getParameterList(); diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/var_arg/PrimitiveArrayArgumentToVariableArgMethod.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/var_arg/PrimitiveArrayArgumentToVariableArgMethod.java index 09d6bb59a169..b6dcd68939dd 100644 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/var_arg/PrimitiveArrayArgumentToVariableArgMethod.java +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/var_arg/PrimitiveArrayArgumentToVariableArgMethod.java @@ -1,11 +1,15 @@ package com.siyeh.igtest.bugs.var_arg; +import java.lang.invoke.MethodHandle; + public class PrimitiveArrayArgumentToVariableArgMethod { - public static void main(String[] arg) + public static void main(String[] arg) throws Throwable { methodVarArgObject(new byte[3]); methodVarArgByteArray(new byte[3]); + MethodHandle meh = null; + meh.invokeExact(new int[] { }); } private static void methodVarArgObject(Object... bytes) From 112030d6d301067716ff59032a701b8a00d87e34 Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Fri, 7 Nov 2014 12:14:04 +0100 Subject: [PATCH 73/84] part II for IDEA-132470 (Wrong code inspections on signature polymorphic method calls) --- .../RedundantArrayForVarargsCallInspection.java | 7 +++++-- .../polymorphicSignature/expected.xml | 3 +++ .../polymorphicSignature/src/Test.java | 9 +++++++++ .../RedundantArrayForVarargsCallInspectionTest.java | 1 + 4 files changed, 18 insertions(+), 2 deletions(-) create mode 100644 java/java-tests/testData/inspection/redundantArrayForVarargs/polymorphicSignature/expected.xml create mode 100644 java/java-tests/testData/inspection/redundantArrayForVarargs/polymorphicSignature/src/Test.java diff --git a/java/java-impl/src/com/intellij/codeInspection/miscGenerics/RedundantArrayForVarargsCallInspection.java b/java/java-impl/src/com/intellij/codeInspection/miscGenerics/RedundantArrayForVarargsCallInspection.java index 13f09cb8edd9..f5e0e5102b5b 100644 --- a/java/java-impl/src/com/intellij/codeInspection/miscGenerics/RedundantArrayForVarargsCallInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/miscGenerics/RedundantArrayForVarargsCallInspection.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,6 +15,7 @@ */ package com.intellij.codeInspection.miscGenerics; +import com.intellij.codeInsight.AnnotationUtil; import com.intellij.codeInsight.ExpectedTypeInfo; import com.intellij.codeInsight.ExpectedTypesProvider; import com.intellij.codeInsight.FileModificationService; @@ -31,6 +32,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.ArrayList; +import java.util.Collections; import java.util.List; /** @@ -93,7 +95,8 @@ public class RedundantArrayForVarargsCallInspection extends GenericsInspectionTo return; } PsiMethod method = (PsiMethod)element; - if (!method.isVarArgs()) { + if (!method.isVarArgs() || + AnnotationUtil.isAnnotated(method, Collections.singletonList("java.lang.invoke.MethodHandle.PolymorphicSignature"))) { return; } PsiParameter[] parameters = method.getParameterList().getParameters(); diff --git a/java/java-tests/testData/inspection/redundantArrayForVarargs/polymorphicSignature/expected.xml b/java/java-tests/testData/inspection/redundantArrayForVarargs/polymorphicSignature/expected.xml new file mode 100644 index 000000000000..5e933496b9cf --- /dev/null +++ b/java/java-tests/testData/inspection/redundantArrayForVarargs/polymorphicSignature/expected.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/java/java-tests/testData/inspection/redundantArrayForVarargs/polymorphicSignature/src/Test.java b/java/java-tests/testData/inspection/redundantArrayForVarargs/polymorphicSignature/src/Test.java new file mode 100644 index 000000000000..b6cd9f28da7f --- /dev/null +++ b/java/java-tests/testData/inspection/redundantArrayForVarargs/polymorphicSignature/src/Test.java @@ -0,0 +1,9 @@ +import java.lang.invoke.MethodHandle; + +public class Test { + + public static void main(String[] args) { + MethodHandle meh = null; + meh.invokeExact(new Object[] {}); + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/RedundantArrayForVarargsCallInspectionTest.java b/java/java-tests/testSrc/com/intellij/codeInspection/RedundantArrayForVarargsCallInspectionTest.java index 2b961772e74a..38ceeff5bab3 100644 --- a/java/java-tests/testSrc/com/intellij/codeInspection/RedundantArrayForVarargsCallInspectionTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInspection/RedundantArrayForVarargsCallInspectionTest.java @@ -24,4 +24,5 @@ public class RedundantArrayForVarargsCallInspectionTest extends InspectionTestCa public void testCheckEnumConstant() throws Exception { doTest(); } public void testGeneric() throws Exception { doTest(); } public void testRawArray() throws Exception { doTest(); } + public void testPolymorphicSignature() throws Exception { doTest(); } } From 706a85bb3dfe34dbb61fa821ec6704e1f1ffadaf Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Fri, 7 Nov 2014 14:09:08 +0300 Subject: [PATCH 74/84] IDEA-132514: merge dialog - repaint scrollbar even if thumb position was not changed --- .../com/intellij/util/ui/ButtonlessScrollBarUI.java | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/platform/platform-api/src/com/intellij/util/ui/ButtonlessScrollBarUI.java b/platform/platform-api/src/com/intellij/util/ui/ButtonlessScrollBarUI.java index a816efde21c5..a8d7bb981ab4 100644 --- a/platform/platform-api/src/com/intellij/util/ui/ButtonlessScrollBarUI.java +++ b/platform/platform-api/src/com/intellij/util/ui/ButtonlessScrollBarUI.java @@ -275,14 +275,8 @@ public class ButtonlessScrollBarUI extends BasicScrollBarUI { super.setThumbBounds(x, y, width, height); } else { - /* If the thumbs bounds haven't changed, we're done. - */ - if ((thumbRect.x == x) && - (thumbRect.y == y) && - (thumbRect.width == width) && - (thumbRect.height == height)) { - return; - } + // We want to repaint whole scrollbar even if thumb wasn't moved (on small scroll of a big panel) + // Even if scrollbar wasn't changed itself, myRepaintCallback could need repaint /* Update thumbRect, and repaint the union of x,y,w,h and * the old thumbRect. From 84b4d1d70c78782c863743c2b7c45d6e15b30a8d Mon Sep 17 00:00:00 2001 From: Mikhail Golubev Date: Wed, 5 Nov 2014 19:45:39 +0300 Subject: [PATCH 75/84] WEB-14048 Add QualifiedNameProvider for JSON --- .../navigation/JsonQualifiedNameProvider.java | 50 +++++++++++++++++++ .../com/intellij/json/JsonNavigationTest.java | 20 ++++++++ .../testData/navigation/CopyReference.json | 11 ++++ .../src/META-INF/JsonPlugin.xml | 1 + 4 files changed, 82 insertions(+) create mode 100644 json/src/com/intellij/json/navigation/JsonQualifiedNameProvider.java create mode 100644 json/tests/test/com/intellij/json/JsonNavigationTest.java create mode 100644 json/tests/testData/navigation/CopyReference.json diff --git a/json/src/com/intellij/json/navigation/JsonQualifiedNameProvider.java b/json/src/com/intellij/json/navigation/JsonQualifiedNameProvider.java new file mode 100644 index 000000000000..75d5a3888033 --- /dev/null +++ b/json/src/com/intellij/json/navigation/JsonQualifiedNameProvider.java @@ -0,0 +1,50 @@ +package com.intellij.json.navigation; + +import com.intellij.ide.actions.QualifiedNameProvider; +import com.intellij.json.psi.JsonElement; +import com.intellij.json.psi.JsonProperty; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.editor.EditorModificationUtil; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.psi.PsiElement; +import com.intellij.psi.util.PsiTreeUtil; +import org.jetbrains.annotations.Nullable; + +import java.util.LinkedList; + +/** + * @author Mikhail Golubev + */ +public class JsonQualifiedNameProvider implements QualifiedNameProvider { + @Nullable + @Override + public PsiElement adjustElementToCopy(PsiElement element) { + return element; + } + + @Nullable + @Override + public String getQualifiedName(PsiElement element) { + if (!(element instanceof JsonElement)) { + return null; + } + final LinkedList qualifiers = new LinkedList(); + JsonProperty parentProperty = PsiTreeUtil.getNonStrictParentOfType(element, JsonProperty.class); + while (parentProperty != null) { + qualifiers.addFirst(parentProperty.getName()); + parentProperty = PsiTreeUtil.getParentOfType(parentProperty, JsonProperty.class); + } + return qualifiers.isEmpty() ? null : StringUtil.join(qualifiers, "."); + } + + @Override + public PsiElement qualifiedNameToElement(String fqn, Project project) { + return null; + } + + @Override + public void insertQualifiedName(String fqn, PsiElement element, Editor editor, Project project) { + EditorModificationUtil.insertStringAtCaret(editor, fqn); + } +} diff --git a/json/tests/test/com/intellij/json/JsonNavigationTest.java b/json/tests/test/com/intellij/json/JsonNavigationTest.java new file mode 100644 index 000000000000..1ca4acf83f8d --- /dev/null +++ b/json/tests/test/com/intellij/json/JsonNavigationTest.java @@ -0,0 +1,20 @@ +package com.intellij.json; + +import com.intellij.ide.actions.CopyReferenceAction; +import com.intellij.json.psi.JsonProperty; +import com.intellij.psi.PsiElement; + +/** + * @author Mikhail Golubev + */ +public class JsonNavigationTest extends JsonTestCase { + + // WEB-14048 + public void testCopyReference() { + myFixture.configureByFile("navigation/" + getTestName(false) + ".json"); + final PsiElement element = myFixture.getElementAtCaret(); + assertInstanceOf(element, JsonProperty.class); + final String qualifiedName = CopyReferenceAction.elementToFqn(element); + assertEquals("foo.bar.baz", qualifiedName); + } +} diff --git a/json/tests/testData/navigation/CopyReference.json b/json/tests/testData/navigation/CopyReference.json new file mode 100644 index 000000000000..c5f889219193 --- /dev/null +++ b/json/tests/testData/navigation/CopyReference.json @@ -0,0 +1,11 @@ +{ + "foo": { + "bar": [ + [ + { + "baz": null + } + ] + ] + } +} \ No newline at end of file diff --git a/platform/platform-resources/src/META-INF/JsonPlugin.xml b/platform/platform-resources/src/META-INF/JsonPlugin.xml index c3d643a5d1da..4dd4b11b044a 100644 --- a/platform/platform-resources/src/META-INF/JsonPlugin.xml +++ b/platform/platform-resources/src/META-INF/JsonPlugin.xml @@ -31,6 +31,7 @@ + From 00f379ed9d508e8242e4dc481d95d21f03e4643d Mon Sep 17 00:00:00 2001 From: Mikhail Golubev Date: Wed, 5 Nov 2014 16:32:43 +0300 Subject: [PATCH 76/84] PY-11357 Make automatic surrounding with custom folding comments more robust * Searching of first parental PSI elements before/after new line correctly stops at the start/end of file. As result it's possible now to surround element at the first/last line in the file. Also corresponding traversal does not try to climb above PSI file. * Even single character can be selected in first place. * In languages that uses indentation to delimit blocks (like Python) several consequent sibling statements can be surrounded even if the last of them is at the end of its parent. --- .../CustomFoldingSurroundDescriptor.java | 126 +++++++++++++----- .../surroundWith/SurrounderOrderTest.groovy | 12 +- ...n.py => CustomFoldingRegionFirstMethod.py} | 0 .../CustomFoldingRegionFirstMethod_after.py | 17 +++ .../CustomFoldingRegionIllegalSelection.py | 4 + ...stomFoldingRegionIllegalSelection_after.py | 4 + ...on.py => CustomFoldingRegionLastMethod.py} | 2 +- .../CustomFoldingRegionLastMethod_after.py | 17 +++ ...ustomFoldingRegionPreservesIndentation.py} | 0 ...oldingRegionPreservesIndentation_after.py} | 0 .../CustomFoldingRegionSeveralMethods.py | 9 ++ ...CustomFoldingRegionSeveralMethods_after.py | 11 ++ .../CustomFoldingRegionSingleCharacter.py | 1 + ...ustomFoldingRegionSingleCharacter_after.py | 3 + ...ustomFoldingRegionSingleStatementInFile.py | 2 + ...oldingRegionSingleStatementInFile_after.py | 3 + .../jetbrains/python/PySurroundWithTest.java | 53 +++++--- 17 files changed, 206 insertions(+), 58 deletions(-) rename python/testData/surround/{SurroundFirstMethodWithCustomFoldingRegion.py => CustomFoldingRegionFirstMethod.py} (100%) create mode 100644 python/testData/surround/CustomFoldingRegionFirstMethod_after.py create mode 100644 python/testData/surround/CustomFoldingRegionIllegalSelection.py create mode 100644 python/testData/surround/CustomFoldingRegionIllegalSelection_after.py rename python/testData/surround/{SurroundLastMethodWithCustomFoldingRegion.py => CustomFoldingRegionLastMethod.py} (87%) create mode 100644 python/testData/surround/CustomFoldingRegionLastMethod_after.py rename python/testData/surround/{SurroundWithCustomFoldingRegion.py => CustomFoldingRegionPreservesIndentation.py} (100%) rename python/testData/surround/{SurroundWithCustomFoldingRegion_after.py => CustomFoldingRegionPreservesIndentation_after.py} (100%) create mode 100644 python/testData/surround/CustomFoldingRegionSeveralMethods.py create mode 100644 python/testData/surround/CustomFoldingRegionSeveralMethods_after.py create mode 100644 python/testData/surround/CustomFoldingRegionSingleCharacter.py create mode 100644 python/testData/surround/CustomFoldingRegionSingleCharacter_after.py create mode 100644 python/testData/surround/CustomFoldingRegionSingleStatementInFile.py create mode 100644 python/testData/surround/CustomFoldingRegionSingleStatementInFile_after.py diff --git a/platform/lang-api/src/com/intellij/lang/folding/CustomFoldingSurroundDescriptor.java b/platform/lang-api/src/com/intellij/lang/folding/CustomFoldingSurroundDescriptor.java index 4062cb45beef..cf63d76e6f38 100644 --- a/platform/lang-api/src/com/intellij/lang/folding/CustomFoldingSurroundDescriptor.java +++ b/platform/lang-api/src/com/intellij/lang/folding/CustomFoldingSurroundDescriptor.java @@ -26,10 +26,7 @@ import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.text.StringUtil; -import com.intellij.psi.PsiDocumentManager; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiFile; -import com.intellij.psi.PsiWhiteSpace; +import com.intellij.psi.*; import com.intellij.psi.codeStyle.CodeStyleManager; import com.intellij.psi.codeStyle.CodeStyleSettingsManager; import com.intellij.psi.codeStyle.CommonCodeStyleSettings; @@ -62,7 +59,7 @@ public class CustomFoldingSurroundDescriptor implements SurroundDescriptor { @NotNull @Override public PsiElement[] getElementsToSurround(PsiFile file, int startOffset, int endOffset) { - if (startOffset >= endOffset - 1) return PsiElement.EMPTY_ARRAY; + if (startOffset >= endOffset) return PsiElement.EMPTY_ARRAY; Commenter commenter = LanguageCommenters.INSTANCE.forLanguage(file.getLanguage()); if (commenter == null || commenter.getLineCommentPrefix() == null) return PsiElement.EMPTY_ARRAY; PsiElement startElement = file.findElementAt(startOffset); @@ -70,18 +67,11 @@ public class CustomFoldingSurroundDescriptor implements SurroundDescriptor { PsiElement endElement = file.findElementAt(endOffset - 1); if (endElement instanceof PsiWhiteSpace) endElement = endElement.getPrevSibling(); if (startElement != null && endElement != null) { - if (startElement.getTextRange().getStartOffset() > endElement.getTextRange().getStartOffset()) return PsiElement.EMPTY_ARRAY; startElement = findClosestParentAfterLineBreak(startElement); if (startElement != null) { endElement = findClosestParentBeforeLineBreak(endElement); if (endElement != null) { - startElement = adjustStartElementIfEndAbsorbed(startElement, endElement); - endElement = adjustEndElementIfStartAbsorbed(startElement, endElement); - final PsiElement commonParent = startElement.getParent(); - if (endElement.getParent() == commonParent) { - if (startElement == endElement) return new PsiElement[]{startElement}; - return new PsiElement[]{startElement, endElement}; - } + return adjustRange(startElement, endElement); } } } @@ -89,46 +79,116 @@ public class CustomFoldingSurroundDescriptor implements SurroundDescriptor { } @NotNull - private static PsiElement adjustEndElementIfStartAbsorbed(@NotNull PsiElement start, @NotNull PsiElement end) { - if (PsiTreeUtil.isAncestor(end, start, false) && start.getTextRange().getEndOffset() == end.getTextRange().getEndOffset()) { - return start; + private static PsiElement[] adjustRange(@NotNull PsiElement start, @NotNull PsiElement end) { + PsiElement newStart = lowerStartElementIfNeeded(start, end); + PsiElement newEnd = lowerEndElementIfNeeded(start, end); + if (newStart == null || newEnd == null) { + return PsiElement.EMPTY_ARRAY; + } + final PsiElement commonParent = findCommonAncestorForWholeRange(newStart, newEnd); + if (commonParent != null) { + return new PsiElement[] {commonParent}; + } + // If either start or end element is the first/last leaf element in its parent, use the parent itself instead + // to prevent selection of clearly illegal ranges like the following: + // [ + // 1 + // ] + // E.g. in case shown, because of that adjustment, closing bracket and number literal won't have the same parent + // and next test will fail. + if (newStart.getParent().getFirstChild() == newStart && newStart.getFirstChild() == null) { + newStart = newStart.getParent(); + } + if (newEnd.getParent().getLastChild() == newEnd && newEnd.getFirstChild() == null) { + newEnd = newEnd.getParent(); + } + if (newStart.getParent() == newEnd.getParent()) { + return new PsiElement[] {newStart, newEnd}; + } + return PsiElement.EMPTY_ARRAY; + } + + @Nullable + private static PsiElement lowerEndElementIfNeeded(@NotNull PsiElement start, @NotNull PsiElement end) { + if (PsiTreeUtil.isAncestor(end, start, true)) { + PsiElement lastChild = end.getLastChild(); + while (lastChild != null && lastChild.getParent() != start.getParent()) { + lastChild = lastChild.getLastChild(); + } + return lastChild; } return end; } - @NotNull - private static PsiElement adjustStartElementIfEndAbsorbed(@NotNull PsiElement start, @NotNull PsiElement end) { - if (PsiTreeUtil.isAncestor(start, end, false) && start.getTextRange().getStartOffset() == end.getTextRange().getStartOffset()) { - return end; + @Nullable + private static PsiElement lowerStartElementIfNeeded(@NotNull PsiElement start, @NotNull PsiElement end) { + if (PsiTreeUtil.isAncestor(start, end, true)) { + PsiElement firstChild = start.getFirstChild(); + while (firstChild != null && firstChild.getParent() != end.getParent()) { + firstChild = firstChild.getFirstChild(); + } + return firstChild; } return start; } @Nullable - private static PsiElement findClosestParentAfterLineBreak(PsiElement element) { - PsiElement parent = element; - while (parent != null) { - PsiElement prev = parent.getPrevSibling(); - while (prev != null && prev.getTextLength() <= 0) { - prev = prev.getPrevSibling(); - } - if (isWhiteSpaceWithLineFeed(prev)) return parent; - parent = parent.getParent(); + private static PsiElement findCommonAncestorForWholeRange(@NotNull PsiElement start, @NotNull PsiElement end) { + final PsiElement parent = PsiTreeUtil.findCommonParent(start, end); + if (parent == null) { + return null; + } + final TextRange parentRange = parent.getTextRange(); + if (parentRange.getStartOffset() == start.getTextRange().getStartOffset() && + parentRange.getEndOffset() == end.getTextRange().getEndOffset()) { + return parent; } return null; } @Nullable - private static PsiElement findClosestParentBeforeLineBreak(PsiElement element) { + private static PsiElement findClosestParentAfterLineBreak(PsiElement element) { PsiElement parent = element; - while (parent != null) { - PsiElement next = parent.getNextSibling(); - if (isWhiteSpaceWithLineFeed(next)) return parent; + while (parent != null && !(parent instanceof PsiFileSystemItem)) { + PsiElement prev = parent.getPrevSibling(); + while (prev != null && prev.getTextLength() <= 0) { + prev = prev.getPrevSibling(); + } + if (firstElementInFile(parent)) { + return parent.getContainingFile(); + } + else if (isWhiteSpaceWithLineFeed(prev)) { + return parent; + } parent = parent.getParent(); } return null; } + private static boolean firstElementInFile(@NotNull PsiElement element) { + return element.getTextOffset() == 0; + } + + @Nullable + private static PsiElement findClosestParentBeforeLineBreak(PsiElement element) { + PsiElement parent = element; + while (parent != null && !(parent instanceof PsiFileSystemItem)) { + final PsiElement next = parent.getNextSibling(); + if (lastElementInFile(parent)) { + return parent.getContainingFile(); + } + else if (isWhiteSpaceWithLineFeed(next)) { + return parent; + } + parent = parent.getParent(); + } + return null; + } + + private static boolean lastElementInFile(@NotNull PsiElement element) { + return element.getTextRange().getEndOffset() == element.getContainingFile().getTextRange().getEndOffset(); + } + private static boolean isWhiteSpaceWithLineFeed(@Nullable PsiElement element) { if (element == null) { return false; diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/surroundWith/SurrounderOrderTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/surroundWith/SurrounderOrderTest.groovy index b038c11de80f..aca3fa8ea5be 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/surroundWith/SurrounderOrderTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/surroundWith/SurrounderOrderTest.groovy @@ -39,7 +39,9 @@ class SurrounderOrderTest extends LightCodeInsightFixtureTestCase { "(expr)", "!(expr)", "((Type) expr)", - "with () {...}" + "with () {...}", + " Comments", + "region...endregion Comments" } public void testStatementWithSemicolon() throws Exception { @@ -50,7 +52,9 @@ class SurrounderOrderTest extends LightCodeInsightFixtureTestCase { "{}", "for", "try / catch", "try / finally", "try / catch / finally", "shouldFail () {...}", - "with () {...}" + "with () {...}", + " Comments", + "region...endregion Comments" } public void testStatementsWithComments() throws Exception { @@ -64,7 +68,9 @@ println c /*also important */ "{}", "for", "try / catch", "try / finally", "try / catch / finally", "shouldFail () {...}", - "with () {...}" + "with () {...}", + " Comments", + "region...endregion Comments" } public void testInnerExpressionSurrounders() { diff --git a/python/testData/surround/SurroundFirstMethodWithCustomFoldingRegion.py b/python/testData/surround/CustomFoldingRegionFirstMethod.py similarity index 100% rename from python/testData/surround/SurroundFirstMethodWithCustomFoldingRegion.py rename to python/testData/surround/CustomFoldingRegionFirstMethod.py diff --git a/python/testData/surround/CustomFoldingRegionFirstMethod_after.py b/python/testData/surround/CustomFoldingRegionFirstMethod_after.py new file mode 100644 index 000000000000..222424499910 --- /dev/null +++ b/python/testData/surround/CustomFoldingRegionFirstMethod_after.py @@ -0,0 +1,17 @@ +class ThisIsATest(): + # + def __init__(self): + self.test = 1 + # + + def another_one(self): + print "Hello, world!" + + def another_two(self): + print "Hello, world!" + + def another_three(self): + print "Hello, world!" + + def another_four(self): + print "Hello, world!" \ No newline at end of file diff --git a/python/testData/surround/CustomFoldingRegionIllegalSelection.py b/python/testData/surround/CustomFoldingRegionIllegalSelection.py new file mode 100644 index 000000000000..bfb208e40e7f --- /dev/null +++ b/python/testData/surround/CustomFoldingRegionIllegalSelection.py @@ -0,0 +1,4 @@ +[ + 1, + 2 +] \ No newline at end of file diff --git a/python/testData/surround/CustomFoldingRegionIllegalSelection_after.py b/python/testData/surround/CustomFoldingRegionIllegalSelection_after.py new file mode 100644 index 000000000000..63964002bf9f --- /dev/null +++ b/python/testData/surround/CustomFoldingRegionIllegalSelection_after.py @@ -0,0 +1,4 @@ +[ + 1, + 2 +] \ No newline at end of file diff --git a/python/testData/surround/SurroundLastMethodWithCustomFoldingRegion.py b/python/testData/surround/CustomFoldingRegionLastMethod.py similarity index 87% rename from python/testData/surround/SurroundLastMethodWithCustomFoldingRegion.py rename to python/testData/surround/CustomFoldingRegionLastMethod.py index 2dbc0cb2d23d..fb75998201cd 100644 --- a/python/testData/surround/SurroundLastMethodWithCustomFoldingRegion.py +++ b/python/testData/surround/CustomFoldingRegionLastMethod.py @@ -12,4 +12,4 @@ class ThisIsATest(): print "Hello, world!" def another_four(self): - print "Hello, world!" + print "Hello, world!" \ No newline at end of file diff --git a/python/testData/surround/CustomFoldingRegionLastMethod_after.py b/python/testData/surround/CustomFoldingRegionLastMethod_after.py new file mode 100644 index 000000000000..c283100ac33b --- /dev/null +++ b/python/testData/surround/CustomFoldingRegionLastMethod_after.py @@ -0,0 +1,17 @@ +class ThisIsATest(): + def __init__(self): + self.test = 1 + + def another_one(self): + print "Hello, world!" + + def another_two(self): + print "Hello, world!" + + def another_three(self): + print "Hello, world!" + + # + def another_four(self): + print "Hello, world!" + # \ No newline at end of file diff --git a/python/testData/surround/SurroundWithCustomFoldingRegion.py b/python/testData/surround/CustomFoldingRegionPreservesIndentation.py similarity index 100% rename from python/testData/surround/SurroundWithCustomFoldingRegion.py rename to python/testData/surround/CustomFoldingRegionPreservesIndentation.py diff --git a/python/testData/surround/SurroundWithCustomFoldingRegion_after.py b/python/testData/surround/CustomFoldingRegionPreservesIndentation_after.py similarity index 100% rename from python/testData/surround/SurroundWithCustomFoldingRegion_after.py rename to python/testData/surround/CustomFoldingRegionPreservesIndentation_after.py diff --git a/python/testData/surround/CustomFoldingRegionSeveralMethods.py b/python/testData/surround/CustomFoldingRegionSeveralMethods.py new file mode 100644 index 000000000000..867f0898db15 --- /dev/null +++ b/python/testData/surround/CustomFoldingRegionSeveralMethods.py @@ -0,0 +1,9 @@ +class C: + def m1(self): + pass + + def m2(self): + pass + + def m3(self): + pass \ No newline at end of file diff --git a/python/testData/surround/CustomFoldingRegionSeveralMethods_after.py b/python/testData/surround/CustomFoldingRegionSeveralMethods_after.py new file mode 100644 index 000000000000..a1f58e5f63b2 --- /dev/null +++ b/python/testData/surround/CustomFoldingRegionSeveralMethods_after.py @@ -0,0 +1,11 @@ +class C: + def m1(self): + pass + + # + def m2(self): + pass + + def m3(self): + pass + # \ No newline at end of file diff --git a/python/testData/surround/CustomFoldingRegionSingleCharacter.py b/python/testData/surround/CustomFoldingRegionSingleCharacter.py new file mode 100644 index 000000000000..d6558960207f --- /dev/null +++ b/python/testData/surround/CustomFoldingRegionSingleCharacter.py @@ -0,0 +1 @@ +x = 'foo' + 'bar' \ No newline at end of file diff --git a/python/testData/surround/CustomFoldingRegionSingleCharacter_after.py b/python/testData/surround/CustomFoldingRegionSingleCharacter_after.py new file mode 100644 index 000000000000..3efae30ebce7 --- /dev/null +++ b/python/testData/surround/CustomFoldingRegionSingleCharacter_after.py @@ -0,0 +1,3 @@ +# +x = 'foo' + 'bar' +# \ No newline at end of file diff --git a/python/testData/surround/CustomFoldingRegionSingleStatementInFile.py b/python/testData/surround/CustomFoldingRegionSingleStatementInFile.py new file mode 100644 index 000000000000..6f8ff0d5f034 --- /dev/null +++ b/python/testData/surround/CustomFoldingRegionSingleStatementInFile.py @@ -0,0 +1,2 @@ +print('foo') + \ No newline at end of file diff --git a/python/testData/surround/CustomFoldingRegionSingleStatementInFile_after.py b/python/testData/surround/CustomFoldingRegionSingleStatementInFile_after.py new file mode 100644 index 000000000000..5991df264bf7 --- /dev/null +++ b/python/testData/surround/CustomFoldingRegionSingleStatementInFile_after.py @@ -0,0 +1,3 @@ +# +print('foo') +# diff --git a/python/testSrc/com/jetbrains/python/PySurroundWithTest.java b/python/testSrc/com/jetbrains/python/PySurroundWithTest.java index 9abfa6313669..2af16ff92edc 100644 --- a/python/testSrc/com/jetbrains/python/PySurroundWithTest.java +++ b/python/testSrc/com/jetbrains/python/PySurroundWithTest.java @@ -19,11 +19,9 @@ import com.intellij.codeInsight.generation.surroundWith.SurroundWithHandler; import com.intellij.lang.folding.CustomFoldingSurroundDescriptor; import com.intellij.lang.surroundWith.Surrounder; import com.intellij.openapi.command.WriteCommandAction; -import com.intellij.openapi.editor.SelectionModel; -import com.intellij.psi.PsiElement; +import com.intellij.openapi.util.Condition; +import com.intellij.util.containers.ContainerUtil; import com.jetbrains.python.fixtures.PyTestCase; -import com.jetbrains.python.psi.PyElement; -import com.jetbrains.python.psi.PyFunction; import com.jetbrains.python.refactoring.surround.surrounders.statements.PyWithIfSurrounder; import com.jetbrains.python.refactoring.surround.surrounders.statements.PyWithTryExceptSurrounder; import com.jetbrains.python.refactoring.surround.surrounders.statements.PyWithWhileSurrounder; @@ -45,32 +43,45 @@ public class PySurroundWithTest extends PyTestCase { } // PY-11357 - public void testSurroundFirstMethodWithCustomFoldingRegion() { - checkCustomFoldingRegionRange(PyFunction.class); + public void testCustomFoldingRegionFirstMethod() throws Exception { + doTestSurroundWithCustomFoldingRegion(); } // PY-11357 - public void testSurroundLastMethodWithCustomFoldingRegion() { - checkCustomFoldingRegionRange(PyFunction.class); + public void testCustomFoldingRegionLastMethod() throws Exception { + doTestSurroundWithCustomFoldingRegion(); } // PY-14261 - public void testSurroundWithCustomFoldingRegion() throws Exception { - doTest(CustomFoldingSurroundDescriptor.SURROUNDERS[0]); + public void testCustomFoldingRegionPreservesIndentation() throws Exception { + doTestSurroundWithCustomFoldingRegion(); } + public void testCustomFoldingRegionSingleCharacter() throws Exception { + doTestSurroundWithCustomFoldingRegion(); + } - private PsiElement[] checkCustomFoldingRegionRange(Class... elementTypes) { - myFixture.configureByFile("/surround/" + getTestName(false) + ".py"); - final SelectionModel selection = myFixture.getEditor().getSelectionModel(); - final PsiElement[] range = CustomFoldingSurroundDescriptor.INSTANCE.getElementsToSurround(myFixture.getFile(), - selection.getSelectionStart(), - selection.getSelectionEnd()); - assertEquals(elementTypes.length, range.length); - for (int i = 0; i < elementTypes.length; i++) { - assertInstanceOf(range[i], elementTypes[i]); - } - return range; + public void testCustomFoldingRegionSingleStatementInFile() throws Exception { + doTestSurroundWithCustomFoldingRegion(); + } + + public void testCustomFoldingRegionIllegalSelection() throws Exception { + doTestSurroundWithCustomFoldingRegion(); + } + + public void testCustomFoldingRegionSeveralMethods() throws Exception { + doTestSurroundWithCustomFoldingRegion(); + } + + private void doTestSurroundWithCustomFoldingRegion() throws Exception { + final Surrounder surrounder = ContainerUtil.find(CustomFoldingSurroundDescriptor.SURROUNDERS, new Condition() { + @Override + public boolean value(Surrounder surrounder) { + return surrounder.getTemplateDescription().contains(" Date: Thu, 6 Nov 2014 20:28:53 +0300 Subject: [PATCH 77/84] PY-11956 Check all possible canonical names if qualifier has union type If user manually suppressed warnings about unresolved reference for attribute of some class and this attribute is later accessed on some expression with union type that includes this class, we should not highlight such attribute as unresolved. --- .../PyUnresolvedReferencesInspection.java | 61 ++++++++++++------- .../ignoredUnresolvedReferenceInUnionType.py | 8 +++ .../PyUnresolvedReferencesInspectionTest.java | 14 +++++ 3 files changed, 60 insertions(+), 23 deletions(-) create mode 100644 python/testData/inspections/PyUnresolvedReferencesInspection/ignoredUnresolvedReferenceInUnionType.py diff --git a/python/src/com/jetbrains/python/inspections/unresolvedReference/PyUnresolvedReferencesInspection.java b/python/src/com/jetbrains/python/inspections/unresolvedReference/PyUnresolvedReferencesInspection.java index daa1fd8fc19a..d737467ba0f6 100644 --- a/python/src/com/jetbrains/python/inspections/unresolvedReference/PyUnresolvedReferencesInspection.java +++ b/python/src/com/jetbrains/python/inspections/unresolvedReference/PyUnresolvedReferencesInspection.java @@ -32,6 +32,8 @@ import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.QualifiedName; import com.intellij.util.Consumer; import com.intellij.util.PlatformUtils; +import com.intellij.util.SmartList; +import com.intellij.util.containers.ContainerUtil; import com.jetbrains.python.PyBundle; import com.jetbrains.python.PyCustomMembersType; import com.jetbrains.python.PyNames; @@ -436,9 +438,9 @@ public class PyUnresolvedReferencesInspection extends PyInspection { return; } - final QualifiedName canonicalQName = getCanonicalName(reference, myTypeEvalContext); - final String canonicalName = canonicalQName != null ? canonicalQName.toString() : null; - if (canonicalName != null) { + final List qualifiedNames = getCanonicalNames(reference, myTypeEvalContext); + for (QualifiedName name: qualifiedNames) { + final String canonicalName = name.toString(); for (String ignored : myIgnoredIdentifiers) { if (ignored.endsWith(END_WILDCARD)) { final String prefix = ignored.substring(0, ignored.length() - END_WILDCARD.length()); @@ -582,10 +584,11 @@ public class PyUnresolvedReferencesInspection extends PyInspection { actions.addAll(GenerateBinaryStubsFix.generateFixes(importStatementBase)); } } - if (canonicalQName != null) { - actions.add(new AddIgnoredIdentifierQuickFix(canonicalQName, false)); - if (canonicalQName.getComponentCount() > 1) { - actions.add(new AddIgnoredIdentifierQuickFix(canonicalQName.removeLastComponent(), true)); + if (qualifiedNames.size() == 1) { + final QualifiedName qualifiedName = qualifiedNames.get(0); + actions.add(new AddIgnoredIdentifierQuickFix(qualifiedName, false)); + if (qualifiedName.getComponentCount() > 1) { + actions.add(new AddIgnoredIdentifierQuickFix(qualifiedName.removeLastComponent(), true)); } } addPluginQuickFixes(reference, actions); @@ -621,20 +624,20 @@ public class PyUnresolvedReferencesInspection extends PyInspection { } /** - * Return the canonical qualified name for a reference (even for an unresolved one). + * Return the canonical qualified names for a reference (even for an unresolved one). + * If reference is qualified and its qualifier has union type, all possible canonical names will be returned. */ - @Nullable - private static QualifiedName getCanonicalName(@NotNull PsiReference reference, @NotNull TypeEvalContext context) { + @NotNull + private static List getCanonicalNames(@NotNull PsiReference reference, @NotNull TypeEvalContext context) { final PsiElement element = reference.getElement(); + final List result = new SmartList(); if (reference instanceof PyOperatorReference && element instanceof PyQualifiedExpression) { final PyExpression receiver = ((PyOperatorReference)reference).getReceiver(); if (receiver != null) { final PyType type = context.getType(receiver); if (type instanceof PyClassType) { - final String name = ((PyClassType)type).getClassQName(); - if (name != null) { - return QualifiedName.fromDottedString(name).append(((PyQualifiedExpression)element).getReferencedName()); - } + final String methodName = ((PyQualifiedExpression)element).getReferencedName(); + ContainerUtil.addIfNotNull(result, extractAttributeQNameFromClassType(methodName, (PyClassType)type)); } } } @@ -646,16 +649,20 @@ public class PyUnresolvedReferencesInspection extends PyInspection { if (qualifier != null) { final PyType type = context.getType(qualifier); if (type instanceof PyClassType) { - final String name = ((PyClassType)type).getClassQName(); - if (name != null) { - return QualifiedName.fromDottedString(name).append(exprName); - } + ContainerUtil.addIfNotNull(result, extractAttributeQNameFromClassType(exprName, (PyClassType)type)); } else if (type instanceof PyModuleType) { final PyFile file = ((PyModuleType)type).getModule(); final QualifiedName name = QualifiedNameFinder.findCanonicalImportPath(file, element); if (name != null) { - return name.append(exprName); + ContainerUtil.addIfNotNull(result, name.append(exprName)); + } + } + else if (type instanceof PyUnionType) { + for (PyType memberType : ((PyUnionType)type).getMembers()) { + if (memberType instanceof PyClassType) { + ContainerUtil.addIfNotNull(result, extractAttributeQNameFromClassType(exprName, (PyClassType)memberType)); + } } } } @@ -664,14 +671,14 @@ public class PyUnresolvedReferencesInspection extends PyInspection { if (parent instanceof PyImportElement) { final PyImportStatementBase importStmt = PsiTreeUtil.getParentOfType(parent, PyImportStatementBase.class); if (importStmt instanceof PyImportStatement) { - return QualifiedName.fromComponents(exprName); + ContainerUtil.addIfNotNull(result, QualifiedName.fromComponents(exprName)); } else if (importStmt instanceof PyFromImportStatement) { final PsiElement resolved = ((PyFromImportStatement)importStmt).resolveImportSource(); if (resolved != null) { final QualifiedName path = QualifiedNameFinder.findCanonicalImportPath(resolved, element); if (path != null) { - return path.append(exprName); + ContainerUtil.addIfNotNull(result, path.append(exprName)); } } } @@ -679,14 +686,22 @@ public class PyUnresolvedReferencesInspection extends PyInspection { else { final QualifiedName path = QualifiedNameFinder.findCanonicalImportPath(element, element); if (path != null) { - return path.append(exprName); + ContainerUtil.addIfNotNull(result, path.append(exprName)); } } } } } else if (reference instanceof DocStringParameterReference) { - return QualifiedName.fromDottedString(reference.getCanonicalText()); + ContainerUtil.addIfNotNull(result, QualifiedName.fromDottedString(reference.getCanonicalText())); + } + return result; + } + + private static QualifiedName extractAttributeQNameFromClassType(String exprName, PyClassType type) { + final String name = type.getClassQName(); + if (name != null) { + return QualifiedName.fromDottedString(name).append(exprName); } return null; } diff --git a/python/testData/inspections/PyUnresolvedReferencesInspection/ignoredUnresolvedReferenceInUnionType.py b/python/testData/inspections/PyUnresolvedReferencesInspection/ignoredUnresolvedReferenceInUnionType.py new file mode 100644 index 000000000000..49000449847d --- /dev/null +++ b/python/testData/inspections/PyUnresolvedReferencesInspection/ignoredUnresolvedReferenceInUnionType.py @@ -0,0 +1,8 @@ +class A: + pass + +a = A() +print(a.foo) + +x = A() or None +print(x.foo) \ No newline at end of file diff --git a/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java b/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java index 9440d666c07f..8971fb78dd55 100644 --- a/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java +++ b/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java @@ -15,6 +15,7 @@ */ package com.jetbrains.python.inspections; +import com.intellij.codeInsight.intention.IntentionAction; import com.jetbrains.python.fixtures.PyInspectionTestCase; import com.jetbrains.python.inspections.unresolvedReference.PyUnresolvedReferencesInspection; import com.jetbrains.python.psi.LanguageLevel; @@ -396,6 +397,19 @@ public class PyUnresolvedReferencesInspectionTest extends PyInspectionTestCase { doMultiFileTest(); } + // PY-11956 + public void testIgnoredUnresolvedReferenceInUnionType() { + final String testName = getTestName(true); + final String inspectionName = getInspectionClass().getSimpleName(); + myFixture.configureByFile("inspections/" + inspectionName + "/" + testName + ".py"); + myFixture.enableInspections(getInspectionClass()); + final String attrQualifiedName = "inspections." + inspectionName + "." + testName + ".A.foo"; + final IntentionAction intentionAction = myFixture.findSingleIntention("Ignore unresolved reference '" + attrQualifiedName + "'"); + assertNotNull(intentionAction); + myFixture.launchAction(intentionAction); + myFixture.checkHighlighting(isWarning(), isInfo(), isWeakWarning()); + } + @NotNull @Override protected Class getInspectionClass() { From 8dd5ec461df43295c8c285d465f084305df192fc Mon Sep 17 00:00:00 2001 From: Mikhail Golubev Date: Fri, 7 Nov 2014 13:47:36 +0300 Subject: [PATCH 78/84] Revert previous fix in custom folding descriptor: copy indentation again Python formatter does not correctly align closing comment after first method in class if opening comment was aligned on first column. The problem is that left margin of block that corresponds to statement list is determined by its first child. If this child is incorrectly indented line comment, all later comments will be aligned wrongly as well, because their blocks have 'none' indent in parent. --- .../lang/folding/CustomFoldingSurroundDescriptor.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/platform/lang-api/src/com/intellij/lang/folding/CustomFoldingSurroundDescriptor.java b/platform/lang-api/src/com/intellij/lang/folding/CustomFoldingSurroundDescriptor.java index cf63d76e6f38..41a6cbe66074 100644 --- a/platform/lang-api/src/com/intellij/lang/folding/CustomFoldingSurroundDescriptor.java +++ b/platform/lang-api/src/com/intellij/lang/folding/CustomFoldingSurroundDescriptor.java @@ -260,6 +260,8 @@ public class CustomFoldingSurroundDescriptor implements SurroundDescriptor { int prefixLength = linePrefix.length(); int startOffset = firstElement.getTextRange().getStartOffset(); final Document document = editor.getDocument(); + final int startLineNumber = document.getLineNumber(startOffset); + final String startIndent = document.getText(new TextRange(document.getLineStartOffset(startLineNumber), startOffset)); int endOffset = lastElement.getTextRange().getEndOffset(); int delta = 0; TextRange rangeToSelect = new TextRange(startOffset, startOffset); @@ -269,12 +271,11 @@ public class CustomFoldingSurroundDescriptor implements SurroundDescriptor { startText = startText.replace("?", DEFAULT_DESC_TEXT); rangeToSelect = new TextRange(startOffset + descPos, startOffset + descPos + DEFAULT_DESC_TEXT.length()); } - String startString = linePrefix + startText + "\n"; + String startString = linePrefix + startText + "\n" + startIndent; String endString = "\n" + linePrefix + myProvider.getEndString(); document.insertString(endOffset, endString); delta += endString.length(); - final int startCommentInsertionOffset = document.getLineStartOffset(document.getLineNumber(startOffset)); - document.insertString(startCommentInsertionOffset, startString); + document.insertString(startOffset, startString); delta += startString.length(); rangeToSelect = rangeToSelect.shiftRight(prefixLength); PsiDocumentManager documentManager = PsiDocumentManager.getInstance(project); @@ -282,7 +283,7 @@ public class CustomFoldingSurroundDescriptor implements SurroundDescriptor { adjustLineIndent(project, psiFile, language, new TextRange(endOffset + delta - endString.length(), endOffset + delta)); adjustLineIndent(project, psiFile, language, - new TextRange(startCommentInsertionOffset, startCommentInsertionOffset + startString.length())); + new TextRange(startOffset, startOffset + startString.length())); return rangeToSelect; } From ca6951a3bc613094f508483834433d22cc5c8e06 Mon Sep 17 00:00:00 2001 From: peter Date: Fri, 7 Nov 2014 11:46:34 +0100 Subject: [PATCH 79/84] IDEA-132454 "Clear Read-Only Status" dialog displayed twice on cancel --- .../codeInsight/lookup/impl/LookupTypedHandler.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupTypedHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupTypedHandler.java index b13bbb4be33e..dd370f6dfe7f 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupTypedHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupTypedHandler.java @@ -59,18 +59,19 @@ public class LookupTypedHandler extends TypedActionHandlerBase { @Override public void execute(@NotNull Editor originalEditor, char charTyped, @NotNull DataContext dataContext) { final Project project = CommonDataKeys.PROJECT.getData(dataContext); - PsiFile file; + PsiFile file = project == null ? null : PsiUtilBase.getPsiFileInEditor(originalEditor, project); - if (project == null - || (file = PsiUtilBase.getPsiFileInEditor(originalEditor, project)) == null - || !CodeInsightUtilBase.prepareEditorForWrite(originalEditor) - || !FileDocumentManager.getInstance().requestWriting(originalEditor.getDocument(), project)) { + if (file == null) { if (myOriginalHandler != null){ myOriginalHandler.execute(originalEditor, charTyped, dataContext); } return; } + if (!CodeInsightUtilBase.prepareEditorForWrite(originalEditor) || !FileDocumentManager.getInstance().requestWriting(originalEditor.getDocument(), project)) { + return; + } + CompletionPhase oldPhase = CompletionServiceImpl.getCompletionPhase(); if (oldPhase instanceof CompletionPhase.CommittingDocuments && ((CompletionPhase.CommittingDocuments)oldPhase).isRestartingCompletion()) { assert oldPhase.indicator != null; From 65ba5b7cb1aeeafb8226993f1cd6782eebe7c70e Mon Sep 17 00:00:00 2001 From: Dmitry Avdeev Date: Fri, 7 Nov 2014 14:59:41 +0300 Subject: [PATCH 80/84] IDEA-126416 Suppress XmlUnusedNamespaceDeclaration --- .../com/intellij/refactoring/XmlImportOptimizer.java | 4 ++++ xml/tests/src/com/intellij/xml/XmlNamespacesTest.java | 11 ++++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/xml/impl/src/com/intellij/refactoring/XmlImportOptimizer.java b/xml/impl/src/com/intellij/refactoring/XmlImportOptimizer.java index fe78e55df189..2e02abcd071f 100644 --- a/xml/impl/src/com/intellij/refactoring/XmlImportOptimizer.java +++ b/xml/impl/src/com/intellij/refactoring/XmlImportOptimizer.java @@ -15,6 +15,7 @@ */ package com.intellij.refactoring; +import com.intellij.codeInsight.daemon.HighlightDisplayKey; import com.intellij.codeInsight.daemon.impl.analysis.XmlUnusedNamespaceInspection; import com.intellij.codeInspection.InspectionManager; import com.intellij.codeInspection.ProblemDescriptor; @@ -23,6 +24,7 @@ import com.intellij.codeInspection.QuickFix; import com.intellij.lang.ImportOptimizer; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Condition; +import com.intellij.profile.codeInspection.InspectionProjectProfileManager; import com.intellij.psi.*; import com.intellij.psi.xml.XmlAttribute; import com.intellij.psi.xml.XmlFile; @@ -64,6 +66,8 @@ public class XmlImportOptimizer implements ImportOptimizer { public void run() { XmlFile xmlFile = (XmlFile)file; Project project = xmlFile.getProject(); + HighlightDisplayKey key = HighlightDisplayKey.find(myInspection.getShortName()); + if (!InspectionProjectProfileManager.getInstance(project).getInspectionProfile().isToolEnabled(key, xmlFile)) return; ProblemsHolder holder = new ProblemsHolder(InspectionManager.getInstance(project), xmlFile, false); final XmlElementVisitor visitor = (XmlElementVisitor)myInspection.buildVisitor(holder, false); new PsiRecursiveElementVisitor() { diff --git a/xml/tests/src/com/intellij/xml/XmlNamespacesTest.java b/xml/tests/src/com/intellij/xml/XmlNamespacesTest.java index c38ce07bc1e2..90e1cdd3310d 100644 --- a/xml/tests/src/com/intellij/xml/XmlNamespacesTest.java +++ b/xml/tests/src/com/intellij/xml/XmlNamespacesTest.java @@ -19,11 +19,13 @@ import com.intellij.codeInsight.actions.OptimizeImportsProcessor; import com.intellij.codeInsight.daemon.impl.analysis.XmlUnusedNamespaceInspection; import com.intellij.codeInsight.intention.IntentionAction; import com.intellij.codeInspection.htmlInspections.XmlInspectionToolProvider; +import com.intellij.ide.highlighter.XmlFileType; import com.intellij.javaee.ExternalResourceManagerExImpl; import com.intellij.openapi.application.Result; import com.intellij.openapi.command.WriteCommandAction; import com.intellij.testFramework.IdeaTestCase; import com.intellij.testFramework.fixtures.CodeInsightFixtureTestCase; +import org.jetbrains.annotations.NotNull; /** * @author Dmitry Avdeev @@ -235,6 +237,13 @@ public class XmlNamespacesTest extends CodeInsightFixtureTestCase { myFixture.testHighlighting("import.xml", "import.xsd"); } + public void testDoNotOptimizeWhenInspectionDisabled() throws Exception { + myFixture.disableInspections(new XmlUnusedNamespaceInspection()); + String text = ""; + myFixture.configureByText(XmlFileType.INSTANCE, text); + doOptimizeImportsTest(text); + } + private void doUnusedDeclarationTest(String text, String after, String name) throws Exception { doUnusedDeclarationTest(text, after, name, true); } @@ -257,7 +266,7 @@ public class XmlNamespacesTest extends CodeInsightFixtureTestCase { myFixture.testHighlighting(); new WriteCommandAction(getProject(), getFile()) { @Override - protected void run(Result result) throws Throwable { + protected void run(@NotNull Result result) throws Throwable { new OptimizeImportsProcessor(getProject(), getFile()).runWithoutProgress(); } }.execute(); From 741f03209c8ae766bde32e6dbf19a81deeb87152 Mon Sep 17 00:00:00 2001 From: "Maxim.Mossienko" Date: Fri, 7 Nov 2014 14:16:27 +0100 Subject: [PATCH 81/84] get rid of LightVirtualFile by generalizing its processing as files in non local filesystem that can not survive their removal / undo of removal --- ... => DocumentReferenceByNonlocalVirtualFile.java} | 7 +++---- .../command/impl/DocumentReferenceManagerImpl.java | 5 ++--- .../openapi/command/impl/UndoRedoStacksHolder.java | 13 +++++++------ 3 files changed, 12 insertions(+), 13 deletions(-) rename platform/platform-impl/src/com/intellij/openapi/command/impl/{DocumentReferenceByLightVirtualFile.java => DocumentReferenceByNonlocalVirtualFile.java} (84%) diff --git a/platform/platform-impl/src/com/intellij/openapi/command/impl/DocumentReferenceByLightVirtualFile.java b/platform/platform-impl/src/com/intellij/openapi/command/impl/DocumentReferenceByNonlocalVirtualFile.java similarity index 84% rename from platform/platform-impl/src/com/intellij/openapi/command/impl/DocumentReferenceByLightVirtualFile.java rename to platform/platform-impl/src/com/intellij/openapi/command/impl/DocumentReferenceByNonlocalVirtualFile.java index d1dde6a49acd..101801ee3440 100644 --- a/platform/platform-impl/src/com/intellij/openapi/command/impl/DocumentReferenceByLightVirtualFile.java +++ b/platform/platform-impl/src/com/intellij/openapi/command/impl/DocumentReferenceByNonlocalVirtualFile.java @@ -19,14 +19,13 @@ import com.intellij.openapi.command.undo.DocumentReference; import com.intellij.openapi.editor.Document; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.testFramework.LightVirtualFile; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -class DocumentReferenceByLightVirtualFile implements DocumentReference { - private LightVirtualFile myFile; +class DocumentReferenceByNonlocalVirtualFile implements DocumentReference { + private final VirtualFile myFile; - DocumentReferenceByLightVirtualFile(@NotNull LightVirtualFile file) { + DocumentReferenceByNonlocalVirtualFile(@NotNull VirtualFile file) { myFile = file; } diff --git a/platform/platform-impl/src/com/intellij/openapi/command/impl/DocumentReferenceManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/command/impl/DocumentReferenceManagerImpl.java index 020ed90d9ad8..7b98099aebcf 100644 --- a/platform/platform-impl/src/com/intellij/openapi/command/impl/DocumentReferenceManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/command/impl/DocumentReferenceManagerImpl.java @@ -28,7 +28,6 @@ import com.intellij.openapi.vfs.VirtualFileEvent; import com.intellij.openapi.vfs.VirtualFileManager; import com.intellij.openapi.vfs.newvfs.NewVirtualFile; import com.intellij.reference.SoftReference; -import com.intellij.testFramework.LightVirtualFile; import com.intellij.util.containers.WeakKeyWeakValueHashMap; import com.intellij.util.containers.WeakValueHashMap; import com.intellij.util.io.fs.FilePath; @@ -134,10 +133,10 @@ public class DocumentReferenceManagerImpl extends DocumentReferenceManager imple public DocumentReference create(@NotNull VirtualFile file) { assertInDispatchThread(); - if (file instanceof LightVirtualFile) { + if (!file.isInLocalFileSystem()) { // we treat local files differently from non local because we can undo their deletion DocumentReference reference = file.getUserData(FILE_TO_STRONG_REF_KEY); if (reference == null) { - file.putUserData(FILE_TO_STRONG_REF_KEY, reference = new DocumentReferenceByLightVirtualFile((LightVirtualFile)file)); + file.putUserData(FILE_TO_STRONG_REF_KEY, reference = new DocumentReferenceByNonlocalVirtualFile(file)); } return reference; } diff --git a/platform/platform-impl/src/com/intellij/openapi/command/impl/UndoRedoStacksHolder.java b/platform/platform-impl/src/com/intellij/openapi/command/impl/UndoRedoStacksHolder.java index 742e3cb9cb23..41f49774bcf5 100644 --- a/platform/platform-impl/src/com/intellij/openapi/command/impl/UndoRedoStacksHolder.java +++ b/platform/platform-impl/src/com/intellij/openapi/command/impl/UndoRedoStacksHolder.java @@ -21,7 +21,6 @@ import com.intellij.openapi.editor.Document; import com.intellij.openapi.util.Key; import com.intellij.openapi.util.UserDataHolder; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.testFramework.LightVirtualFile; import com.intellij.util.containers.HashMap; import com.intellij.util.containers.WeakList; import gnu.trove.THashSet; @@ -35,9 +34,11 @@ class UndoRedoStacksHolder { private final boolean myUndo; private final LinkedList myGlobalStack = new LinkedList(); + // strongly reference local files for which we can undo file removal + // document without files and nonlocal files are stored without strong reference private final Map> myDocumentStacks = new HashMap>(); private final WeakList myDocumentsWithStacks = new WeakList(); - private final WeakList myLightVirtualFilesWithStacks = new WeakList(); + private final WeakList myNonlocalVirtualFilesWithStacks = new WeakList(); public UndoRedoStacksHolder(boolean isUndo) { myUndo = isUndo; @@ -53,8 +54,8 @@ class UndoRedoStacksHolder { LinkedList result; VirtualFile file = r.getFile(); - if (file instanceof LightVirtualFile) { - result = addWeaklyTrackedEmptyStack((LightVirtualFile)file, myLightVirtualFilesWithStacks); + if (!file.isInLocalFileSystem()) { + result = addWeaklyTrackedEmptyStack(file, myNonlocalVirtualFilesWithStacks); } else { result = myDocumentStacks.get(r); @@ -178,7 +179,7 @@ class UndoRedoStacksHolder { cleanWeaklyTrackedEmptyStacks(myDocumentsWithStacks); - cleanWeaklyTrackedEmptyStacks(myLightVirtualFilesWithStacks); + cleanWeaklyTrackedEmptyStacks(myNonlocalVirtualFilesWithStacks); } private void cleanWeaklyTrackedEmptyStacks(WeakList stackHolders) { @@ -240,7 +241,7 @@ class UndoRedoStacksHolder { for (Document each : myDocumentsWithStacks) { result.add(documentReferenceManager.create(each)); } - for (LightVirtualFile each : myLightVirtualFilesWithStacks) { + for (VirtualFile each : myNonlocalVirtualFilesWithStacks) { result.add(documentReferenceManager.create(each)); } } From ad6c010beba81c5bf35b5ff97db2ef9b335efd55 Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Fri, 7 Nov 2014 16:09:16 +0300 Subject: [PATCH 82/84] [git] IDEA-132552 Use THashSet instead of HashSet for VcsRefs to save some memory --- .../src/git4idea/log/GitLogProvider.java | 28 +++++++++++++------ 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/plugins/git4idea/src/git4idea/log/GitLogProvider.java b/plugins/git4idea/src/git4idea/log/GitLogProvider.java index 0b50a55c5e1a..8d956cfe801e 100644 --- a/plugins/git4idea/src/git4idea/log/GitLogProvider.java +++ b/plugins/git4idea/src/git4idea/log/GitLogProvider.java @@ -39,6 +39,7 @@ import git4idea.history.GitHistoryUtils; import git4idea.repo.GitRepository; import git4idea.repo.GitRepositoryChangeListener; import git4idea.repo.GitRepositoryManager; +import gnu.trove.THashSet; import gnu.trove.TObjectHashingStrategy; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -121,10 +122,10 @@ public class GitLogProvider implements VcsLogProvider { currentTagNames = readCurrentTagNames(root); addOldStillExistingTags(allRefs, currentTagNames, rex.getPreviousRefs()); - allDetails = ContainerUtil.newHashSet(data.getCommits()); + allDetails = newHashSet(data.getCommits()); - Set previousTags = new HashSet(ContainerUtil.mapNotNull(rex.getPreviousRefs(), GET_TAG_NAME)); - Set safeTags = new HashSet(ContainerUtil.mapNotNull(safeRefs, GET_TAG_NAME)); + Set previousTags = newHashSet(ContainerUtil.mapNotNull(rex.getPreviousRefs(), GET_TAG_NAME)); + Set safeTags = newHashSet(ContainerUtil.mapNotNull(safeRefs, GET_TAG_NAME)); Set newUnmatchedTags = remove(currentTagNames, previousTags, safeTags); if (!newUnmatchedTags.isEmpty()) { @@ -263,14 +264,14 @@ public class GitLogProvider implements VcsLogProvider { @NotNull private Set readCurrentTagNames(@NotNull VirtualFile root) throws VcsException { - Set tags = ContainerUtil.newHashSet(); + Set tags = newHashSet(); GitTag.listAsStrings(myProject, root, tags, null); return tags; } @NotNull private static Set remove(@NotNull Set original, @NotNull Set... toRemove) { - Set result = ContainerUtil.newHashSet(original); + Set result = newHashSet(original); for (Set set : toRemove) { result.removeAll(set); } @@ -305,8 +306,8 @@ public class GitLogProvider implements VcsLogProvider { parameters.add("--sparse"); final GitBekParentFixer parentFixer = GitBekParentFixer.prepare(root, this); - Set userRegistry = ContainerUtil.newHashSet(); - Set refs = ContainerUtil.newHashSet(); + Set userRegistry = newHashSet(); + Set refs = newHashSet(); GitHistoryUtils.readCommits(myProject, root, parameters, new CollectConsumer(userRegistry), new CollectConsumer(refs), new Consumer() { @Override @@ -339,7 +340,7 @@ public class GitLogProvider implements VcsLogProvider { VirtualFile root = repository.getRoot(); Collection localBranches = repository.getBranches().getLocalBranches(); Collection remoteBranches = repository.getBranches().getRemoteBranches(); - Set refs = new HashSet(localBranches.size() + remoteBranches.size()); + Set refs = new THashSet(localBranches.size() + remoteBranches.size()); for (GitLocalBranch localBranch : localBranches) { refs.add( myVcsObjectsFactory.createRef(HashImpl.build(localBranch.getHash()), localBranch.getName(), GitRefManager.LOCAL_BRANCH, root)); @@ -495,4 +496,15 @@ public class GitLogProvider implements VcsLogProvider { } return true; } + + @NotNull + private static Set newHashSet() { + return new THashSet(); + } + + @NotNull + private static Set newHashSet(@NotNull Collection initialCollection) { + return new THashSet(initialCollection); + } + } \ No newline at end of file From adc560a854d5dabfe5736f4aa39ec5198443abc5 Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Fri, 7 Nov 2014 16:15:56 +0300 Subject: [PATCH 83/84] [git] IDEA-132229 Remove Hash<->String conversion to avoid extra HashImpl and String objects allocation --- plugins/git4idea/src/git4idea/GitBranch.java | 4 ++-- plugins/git4idea/src/git4idea/log/GitLogProvider.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/git4idea/src/git4idea/GitBranch.java b/plugins/git4idea/src/git4idea/GitBranch.java index 0c7d394befda..acdd45a7f050 100644 --- a/plugins/git4idea/src/git4idea/GitBranch.java +++ b/plugins/git4idea/src/git4idea/GitBranch.java @@ -66,8 +66,8 @@ public abstract class GitBranch extends GitReference { * if this information wasn't supplied to the GitBranch constructor.

*/ @NotNull - public String getHash() { - return myHash.asString(); + public Hash getHash() { + return myHash; } /** diff --git a/plugins/git4idea/src/git4idea/log/GitLogProvider.java b/plugins/git4idea/src/git4idea/log/GitLogProvider.java index 8d956cfe801e..d89d2540592a 100644 --- a/plugins/git4idea/src/git4idea/log/GitLogProvider.java +++ b/plugins/git4idea/src/git4idea/log/GitLogProvider.java @@ -343,10 +343,10 @@ public class GitLogProvider implements VcsLogProvider { Set refs = new THashSet(localBranches.size() + remoteBranches.size()); for (GitLocalBranch localBranch : localBranches) { refs.add( - myVcsObjectsFactory.createRef(HashImpl.build(localBranch.getHash()), localBranch.getName(), GitRefManager.LOCAL_BRANCH, root)); + myVcsObjectsFactory.createRef(localBranch.getHash(), localBranch.getName(), GitRefManager.LOCAL_BRANCH, root)); } for (GitRemoteBranch remoteBranch : remoteBranches) { - refs.add(myVcsObjectsFactory.createRef(HashImpl.build(remoteBranch.getHash()), remoteBranch.getNameForLocalOperations(), + refs.add(myVcsObjectsFactory.createRef(remoteBranch.getHash(), remoteBranch.getNameForLocalOperations(), GitRefManager.REMOTE_BRANCH, root)); } String currentRevision = repository.getCurrentRevision(); From 9ec2fa983af60e8b1b3a83e612570d3b706a5641 Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Fri, 7 Nov 2014 16:23:11 +0300 Subject: [PATCH 84/84] [log] Don't log PCE --- .../impl/src/com/intellij/vcs/log/data/VcsLogDataHolder.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogDataHolder.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogDataHolder.java index f076e1325b4b..83638e2aa70e 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogDataHolder.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogDataHolder.java @@ -19,6 +19,7 @@ import com.intellij.openapi.Disposable; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.BackgroundTaskQueue; +import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.Task; import com.intellij.openapi.project.Project; @@ -111,7 +112,9 @@ public class VcsLogDataHolder implements Disposable, VcsLogDataProvider { myDataPackUpdateHandler, new Consumer() { @Override public void consume(Exception e) { - LOG.error(e); + if (!(e instanceof ProcessCanceledException)) { + LOG.error(e); + } } }, mySettings.getRecentCommitsCount()); }