From b37b0440d06989a4612262a1574678ffa8981650 Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Mon, 22 Dec 2014 14:05:31 +0300 Subject: [PATCH 001/137] PY-11932 Put nulls for unresolved class types in MRO Some of the ancestor class-like types may be unresolved. The best we can do is to put nulls for all the unresolved classes to appropriate places inside the MRO chain. What we used to do in this case it return the empty sequence of the ancestors. --- .../python/psi/impl/PyClassImpl.java | 13 +++++-- .../UnresolvedClassesImpossibleToBuildMRO.py | 34 +++++++++++++++++++ .../python/codeInsight/PyClassMROTest.java | 7 ++++ 3 files changed, 51 insertions(+), 3 deletions(-) create mode 100644 python/testData/codeInsight/classMRO/UnresolvedClassesImpossibleToBuildMRO.py diff --git a/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java b/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java index a94f11e3d2c9..30587ef1d5d1 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java @@ -335,6 +335,11 @@ public class PyClassImpl extends PyBaseElementImpl implements PyCla PyClassLikeType head = null; // to keep compiler happy; really head is assigned in the loop at least once. for (List seq : nonBlankSequences) { head = seq.get(0); + if (head == null) { + seq.remove(0); + found = true; + break; + } boolean head_in_tails = false; for (List tail_seq : nonBlankSequences) { if (tail_seq.indexOf(head) > 0) { // -1 is not found, 0 is head, >0 is tail. @@ -357,9 +362,11 @@ public class PyClassImpl extends PyBaseElementImpl implements PyCla // our head is clean; result.add(head); // remove it from heads of other sequences - for (List seq : nonBlankSequences) { - if (Comparing.equal(seq.get(0), head)) { - seq.remove(0); + if (head != null) { + for (List seq : nonBlankSequences) { + if (Comparing.equal(seq.get(0), head)) { + seq.remove(0); + } } } } // we either return inside the loop or die by assertion diff --git a/python/testData/codeInsight/classMRO/UnresolvedClassesImpossibleToBuildMRO.py b/python/testData/codeInsight/classMRO/UnresolvedClassesImpossibleToBuildMRO.py new file mode 100644 index 000000000000..9514c0f31690 --- /dev/null +++ b/python/testData/codeInsight/classMRO/UnresolvedClassesImpossibleToBuildMRO.py @@ -0,0 +1,34 @@ +class EtagSupport(object): + pass + + +class LockableItem(EtagSupport): + pass + + +class Resource(LockableItem, _Unresolved): + pass + + +class CopyContainer(_Unresolved): + pass + + +class Navigation(_Unresolved): + pass + + +class Tabs(_Unresolved): + pass + + +class Collection(Resource): + pass + + +class Traversable(object): + pass + + +class ObjectManager(CopyContainer, Navigation, Tabs, _Unresolved, _Unresolved, Collection, Traversable): + pass diff --git a/python/testSrc/com/jetbrains/python/codeInsight/PyClassMROTest.java b/python/testSrc/com/jetbrains/python/codeInsight/PyClassMROTest.java index eb828b7eed8c..2f500d573511 100644 --- a/python/testSrc/com/jetbrains/python/codeInsight/PyClassMROTest.java +++ b/python/testSrc/com/jetbrains/python/codeInsight/PyClassMROTest.java @@ -71,6 +71,13 @@ public class PyClassMROTest extends PyTestCase { assertMRO(getClass("H"), "E", "F", "B", "G", "C", "D", "A", "object"); } + // PY-11932 + public void testUnresolvedClassesImpossibleToBuildMRO() { + assertMRO(getClass("ObjectManager"), + "CopyContainer", "unknown", "Navigation", "unknown", "Tabs", "unknown", "unknown", "unknown", "Collection", "Resource", + "LockableItem", "EtagSupport", "Traversable", "object", "unknown"); + } + public void assertMRO(@NotNull PyClass cls, @NotNull String... mro) { final List types = cls.getAncestorTypes(TypeEvalContext.codeInsightFallback(cls.getProject())); final List classNames = new ArrayList(); From 19e9c38a86c4e9bd694ee0bbcd86afc69f08af19 Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Tue, 23 Dec 2014 17:14:23 +0300 Subject: [PATCH 002/137] Fall back to old-style ancestors if C3 MRO fails and there are unresolved ancestors (PY-11401) If the C3 MRO algorithm fails and the old-style ancestors algorithm tells that there are unresolved ancestors, we return a single 'null' ancestor as a sign that we don't know who the ancestors really are. If there are no unresolved ancestors, then we fall back to the old-style ancestors algorithm in order to make resolve work. A future inspection for detecting incorrect MRO may warn the user about this situation. --- .../python/psi/impl/PyClassImpl.java | 49 ++++++++++++++----- ...StyleMROIfUnresolvedAncestorsAndC3Fails.py | 22 +++++++++ ...nresolvedReferencesForClassesWithBadMRO.py | 26 ++++++++++ ...yleMROWhenUnresolvedAncestorsAndC3Fails.py | 23 +++++++++ .../com/jetbrains/python/PyResolveTest.java | 5 ++ .../python/codeInsight/PyClassMROTest.java | 8 +-- .../PyUnresolvedReferencesInspectionTest.java | 10 ++++ 7 files changed, 127 insertions(+), 16 deletions(-) create mode 100644 python/testData/inspections/PyUnresolvedReferencesInspection/fallbackToOldStyleMROIfUnresolvedAncestorsAndC3Fails.py create mode 100644 python/testData/inspections/PyUnresolvedReferencesInspection/noUnresolvedReferencesForClassesWithBadMRO.py create mode 100644 python/testData/resolve/ResolveAttributesUsingOldStyleMROWhenUnresolvedAncestorsAndC3Fails.py diff --git a/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java b/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java index 30587ef1d5d1..5532fa37da30 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java @@ -63,6 +63,12 @@ import static com.intellij.openapi.util.text.StringUtil.notNullize; * @author yole */ public class PyClassImpl extends PyBaseElementImpl implements PyClass { + public static class MROException extends Exception { + public MROException(String s) { + super(s); + } + } + public static final PyClass[] EMPTY_ARRAY = new PyClassImpl[0]; private List myInstanceAttributes; @@ -80,7 +86,28 @@ public class PyClassImpl extends PyBaseElementImpl implements PyCla @Nullable @Override public CachedValueProvider.Result> compute(@NotNull TypeEvalContext context) { - final List ancestorTypes = isNewStyleClass() ? getMROAncestorTypes(context) : getOldStyleAncestorTypes(context); + List ancestorTypes; + if (isNewStyleClass()) { + try { + ancestorTypes = getMROAncestorTypes(context); + } + catch (MROException e) { + ancestorTypes = getOldStyleAncestorTypes(context); + boolean hasUnresolvedAncestorTypes = false; + for (PyClassLikeType type : ancestorTypes) { + if (type == null) { + hasUnresolvedAncestorTypes = true; + break; + } + } + if (!hasUnresolvedAncestorTypes) { + ancestorTypes = Collections.singletonList(null); + } + } + } + else { + ancestorTypes = getOldStyleAncestorTypes(context); + } return CachedValueProvider.Result.create(ancestorTypes, PsiModificationTracker.MODIFICATION_COUNT); } } @@ -321,7 +348,7 @@ public class PyClassImpl extends PyBaseElementImpl implements PyCla } @NotNull - private static List mroMerge(@NotNull List> sequences) { + private static List mroMerge(@NotNull List> sequences) throws MROException { List result = new LinkedList(); // need to insert to 0th position on linearize while (true) { // filter blank sequences @@ -357,7 +384,7 @@ public class PyClassImpl extends PyBaseElementImpl implements PyCla } if (!found) { // Inconsistent hierarchy results in TypeError - throw new IllegalStateException("Inconsistent class hierarchy"); + throw new MROException("Inconsistent class hierarchy"); } // our head is clean; result.add(head); @@ -374,9 +401,9 @@ public class PyClassImpl extends PyBaseElementImpl implements PyCla @NotNull private static List mroLinearize(@NotNull PyClassLikeType type, @NotNull Set seen, boolean addThisType, - @NotNull TypeEvalContext context) { + @NotNull TypeEvalContext context) throws MROException { if (seen.contains(type)) { - throw new IllegalStateException("Circular class inheritance"); + throw new MROException("Circular class inheritance"); } final List bases = type.getSuperClassTypes(context); List> lines = new ArrayList>(); @@ -1300,16 +1327,14 @@ public class PyClassImpl extends PyBaseElementImpl implements PyCla } @NotNull - private List getMROAncestorTypes(@NotNull TypeEvalContext context) { + private List getMROAncestorTypes(@NotNull TypeEvalContext context) throws MROException { final PyType thisType = context.getType(this); if (thisType instanceof PyClassLikeType) { - try { - return mroLinearize((PyClassLikeType)thisType, new HashSet(), false, context); - } - catch (IllegalStateException ignored) { - } + return mroLinearize((PyClassLikeType)thisType, new HashSet(), false, context); + } + else { + return Collections.emptyList(); } - return Collections.emptyList(); } @NotNull diff --git a/python/testData/inspections/PyUnresolvedReferencesInspection/fallbackToOldStyleMROIfUnresolvedAncestorsAndC3Fails.py b/python/testData/inspections/PyUnresolvedReferencesInspection/fallbackToOldStyleMROIfUnresolvedAncestorsAndC3Fails.py new file mode 100644 index 000000000000..edd8344dfae9 --- /dev/null +++ b/python/testData/inspections/PyUnresolvedReferencesInspection/fallbackToOldStyleMROIfUnresolvedAncestorsAndC3Fails.py @@ -0,0 +1,22 @@ +class X(Unresolved): + pass + + +class Y(Unresolved): + pass + + +class A(X, Y): + def foo(self): + pass + + +class B(Y, X): + pass + + +class C(A, B): # we don't know whether MRO is OK or not + pass + + +print(C.foo) # pass diff --git a/python/testData/inspections/PyUnresolvedReferencesInspection/noUnresolvedReferencesForClassesWithBadMRO.py b/python/testData/inspections/PyUnresolvedReferencesInspection/noUnresolvedReferencesForClassesWithBadMRO.py new file mode 100644 index 000000000000..600ec8e33a53 --- /dev/null +++ b/python/testData/inspections/PyUnresolvedReferencesInspection/noUnresolvedReferencesForClassesWithBadMRO.py @@ -0,0 +1,26 @@ +class O(object): + pass + + +class X(O): + pass + + +class Y(O): + pass + + +class A(X, Y): + def foo(self): + pass + + +class B(Y, X): + pass + + +class C(A, B): # bad MRO + pass + + +print(C.foo) # pass diff --git a/python/testData/resolve/ResolveAttributesUsingOldStyleMROWhenUnresolvedAncestorsAndC3Fails.py b/python/testData/resolve/ResolveAttributesUsingOldStyleMROWhenUnresolvedAncestorsAndC3Fails.py new file mode 100644 index 000000000000..c279d67c9a4c --- /dev/null +++ b/python/testData/resolve/ResolveAttributesUsingOldStyleMROWhenUnresolvedAncestorsAndC3Fails.py @@ -0,0 +1,23 @@ +class X(Unresolved): + pass + + +class Y(Unresolved): + pass + + +class A(X, Y): + def foo(self): + pass + + +class B(Y, X): + pass + + +class C(A, B): # we don't know whether MRO is OK or not + pass + + +print(C.foo) +# diff --git a/python/testSrc/com/jetbrains/python/PyResolveTest.java b/python/testSrc/com/jetbrains/python/PyResolveTest.java index 91a8955938cf..52089593aec6 100644 --- a/python/testSrc/com/jetbrains/python/PyResolveTest.java +++ b/python/testSrc/com/jetbrains/python/PyResolveTest.java @@ -567,4 +567,9 @@ public class PyResolveTest extends PyResolveTestCase { PyTargetExpression xyzzy = assertResolvesTo(PyTargetExpression.class, "xyzzy"); assertEquals("__init__", PsiTreeUtil.getParentOfType(xyzzy, PyFunction.class).getName()); } + + // PY-11401 + public void testResolveAttributesUsingOldStyleMROWhenUnresolvedAncestorsAndC3Fails() { + assertResolvesTo(PyFunction.class, "foo"); + } } diff --git a/python/testSrc/com/jetbrains/python/codeInsight/PyClassMROTest.java b/python/testSrc/com/jetbrains/python/codeInsight/PyClassMROTest.java index 2f500d573511..a6a2adc488c5 100644 --- a/python/testSrc/com/jetbrains/python/codeInsight/PyClassMROTest.java +++ b/python/testSrc/com/jetbrains/python/codeInsight/PyClassMROTest.java @@ -35,7 +35,7 @@ public class PyClassMROTest extends PyTestCase { // TypeError in Python public void testMROConflict() { - assertMRO(getClass("C")); + assertMRO(getClass("C"), "unknown"); } public void testCircularInheritance() { @@ -43,7 +43,7 @@ public class PyClassMROTest extends PyTestCase { myFixture.configureByFiles(getPath(testName), getPath(testName + "2")); final PyClass cls = myFixture.findElementByText("Foo", PyClass.class); assertNotNull(cls); - assertMRO(cls); + assertMRO(cls, "unknown"); } public void testExampleFromDoc1() { @@ -55,7 +55,7 @@ public class PyClassMROTest extends PyTestCase { } public void testExampleFromDoc3() { - assertMRO(getClass("G")); + assertMRO(getClass("G"), "unknown"); } public void testExampleFromDoc4() { @@ -71,7 +71,7 @@ public class PyClassMROTest extends PyTestCase { assertMRO(getClass("H"), "E", "F", "B", "G", "C", "D", "A", "object"); } - // PY-11932 + // PY-11401 public void testUnresolvedClassesImpossibleToBuildMRO() { assertMRO(getClass("ObjectManager"), "CopyContainer", "unknown", "Navigation", "unknown", "Tabs", "unknown", "unknown", "unknown", "Collection", "Resource", diff --git a/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java b/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java index b367fcb8089f..d67766e31468 100644 --- a/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java +++ b/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java @@ -440,6 +440,16 @@ public class PyUnresolvedReferencesInspectionTest extends PyInspectionTestCase { doMultiFileTest("p1/__init__.py"); } + // PY-11401 + public void testNoUnresolvedReferencesForClassesWithBadMRO() { + doTest(); + } + + // PY-11401 + public void testFallbackToOldStyleMROIfUnresolvedAncestorsAndC3Fails() { + doTest(); + } + @NotNull @Override protected Class getInspectionClass() { From 645bd3a1b27bb3c3a45e557350fb3b81da1ab52a Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Tue, 23 Dec 2014 18:05:48 +0300 Subject: [PATCH 003/137] If mro() is overridden in metaclass, use normal MRO + unresolved ancestor (PY-11401) We cannot evaluate the result of an overridden mro() method, so we don't know the actual MRO chain. Let's assume that MRO is almost the same as without this override and add an element of uncertainty by appending a fake unresolved ancestor type to the MRO chain. Doing so results in, for example, the unresolved references inspection ignoring unresolved references for such a class. --- .../src/com/jetbrains/python/PyNames.java | 2 ++ .../python/psi/impl/PyClassImpl.java | 36 ++++++++++++++++++- .../overriddenMRO.py | 22 ++++++++++++ .../overriddenMROInAncestors.py | 28 +++++++++++++++ .../PyUnresolvedReferencesInspectionTest.java | 10 ++++++ 5 files changed, 97 insertions(+), 1 deletion(-) create mode 100644 python/testData/inspections/PyUnresolvedReferencesInspection/overriddenMRO.py create mode 100644 python/testData/inspections/PyUnresolvedReferencesInspection/overriddenMROInAncestors.py diff --git a/python/psi-api/src/com/jetbrains/python/PyNames.java b/python/psi-api/src/com/jetbrains/python/PyNames.java index 21e5be632d59..20a37449454e 100644 --- a/python/psi-api/src/com/jetbrains/python/PyNames.java +++ b/python/psi-api/src/com/jetbrains/python/PyNames.java @@ -503,4 +503,6 @@ public class PyNames { public static final ImmutableSet METHOD_SPECIAL_ATTRIBUTES = ImmutableSet.of("__func__", "__self__"); public static final ImmutableSet LEGACY_METHOD_SPECIAL_ATTRIBUTES = ImmutableSet.of("im_func", "im_self", "im_class"); + + public static final String MRO = "mro"; } diff --git a/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java b/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java index 5532fa37da30..c03fe346b6e3 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java @@ -1330,13 +1330,47 @@ public class PyClassImpl extends PyBaseElementImpl implements PyCla private List getMROAncestorTypes(@NotNull TypeEvalContext context) throws MROException { final PyType thisType = context.getType(this); if (thisType instanceof PyClassLikeType) { - return mroLinearize((PyClassLikeType)thisType, new HashSet(), false, context); + final PyClassLikeType thisClassLikeType = (PyClassLikeType)thisType; + final List ancestorTypes = mroLinearize(thisClassLikeType, new HashSet(), false, context); + if (isOverriddenMRO(ancestorTypes, context)) { + ancestorTypes.add(null); + } + return ancestorTypes; } else { return Collections.emptyList(); } } + private boolean isOverriddenMRO(@NotNull List ancestorTypes, @NotNull TypeEvalContext context) { + final List classes = new ArrayList(); + classes.add(this); + for (PyClassLikeType ancestorType : ancestorTypes) { + if (ancestorType instanceof PyClassType) { + final PyClassType classType = (PyClassType)ancestorType; + classes.add(classType.getPyClass()); + } + } + + final PyClass typeClass = PyBuiltinCache.getInstance(this).getClass("type"); + + for (PyClass cls : classes) { + final PyType metaClassType = cls.getMetaClassType(context); + if (metaClassType instanceof PyClassType) { + final PyClass metaClass = ((PyClassType)metaClassType).getPyClass(); + final PyFunction mroMethod = metaClass.findMethodByName(PyNames.MRO, true); + if (mroMethod != null) { + final PyClass mroClass = mroMethod.getContainingClass(); + if (mroClass != null && mroClass != typeClass) { + return true; + } + } + } + } + + return false; + } + @NotNull private List getOldStyleAncestorTypes(@NotNull TypeEvalContext context) { final List results = new ArrayList(); diff --git a/python/testData/inspections/PyUnresolvedReferencesInspection/overriddenMRO.py b/python/testData/inspections/PyUnresolvedReferencesInspection/overriddenMRO.py new file mode 100644 index 000000000000..e1f25b3568c8 --- /dev/null +++ b/python/testData/inspections/PyUnresolvedReferencesInspection/overriddenMRO.py @@ -0,0 +1,22 @@ +class A(object): + def foo(self): + return 0 + + +class B(object): + def bar(self): + return 0 + + +class MyMeta(type): + def mro(cls): + return A, B + + +class C(B): + __metaclass__ = MyMeta + + +c = C() +print(c.foo().lower()) # pass +print(c.bar().lower()) diff --git a/python/testData/inspections/PyUnresolvedReferencesInspection/overriddenMROInAncestors.py b/python/testData/inspections/PyUnresolvedReferencesInspection/overriddenMROInAncestors.py new file mode 100644 index 000000000000..15cd8ae700d5 --- /dev/null +++ b/python/testData/inspections/PyUnresolvedReferencesInspection/overriddenMROInAncestors.py @@ -0,0 +1,28 @@ +class A(object): + def foo(self): + return 0 + + +class MyMeta(type): + def mro(cls): + return A, B + + +class MyMeta2(MyMeta): + pass + + +class B(object): + __metaclass__ = MyMeta2 + + def bar(self): + return 0 + + +class C(B): + pass + + +c = C() +print(c.foo().lower()) # pass +print(c.bar().lower()) diff --git a/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java b/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java index d67766e31468..327cecabf147 100644 --- a/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java +++ b/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java @@ -450,6 +450,16 @@ public class PyUnresolvedReferencesInspectionTest extends PyInspectionTestCase { doTest(); } + // PY-11401 + public void testOverriddenMRO() { + doTest(); + } + + // PY-11401 + public void testOverriddenMROInAncestors() { + doTest(); + } + @NotNull @Override protected Class getInspectionClass() { From f981cc78ba9122aa8bf6fe0734f73eaf56fe8ccd Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Tue, 23 Dec 2014 20:08:18 +0300 Subject: [PATCH 004/137] Fix NPE for default project case, mark Project.getBaseDir as Nullable --- platform/core-api/src/com/intellij/openapi/project/Project.java | 1 + platform/core-impl/src/com/intellij/mock/MockProject.java | 1 + platform/dvcs-impl/src/com/intellij/dvcs/DvcsUtil.java | 2 +- .../src/com/intellij/openapi/command/impl/DummyProject.java | 1 + .../src/com/intellij/openapi/project/impl/ProjectImpl.java | 1 + 5 files changed, 5 insertions(+), 1 deletion(-) diff --git a/platform/core-api/src/com/intellij/openapi/project/Project.java b/platform/core-api/src/com/intellij/openapi/project/Project.java index 122659950375..f27e9e2e7410 100644 --- a/platform/core-api/src/com/intellij/openapi/project/Project.java +++ b/platform/core-api/src/com/intellij/openapi/project/Project.java @@ -59,6 +59,7 @@ public interface Project extends ComponentManager, AreaInstance { * * @return a path to a project base directory, or null for default project */ + @Nullable @NonNls String getBasePath(); diff --git a/platform/core-impl/src/com/intellij/mock/MockProject.java b/platform/core-impl/src/com/intellij/mock/MockProject.java index 8e8016f1f659..72870cc78365 100644 --- a/platform/core-impl/src/com/intellij/mock/MockProject.java +++ b/platform/core-impl/src/com/intellij/mock/MockProject.java @@ -120,6 +120,7 @@ public class MockProject extends MockComponentManager implements Project { return myBaseDir; } + @Nullable @Override public String getBasePath() { return null; diff --git a/platform/dvcs-impl/src/com/intellij/dvcs/DvcsUtil.java b/platform/dvcs-impl/src/com/intellij/dvcs/DvcsUtil.java index ae9812121828..fc95b7720b0e 100644 --- a/platform/dvcs-impl/src/com/intellij/dvcs/DvcsUtil.java +++ b/platform/dvcs-impl/src/com/intellij/dvcs/DvcsUtil.java @@ -296,7 +296,7 @@ public class DvcsUtil { } public static void addMappingIfSubRoot(@NotNull Project project, @NotNull String newRepositoryPath, @NotNull String vcsName) { - if (FileUtil.isAncestor(project.getBasePath(), newRepositoryPath, true)) { + if (project.getBasePath() != null && FileUtil.isAncestor(project.getBasePath(), newRepositoryPath, true)) { ProjectLevelVcsManager manager = ProjectLevelVcsManager.getInstance(project); manager.setDirectoryMappings(VcsUtil.addMapping(manager.getDirectoryMappings(), newRepositoryPath, vcsName)); } diff --git a/platform/platform-impl/src/com/intellij/openapi/command/impl/DummyProject.java b/platform/platform-impl/src/com/intellij/openapi/command/impl/DummyProject.java index 2b7e32717318..08bd9dbbab6b 100644 --- a/platform/platform-impl/src/com/intellij/openapi/command/impl/DummyProject.java +++ b/platform/platform-impl/src/com/intellij/openapi/command/impl/DummyProject.java @@ -88,6 +88,7 @@ public class DummyProject extends UserDataHolderBase implements Project { return null; } + @Nullable @Override public String getBasePath() { return null; diff --git a/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectImpl.java b/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectImpl.java index 6ab2ac759d83..1a0e16dfc640 100644 --- a/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectImpl.java @@ -238,6 +238,7 @@ public class ProjectImpl extends PlatformComponentManagerImpl implements Project return getStateStore().getProjectBaseDir(); } + @Nullable @Override public String getBasePath() { return getStateStore().getProjectBasePath(); From 5388808bfca735092f729d37902de98691f32cda Mon Sep 17 00:00:00 2001 From: Dmitry Batkovich Date: Wed, 24 Dec 2014 13:00:43 +0300 Subject: [PATCH 005/137] inspections settings manage button ui updated --- .../profile/codeInspection/ui/header/ManageButton.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/header/ManageButton.java b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/header/ManageButton.java index fd26822af52d..5f75e2f813c2 100644 --- a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/header/ManageButton.java +++ b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/header/ManageButton.java @@ -36,7 +36,9 @@ public class ManageButton extends ComboBoxAction implements DumbAware { public ManageButton(final ManageButtonBuilder builder) { myBuilder = builder; getTemplatePresentation().setText("Manage"); - setSmallVariant(false); + if (SystemInfo.isMac) { + setSmallVariant(false); + } } public JComponent build() { From 8e10b7b8fc374fdbaeb1be6666e8d0017ae1a92b Mon Sep 17 00:00:00 2001 From: Dmitry Batrak Date: Wed, 24 Dec 2014 12:56:08 +0300 Subject: [PATCH 006/137] fix soft wrap recalculation issue --- .../softwrap/mapping/SoftWrapApplianceManager.java | 1 + .../SoftWrapApplianceOnDocumentModificationTest.java | 11 +++++++++++ 2 files changed, 12 insertions(+) diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/mapping/SoftWrapApplianceManager.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/mapping/SoftWrapApplianceManager.java index 6bc28ed89ce2..a24422aa64ba 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/mapping/SoftWrapApplianceManager.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/mapping/SoftWrapApplianceManager.java @@ -395,6 +395,7 @@ public class SoftWrapApplianceManager implements Dumpable { if (myContext.delayedSoftWrap != null) { myStorage.remove(myContext.delayedSoftWrap); + myContext.delayedSoftWrap = null; } if (softWrap == null) { diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/softwrap/mapping/SoftWrapApplianceOnDocumentModificationTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/softwrap/mapping/SoftWrapApplianceOnDocumentModificationTest.java index 6f1e8c0657c3..5fb8396715ed 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/softwrap/mapping/SoftWrapApplianceOnDocumentModificationTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/softwrap/mapping/SoftWrapApplianceOnDocumentModificationTest.java @@ -1106,6 +1106,17 @@ public class SoftWrapApplianceOnDocumentModificationTest extends AbstractEditorT verifySoftWrapPositions(); } + public void testFoldRegionPreventsLaterWrapping() throws Exception { + initText("unbreakableText.txt"); + configureSoftWraps(10); + verifySoftWrapPositions(15); + + addCollapsedFoldRegion(12, 13, "."); + + verifySoftWrapPositions(12); + assertEquals(1, myEditor.offsetToVisualPosition(19).line); + } + private void init(final int visibleWidthInColumns, @NotNull String fileText) throws IOException { init(visibleWidthInColumns, 7, fileText); } From 830bb35156ef24a2d50116c2fc3c349011bae3f0 Mon Sep 17 00:00:00 2001 From: Dmitry Batrak Date: Wed, 24 Dec 2014 13:06:28 +0300 Subject: [PATCH 007/137] following review CR-IC-7083 (IDEA-58130) --- .../notification/impl/GotItStateKeeper.java | 73 ------------------- .../ForcedSoftWrapsNotificationProvider.java | 8 +- .../src/META-INF/PlatformExtensions.xml | 2 - 3 files changed, 4 insertions(+), 79 deletions(-) delete mode 100644 platform/platform-impl/src/com/intellij/notification/impl/GotItStateKeeper.java diff --git a/platform/platform-impl/src/com/intellij/notification/impl/GotItStateKeeper.java b/platform/platform-impl/src/com/intellij/notification/impl/GotItStateKeeper.java deleted file mode 100644 index 8f2092b413d8..000000000000 --- a/platform/platform-impl/src/com/intellij/notification/impl/GotItStateKeeper.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright 2000-2014 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.intellij.notification.impl; - -import com.intellij.openapi.components.*; -import gnu.trove.THashSet; -import org.jdom.Element; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.Set; - -@State( - name = GotItStateKeeper.COMPONENT_NAME, - storages = @Storage(file = StoragePathMacros.APP_CONFIG + "/gotIt.xml", - roamingType = RoamingType.DISABLED) -) -public class GotItStateKeeper implements PersistentStateComponent { - public static final String COMPONENT_NAME = "GotItState"; - - private static final String ELEMENT_NAME = "disabledNotification"; - private static final String ATTRIBUTE_NAME = "key"; - - private final Set myDisabledNotifications = new THashSet(); - - public static GotItStateKeeper getInstance() { - return ServiceManager.getService(GotItStateKeeper.class); - } - - public synchronized boolean isNotificationDisabled(@NotNull String key) { - return myDisabledNotifications.contains(key); - } - - public synchronized void disableNotification(@NotNull String key) { - myDisabledNotifications.add(key); - } - - @Nullable - @Override - public synchronized Element getState() { - Element element = new Element(COMPONENT_NAME); - for (String key : myDisabledNotifications) { - Element child = new Element(ELEMENT_NAME); - child.setAttribute(ATTRIBUTE_NAME, key); - element.addContent(child); - } - return element; - } - - @Override - public synchronized void loadState(Element state) { - myDisabledNotifications.clear(); - for (Element child : state.getChildren(ELEMENT_NAME)) { - String key = child.getAttributeValue(ATTRIBUTE_NAME); - if (key != null) { - myDisabledNotifications.add(key); - } - } - } -} diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/ForcedSoftWrapsNotificationProvider.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/ForcedSoftWrapsNotificationProvider.java index a89a42e2803d..9d9004ad6cd2 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/ForcedSoftWrapsNotificationProvider.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/ForcedSoftWrapsNotificationProvider.java @@ -15,7 +15,7 @@ */ package com.intellij.openapi.editor.impl; -import com.intellij.notification.impl.GotItStateKeeper; +import com.intellij.ide.util.PropertiesComponent; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.EditorBundle; import com.intellij.openapi.fileEditor.FileEditor; @@ -30,7 +30,7 @@ import org.jetbrains.annotations.Nullable; public class ForcedSoftWrapsNotificationProvider extends EditorNotifications.Provider { private static final Key KEY = Key.create("forced.soft.wraps.notification.panel"); - private static final String GOT_IT_KEY = "Forced soft wraps in editor"; + private static final String DISABLED_NOTIFICATION_KEY = "disable.forced.soft.wraps.notification"; @NotNull @Override @@ -46,7 +46,7 @@ public class ForcedSoftWrapsNotificationProvider extends EditorNotifications.Pro final Project project = editor.getProject(); if (project == null || !Boolean.TRUE.equals(editor.getUserData(EditorImpl.FORCED_SOFT_WRAPS)) - || GotItStateKeeper.getInstance().isNotificationDisabled(GOT_IT_KEY)) return null; + || PropertiesComponent.getInstance().isTrueValue(DISABLED_NOTIFICATION_KEY)) return null; final EditorNotificationPanel panel = new EditorNotificationPanel(); panel.setText(EditorBundle.message("forced.soft.wrap.message")); @@ -60,7 +60,7 @@ public class ForcedSoftWrapsNotificationProvider extends EditorNotifications.Pro panel.createActionLabel(EditorBundle.message("forced.soft.wrap.dont.show.again.message"), new Runnable() { @Override public void run() { - GotItStateKeeper.getInstance().disableNotification(GOT_IT_KEY); + PropertiesComponent.getInstance().setValue(DISABLED_NOTIFICATION_KEY, "true"); EditorNotifications.getInstance(project).updateAllNotifications(); } }); diff --git a/platform/platform-resources/src/META-INF/PlatformExtensions.xml b/platform/platform-resources/src/META-INF/PlatformExtensions.xml index 609aa5a38167..14ef0cd79cc2 100644 --- a/platform/platform-resources/src/META-INF/PlatformExtensions.xml +++ b/platform/platform-resources/src/META-INF/PlatformExtensions.xml @@ -335,8 +335,6 @@ - - From c77b401cd8703b51d2563bd248501e01a222b92f Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Wed, 24 Dec 2014 13:08:56 +0300 Subject: [PATCH 008/137] [git] Make read commands silent by default (i.e. not spamming to the log) --- plugins/git4idea/src/git4idea/commands/GitHandler.java | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/git4idea/src/git4idea/commands/GitHandler.java b/plugins/git4idea/src/git4idea/commands/GitHandler.java index 64497ddbd505..3fe591e38d62 100644 --- a/plugins/git4idea/src/git4idea/commands/GitHandler.java +++ b/plugins/git4idea/src/git4idea/commands/GitHandler.java @@ -138,6 +138,7 @@ public abstract class GitHandler { } myCommandLine.addParameter(command.name()); myStdoutSuppressed = true; + mySilent = myCommand.lockingPolicy() == GitCommand.LockingPolicy.READ; } /** From fc2f556f4dd3ae9732faffb6bac9d0a1efab9ddc Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Wed, 24 Dec 2014 13:12:54 +0300 Subject: [PATCH 009/137] [git] Make fetch command not silent: it is reading, but important one --- plugins/git4idea/src/git4idea/commands/GitImpl.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/git4idea/src/git4idea/commands/GitImpl.java b/plugins/git4idea/src/git4idea/commands/GitImpl.java index 5a577f024437..3fdaa5bd8b77 100644 --- a/plugins/git4idea/src/git4idea/commands/GitImpl.java +++ b/plugins/git4idea/src/git4idea/commands/GitImpl.java @@ -481,6 +481,8 @@ public class GitImpl implements Git { @Override public GitLineHandler compute() { final GitLineHandler h = new GitLineHandler(repository.getProject(), repository.getRoot(), GitCommand.FETCH); + h.setSilent(false); + h.setStdoutSuppressed(false); h.setUrl(url); h.addParameters(remote); h.addParameters(params); From 9a692ff5bee3f449b3325750758871f3699fc17d Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Wed, 24 Dec 2014 10:59:28 +0100 Subject: [PATCH 010/137] cleanup --- .../templates/ManageProjectTemplatesDialog.java | 10 ++++------ .../com/intellij/platform/ProjectTemplatesFactory.java | 2 +- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/java/idea-ui/src/com/intellij/platform/templates/ManageProjectTemplatesDialog.java b/java/idea-ui/src/com/intellij/platform/templates/ManageProjectTemplatesDialog.java index 3a8a97b91cef..c9b87cd80945 100644 --- a/java/idea-ui/src/com/intellij/platform/templates/ManageProjectTemplatesDialog.java +++ b/java/idea-ui/src/com/intellij/platform/templates/ManageProjectTemplatesDialog.java @@ -19,6 +19,7 @@ import com.intellij.CommonBundle; import com.intellij.ide.util.projectWizard.WizardContext; import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.ui.Messages; +import com.intellij.openapi.util.io.FileUtil; import com.intellij.platform.ProjectTemplate; import com.intellij.platform.ProjectTemplatesFactory; import com.intellij.ui.CollectionListModel; @@ -35,7 +36,6 @@ import javax.swing.event.ListSelectionListener; import java.awt.*; import java.awt.event.ActionEvent; import java.io.File; -import java.net.URL; import java.util.Arrays; /** @@ -53,18 +53,16 @@ class ManageProjectTemplatesDialog extends DialogWrapper { setTitle("Manage Project Templates"); final ProjectTemplate[] templates = new ArchivedTemplatesFactory().createTemplates(ProjectTemplatesFactory.CUSTOM_GROUP, new WizardContext(null)); - final CollectionListModel model = new CollectionListModel(Arrays.asList(templates)) { + myTemplatesList = new JBList(new CollectionListModel(Arrays.asList(templates)) { @Override public void remove(int index) { ProjectTemplate template = getElementAt(index); super.remove(index); if (template instanceof LocalArchivedTemplate) { - URL path = ((LocalArchivedTemplate)template).getArchivePath(); - new File(path.getPath()).delete(); + FileUtil.delete(new File(((LocalArchivedTemplate)template).getArchivePath().getPath())); } } - }; - myTemplatesList = new JBList(model); + }); myTemplatesList.setEmptyText("No user-defined project templates"); myTemplatesList.setPreferredSize(new Dimension(300, 100)); myTemplatesList.setCellRenderer(new ColoredListCellRenderer() { diff --git a/platform/platform-impl/src/com/intellij/platform/ProjectTemplatesFactory.java b/platform/platform-impl/src/com/intellij/platform/ProjectTemplatesFactory.java index cb66ab0bcd6c..6a1a9837beef 100644 --- a/platform/platform-impl/src/com/intellij/platform/ProjectTemplatesFactory.java +++ b/platform/platform-impl/src/com/intellij/platform/ProjectTemplatesFactory.java @@ -36,7 +36,7 @@ public abstract class ProjectTemplatesFactory { public abstract String[] getGroups(); @NotNull - public abstract ProjectTemplate[] createTemplates(String group, WizardContext context); + public abstract ProjectTemplate[] createTemplates(@NotNull String group, WizardContext context); public Icon getGroupIcon(String group) { return null; From 48744d2b8eff75f3e573778d59b4fcaefc33401d Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Wed, 24 Dec 2014 11:26:45 +0100 Subject: [PATCH 011/137] cleanup --- .../templates/ArchivedTemplatesFactory.java | 33 +++++++++---------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/java/idea-ui/src/com/intellij/platform/templates/ArchivedTemplatesFactory.java b/java/idea-ui/src/com/intellij/platform/templates/ArchivedTemplatesFactory.java index 23f4e7e2db73..d57c45019f5d 100644 --- a/java/idea-ui/src/com/intellij/platform/templates/ArchivedTemplatesFactory.java +++ b/java/idea-ui/src/com/intellij/platform/templates/ArchivedTemplatesFactory.java @@ -26,6 +26,7 @@ import com.intellij.platform.ProjectTemplate; import com.intellij.platform.ProjectTemplatesFactory; import com.intellij.util.ArrayUtil; import com.intellij.util.containers.MultiMap; +import gnu.trove.THashMap; import org.jetbrains.annotations.NotNull; import javax.swing.*; @@ -33,13 +34,17 @@ import java.io.File; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; -import java.util.*; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; /** * @author Dmitry Avdeev * @since 10/1/12 */ public class ArchivedTemplatesFactory extends ProjectTemplatesFactory { + private final static Logger LOG = Logger.getInstance(ArchivedTemplatesFactory.class); static final String ZIP = ".zip"; @@ -47,8 +52,8 @@ public class ArchivedTemplatesFactory extends ProjectTemplatesFactory { @NotNull @Override protected MultiMap> compute() { - MultiMap> map = new MultiMap>(); - Map urls = new HashMap(); + MultiMap> map = MultiMap.createSmartList(); + Map urls = new THashMap(); //for (IdeaPluginDescriptor plugin : plugins) { // if (!plugin.isEnabled()) continue; // try { @@ -65,9 +70,7 @@ public class ArchivedTemplatesFactory extends ProjectTemplatesFactory { //} URL configURL = getCustomTemplatesURL(); - if (configURL != null) { - urls.put(configURL, ClassLoader.getSystemClassLoader()); - } + urls.put(configURL, ClassLoader.getSystemClassLoader()); for (Map.Entry url : urls.entrySet()) { try { @@ -94,23 +97,23 @@ public class ArchivedTemplatesFactory extends ProjectTemplatesFactory { } }; + @NotNull private static URL getCustomTemplatesURL() { - String path = getCustomTemplatesPath(); try { - return new File(path).toURI().toURL(); + return new File(getCustomTemplatesPath()).toURI().toURL(); } catch (MalformedURLException e) { throw new RuntimeException(e); } } + @NotNull static String getCustomTemplatesPath() { return PathManager.getConfigPath() + "/projectTemplates"; } public static File getTemplateFile(String name) { - String configURL = getCustomTemplatesPath(); - return new File(configURL + "/" + name + ".zip"); + return new File(getCustomTemplatesPath() + "/" + name + ".zip"); } @NotNull @@ -123,13 +126,11 @@ public class ArchivedTemplatesFactory extends ProjectTemplatesFactory { @NotNull @Override - public ProjectTemplate[] createTemplates(String group, WizardContext context) { - Collection> urls = myGroups.getValue().get(group); + public ProjectTemplate[] createTemplates(@NotNull String group, WizardContext context) { List templates = new ArrayList(); - for (Pair url : urls) { + for (Pair url : myGroups.getValue().get(group)) { try { - List children = UrlUtil.getChildrenRelativePaths(url.first); - for (String child : children) { + for (String child : UrlUtil.getChildrenRelativePaths(url.first)) { if (child.endsWith(ZIP)) { URL templateUrl = new URL(url.first.toExternalForm() + "/" + child); templates.add(new LocalArchivedTemplate(templateUrl, url.second)); @@ -152,6 +153,4 @@ public class ArchivedTemplatesFactory extends ProjectTemplatesFactory { public Icon getGroupIcon(String group) { return CUSTOM_GROUP.equals(group) ? AllIcons.Modules.Types.UserDefined : super.getGroupIcon(group); } - - private final static Logger LOG = Logger.getInstance(ArchivedTemplatesFactory.class); } From 3a2fc03d0ad8659905a39ed8af281373041511f4 Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Wed, 24 Dec 2014 11:28:08 +0100 Subject: [PATCH 012/137] cleanup, use HttpRequests --- .../templates/ArchivedProjectTemplate.java | 27 ++-- .../templates/LocalArchivedTemplate.java | 56 +++----- .../templates/RemoteTemplatesFactory.java | 134 +++++++----------- .../templates/TemplateModuleBuilder.java | 28 ++-- 4 files changed, 104 insertions(+), 141 deletions(-) diff --git a/java/idea-ui/src/com/intellij/platform/templates/ArchivedProjectTemplate.java b/java/idea-ui/src/com/intellij/platform/templates/ArchivedProjectTemplate.java index 35944487e624..d8edc9c425a2 100644 --- a/java/idea-ui/src/com/intellij/platform/templates/ArchivedProjectTemplate.java +++ b/java/idea-ui/src/com/intellij/platform/templates/ArchivedProjectTemplate.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. @@ -21,6 +21,7 @@ import com.intellij.ide.util.projectWizard.ProjectTemplateParameterFactory; import com.intellij.ide.util.projectWizard.WizardInputField; import com.intellij.openapi.module.ModuleType; import com.intellij.openapi.ui.ValidationInfo; +import com.intellij.openapi.util.io.StreamUtil; import com.intellij.platform.ProjectTemplate; import com.intellij.util.Function; import com.intellij.util.containers.ContainerUtil; @@ -29,7 +30,6 @@ import com.intellij.util.xmlb.annotations.AbstractCollection; import com.intellij.util.xmlb.annotations.Property; import com.intellij.util.xmlb.annotations.Tag; import org.jdom.Element; -import org.jdom.Namespace; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -45,7 +45,6 @@ import java.util.zip.ZipInputStream; */ @Tag("template") public abstract class ArchivedProjectTemplate implements ProjectTemplate { - public static final String INPUT_FIELD = "input-field"; protected final String myDisplayName; @@ -110,22 +109,26 @@ public abstract class ArchivedProjectTemplate implements ProjectTemplate { return null; } - public abstract ZipInputStream getStream() throws IOException; + public static abstract class StreamConsumer { + public abstract T consume(@NotNull ZipInputStream stream) throws IOException; + } + + public abstract void getStream(@NotNull StreamConsumer consumer) throws IOException; @Nullable public String getCategory() { return myCategory; } - public void populateFromElement(@NotNull Element element, final Namespace ns) { + public void populateFromElement(@NotNull Element element) { XmlSerializer.deserializeInto(this, element); - myInputFields = getFields(element, ns); + myInputFields = getFields(element); } - private static List getFields(Element templateElement, final Namespace ns) { + private static List getFields(Element templateElement) { //noinspection unchecked return ContainerUtil - .mapNotNull(templateElement.getChildren(INPUT_FIELD, ns), new Function() { + .mapNotNull(templateElement.getChildren(INPUT_FIELD), new Function() { @Override public WizardInputField fun(Element element) { ProjectTemplateParameterFactory factory = WizardInputField.getFactoryById(element.getText()); @@ -134,4 +137,12 @@ public abstract class ArchivedProjectTemplate implements ProjectTemplate { }); } + static void consumeZipStream(@NotNull StreamConsumer consumer, @NotNull ZipInputStream stream) throws IOException { + try { + consumer.consume(stream); + } + finally { + StreamUtil.closeStream(stream); + } + } } diff --git a/java/idea-ui/src/com/intellij/platform/templates/LocalArchivedTemplate.java b/java/idea-ui/src/com/intellij/platform/templates/LocalArchivedTemplate.java index 8d69635b3cbb..d0b4d540fa0b 100644 --- a/java/idea-ui/src/com/intellij/platform/templates/LocalArchivedTemplate.java +++ b/java/idea-ui/src/com/intellij/platform/templates/LocalArchivedTemplate.java @@ -19,14 +19,12 @@ import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleType; import com.intellij.openapi.module.ModuleTypeManager; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.IconLoader; import com.intellij.openapi.util.JDOMUtil; import com.intellij.openapi.util.io.StreamUtil; import com.intellij.openapi.vfs.CharsetToolkit; import org.jdom.Document; import org.jdom.Element; -import org.jdom.Namespace; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -42,7 +40,6 @@ import java.util.zip.ZipInputStream; * Date: 10/1/12 */ public class LocalArchivedTemplate extends ArchivedProjectTemplate { - public static final String DESCRIPTION_PATH = Project.DIRECTORY_STORE_FOLDER + "/description.html"; static final String TEMPLATE_DESCRIPTOR = Project.DIRECTORY_STORE_FOLDER + "/project-template.xml"; @@ -56,16 +53,11 @@ public class LocalArchivedTemplate extends ArchivedProjectTemplate { myArchivePath = archivePath; myModuleType = computeModuleType(this); - String s = readEntry(new Condition() { - @Override - public boolean value(ZipEntry entry) { - return entry.getName().endsWith(TEMPLATE_DESCRIPTOR); - } - }); + String s = readEntry(TEMPLATE_DESCRIPTOR); if (s != null) { try { Element templateElement = JDOMUtil.loadDocument(s).getRootElement(); - populateFromElement(templateElement, Namespace.NO_NAMESPACE); + populateFromElement(templateElement); String iconPath = templateElement.getChildText("icon-path"); if (iconPath != null) { myIcon = IconLoader.findIcon(iconPath, classLoader); @@ -84,12 +76,7 @@ public class LocalArchivedTemplate extends ArchivedProjectTemplate { @Override public String getDescription() { - return readEntry(new Condition() { - @Override - public boolean value(ZipEntry entry) { - return entry.getName().endsWith(DESCRIPTION_PATH); - } - }); + return readEntry(DESCRIPTION_PATH); } @Override @@ -98,34 +85,29 @@ public class LocalArchivedTemplate extends ArchivedProjectTemplate { } @Nullable - String readEntry(Condition condition) { - ZipInputStream stream = null; + String readEntry(@NotNull final String endsWith) { try { - stream = getStream(); - ZipEntry entry; - while ((entry = stream.getNextEntry()) != null) { - if (condition.value(entry)) { - return StreamUtil.readText(stream, CharsetToolkit.UTF8_CHARSET); + getStream(new StreamConsumer() { + @Override + public String consume(@NotNull ZipInputStream stream) throws IOException { + ZipEntry entry; + while ((entry = stream.getNextEntry()) != null) { + if (entry.getName().endsWith(endsWith)) { + return StreamUtil.readText(stream, CharsetToolkit.UTF8_CHARSET); + } + } + return null; } - } + }); } - catch (IOException e) { - return null; - } - finally { - StreamUtil.closeStream(stream); + catch (IOException ignored) { } return null; } @NotNull private static ModuleType computeModuleType(LocalArchivedTemplate template) { - String iml = template.readEntry(new Condition() { - @Override - public boolean value(ZipEntry entry) { - return entry.getName().endsWith(".iml"); - } - }); + String iml = template.readEntry(".iml"); if (iml == null) return ModuleType.EMPTY; try { Document document = JDOMUtil.loadDocument(iml); @@ -143,8 +125,8 @@ public class LocalArchivedTemplate extends ArchivedProjectTemplate { } @Override - public ZipInputStream getStream() throws IOException { - return new ZipInputStream(myArchivePath.openStream()); + public void getStream(@NotNull StreamConsumer consumer) throws IOException { + consumeZipStream(consumer, new ZipInputStream(myArchivePath.openStream())); } public URL getArchivePath() { diff --git a/java/idea-ui/src/com/intellij/platform/templates/RemoteTemplatesFactory.java b/java/idea-ui/src/com/intellij/platform/templates/RemoteTemplatesFactory.java index 956108b951f0..9a2d7dcd2658 100644 --- a/java/idea-ui/src/com/intellij/platform/templates/RemoteTemplatesFactory.java +++ b/java/idea-ui/src/com/intellij/platform/templates/RemoteTemplatesFactory.java @@ -24,25 +24,20 @@ import com.intellij.openapi.module.ModuleType; import com.intellij.openapi.module.ModuleTypeManager; import com.intellij.openapi.util.ClearableLazyValue; import com.intellij.openapi.util.JDOMUtil; -import com.intellij.openapi.util.io.StreamUtil; -import com.intellij.openapi.vfs.CharsetToolkit; import com.intellij.platform.ProjectTemplate; import com.intellij.platform.ProjectTemplatesFactory; import com.intellij.util.ArrayUtil; -import com.intellij.util.Function; import com.intellij.util.NullableFunction; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.MultiMap; -import com.intellij.util.net.HttpConfigurable; +import com.intellij.util.io.HttpRequests; import org.jdom.Element; import org.jdom.JDOMException; -import org.jdom.Namespace; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.TestOnly; import java.io.IOException; -import java.io.InputStream; -import java.net.HttpURLConnection; import java.util.Collection; import java.util.List; import java.util.zip.ZipInputStream; @@ -52,23 +47,39 @@ import java.util.zip.ZipInputStream; * Date: 11/14/12 */ public class RemoteTemplatesFactory extends ProjectTemplatesFactory { + private final static Logger LOG = Logger.getInstance(RemoteTemplatesFactory.class); - private static final String URL = "http://download.jetbrains.com/idea/project_templates/"; + private static final String URL = "https://download.jetbrains.com/idea/project_templates/"; public static final String TEMPLATE = "template"; public static final String INPUT_DEFAULT = "default"; - public static final Function ELEMENT_STRING_FUNCTION = new Function() { - @Override - public String fun(Element element) { - return element.getText(); - } - }; private final ClearableLazyValue> myTemplates = new ClearableLazyValue>() { @NotNull @Override protected MultiMap compute() { - return getTemplates(); + try { + return HttpRequests.request(URL + ApplicationInfo.getInstance().getBuild().getProductCode() + "_templates.xml") + .connect(new HttpRequests.RequestProcessor>() { + @Override + public MultiMap process(@NotNull HttpRequests.Request request) throws IOException { + try { + return create(JDOMUtil.load(request.getReader())); + } + catch (JDOMException e) { + LOG.error(e); + return MultiMap.emptyInstance(); + } + } + }); + } + catch (IOException e) { // timeouts, lost connection etc + LOG.info(e); + } + catch (Exception e) { + LOG.error(e); + } + return MultiMap.emptyInstance(); } }; @@ -81,98 +92,56 @@ public class RemoteTemplatesFactory extends ProjectTemplatesFactory { @NotNull @Override - public ProjectTemplate[] createTemplates(String group, WizardContext context) { + public ProjectTemplate[] createTemplates(@NotNull String group, WizardContext context) { Collection templates = myTemplates.getValue().get(group); return templates.toArray(new ProjectTemplate[templates.size()]); } - private static MultiMap getTemplates() { - InputStream stream = null; - HttpURLConnection connection = null; - String code = ApplicationInfo.getInstance().getBuild().getProductCode(); - try { - connection = getConnection(code + "_templates.xml"); - stream = connection.getInputStream(); - String text = StreamUtil.readText(stream, CharsetToolkit.UTF8_CHARSET); - return createFromText(text); - } - catch (IOException ex) { // timeouts, lost connection etc - LOG.info(ex); - return MultiMap.emptyInstance(); - } - catch (Exception e) { - LOG.error(e); - return MultiMap.emptyInstance(); - } - finally { - StreamUtil.closeStream(stream); - if (connection != null) { - connection.disconnect(); - } - } + @NotNull + @TestOnly + public static MultiMap createFromText(@NotNull String value) throws IOException, JDOMException { + return create(JDOMUtil.loadDocument(value).getRootElement()); } - @SuppressWarnings("unchecked") - public static MultiMap createFromText(String text) throws IOException, JDOMException { - - MultiMap map = new MultiMap(); - Element rootElement = JDOMUtil.loadDocument(text).getRootElement(); - List templates = createGroupTemplates(rootElement, Namespace.NO_NAMESPACE); - for (ArchivedProjectTemplate template : templates) { + @NotNull + private static MultiMap create(@NotNull Element element) throws IOException, JDOMException { + MultiMap map = MultiMap.createSmartList(); + for (ArchivedProjectTemplate template : createGroupTemplates(element)) { map.putValue(template.getCategory(), template); } return map; } @SuppressWarnings("unchecked") - private static List createGroupTemplates(Element groupElement, final Namespace ns) { - List elements = groupElement.getChildren(TEMPLATE, ns); - + private static List createGroupTemplates(Element groupElement) { + List elements = groupElement.getChildren(TEMPLATE); return ContainerUtil.mapNotNull(elements, new NullableFunction() { @Override public ArchivedProjectTemplate fun(final Element element) { - - if (!checkRequiredPlugins(element, ns)) return null; + if (!checkRequiredPlugins(element)) return null; String type = element.getChildText("moduleType"); final ModuleType moduleType = ModuleTypeManager.getInstance().findByID(type); - final String path = element.getChildText("path", ns); - final String description = element.getChildTextTrim("description", ns); - String name = element.getChildTextTrim("name", ns); + final String path = element.getChildText("path"); + final String description = element.getChildTextTrim("description"); + String name = element.getChildTextTrim("name"); RemoteProjectTemplate template = new RemoteProjectTemplate(name, element, moduleType, path, description); - template.populateFromElement(element, ns); + template.populateFromElement(element); return template; } }); } - public static List getFrameworks(Element element) { - List frameworks = element.getChildren("framework"); - return ContainerUtil.map(frameworks, ELEMENT_STRING_FUNCTION); - } - - private static boolean checkRequiredPlugins(Element element, Namespace ns) { - @SuppressWarnings("unchecked") List plugins = element.getChildren("requiredPlugin", ns); - for (Element plugin : plugins) { - String id = plugin.getTextTrim(); - if (!PluginManager.isPluginInstalled(PluginId.getId(id))) { + private static boolean checkRequiredPlugins(Element element) { + for (Element plugin : element.getChildren("requiredPlugin")) { + if (!PluginManager.isPluginInstalled(PluginId.getId(plugin.getTextTrim()))) { return false; } } return true; } - private static HttpURLConnection getConnection(String path) throws IOException { - HttpURLConnection connection = HttpConfigurable.getInstance().openHttpConnection(URL + path); - connection.setConnectTimeout(2000); - connection.setReadTimeout(2000); - connection.connect(); - return connection; - } - - private final static Logger LOG = Logger.getInstance(RemoteTemplatesFactory.class); - private static class RemoteProjectTemplate extends ArchivedProjectTemplate { private final ModuleType myModuleType; private final String myPath; @@ -194,15 +163,14 @@ public class RemoteTemplatesFactory extends ProjectTemplatesFactory { } @Override - public ZipInputStream getStream() throws IOException { - final HttpURLConnection connection = getConnection(myPath); - return new ZipInputStream(connection.getInputStream()) { + public void getStream(@NotNull final StreamConsumer consumer) throws IOException { + HttpRequests.request(URL + myPath).connect(new HttpRequests.RequestProcessor() { @Override - public void close() throws IOException { - super.close(); - connection.disconnect(); + public Void process(@NotNull HttpRequests.Request request) throws IOException { + consumeZipStream(consumer, new ZipInputStream(request.getInputStream())); + return null; } - }; + }); } @Nullable diff --git a/java/idea-ui/src/com/intellij/platform/templates/TemplateModuleBuilder.java b/java/idea-ui/src/com/intellij/platform/templates/TemplateModuleBuilder.java index 9771d58b625f..475cf4e42c05 100644 --- a/java/idea-ui/src/com/intellij/platform/templates/TemplateModuleBuilder.java +++ b/java/idea-ui/src/com/intellij/platform/templates/TemplateModuleBuilder.java @@ -40,7 +40,6 @@ import com.intellij.openapi.util.InvalidDataException; import com.intellij.openapi.util.NullableComputable; import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.io.FileUtilRt; -import com.intellij.openapi.util.io.StreamUtil; import com.intellij.openapi.util.text.StringUtilRt; import com.intellij.openapi.vfs.CharsetToolkit; import com.intellij.openapi.vfs.LocalFileSystem; @@ -200,12 +199,9 @@ public class TemplateModuleBuilder extends ModuleBuilder { } private void unzip(final @Nullable String projectName, String path, final boolean moduleMode) { - File dir = new File(path); - ZipInputStream zipInputStream = null; final WizardInputField basePackage = getBasePackageField(); try { - zipInputStream = myTemplate.getStream(); - NullableFunction pathConvertor = new NullableFunction() { + final NullableFunction pathConvertor = new NullableFunction() { @Nullable @Override public String fun(String path) { @@ -216,13 +212,22 @@ public class TemplateModuleBuilder extends ModuleBuilder { return path; } }; - ZipUtil.unzip(ProgressManager.getInstance().getProgressIndicator(), dir, zipInputStream, pathConvertor, new ZipUtil.ContentProcessor() { + + final File dir = new File(path); + myTemplate.getStream(new ArchivedProjectTemplate.StreamConsumer() { @Override - public byte[] processContent(byte[] content, File file) throws IOException { - FileType fileType = FileTypeManager.getInstance().getFileTypeByExtension(FileUtilRt.getExtension(file.getName())); - return fileType.isBinary() ? content : processTemplates(projectName, new String(content, CharsetToolkit.UTF8_CHARSET), file); + public Void consume(@NotNull ZipInputStream stream) throws IOException { + ZipUtil.unzip(ProgressManager.getInstance().getProgressIndicator(), dir, stream, pathConvertor, new ZipUtil.ContentProcessor() { + @Override + public byte[] processContent(byte[] content, File file) throws IOException { + FileType fileType = FileTypeManager.getInstance().getFileTypeByExtension(FileUtilRt.getExtension(file.getName())); + return fileType.isBinary() ? content : processTemplates(projectName, new String(content, CharsetToolkit.UTF8_CHARSET), file); + } + }, true); + return null; } - }, true); + }); + String iml = ContainerUtil.find(dir.list(), new Condition() { @Override public boolean value(String s) { @@ -245,9 +250,6 @@ public class TemplateModuleBuilder extends ModuleBuilder { catch (IOException e) { throw new RuntimeException(e); } - finally { - StreamUtil.closeStream(zipInputStream); - } } private static String getPathFragment(String value) { From 0be64e4e88a8b3095f3d561771d35acc9aeb7271 Mon Sep 17 00:00:00 2001 From: Dmitry Batkovich Date: Wed, 24 Dec 2014 13:32:44 +0300 Subject: [PATCH 013/137] dissociation of few resource bundles in one action --- .../DissociateResourceBundleAction.java | 76 +++++++++++++------ 1 file changed, 53 insertions(+), 23 deletions(-) diff --git a/plugins/properties/src/com/intellij/lang/properties/customizeActions/DissociateResourceBundleAction.java b/plugins/properties/src/com/intellij/lang/properties/customizeActions/DissociateResourceBundleAction.java index 10041448d97c..1c32268eb700 100644 --- a/plugins/properties/src/com/intellij/lang/properties/customizeActions/DissociateResourceBundleAction.java +++ b/plugins/properties/src/com/intellij/lang/properties/customizeActions/DissociateResourceBundleAction.java @@ -24,16 +24,23 @@ import com.intellij.lang.properties.editor.ResourceBundleAsVirtualFile; import com.intellij.lang.properties.psi.PropertiesFile; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; -import com.intellij.openapi.actionSystem.PlatformDataKeys; +import com.intellij.openapi.actionSystem.LangDataKeys; import com.intellij.openapi.fileEditor.FileEditorManager; import com.intellij.openapi.project.Project; -import org.jetbrains.annotations.Nullable; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.containers.HashSet; +import org.jetbrains.annotations.NotNull; + +import java.util.*; /** * @author Dmitry Batkovich */ public class DissociateResourceBundleAction extends AnAction { - private static final String PRESENTATION_TEXT_TEMPLATE = "Dissociate Resource Bundle '%s'"; + private static final String SINGLE_RB_PRESENTATION_TEXT_TEMPLATE = "Dissociate Resource Bundle '%s'"; + private static final String MULTIPLE_RB_PRESENTATION_TEXT_TEMPLATE = "Dissociate %s Resource Bundles"; public DissociateResourceBundleAction() { super(null, null, AllIcons.FileTypes.Properties); @@ -41,40 +48,63 @@ public class DissociateResourceBundleAction extends AnAction { @Override public void actionPerformed(final AnActionEvent e) { - final ResourceBundle resourceBundle = extractResourceBundle(e); - assert resourceBundle != null; - final Project project = resourceBundle.getProject(); + final Project project = e.getProject(); + if (project == null) { + return; + } + final Collection resourceBundles = extractResourceBundles(e); + assert resourceBundles.size() > 0; final FileEditorManager fileEditorManager = FileEditorManager.getInstance(project); - fileEditorManager.closeFile(new ResourceBundleAsVirtualFile(resourceBundle)); - for (final PropertiesFile propertiesFile : resourceBundle.getPropertiesFiles()) { - fileEditorManager.closeFile(propertiesFile.getVirtualFile()); + for (ResourceBundle resourceBundle : resourceBundles) { + fileEditorManager.closeFile(new ResourceBundleAsVirtualFile(resourceBundle)); + for (final PropertiesFile propertiesFile : resourceBundle.getPropertiesFiles()) { + fileEditorManager.closeFile(propertiesFile.getVirtualFile()); + } + ResourceBundleManager.getInstance(e.getProject()).dissociateResourceBundle(resourceBundle); } - ResourceBundleManager.getInstance(e.getProject()).dissociateResourceBundle(resourceBundle); ProjectView.getInstance(project).refresh(); } @Override public void update(final AnActionEvent e) { - final ResourceBundle resourceBundle = extractResourceBundle(e); - if (resourceBundle != null) { - e.getPresentation().setText(String.format(PRESENTATION_TEXT_TEMPLATE, resourceBundle.getBaseName()), false); + final Collection resourceBundles = extractResourceBundles(e); + if (!resourceBundles.isEmpty()) { + if (resourceBundles.size() == 1) { + e.getPresentation().setText(String.format(SINGLE_RB_PRESENTATION_TEXT_TEMPLATE, ContainerUtil.getFirstItem(resourceBundles).getBaseName()), false); + } else { + e.getPresentation().setText(String.format(MULTIPLE_RB_PRESENTATION_TEXT_TEMPLATE, resourceBundles.size()), false); + } e.getPresentation().setVisible(true); } else { e.getPresentation().setVisible(false); } } - @Nullable - private static ResourceBundle extractResourceBundle(final AnActionEvent event) { - final ResourceBundle[] data = event.getData(ResourceBundle.ARRAY_DATA_KEY); - if (data != null && data.length == 1 && data[0].getPropertiesFiles().size() > 1) { - return data[0]; + @NotNull + private static Collection extractResourceBundles(final AnActionEvent event) { + final Set targetResourceBundles = new HashSet(); + final ResourceBundle[] chosenResourceBundles = event.getData(ResourceBundle.ARRAY_DATA_KEY); + if (chosenResourceBundles != null) { + for (ResourceBundle resourceBundle : chosenResourceBundles) { + if (resourceBundle.getPropertiesFiles().size() > 1) { + targetResourceBundles.add(resourceBundle); + } + } } - final PropertiesFile propertiesFile = PropertiesImplUtil.getPropertiesFile(event.getData(PlatformDataKeys.PSI_FILE)); - if (propertiesFile == null) { - return null; + final PsiElement[] psiElements = event.getData(LangDataKeys.PSI_ELEMENT_ARRAY); + if (psiElements != null) { + for (PsiElement element : psiElements) { + if (element instanceof PsiFile) { + final PropertiesFile propertiesFile = PropertiesImplUtil.getPropertiesFile((PsiFile)element); + if (propertiesFile != null) { + final ResourceBundle bundle = propertiesFile.getResourceBundle(); + if (bundle.getPropertiesFiles().size() > 1) { + targetResourceBundles.add(bundle); + } + } + } + } } - final ResourceBundle resourceBundle = propertiesFile.getResourceBundle(); - return resourceBundle.getPropertiesFiles().size() > 1 ? resourceBundle : null; + return targetResourceBundles; } } From d993ffcd6da21a78f02f4c8a0f28e2111f82084e Mon Sep 17 00:00:00 2001 From: Dmitry Batkovich Date: Wed, 24 Dec 2014 13:42:49 +0300 Subject: [PATCH 014/137] cleanup --- .../customizeActions/DissociateResourceBundleAction.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/plugins/properties/src/com/intellij/lang/properties/customizeActions/DissociateResourceBundleAction.java b/plugins/properties/src/com/intellij/lang/properties/customizeActions/DissociateResourceBundleAction.java index 1c32268eb700..5ccff9f9b249 100644 --- a/plugins/properties/src/com/intellij/lang/properties/customizeActions/DissociateResourceBundleAction.java +++ b/plugins/properties/src/com/intellij/lang/properties/customizeActions/DissociateResourceBundleAction.java @@ -69,11 +69,10 @@ public class DissociateResourceBundleAction extends AnAction { public void update(final AnActionEvent e) { final Collection resourceBundles = extractResourceBundles(e); if (!resourceBundles.isEmpty()) { - if (resourceBundles.size() == 1) { - e.getPresentation().setText(String.format(SINGLE_RB_PRESENTATION_TEXT_TEMPLATE, ContainerUtil.getFirstItem(resourceBundles).getBaseName()), false); - } else { - e.getPresentation().setText(String.format(MULTIPLE_RB_PRESENTATION_TEXT_TEMPLATE, resourceBundles.size()), false); - } + final String actionText = resourceBundles.size() == 1 ? + String.format(SINGLE_RB_PRESENTATION_TEXT_TEMPLATE, ContainerUtil.getFirstItem(resourceBundles).getBaseName()) : + String.format(MULTIPLE_RB_PRESENTATION_TEXT_TEMPLATE, resourceBundles.size()); + e.getPresentation().setText(actionText, false); e.getPresentation().setVisible(true); } else { e.getPresentation().setVisible(false); From fa405f7c5613168a5aaca426c0c33f2f63d86056 Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Wed, 24 Dec 2014 11:51:35 +0100 Subject: [PATCH 015/137] IDEA-CR-1100 get rid of service --- .../com/intellij/util/io/HttpRequests.java | 34 ++++++++-------- .../intellij/util/io/HttpRequestsImpl.java | 40 ------------------- .../src/META-INF/PlatformExtensions.xml | 2 - 3 files changed, 16 insertions(+), 60 deletions(-) delete mode 100644 platform/platform-impl/src/com/intellij/util/io/HttpRequestsImpl.java diff --git a/platform/platform-api/src/com/intellij/util/io/HttpRequests.java b/platform/platform-api/src/com/intellij/util/io/HttpRequests.java index 710a06751587..5b276751df0c 100644 --- a/platform/platform-api/src/com/intellij/util/io/HttpRequests.java +++ b/platform/platform-api/src/com/intellij/util/io/HttpRequests.java @@ -16,8 +16,9 @@ package com.intellij.util.io; import com.intellij.ide.IdeBundle; +import com.intellij.openapi.application.Application; +import com.intellij.openapi.application.ApplicationInfo; import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.util.SystemInfo; @@ -27,7 +28,6 @@ import com.intellij.openapi.util.io.StreamUtil; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.CharsetToolkit; import com.intellij.util.ArrayUtil; -import com.intellij.util.ReflectionUtil; import com.intellij.util.SystemProperties; import com.intellij.util.net.HTTPMethod; import com.intellij.util.net.HttpConfigurable; @@ -55,7 +55,7 @@ import java.util.zip.GZIPInputStream; * }); * } */ -public abstract class HttpRequests { +public final class HttpRequests { private static final boolean ourWrapClassLoader = SystemInfo.isJavaVersionAtLeast("1.7") && !SystemProperties.getBooleanProperty("idea.parallel.class.loader", true); @@ -84,7 +84,7 @@ public abstract class HttpRequests { T process(@NotNull Request request) throws IOException; } - protected HttpRequests() { + private HttpRequests() { } @NotNull @@ -98,7 +98,7 @@ public abstract class HttpRequests { return errorMessage; } - public abstract static class RequestBuilder { + public final static class RequestBuilder { private final String myUrl; private int myConnectTimeout = HttpConfigurable.CONNECTION_TIMEOUT; private int myTimeout = HttpConfigurable.READ_TIMEOUT; @@ -111,7 +111,7 @@ public abstract class HttpRequests { private HTTPMethod myMethod; - protected RequestBuilder(@NotNull String url) { + private RequestBuilder(@NotNull String url) { myUrl = url; } @@ -158,7 +158,15 @@ public abstract class HttpRequests { } @NotNull - public abstract RequestBuilder userAgent(); + public RequestBuilder userAgent() { + Application app = ApplicationManager.getApplication(); + if (app != null && !app.isDisposed()) { + return userAgent(ApplicationInfo.getInstance().getVersionName()); + } + else { + return userAgent("IntelliJ"); + } + } @NotNull public RequestBuilder accept(@Nullable String mimeType) { @@ -224,15 +232,7 @@ public abstract class HttpRequests { @NotNull public static RequestBuilder request(@NotNull String url) { - if (ApplicationManager.getApplication() == null) { - try { - return ((HttpRequests)ReflectionUtil.newInstance(Class.forName("com.intellij.util.io.HttpRequestsImpl"))).createRequestBuilder(url); - } - catch (ClassNotFoundException e) { - throw new RuntimeException(e); - } - } - return ServiceManager.getService(HttpRequests.class).createRequestBuilder(url); + return new RequestBuilder(url); } @NotNull @@ -242,8 +242,6 @@ public abstract class HttpRequests { return builder; } - protected abstract RequestBuilder createRequestBuilder(@NotNull String url); - private static T wrapAndProcess(RequestBuilder builder, RequestProcessor processor) throws IOException { // hack-around for class loader lock in sun.net.www.protocol.http.NegotiateAuthentication (IDEA-131621) ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader(); diff --git a/platform/platform-impl/src/com/intellij/util/io/HttpRequestsImpl.java b/platform/platform-impl/src/com/intellij/util/io/HttpRequestsImpl.java deleted file mode 100644 index fba7ccc1dbc6..000000000000 --- a/platform/platform-impl/src/com/intellij/util/io/HttpRequestsImpl.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2000-2014 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.intellij.util.io; - -import com.intellij.openapi.application.Application; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.application.ex.ApplicationInfoEx; -import org.jetbrains.annotations.NotNull; - -class HttpRequestsImpl extends HttpRequests { - @Override - protected RequestBuilder createRequestBuilder(@NotNull String url) { - return new RequestBuilder(url) { - @NotNull - @Override - public RequestBuilder userAgent() { - Application app = ApplicationManager.getApplication(); - if (app != null && !app.isDisposed()) { - return userAgent(ApplicationInfoEx.getInstanceEx().getFullApplicationName()); - } - else { - return userAgent("IntelliJ IDEA (?)"); - } - } - }; - } -} diff --git a/platform/platform-resources/src/META-INF/PlatformExtensions.xml b/platform/platform-resources/src/META-INF/PlatformExtensions.xml index 14ef0cd79cc2..c40d2ed178f0 100644 --- a/platform/platform-resources/src/META-INF/PlatformExtensions.xml +++ b/platform/platform-resources/src/META-INF/PlatformExtensions.xml @@ -265,8 +265,6 @@ - - From e9b13d6e189c16ce8877cb80037c637157dd5b4a Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Wed, 24 Dec 2014 12:04:53 +0100 Subject: [PATCH 016/137] reverted 'tests: platform prefix for light CodeInsight tests' --- .../testFramework/LightPlatformCodeInsightTestCase.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/testFramework/src/com/intellij/testFramework/LightPlatformCodeInsightTestCase.java b/platform/testFramework/src/com/intellij/testFramework/LightPlatformCodeInsightTestCase.java index b6dc8b458d06..40d8994e1cb1 100644 --- a/platform/testFramework/src/com/intellij/testFramework/LightPlatformCodeInsightTestCase.java +++ b/platform/testFramework/src/com/intellij/testFramework/LightPlatformCodeInsightTestCase.java @@ -68,7 +68,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; -public abstract class LightPlatformCodeInsightTestCase extends LightPlatformLangTestCase { +public abstract class LightPlatformCodeInsightTestCase extends LightPlatformTestCase { private static final Logger LOG = Logger.getInstance("#com.intellij.testFramework.LightCodeInsightTestCase"); protected static Editor myEditor; From 9acd5f3bf27f21805756704a1d8a2aa54977e6b3 Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Wed, 24 Dec 2014 12:20:29 +0100 Subject: [PATCH 017/137] IDEA-CR-1100 move RequestBuilder to top level --- .../com/intellij/util/io/HttpRequests.java | 171 ++---------------- .../com/intellij/util/io/RequestBuilder.java | 169 +++++++++++++++++ .../ide/plugins/RepositoryHelper.java | 3 +- 3 files changed, 186 insertions(+), 157 deletions(-) create mode 100644 platform/platform-api/src/com/intellij/util/io/RequestBuilder.java diff --git a/platform/platform-api/src/com/intellij/util/io/HttpRequests.java b/platform/platform-api/src/com/intellij/util/io/HttpRequests.java index 5b276751df0c..0180ea1ad8a6 100644 --- a/platform/platform-api/src/com/intellij/util/io/HttpRequests.java +++ b/platform/platform-api/src/com/intellij/util/io/HttpRequests.java @@ -16,26 +16,20 @@ package com.intellij.util.io; import com.intellij.ide.IdeBundle; -import com.intellij.openapi.application.Application; -import com.intellij.openapi.application.ApplicationInfo; import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.ProgressIndicator; -import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.io.BufferExposingByteArrayOutputStream; import com.intellij.openapi.util.io.FileUtilRt; import com.intellij.openapi.util.io.StreamUtil; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.CharsetToolkit; import com.intellij.util.ArrayUtil; -import com.intellij.util.SystemProperties; import com.intellij.util.net.HTTPMethod; import com.intellij.util.net.HttpConfigurable; import com.intellij.util.net.NetUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import javax.net.ssl.HostnameVerifier; import javax.net.ssl.HttpsURLConnection; import java.io.*; import java.net.HttpURLConnection; @@ -56,8 +50,8 @@ import java.util.zip.GZIPInputStream; * } */ public final class HttpRequests { - private static final boolean ourWrapClassLoader = - SystemInfo.isJavaVersionAtLeast("1.7") && !SystemProperties.getBooleanProperty("idea.parallel.class.loader", true); + private HttpRequests() { + } public interface Request { @NotNull @@ -84,7 +78,16 @@ public final class HttpRequests { T process(@NotNull Request request) throws IOException; } - private HttpRequests() { + @NotNull + public static RequestBuilder request(@NotNull String url) { + return new RequestBuilder(url); + } + + @NotNull + public static RequestBuilder head(@NotNull String url) { + RequestBuilder builder = request(url); + builder.myMethod = HTTPMethod.HEAD; + return builder; } @NotNull @@ -98,151 +101,7 @@ public final class HttpRequests { return errorMessage; } - public final static class RequestBuilder { - private final String myUrl; - private int myConnectTimeout = HttpConfigurable.CONNECTION_TIMEOUT; - private int myTimeout = HttpConfigurable.READ_TIMEOUT; - private int myRedirectLimit = HttpConfigurable.REDIRECT_LIMIT; - private boolean myGzip = true; - private boolean myForceHttps; - private HostnameVerifier myHostnameVerifier; - private String myUserAgent; - private String myAccept; - - private HTTPMethod myMethod; - - private RequestBuilder(@NotNull String url) { - myUrl = url; - } - - @NotNull - public RequestBuilder connectTimeout(int value) { - myConnectTimeout = value; - return this; - } - - @NotNull - public RequestBuilder readTimeout(int value) { - myTimeout = value; - return this; - } - - @NotNull - public RequestBuilder redirectLimit(int redirectLimit) { - myRedirectLimit = redirectLimit; - return this; - } - - @NotNull - public RequestBuilder gzip(boolean value) { - myGzip = value; - return this; - } - - @NotNull - public RequestBuilder forceHttps(boolean forceHttps) { - myForceHttps = forceHttps; - return this; - } - - @NotNull - public RequestBuilder hostNameVerifier(@Nullable HostnameVerifier hostnameVerifier) { - myHostnameVerifier = hostnameVerifier; - return this; - } - - @NotNull - public RequestBuilder userAgent(@Nullable String userAgent) { - myUserAgent = userAgent; - return this; - } - - @NotNull - public RequestBuilder userAgent() { - Application app = ApplicationManager.getApplication(); - if (app != null && !app.isDisposed()) { - return userAgent(ApplicationInfo.getInstance().getVersionName()); - } - else { - return userAgent("IntelliJ"); - } - } - - @NotNull - public RequestBuilder accept(@Nullable String mimeType) { - myAccept = mimeType; - return this; - } - - public T connect(@NotNull RequestProcessor processor) throws IOException { - // todo[r.sh] drop condition in IDEA 15 - if (ourWrapClassLoader) { - return wrapAndProcess(this, processor); - } - else { - return process(this, processor); - } - } - - public T connect(@NotNull RequestProcessor processor, T errorValue, @Nullable Logger logger) { - try { - return connect(processor); - } - catch (Throwable e) { - if (logger != null) { - logger.warn(e); - } - return errorValue; - } - } - - public void saveToFile(@NotNull final File file, @Nullable final ProgressIndicator indicator) throws IOException { - connect(new HttpRequests.RequestProcessor() { - @Override - public Void process(@NotNull HttpRequests.Request request) throws IOException { - request.saveToFile(file, indicator); - return null; - } - }); - } - - @NotNull - public byte[] readBytes(@Nullable final ProgressIndicator indicator) throws IOException { - return connect(new HttpRequests.RequestProcessor() { - @Override - public byte[] process(@NotNull HttpRequests.Request request) throws IOException { - return request.readBytes(indicator); - } - }); - } - - @NotNull - public String readString(@Nullable final ProgressIndicator indicator) throws IOException { - return connect(new HttpRequests.RequestProcessor() { - @Override - public String process(@NotNull HttpRequests.Request request) throws IOException { - int contentLength = request.getConnection().getContentLength(); - BufferExposingByteArrayOutputStream out = new BufferExposingByteArrayOutputStream(contentLength > 0 ? contentLength : 16 * 1024); - NetUtils.copyStreamContent(indicator, request.getInputStream(), out, contentLength); - return new String(out.getInternalBuffer(), 0, out.size(), getCharset(request)); - } - }); - } - } - - @NotNull - public static RequestBuilder request(@NotNull String url) { - return new RequestBuilder(url); - } - - @NotNull - public static RequestBuilder head(@NotNull String url) { - RequestBuilder builder = request(url); - builder.myMethod = HTTPMethod.HEAD; - return builder; - } - - private static T wrapAndProcess(RequestBuilder builder, RequestProcessor processor) throws IOException { + static T wrapAndProcess(RequestBuilder builder, RequestProcessor processor) throws IOException { // hack-around for class loader lock in sun.net.www.protocol.http.NegotiateAuthentication (IDEA-131621) ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader(); Thread.currentThread().setContextClassLoader(new URLClassLoader(new URL[0], oldClassLoader)); @@ -255,7 +114,7 @@ public final class HttpRequests { } @NotNull - private static Charset getCharset(@NotNull Request request) throws IOException { + static Charset getCharset(@NotNull Request request) throws IOException { String contentEncoding = request.getConnection().getContentEncoding(); if (contentEncoding != null) { try { @@ -267,7 +126,7 @@ public final class HttpRequests { return CharsetToolkit.UTF8_CHARSET; } - private static T process(final RequestBuilder builder, RequestProcessor processor) throws IOException { + static T process(final RequestBuilder builder, RequestProcessor processor) throws IOException { class RequestImpl implements Request { private URLConnection myConnection; private InputStream myInputStream; diff --git a/platform/platform-api/src/com/intellij/util/io/RequestBuilder.java b/platform/platform-api/src/com/intellij/util/io/RequestBuilder.java new file mode 100644 index 000000000000..09625cfa71c8 --- /dev/null +++ b/platform/platform-api/src/com/intellij/util/io/RequestBuilder.java @@ -0,0 +1,169 @@ +/* + * 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.util.io; + +import com.intellij.openapi.application.Application; +import com.intellij.openapi.application.ApplicationInfo; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.util.SystemInfo; +import com.intellij.openapi.util.io.BufferExposingByteArrayOutputStream; +import com.intellij.util.SystemProperties; +import com.intellij.util.net.HTTPMethod; +import com.intellij.util.net.HttpConfigurable; +import com.intellij.util.net.NetUtils; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.net.ssl.HostnameVerifier; +import java.io.File; +import java.io.IOException; + +public final class RequestBuilder { + private static final boolean ourWrapClassLoader = + SystemInfo.isJavaVersionAtLeast("1.7") && !SystemProperties.getBooleanProperty("idea.parallel.class.loader", true); + + final String myUrl; + int myConnectTimeout = HttpConfigurable.CONNECTION_TIMEOUT; + int myTimeout = HttpConfigurable.READ_TIMEOUT; + int myRedirectLimit = HttpConfigurable.REDIRECT_LIMIT; + boolean myGzip = true; + boolean myForceHttps; + HostnameVerifier myHostnameVerifier; + String myUserAgent; + String myAccept; + + HTTPMethod myMethod; + + RequestBuilder(@NotNull String url) { + myUrl = url; + } + + @NotNull + public RequestBuilder connectTimeout(int value) { + myConnectTimeout = value; + return this; + } + + @NotNull + public RequestBuilder readTimeout(int value) { + myTimeout = value; + return this; + } + + @NotNull + public RequestBuilder redirectLimit(int redirectLimit) { + myRedirectLimit = redirectLimit; + return this; + } + + @NotNull + public RequestBuilder gzip(boolean value) { + myGzip = value; + return this; + } + + @NotNull + public RequestBuilder forceHttps(boolean forceHttps) { + myForceHttps = forceHttps; + return this; + } + + @NotNull + public RequestBuilder hostNameVerifier(@Nullable HostnameVerifier hostnameVerifier) { + myHostnameVerifier = hostnameVerifier; + return this; + } + + @NotNull + public RequestBuilder userAgent(@Nullable String userAgent) { + myUserAgent = userAgent; + return this; + } + + @NotNull + public RequestBuilder userAgent() { + Application app = ApplicationManager.getApplication(); + if (app != null && !app.isDisposed()) { + return userAgent(ApplicationInfo.getInstance().getVersionName()); + } + else { + return userAgent("IntelliJ"); + } + } + + @NotNull + public RequestBuilder accept(@Nullable String mimeType) { + myAccept = mimeType; + return this; + } + + public T connect(@NotNull HttpRequests.RequestProcessor processor) throws IOException { + // todo[r.sh] drop condition in IDEA 15 + if (ourWrapClassLoader) { + return HttpRequests.wrapAndProcess(this, processor); + } + else { + return HttpRequests.process(this, processor); + } + } + + public T connect(@NotNull HttpRequests.RequestProcessor processor, T errorValue, @Nullable Logger logger) { + try { + return connect(processor); + } + catch (Throwable e) { + if (logger != null) { + logger.warn(e); + } + return errorValue; + } + } + + public void saveToFile(@NotNull final File file, @Nullable final ProgressIndicator indicator) throws IOException { + connect(new HttpRequests.RequestProcessor() { + @Override + public Void process(@NotNull HttpRequests.Request request) throws IOException { + request.saveToFile(file, indicator); + return null; + } + }); + } + + @NotNull + public byte[] readBytes(@Nullable final ProgressIndicator indicator) throws IOException { + return connect(new HttpRequests.RequestProcessor() { + @Override + public byte[] process(@NotNull HttpRequests.Request request) throws IOException { + return request.readBytes(indicator); + } + }); + } + + @NotNull + public String readString(@Nullable final ProgressIndicator indicator) throws IOException { + return connect(new HttpRequests.RequestProcessor() { + @Override + public String process(@NotNull HttpRequests.Request request) throws IOException { + int contentLength = request.getConnection().getContentLength(); + BufferExposingByteArrayOutputStream out = new BufferExposingByteArrayOutputStream(contentLength > 0 ? contentLength : 16 * 1024); + NetUtils.copyStreamContent(indicator, request.getInputStream(), out, contentLength); + return new String(out.getInternalBuffer(), 0, out.size(), HttpRequests.getCharset(request)); + } + }); + } +} diff --git a/platform/platform-impl/src/com/intellij/ide/plugins/RepositoryHelper.java b/platform/platform-impl/src/com/intellij/ide/plugins/RepositoryHelper.java index 88f3dfe8d43e..2e457f19dfc0 100644 --- a/platform/platform-impl/src/com/intellij/ide/plugins/RepositoryHelper.java +++ b/platform/platform-impl/src/com/intellij/ide/plugins/RepositoryHelper.java @@ -27,6 +27,7 @@ import com.intellij.openapi.util.BuildNumber; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vfs.CharsetToolkit; import com.intellij.util.io.HttpRequests; +import com.intellij.util.io.RequestBuilder; import com.intellij.util.io.URLUtil; import org.apache.http.client.utils.URIBuilder; import org.jetbrains.annotations.NotNull; @@ -102,7 +103,7 @@ public class RepositoryHelper { indicator.setText2(IdeBundle.message("progress.connecting.to.plugin.manager", uriBuilder.getHost())); } - HttpRequests.RequestBuilder request = HttpRequests.request(uriBuilder.toString()).forceHttps(forceHttps); + RequestBuilder request = HttpRequests.request(uriBuilder.toString()).forceHttps(forceHttps); return process(repositoryUrl, request.connect(new HttpRequests.RequestProcessor>() { @Override public List process(@NotNull HttpRequests.Request request) throws IOException { From aac529f110804dbcdd7e19950203a33b59813ae3 Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Wed, 24 Dec 2014 12:22:07 +0100 Subject: [PATCH 018/137] IDEA-CR-1100 rename to productNameAsUserAgent --- .../intellij/facet/frameworks/SettingsConnectionService.java | 2 +- .../com/intellij/platform/templates/github/DownloadUtil.java | 2 +- .../platform-api/src/com/intellij/util/io/RequestBuilder.java | 2 +- .../openapi/vfs/impl/http/DefaultRemoteContentProvider.java | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/platform/lang-api/src/com/intellij/facet/frameworks/SettingsConnectionService.java b/platform/lang-api/src/com/intellij/facet/frameworks/SettingsConnectionService.java index a8a9d8efcbd7..a4ec415abcb6 100644 --- a/platform/lang-api/src/com/intellij/facet/frameworks/SettingsConnectionService.java +++ b/platform/lang-api/src/com/intellij/facet/frameworks/SettingsConnectionService.java @@ -65,7 +65,7 @@ public abstract class SettingsConnectionService { @Nullable private Map readSettings(final String... attributes) { return HttpRequests.request(mySettingsUrl) - .userAgent() + .productNameAsUserAgent() .connect(new HttpRequests.RequestProcessor>() { @Override public Map process(@NotNull HttpRequests.Request request) throws IOException { diff --git a/platform/lang-impl/src/com/intellij/platform/templates/github/DownloadUtil.java b/platform/lang-impl/src/com/intellij/platform/templates/github/DownloadUtil.java index 792fdc40d45e..07a35d8c4f95 100644 --- a/platform/lang-impl/src/com/intellij/platform/templates/github/DownloadUtil.java +++ b/platform/lang-impl/src/com/intellij/platform/templates/github/DownloadUtil.java @@ -173,7 +173,7 @@ public class DownloadUtil { try { HttpRequests.request(location) - .userAgent() + .productNameAsUserAgent() .connect(new HttpRequests.RequestProcessor() { @Override public Object process(@NotNull HttpRequests.Request request) throws IOException { diff --git a/platform/platform-api/src/com/intellij/util/io/RequestBuilder.java b/platform/platform-api/src/com/intellij/util/io/RequestBuilder.java index 09625cfa71c8..a07a91d3b6e8 100644 --- a/platform/platform-api/src/com/intellij/util/io/RequestBuilder.java +++ b/platform/platform-api/src/com/intellij/util/io/RequestBuilder.java @@ -96,7 +96,7 @@ public final class RequestBuilder { } @NotNull - public RequestBuilder userAgent() { + public RequestBuilder productNameAsUserAgent() { Application app = ApplicationManager.getApplication(); if (app != null && !app.isDisposed()) { return userAgent(ApplicationInfo.getInstance().getVersionName()); diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/impl/http/DefaultRemoteContentProvider.java b/platform/platform-impl/src/com/intellij/openapi/vfs/impl/http/DefaultRemoteContentProvider.java index 1ee07d2fcab8..80b8c78f10e9 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/impl/http/DefaultRemoteContentProvider.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/impl/http/DefaultRemoteContentProvider.java @@ -60,7 +60,7 @@ public class DefaultRemoteContentProvider extends RemoteContentProvider { try { HttpRequests.request(url.toExternalForm()) .connectTimeout(60 * 1000) - .userAgent() + .productNameAsUserAgent() .hostNameVerifier(CertificateManager.HOSTNAME_VERIFIER) .connect(new HttpRequests.RequestProcessor() { @Override From aa0d78697bb5a0ba58c317e7461d4fb70c485349 Mon Sep 17 00:00:00 2001 From: peter Date: Wed, 24 Dec 2014 11:39:42 +0100 Subject: [PATCH 019/137] don't infer that simple getters are pure: currently it provides no value for the user --- .../com/intellij/codeInspection/dataFlow/PurityInference.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/PurityInference.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/PurityInference.java index ee81e7c09fd3..c626a96f8222 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/PurityInference.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/PurityInference.java @@ -22,6 +22,7 @@ import com.intellij.psi.*; import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.CachedValueProvider; import com.intellij.psi.util.CachedValuesManager; +import com.intellij.psi.util.PropertyUtil; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -37,7 +38,8 @@ public class PurityInference { if (!InferenceFromSourceUtil.shouldInferFromSource(method) || method.getReturnType() == PsiType.VOID || method.getBody() == null || - method.isConstructor()) { + method.isConstructor() || + PropertyUtil.isSimpleGetter(method)) { return false; } From 56f2123663cf585f21037d6000db776f82a7fb52 Mon Sep 17 00:00:00 2001 From: Nadya Zabrodina Date: Wed, 24 Dec 2014 14:28:31 +0300 Subject: [PATCH 020/137] perform commit command with hgRepository instance as argument instead of VF * tests fixed * unnecessary checks removed --- .../src/org/zmlx/hg4idea/HgTaskHandler.java | 2 +- .../zmlx/hg4idea/command/HgCommitCommand.java | 28 +++++++------------ .../provider/commit/HgCheckinEnvironment.java | 2 +- .../provider/update/HgRegularUpdater.java | 19 +++++++++---- .../testSrc/hg4idea/test/HgEncodingTest.java | 8 ++++-- .../testSrc/hg4idea/test/HgPlatformTest.java | 1 + .../hg4idea/test/commit/HgCommitTest.java | 5 +++- 7 files changed, 37 insertions(+), 28 deletions(-) diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/HgTaskHandler.java b/plugins/hg4idea/src/org/zmlx/hg4idea/HgTaskHandler.java index 8aea83070925..1c9bc0e95de8 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/HgTaskHandler.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/HgTaskHandler.java @@ -78,7 +78,7 @@ public class HgTaskHandler extends DvcsTaskHandler { Project project = repository.getProject(); VirtualFile repositoryRoot = repository.getRoot(); try { - new HgCommitCommand(project, repositoryRoot, "Automated merge with " + branch).execute(); + new HgCommitCommand(project, repository, "Automated merge with " + branch).execute(); new HgBookmarkCommand(project, repositoryRoot, branch).deleteBookmark(); } catch (HgCommandException e) { diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgCommitCommand.java b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgCommitCommand.java index 4ba12ee4add0..7ff85c106bfa 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgCommitCommand.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgCommitCommand.java @@ -18,7 +18,6 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vcs.VcsException; -import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.Function; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.messages.MessageBus; @@ -30,9 +29,7 @@ import org.zmlx.hg4idea.HgVcsMessages; import org.zmlx.hg4idea.execution.HgCommandException; import org.zmlx.hg4idea.execution.HgCommandExecutor; import org.zmlx.hg4idea.repo.HgRepository; -import org.zmlx.hg4idea.repo.HgRepositoryManager; import org.zmlx.hg4idea.util.HgEncodingUtil; -import org.zmlx.hg4idea.util.HgUtil; import java.io.File; import java.io.IOException; @@ -49,7 +46,7 @@ public class HgCommitCommand { private static final String TEMP_FILE_NAME = ".hg4idea-commit.tmp"; private final Project myProject; - private final VirtualFile myRoot; + private final HgRepository myRepository; private final String myMessage; @NotNull private final Charset myCharset; private final boolean myAmend; @@ -58,21 +55,21 @@ public class HgCommitCommand { private Set myFiles = Collections.emptySet(); @NotNull private List mySubrepos = Collections.emptyList(); - public HgCommitCommand(@NotNull Project project, @NotNull VirtualFile root, String message, boolean amend, boolean closeBranch) { + public HgCommitCommand(@NotNull Project project, @NotNull HgRepository repository, String message, boolean amend, boolean closeBranch) { myProject = project; - myRoot = root; + myRepository = repository; myMessage = message; myCharset = HgEncodingUtil.getDefaultCharset(myProject); myAmend = amend; myCloseBranch = closeBranch; } - public HgCommitCommand(@NotNull Project project, @NotNull VirtualFile root, String message, boolean amend) { - this(project, root, message, amend, false); + public HgCommitCommand(@NotNull Project project, @NotNull HgRepository repo, String message, boolean amend) { + this(project, repo, message, amend, false); } - public HgCommitCommand(Project project, @NotNull VirtualFile root, String message) { - this(project, root, message, false); + public HgCommitCommand(Project project, @NotNull HgRepository repo, String message) { + this(project, repo, message, false); } public void setFiles(@NotNull Set files) { @@ -110,10 +107,7 @@ public class HgCommitCommand { commitChunkFiles(chunk, amendCommit, false, myCloseBranch && i == size - 1); } } - if (!myProject.isDisposed()) { - HgRepositoryManager manager = HgUtil.getRepositoryManager(myProject); - manager.updateRepository(myRoot); - } + myRepository.update(); final MessageBus messageBus = myProject.getMessageBus(); messageBus.syncPublisher(HgVcs.REMOTE_TOPIC).update(myProject, null); messageBus.syncPublisher(HgVcs.BRANCH_TOPIC).update(myProject, null); @@ -125,8 +119,6 @@ public class HgCommitCommand { private void commitChunkFiles(@NotNull List chunk, boolean amendCommit, boolean withSubrepos, boolean closeBranch) throws VcsException { - HgRepository repository = HgUtil.getRepositoryForFile(myProject, myRoot); - assert repository != null; List parameters = new LinkedList(); parameters.add("--logfile"); parameters.add(saveCommitMessage().getAbsolutePath()); @@ -139,7 +131,7 @@ public class HgCommitCommand { parameters.add("--amend"); } if (closeBranch) { - if (chunk.isEmpty() && repository.getState() != Repository.State.MERGING) { + if (chunk.isEmpty() && myRepository.getState() != Repository.State.MERGING) { //if there are changed files but nothing selected -> need to exclude all; if merge commit then nothing excluded parameters.add("-X"); parameters.add("\"**\""); @@ -149,7 +141,7 @@ public class HgCommitCommand { parameters.addAll(chunk); HgCommandExecutor executor = new HgCommandExecutor(myProject); executor.setCharset(myCharset); - ensureSuccess(executor.executeInCurrentThread(myRoot, "commit", parameters)); + ensureSuccess(executor.executeInCurrentThread(myRepository.getRoot(), "commit", parameters)); } private File saveCommitMessage() throws VcsException { diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/provider/commit/HgCheckinEnvironment.java b/plugins/hg4idea/src/org/zmlx/hg4idea/provider/commit/HgCheckinEnvironment.java index fe13294ef8ab..94c37209a557 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/provider/commit/HgCheckinEnvironment.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/provider/commit/HgCheckinEnvironment.java @@ -104,7 +104,7 @@ public class HgCheckinEnvironment implements CheckinEnvironment { HgRepository repo = entry.getKey(); Set selectedFiles = entry.getValue(); HgCommitCommand command = - new HgCommitCommand(myProject, repo.getRoot(), preparedComment, myNextCommitAmend, myCloseBranch); + new HgCommitCommand(myProject, repo, preparedComment, myNextCommitAmend, myCloseBranch); if (isMergeCommit(repo.getRoot())) { //partial commits are not allowed during merges diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/provider/update/HgRegularUpdater.java b/plugins/hg4idea/src/org/zmlx/hg4idea/provider/update/HgRegularUpdater.java index 5527efd32226..aa1a7c432e70 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/provider/update/HgRegularUpdater.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/provider/update/HgRegularUpdater.java @@ -12,6 +12,7 @@ // limitations under the License. package org.zmlx.hg4idea.provider.update; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.text.StringUtil; @@ -43,6 +44,7 @@ public class HgRegularUpdater implements HgUpdater { @NotNull private final Project project; @NotNull private final VirtualFile repoRoot; @NotNull private final HgUpdateConfigurationSettings updateConfiguration; + private static final Logger LOG = Logger.getInstance(HgRegularUpdater.class); public HgRegularUpdater(@NotNull Project project, @NotNull VirtualFile repository, @NotNull HgUpdateConfigurationSettings configuration) { this.project = project; @@ -185,14 +187,21 @@ public class HgRegularUpdater implements HgUpdater { private void commitOrWarnAboutConflicts(List exceptions, HgCommandResult mergeResult) throws VcsException { if (mergeResult.getExitValue() == 0) { //operation successful and no conflicts try { - new HgCommitCommand(project, repoRoot, "Automated merge").execute(); - } catch (HgCommandException e) { + HgRepository hgRepository = HgUtil.getRepositoryForFile(project, repoRoot); + if (hgRepository == null) { + LOG.warn("Couldn't find repository info for " + repoRoot.getName()); + return; + } + new HgCommitCommand(project, hgRepository, "Automated merge").execute(); + } + catch (HgCommandException e) { throw new VcsException(e); } - } else { - reportWarning(exceptions, HgVcsMessages.message("hg4idea.update.warning.merge.conflicts", repoRoot.getPath())); - } } + else { + reportWarning(exceptions, HgVcsMessages.message("hg4idea.update.warning.merge.conflicts", repoRoot.getPath())); + } + } private HgCommandResult doMerge(ProgressIndicator indicator) throws VcsException { indicator.setText2(HgVcsMessages.message("hg4idea.update.progress.merging")); diff --git a/plugins/hg4idea/testSrc/hg4idea/test/HgEncodingTest.java b/plugins/hg4idea/testSrc/hg4idea/test/HgEncodingTest.java index 7c41b93e806e..009f90c9a58a 100644 --- a/plugins/hg4idea/testSrc/hg4idea/test/HgEncodingTest.java +++ b/plugins/hg4idea/testSrc/hg4idea/test/HgEncodingTest.java @@ -22,6 +22,8 @@ import org.zmlx.hg4idea.HgFileRevision; import org.zmlx.hg4idea.command.HgCommitCommand; import org.zmlx.hg4idea.command.HgLogCommand; import org.zmlx.hg4idea.execution.HgCommandException; +import org.zmlx.hg4idea.repo.HgRepository; +import org.zmlx.hg4idea.repo.HgRepositoryImpl; import java.util.List; @@ -37,7 +39,8 @@ public class HgEncodingTest extends HgPlatformTest { public void testCommitUtfMessage() throws HgCommandException, VcsException { cd(myRepository); echo("file.txt", "lalala"); - HgCommitCommand commitCommand = new HgCommitCommand(myProject, myRepository, "сообщение"); + HgRepository hgRepo = HgRepositoryImpl.getInstance(myRepository, myProject, myProject); + HgCommitCommand commitCommand = new HgCommitCommand(myProject, hgRepo, "сообщение"); commitCommand.execute(); } @@ -47,7 +50,8 @@ public class HgEncodingTest extends HgPlatformTest { String fileName = "file.txt"; echo(fileName, "lalala"); String comment = "öäüß"; - HgCommitCommand commitCommand = new HgCommitCommand(myProject, myRepository, comment); + HgRepository hgRepo = HgRepositoryImpl.getInstance(myRepository, myProject, myProject); + HgCommitCommand commitCommand = new HgCommitCommand(myProject, hgRepo, comment); commitCommand.execute(); HgLogCommand logCommand = new HgLogCommand(myProject); myRepository.refresh(false, true); diff --git a/plugins/hg4idea/testSrc/hg4idea/test/HgPlatformTest.java b/plugins/hg4idea/testSrc/hg4idea/test/HgPlatformTest.java index 7099c3bbf88d..28d69f9340ac 100644 --- a/plugins/hg4idea/testSrc/hg4idea/test/HgPlatformTest.java +++ b/plugins/hg4idea/testSrc/hg4idea/test/HgPlatformTest.java @@ -107,6 +107,7 @@ public abstract class HgPlatformTest extends UsefulTestCase { File hgrc = new File(new File(repositoryRoot.getPath(), ".hg"), "hgrc"); FileUtil.appendToFile(hgrc, FileUtil.loadFile(hgrcFile)); assertTrue(hgrc.exists()); + repositoryRoot.refresh(false, true); } protected static void appendToHgrc(@NotNull VirtualFile repositoryRoot, @NotNull String text) throws IOException { diff --git a/plugins/hg4idea/testSrc/hg4idea/test/commit/HgCommitTest.java b/plugins/hg4idea/testSrc/hg4idea/test/commit/HgCommitTest.java index 81387d18735b..36fe33f8d9b6 100644 --- a/plugins/hg4idea/testSrc/hg4idea/test/commit/HgCommitTest.java +++ b/plugins/hg4idea/testSrc/hg4idea/test/commit/HgCommitTest.java @@ -23,6 +23,8 @@ import org.zmlx.hg4idea.HgFileRevision; import org.zmlx.hg4idea.command.HgCommitCommand; import org.zmlx.hg4idea.command.HgLogCommand; import org.zmlx.hg4idea.execution.HgCommandException; +import org.zmlx.hg4idea.repo.HgRepository; +import org.zmlx.hg4idea.repo.HgRepositoryImpl; import java.util.List; @@ -51,7 +53,8 @@ public class HgCommitTest extends HgPlatformTest { logCommand.setLogFile(false); HgFile hgFile = new HgFile(myRepository, VfsUtilCore.virtualToIoFile(myRepository)); List revisions = logCommand.execute(hgFile, -1, false); - HgCommitCommand commit = new HgCommitCommand(myProject, myRepository, changedCommit, true); + HgRepository hgRepo = HgRepositoryImpl.getInstance(myRepository, myProject, myProject); + HgCommitCommand commit = new HgCommitCommand(myProject, hgRepo, changedCommit, true); commit.execute(); List revisionsAfterAmendCommit = logCommand.execute(hgFile, -1, false); assertTrue(revisions.size() == revisionsAfterAmendCommit.size()); From 4da8d8a4a461dd925076f8a5546d0414be93054d Mon Sep 17 00:00:00 2001 From: Dmitry Batrak Date: Wed, 24 Dec 2014 14:41:38 +0300 Subject: [PATCH 021/137] preserve folding model consistency on document change - remove fold regions which become equal --- .../openapi/editor/impl/FoldRegionsTree.java | 23 ++++++++++++++++++- .../intellij/openapi/editor/FoldingTest.java | 21 +++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/FoldRegionsTree.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/FoldRegionsTree.java index 2605c4f74852..876018fe447e 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/FoldRegionsTree.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/FoldRegionsTree.java @@ -19,6 +19,8 @@ import com.intellij.openapi.editor.*; import com.intellij.openapi.util.Key; import com.intellij.util.ArrayUtil; import com.intellij.util.containers.ContainerUtil; +import gnu.trove.THashSet; +import gnu.trove.TObjectHashingStrategy; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -47,6 +49,18 @@ abstract class FoldRegionsTree { }; private static final Comparator BY_END_OFFSET_REVERSE = Collections.reverseOrder(BY_END_OFFSET); + private static final TObjectHashingStrategy OFFSET_BASED_HASHING_STRATEGY = new TObjectHashingStrategy() { + @Override + public int computeHashCode(FoldRegion o) { + return o.getStartOffset() * 31 + o.getEndOffset(); + } + + @Override + public boolean equals(FoldRegion o1, FoldRegion o2) { + return o1.getStartOffset() == o2.getStartOffset() && o1.getEndOffset() == o2.getEndOffset(); + } + }; + void clear() { clearCachedValues(); @@ -67,11 +81,16 @@ abstract class FoldRegionsTree { List topLevels = new ArrayList(myRegions.size() / 2); List visible = new ArrayList(myRegions.size()); List allValid = new ArrayList(myRegions.size()); + Set distinctRegions = new THashSet(myRegions.size(), OFFSET_BASED_HASHING_STRATEGY); FoldRegion currentCollapsed = null; for (FoldRegion region : myRegions) { if (!region.isValid()) { continue; } + if (!distinctRegions.add(region)) { + region.dispose(); + continue; + } allValid.add(region); } @@ -134,9 +153,11 @@ abstract class FoldRegionsTree { rebuild(); return; } + + Set distinctRegions = new THashSet(visibleRegions.length, OFFSET_BASED_HASHING_STRATEGY); for (FoldRegion foldRegion : visibleRegions) { - if (!foldRegion.isValid()) { + if (!foldRegion.isValid() || !distinctRegions.add(foldRegion)) { rebuild(); return; } diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/editor/FoldingTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/editor/FoldingTest.java index 30e7860638b6..f6dff65607ba 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/editor/FoldingTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/editor/FoldingTest.java @@ -22,6 +22,7 @@ import com.intellij.testFramework.PlatformTestCase; import com.intellij.testFramework.TestFileType; import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertTrue; /** * @author max @@ -195,4 +196,24 @@ public class FoldingTest extends AbstractEditorTest { assertTrue(myModel.isOffsetCollapsed(5)); } + + public void testIdenticalRegionsAreRemoved() { + addFoldRegion(0, 5, "..."); + addFoldRegion(0, 4, "..."); + assertNumberOfValidFoldRegions(2); + + myEditor.getDocument().deleteString(4, 5); + + assertNumberOfValidFoldRegions(1); + } + + private void assertNumberOfValidFoldRegions(int expectedValue) { + int actualValue = 0; + for (FoldRegion region : myModel.getAllFoldRegions()) { + if (region.isValid()) { + actualValue++; + } + } + assertEquals(expectedValue, actualValue); + } } From aed9f7750b030511935c153d667a94e9391676e9 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Wed, 24 Dec 2014 12:42:52 +0100 Subject: [PATCH 022/137] vfs: consistency checks on file operations --- .../testFramework/ResolveTestCase.java | 61 +++-- .../psi/impl/file/PsiDirectoryImpl.java | 2 +- .../vfs/impl/local/LocalFileSystemBase.java | 250 ++++++++++++------ .../src/messages/VfsBundle.properties | 25 +- .../vfs/local/LocalFileSystemTest.java | 43 ++- .../intellij/testFramework/VfsTestUtil.java | 10 +- .../vcs/AbstractVcsTestCase.java | 2 +- .../com/intellij/openapi/vcs/VcsTestUtil.java | 2 +- .../git4idea/tests/GitChangeProviderTest.java | 4 +- 9 files changed, 284 insertions(+), 115 deletions(-) diff --git a/java/testFramework/src/com/intellij/testFramework/ResolveTestCase.java b/java/testFramework/src/com/intellij/testFramework/ResolveTestCase.java index e2cebe40700a..865a6f76ed30 100644 --- a/java/testFramework/src/com/intellij/testFramework/ResolveTestCase.java +++ b/java/testFramework/src/com/intellij/testFramework/ResolveTestCase.java @@ -1,6 +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. @@ -17,49 +16,75 @@ package com.intellij.testFramework; import com.intellij.openapi.application.ex.PathManagerEx; +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.LocalFileSystem; -import com.intellij.openapi.vfs.VfsUtil; +import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.PsiManager; import com.intellij.psi.PsiReference; -import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.File; public abstract class ResolveTestCase extends PsiTestCase { - @NonNls protected static final String MARKER = ""; + protected static final String MARKER = ""; - protected PsiReference configureByFile(@NonNls String filePath) throws Exception{ + private Document myDocument; + + @Override + protected void tearDown() throws Exception { + if (myDocument != null) { + FileDocumentManager.getInstance().reloadFromDisk(myDocument); + } + + super.tearDown(); + } + + protected PsiReference configureByFile(@NotNull String filePath) throws Exception { return configureByFile(filePath, null); } - - protected PsiReference configureByFile(@TestDataFile @NonNls String filePath, @Nullable VirtualFile parentDir) throws Exception{ + + protected PsiReference configureByFile(@TestDataFile @NotNull String filePath, @Nullable VirtualFile parentDir) throws Exception { final String fullPath = getTestDataPath() + filePath; final VirtualFile vFile = LocalFileSystem.getInstance().findFileByPath(fullPath.replace(File.separatorChar, '/')); assertNotNull("file " + filePath + " not found", vFile); - String fileText = StringUtil.convertLineSeparators(VfsUtil.loadText(vFile)); - - final String fileName = vFile.getName(); - - return configureByFileText(fileText, fileName, parentDir); + String fileText = StringUtil.convertLineSeparators(VfsUtilCore.loadText(vFile)); + return configureByFileText(fileText, vFile.getName(), parentDir); } protected PsiReference configureByFileText(String fileText, String fileName) throws Exception { return configureByFileText(fileText, fileName, null); } - - protected PsiReference configureByFileText(String fileText, String fileName, @Nullable final VirtualFile parentDir) throws Exception { + + protected PsiReference configureByFileText(String fileText, String fileName, @Nullable VirtualFile parentDir) throws Exception { int offset = fileText.indexOf(MARKER); assertTrue(offset >= 0); fileText = fileText.substring(0, offset) + fileText.substring(offset + MARKER.length()); - myFile = parentDir == null? createFile(myModule, fileName, fileText) : createFile(myModule, parentDir, fileName, fileText); + if (parentDir == null) { + myFile = createFile(myModule, fileName, fileText); + } + else { + VirtualFile existing = parentDir.findChild(fileName); + if (existing != null) { + myDocument = FileDocumentManager.getInstance().getDocument(existing); + assertNotNull(myDocument); + myDocument.setText(fileText); + myFile = PsiManager.getInstance(getProject()).findFile(existing); + assertNotNull(myFile); + assertEquals(fileText, myFile.getText()); + } + else { + myFile = createFile(myModule, parentDir, fileName, fileText); + } + } + PsiReference ref = myFile.findReferenceAt(offset); - assertNotNull(ref); - return ref; } diff --git a/platform/core-impl/src/com/intellij/psi/impl/file/PsiDirectoryImpl.java b/platform/core-impl/src/com/intellij/psi/impl/file/PsiDirectoryImpl.java index e0ed0dd9182e..8bdd768c91f1 100644 --- a/platform/core-impl/src/com/intellij/psi/impl/file/PsiDirectoryImpl.java +++ b/platform/core-impl/src/com/intellij/psi/impl/file/PsiDirectoryImpl.java @@ -150,7 +150,7 @@ public class PsiDirectoryImpl extends PsiElementBase implements PsiDirectory, Qu CheckUtil.checkWritable(this); VirtualFile parentFile = myFile.getParent(); if (parentFile == null) { - throw new IncorrectOperationException(VfsBundle.message("cannot.rename.root.directory")); + throw new IncorrectOperationException(VfsBundle.message("cannot.rename.root.directory", myFile.getPath())); } VirtualFile child = parentFile.findChild(name); if (child != null && !child.equals(myFile)) { diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/impl/local/LocalFileSystemBase.java b/platform/platform-impl/src/com/intellij/openapi/vfs/impl/local/LocalFileSystemBase.java index 9ed819cdd1aa..51ded3f9e4cb 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/impl/local/LocalFileSystemBase.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/impl/local/LocalFileSystemBase.java @@ -32,7 +32,6 @@ import com.intellij.openapi.vfs.newvfs.RefreshQueue; import com.intellij.openapi.vfs.newvfs.VfsImplUtil; import com.intellij.openapi.vfs.newvfs.impl.FakeVirtualFile; import com.intellij.util.ArrayUtil; -import com.intellij.util.PathUtil; import com.intellij.util.Processor; import com.intellij.util.ThrowableConsumer; import com.intellij.util.containers.ContainerUtil; @@ -341,19 +340,12 @@ public abstract class LocalFileSystemBase extends LocalFileSystem { return false; } - private void auxNotifyCompleted(@NotNull ThrowableConsumer consumer) { - for (LocalFileOperationsHandler handler : myHandlers) { - handler.afterDone(consumer); - } - } - - @Nullable - private File auxCopy(@NotNull VirtualFile file, @NotNull VirtualFile toDir, @NotNull String copyName) throws IOException { + private boolean auxCopy(@NotNull VirtualFile file, @NotNull VirtualFile toDir, @NotNull String copyName) throws IOException { for (LocalFileOperationsHandler handler : myHandlers) { final File copy = handler.copy(file, toDir, copyName); - if (copy != null) return copy; + if (copy != null) return true; } - return null; + return false; } private boolean auxRename(@NotNull VirtualFile file, @NotNull String newName) throws IOException { @@ -377,53 +369,97 @@ public abstract class LocalFileSystemBase extends LocalFileSystem { return false; } - private static void delete(@NotNull File physicalFile) throws IOException { - if (!FileUtil.delete(physicalFile)) { - throw new IOException(VfsBundle.message("file.delete.error", physicalFile.getPath())); + private void auxNotifyCompleted(@NotNull ThrowableConsumer consumer) { + for (LocalFileOperationsHandler handler : myHandlers) { + handler.afterDone(consumer); } } @Override @NotNull - public VirtualFile createChildDirectory(final Object requestor, @NotNull final VirtualFile parent, @NotNull final String dir) throws IOException { - final File ioDir = new File(convertToIOFile(parent), dir); - final boolean succeed = auxCreateDirectory(parent, dir) || ioDir.mkdirs(); + public VirtualFile createChildDirectory(Object requestor, @NotNull final VirtualFile parent, @NotNull final String dir) throws IOException { + if (!VirtualFile.isValidName(dir)) { + throw new IOException(VfsBundle.message("directory.invalid.name.error", dir)); + } + + if (!parent.exists() || !parent.isDirectory()) { + throw new IOException(VfsBundle.message("vfs.target.not.directory.error", parent.getPath())); + } + if (parent.findChild(dir) != null) { + throw new IOException(VfsBundle.message("vfs.target.already.exists.error", parent.getPath() + "/" + dir)); + } + + File ioParent = convertToIOFile(parent); + if (!ioParent.isDirectory()) { + throw new IOException(VfsBundle.message("target.not.directory.error", ioParent.getPath())); + } + + if (!auxCreateDirectory(parent, dir)) { + File ioDir = new File(ioParent, dir); + if (!(ioDir.mkdirs() || ioDir.isDirectory())) { + throw new IOException(VfsBundle.message("new.directory.failed.error", ioDir.getPath())); + } + } + auxNotifyCompleted(new ThrowableConsumer() { @Override public void consume(LocalFileOperationsHandler handler) throws IOException { handler.createDirectory(parent, dir); } }); - if (!succeed) { - throw new IOException("Failed to create directory: " + ioDir.getPath()); - } return new FakeVirtualFile(parent, dir); } @NotNull @Override - public VirtualFile createChildFile(final Object requestor, @NotNull final VirtualFile parent, @NotNull final String file) throws IOException { - final File ioFile = new File(convertToIOFile(parent), file); - final boolean succeed = auxCreateFile(parent, file) || FileUtil.createIfDoesntExist(ioFile); + public VirtualFile createChildFile(Object requestor, @NotNull final VirtualFile parent, @NotNull final String file) throws IOException { + if (!VirtualFile.isValidName(file)) { + throw new IOException(VfsBundle.message("file.invalid.name.error", file)); + } + + if (!parent.exists() || !parent.isDirectory()) { + throw new IOException(VfsBundle.message("vfs.target.not.directory.error", parent.getPath())); + } + if (parent.findChild(file) != null) { + throw new IOException(VfsBundle.message("vfs.target.already.exists.error", parent.getPath() + "/" + file)); + } + + File ioParent = convertToIOFile(parent); + if (!ioParent.isDirectory()) { + throw new IOException(VfsBundle.message("target.not.directory.error", ioParent.getPath())); + } + + if (!auxCreateFile(parent, file)) { + File ioFile = new File(ioParent, file); + if (!FileUtil.createIfDoesntExist(ioFile)) { + throw new IOException(VfsBundle.message("new.file.failed.error", ioFile.getPath())); + } + } + auxNotifyCompleted(new ThrowableConsumer() { @Override public void consume(LocalFileOperationsHandler handler) throws IOException { handler.createFile(parent, file); } }); - if (!succeed) { - throw new IOException("Failed to create child file at " + ioFile.getPath()); - } return new FakeVirtualFile(parent, file); } @Override - public void deleteFile(final Object requestor, @NotNull final VirtualFile file) throws IOException { - if (!auxDelete(file)) { - delete(convertToIOFile(file)); + public void deleteFile(Object requestor, @NotNull final VirtualFile file) throws IOException { + if (file.getParent() == null) { + throw new IOException(VfsBundle.message("cannot.delete.root.directory", file.getPath())); } + + if (!auxDelete(file)) { + File ioFile = convertToIOFile(file); + if (!FileUtil.delete(ioFile)) { + throw new IOException(VfsBundle.message("delete.failed.error", ioFile.getPath())); + } + } + auxNotifyCompleted(new ThrowableConsumer() { @Override public void consume(LocalFileOperationsHandler handler) throws IOException { @@ -484,17 +520,41 @@ public abstract class LocalFileSystemBase extends LocalFileSystem { } @Override - public void moveFile(final Object requestor, @NotNull final VirtualFile file, @NotNull final VirtualFile newParent) throws IOException { + public void moveFile(Object requestor, @NotNull final VirtualFile file, @NotNull final VirtualFile newParent) throws IOException { + String name = file.getName(); + + if (!file.exists()) { + throw new IOException(VfsBundle.message("vfs.file.not.exist.error", file.getPath())); + } + if (file.getParent() == null) { + throw new IOException(VfsBundle.message("cannot.rename.root.directory", file.getPath())); + } + if (!newParent.exists() || !newParent.isDirectory()) { + throw new IOException(VfsBundle.message("vfs.target.not.directory.error", newParent.getPath())); + } + if (newParent.findChild(name) != null) { + throw new IOException(VfsBundle.message("vfs.target.already.exists.error", newParent.getPath() + "/" + name)); + } + + File ioFile = convertToIOFile(file); + if (!ioFile.exists()) { + throw new FileNotFoundException(VfsBundle.message("file.not.exist.error", ioFile.getPath())); + } + File ioParent = convertToIOFile(newParent); + if (!ioParent.isDirectory()) { + throw new IOException(VfsBundle.message("target.not.directory.error", ioParent.getPath())); + } + File ioTarget = new File(ioParent, name); + if (ioTarget.exists()) { + throw new IOException(VfsBundle.message("target.already.exists.error", ioTarget.getPath())); + } + if (!auxMove(file, newParent)) { - final File ioFrom = convertToIOFile(file); - final File ioParent = convertToIOFile(newParent); - if (!ioParent.isDirectory()) { - throw new IOException("Target '" + ioParent + "' is not a directory"); - } - if (!ioFrom.renameTo(new File(ioParent, file.getName()))) { - throw new IOException("Move failed: '" + file.getPath() + "' to '" + newParent.getPath() +"'"); + if (!ioFile.renameTo(ioTarget)) { + throw new IOException(VfsBundle.message("move.failed.error", ioFile.getPath(), ioParent.getPath())); } } + auxNotifyCompleted(new ThrowableConsumer() { @Override public void consume(LocalFileOperationsHandler handler) throws IOException { @@ -504,24 +564,39 @@ public abstract class LocalFileSystemBase extends LocalFileSystem { } @Override - public void renameFile(final Object requestor, @NotNull final VirtualFile file, @NotNull final String newName) throws IOException { - if (!file.exists()) { - throw new IOException("File to move does not exist: " + file.getPath()); + public void renameFile(Object requestor, @NotNull final VirtualFile file, @NotNull final String newName) throws IOException { + if (!VirtualFile.isValidName(newName)) { + throw new IOException(VfsBundle.message("file.invalid.name.error", newName)); } - final VirtualFile parent = file.getParent(); - assert parent != null; + boolean sameName = !isCaseSensitive() && newName.equalsIgnoreCase(file.getName()); + + if (!file.exists()) { + throw new IOException(VfsBundle.message("vfs.file.not.exist.error", file.getPath())); + } + VirtualFile parent = file.getParent(); + if (parent == null) { + throw new IOException(VfsBundle.message("cannot.rename.root.directory", file.getPath())); + } + if (!sameName && parent.findChild(newName) != null) { + throw new IOException(VfsBundle.message("vfs.target.already.exists.error", parent.getPath() + "/" + newName)); + } + + File ioFile = convertToIOFile(file); + if (!ioFile.exists()) { + throw new FileNotFoundException(VfsBundle.message("file.not.exist.error", ioFile.getPath())); + } + File ioTarget = new File(convertToIOFile(parent), newName); + if (!sameName && ioTarget.exists()) { + throw new IOException(VfsBundle.message("target.already.exists.error", ioTarget.getPath())); + } if (!auxRename(file, newName)) { - final File target = new File(convertToIOFile(parent), newName); - if (!convertToIOFile(file).renameTo(target)) { - if (target.exists()) { - throw new IOException("Destination already exists: " + parent.getPath() + "/" + newName); - } else { - throw new IOException("Unable to rename " + file.getPath()); - } + if (!ioFile.renameTo(ioTarget)) { + throw new IOException(VfsBundle.message("rename.failed.error", ioFile.getPath(), newName)); } } + auxNotifyCompleted(new ThrowableConsumer() { @Override public void consume(LocalFileOperationsHandler handler) throws IOException { @@ -532,49 +607,62 @@ public abstract class LocalFileSystemBase extends LocalFileSystem { @NotNull @Override - public VirtualFile copyFile(final Object requestor, - @NotNull final VirtualFile vFile, + public VirtualFile copyFile(Object requestor, + @NotNull final VirtualFile file, @NotNull final VirtualFile newParent, @NotNull final String copyName) throws IOException { - if (!PathUtil.isValidFileName(copyName)) { - throw new IOException("Invalid file name: " + copyName); + if (!VirtualFile.isValidName(copyName)) { + throw new IOException(VfsBundle.message("file.invalid.name.error", copyName)); } - FileAttributes attributes = getAttributes(vFile); - if (attributes == null || attributes.isSpecial()) { - throw new FileNotFoundException("Not a file: " + vFile); + if (!file.exists()) { + throw new IOException(VfsBundle.message("vfs.file.not.exist.error", file.getPath())); + } + if (!newParent.exists() || !newParent.isDirectory()) { + throw new IOException(VfsBundle.message("vfs.target.not.directory.error", newParent.getPath())); + } + if (newParent.findChild(copyName) != null) { + throw new IOException(VfsBundle.message("vfs.target.already.exists.error", newParent.getPath() + "/" + copyName)); } - File physicalFile = convertToIOFile(vFile); - File physicalCopy = auxCopy(vFile, newParent, copyName); + FileAttributes attributes = getAttributes(file); + if (attributes == null) { + throw new FileNotFoundException(VfsBundle.message("file.not.exist.error", file.getPath())); + } + if (attributes.isSpecial()) { + throw new FileNotFoundException("Not a file: " + file); + } + File ioParent = convertToIOFile(newParent); + if (!ioParent.isDirectory()) { + throw new IOException(VfsBundle.message("target.not.directory.error", ioParent.getPath())); + } + File ioTarget = new File(ioParent, copyName); + if (ioTarget.exists()) { + throw new IOException(VfsBundle.message("target.already.exists.error", ioTarget.getPath())); + } - try { - if (physicalCopy == null) { - File newPhysicalParent = convertToIOFile(newParent); - physicalCopy = new File(newPhysicalParent, copyName); - - try { - if (attributes.isDirectory()) { - FileUtil.copyDir(physicalFile, physicalCopy); - } - else { - FileUtil.copy(physicalFile, physicalCopy); - } + if (!auxCopy(file, newParent, copyName)) { + try { + File ioFile = convertToIOFile(file); + if (attributes.isDirectory()) { + FileUtil.copyDir(ioFile, ioTarget); } - catch (IOException e) { - FileUtil.delete(physicalCopy); - throw e; + else { + FileUtil.copy(ioFile, ioTarget); } } + catch (IOException e) { + FileUtil.delete(ioTarget); + throw e; + } } - finally { - auxNotifyCompleted(new ThrowableConsumer() { - @Override - public void consume(LocalFileOperationsHandler handler) throws IOException { - handler.copy(vFile, newParent, copyName); - } - }); - } + + auxNotifyCompleted(new ThrowableConsumer() { + @Override + public void consume(LocalFileOperationsHandler handler) throws IOException { + handler.copy(file, newParent, copyName); + } + }); return new FakeVirtualFile(newParent, copyName); } diff --git a/platform/platform-resources-en/src/messages/VfsBundle.properties b/platform/platform-resources-en/src/messages/VfsBundle.properties index f9c5c0c0a581..293cc3026d97 100644 --- a/platform/platform-resources-en/src/messages/VfsBundle.properties +++ b/platform/platform-resources-en/src/messages/VfsBundle.properties @@ -15,15 +15,28 @@ cannot.create.local.file=Cannot create local file: {0} download.progress.connecting=Connecting to ''{0}''... download.progress.downloading=Downloading ''{0}''... -file.invalid.name.error=Invalid file name: \"{0}\" -directory.invalid.name.error=Invalid directory name: \"{0}\" +vfs.file.not.exist.error=''{0}'' does not exist in VFS +vfs.target.already.exists.error=''{0}'' already exists in VFS +vfs.target.not.directory.error=''{0}'' is not a directory in VFS +file.not.exist.error=''{0}'' does not exist +target.already.exists.error=''{0}'' already exists +target.not.directory.error=''{0}'' is not a directory +file.invalid.name.error=Invalid file name: ''{0}'' +directory.invalid.name.error=Invalid directory name: ''{0}'' + +rename.failed.error=Cannot rename ''{0}'' to ''{1}'' +move.failed.error=Cannot move ''{0}'' to ''{1}'' +delete.failed.error=Cannot delete ''{0}'' +new.file.failed.error=Cannot create file ''{0}'' +new.directory.failed.error=Cannot create directory ''{0}'' + directory.create.wrong.parent.error=Not a directory. Cannot create new directory in. file.create.wrong.parent.error=Not a directory. Cannot create new file in. file.already.exists.error=Cannot create file ''{0}''. File already exists. dir.already.exists.error=Cannot create directory ''{0}''. Directory already exists. invalid.directory.create.files=Invalid directory. Cannot create files. -file.delete.error=Cannot delete file {0}. -file.move.error=Can not move file to {0} -file.copy.error=Can not copy file to {0} +file.move.error=Cannot move file to {0} +file.copy.error=Cannot copy file to {0} file.copy.target.must.be.directory=Cannot copy, target must be directory. -cannot.rename.root.directory=Cannot rename root directory. \ No newline at end of file +cannot.rename.root.directory=Cannot rename root directory ''{0}'' +cannot.delete.root.directory=Cannot delete root directory ''{0}'' diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/vfs/local/LocalFileSystemTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/vfs/local/LocalFileSystemTest.java index 82bda836bf89..c75f101e5357 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/vfs/local/LocalFileSystemTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/vfs/local/LocalFileSystemTest.java @@ -17,6 +17,8 @@ package com.intellij.openapi.vfs.local; import com.intellij.ide.GeneralSettings; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.Result; +import com.intellij.openapi.application.WriteAction; import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.io.FileAttributes; import com.intellij.openapi.util.io.FileUtil; @@ -452,7 +454,7 @@ public class LocalFileSystemTest extends PlatformLangTestCase { assertEquals(newName, sourceFile.getName()); topDir.getChildren(); - newName = newName.toLowerCase(); + newName = newName.toLowerCase(Locale.ENGLISH); FileUtil.rename(file, intermediate); FileUtil.rename(intermediate, new File(top, newName)); topDir.refresh(false, true); @@ -582,4 +584,43 @@ public class LocalFileSystemTest extends PlatformLangTestCase { RefreshWorker.setCancellingCondition(null); } } + + public void testInvalidFileName() { + new WriteAction() { + @Override + protected void run(@NotNull Result result) throws Throwable { + VirtualFile tempDir = myFS.refreshAndFindFileByIoFile(createTempDirectory()); + assertNotNull(tempDir); + try { + tempDir.createChildData(this, "a/b"); + fail("invalid file name should have been rejected"); + } + catch (IOException e) { + assertEquals(VfsBundle.message("file.invalid.name.error", "a/b"), e.getMessage()); + } + } + }.execute(); + } + + public void testDuplicateViaRename() { + new WriteAction() { + @Override + protected void run(@NotNull Result result) throws Throwable { + VirtualFile tempDir = myFS.refreshAndFindFileByIoFile(createTempDirectory()); + assertNotNull(tempDir); + + VirtualFile file1 = tempDir.createChildData(this, "a.txt"); + FileUtil.delete(VfsUtilCore.virtualToIoFile(file1)); + + VirtualFile file2 = tempDir.createChildData(this, "b.txt"); + try { + file2.rename(this, "a.txt"); + fail("duplicate file name should have been rejected"); + } + catch (IOException e) { + assertEquals(VfsBundle.message("vfs.target.already.exists.error", file1.getPath()), e.getMessage()); + } + } + }.execute(); + } } diff --git a/platform/testFramework/src/com/intellij/testFramework/VfsTestUtil.java b/platform/testFramework/src/com/intellij/testFramework/VfsTestUtil.java index 279e640d4a2d..ccc7c0a46787 100644 --- a/platform/testFramework/src/com/intellij/testFramework/VfsTestUtil.java +++ b/platform/testFramework/src/com/intellij/testFramework/VfsTestUtil.java @@ -67,16 +67,18 @@ public class VfsTestUtil { } parent = child; } - final VirtualFile file; + + VirtualFile file; parent.getChildren();//need this to ensure that fileCreated event is fired if (dir) { file = parent.createChildDirectory(VfsTestUtil.class, PathUtil.getFileName(relativePath)); } else { - file = parent.createChildData(VfsTestUtil.class, PathUtil.getFileName(relativePath)); - if (!text.isEmpty()) { - VfsUtil.saveText(file, text); + file = parent.findFileByRelativePath(relativePath); + if (file == null) { + file = parent.createChildData(VfsTestUtil.class, PathUtil.getFileName(relativePath)); } + VfsUtil.saveText(file, text); } return file; } diff --git a/platform/testFramework/testSrc/com/intellij/testFramework/vcs/AbstractVcsTestCase.java b/platform/testFramework/testSrc/com/intellij/testFramework/vcs/AbstractVcsTestCase.java index bc20186244dd..6643acfd3803 100644 --- a/platform/testFramework/testSrc/com/intellij/testFramework/vcs/AbstractVcsTestCase.java +++ b/platform/testFramework/testSrc/com/intellij/testFramework/vcs/AbstractVcsTestCase.java @@ -132,7 +132,7 @@ public abstract class AbstractVcsTestCase { } public VirtualFile createDirInCommand(final VirtualFile parent, final String name) { - return VcsTestUtil.createDir(myProject, parent, name); + return VcsTestUtil.findOrCreateDir(myProject, parent, name); } protected void clearDirInCommand(final VirtualFile dir, final Processor filter) { diff --git a/platform/vcs-impl/testSrc/com/intellij/openapi/vcs/VcsTestUtil.java b/platform/vcs-impl/testSrc/com/intellij/openapi/vcs/VcsTestUtil.java index c7da2ad49a04..a31a76e73fa6 100644 --- a/platform/vcs-impl/testSrc/com/intellij/openapi/vcs/VcsTestUtil.java +++ b/platform/vcs-impl/testSrc/com/intellij/openapi/vcs/VcsTestUtil.java @@ -60,7 +60,7 @@ public class VcsTestUtil { * @param name Name of the directory. * @return reference to the created or already existing directory. */ - public static VirtualFile createDir(@NotNull final Project project, @NotNull final VirtualFile parent, @NotNull final String name) { + public static VirtualFile findOrCreateDir(@NotNull final Project project, @NotNull final VirtualFile parent, @NotNull final String name) { return new WriteCommandAction(project) { @Override protected void run(@NotNull Result result) throws Throwable { diff --git a/plugins/git4idea/tests/git4idea/tests/GitChangeProviderTest.java b/plugins/git4idea/tests/git4idea/tests/GitChangeProviderTest.java index 39eacd86883a..e5259354ba7f 100644 --- a/plugins/git4idea/tests/git4idea/tests/GitChangeProviderTest.java +++ b/plugins/git4idea/tests/git4idea/tests/GitChangeProviderTest.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. @@ -222,7 +222,7 @@ public abstract class GitChangeProviderTest extends GitSingleRepoTest { private VirtualFile create(VirtualFile parent, String name, boolean dir) { final VirtualFile file = dir ? - VcsTestUtil.createDir(myProject, parent, name) : + VcsTestUtil.findOrCreateDir(myProject, parent, name) : createFile(myProject, parent, name, "content" + Math.random()); dirty(file); return file; From 3ea48786a6c8f02e0cf3c1f37a9762835f4fed30 Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Wed, 24 Dec 2014 12:39:39 +0100 Subject: [PATCH 023/137] IDEA-CR-1106 don't include headers to error message by default --- .../platform/templates/github/DownloadUtil.java | 2 +- .../src/com/intellij/util/io/HttpRequests.java | 14 +++++++++----- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/platform/templates/github/DownloadUtil.java b/platform/lang-impl/src/com/intellij/platform/templates/github/DownloadUtil.java index 07a35d8c4f95..ac0af0927218 100644 --- a/platform/lang-impl/src/com/intellij/platform/templates/github/DownloadUtil.java +++ b/platform/lang-impl/src/com/intellij/platform/templates/github/DownloadUtil.java @@ -183,7 +183,7 @@ public class DownloadUtil { NetUtils.copyStreamContent(progress, request.getInputStream(), output, contentLength); } catch (IOException e) { - throw new IOException(HttpRequests.createErrorMessage(e, request), e); + throw new IOException(HttpRequests.createErrorMessage(e, request, true), e); } return null; } diff --git a/platform/platform-api/src/com/intellij/util/io/HttpRequests.java b/platform/platform-api/src/com/intellij/util/io/HttpRequests.java index 0180ea1ad8a6..7012dd83d476 100644 --- a/platform/platform-api/src/com/intellij/util/io/HttpRequests.java +++ b/platform/platform-api/src/com/intellij/util/io/HttpRequests.java @@ -91,14 +91,18 @@ public final class HttpRequests { } @NotNull - public static String createErrorMessage(@NotNull IOException e, @NotNull Request request) throws IOException { + public static String createErrorMessage(@NotNull IOException e, @NotNull Request request, boolean includeHeaders) throws IOException { URLConnection connection = request.getConnection(); - String errorMessage = "Cannot download '" + connection.getURL().toExternalForm() + "': " + e.getMessage() + "\n, headers: " + connection.getHeaderFields(); + StringBuilder builder = new StringBuilder(); + builder.append("Cannot download '").append(connection.getURL().toExternalForm()).append("': ").append(e.getMessage()); + if (includeHeaders) { + builder.append("\n, headers: ").append(connection.getHeaderFields()); + } if (connection instanceof HttpURLConnection) { HttpURLConnection httpConnection = (HttpURLConnection)connection; - errorMessage += "\n, response: " + httpConnection.getResponseCode() + ' ' + httpConnection.getResponseMessage(); + builder.append("\n, response: ").append(httpConnection.getResponseCode()).append(' ').append(httpConnection.getResponseMessage()); } - return errorMessage; + return builder.toString(); } static T wrapAndProcess(RequestBuilder builder, RequestProcessor processor) throws IOException { @@ -211,7 +215,7 @@ public final class HttpRequests { deleteFile = false; } catch (IOException e) { - throw new IOException(createErrorMessage(e, this), e); + throw new IOException(createErrorMessage(e, this, false), e); } finally { out.close(); From 1807ab51a541a695674485d089db1d2c9bd31f2d Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Wed, 24 Dec 2014 12:52:45 +0100 Subject: [PATCH 024/137] simplify --- .../com/intellij/util/io/ProgressMonitorInputStream.java | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/platform/platform-api/src/com/intellij/util/io/ProgressMonitorInputStream.java b/platform/platform-api/src/com/intellij/util/io/ProgressMonitorInputStream.java index 59231206cbbb..369e4fd49c82 100644 --- a/platform/platform-api/src/com/intellij/util/io/ProgressMonitorInputStream.java +++ b/platform/platform-api/src/com/intellij/util/io/ProgressMonitorInputStream.java @@ -20,7 +20,6 @@ import org.jetbrains.annotations.NotNull; import java.io.IOException; import java.io.InputStream; -import java.io.InterruptedIOException; final class ProgressMonitorInputStream extends InputStream { private final ProgressIndicator indicator; @@ -41,12 +40,8 @@ final class ProgressMonitorInputStream extends InputStream { return c; } - private void updateProgress(long increment) throws InterruptedIOException { - if (indicator.isCanceled()) { - InterruptedIOException exception = new InterruptedIOException("progress"); - exception.bytesTransferred = (int)count; - throw exception; - } + private void updateProgress(long increment) { + indicator.checkCanceled(); if (increment > 0) { count += increment; indicator.setFraction((double)count / available); From aa924787957ddedabd814f964fa1fe07bc7cf978 Mon Sep 17 00:00:00 2001 From: Dennis Ushakov Date: Wed, 24 Dec 2014 15:26:21 +0300 Subject: [PATCH 025/137] don't lowercase tags in html #WEB-14679 fixed --- .../testData/inspections/wrongClosingTagName/after4.html | 2 ++ .../inspections/wrongClosingTagName/before4.html | 2 ++ .../XmlWrongClosingTagNameInspection.java | 9 ++++----- 3 files changed, 8 insertions(+), 5 deletions(-) create mode 100644 xml/tests/testData/inspections/wrongClosingTagName/after4.html create mode 100644 xml/tests/testData/inspections/wrongClosingTagName/before4.html diff --git a/xml/tests/testData/inspections/wrongClosingTagName/after4.html b/xml/tests/testData/inspections/wrongClosingTagName/after4.html new file mode 100644 index 000000000000..d2cf77c1d26b --- /dev/null +++ b/xml/tests/testData/inspections/wrongClosingTagName/after4.html @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/xml/tests/testData/inspections/wrongClosingTagName/before4.html b/xml/tests/testData/inspections/wrongClosingTagName/before4.html new file mode 100644 index 000000000000..01fc1caf0f85 --- /dev/null +++ b/xml/tests/testData/inspections/wrongClosingTagName/before4.html @@ -0,0 +1,2 @@ + +stTag> \ No newline at end of file diff --git a/xml/xml-analysis-impl/src/com/intellij/codeInspection/htmlInspections/XmlWrongClosingTagNameInspection.java b/xml/xml-analysis-impl/src/com/intellij/codeInspection/htmlInspections/XmlWrongClosingTagNameInspection.java index 7ecdf14bad43..0623926b7f59 100644 --- a/xml/xml-analysis-impl/src/com/intellij/codeInspection/htmlInspections/XmlWrongClosingTagNameInspection.java +++ b/xml/xml-analysis-impl/src/com/intellij/codeInspection/htmlInspections/XmlWrongClosingTagNameInspection.java @@ -30,7 +30,6 @@ import com.intellij.psi.PsiFile; import com.intellij.psi.html.HtmlTag; import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.psi.xml.XmlElementType; import com.intellij.psi.xml.XmlTag; import com.intellij.psi.xml.XmlToken; import com.intellij.psi.xml.XmlTokenType; @@ -104,8 +103,8 @@ public class XmlWrongClosingTagNameInspection implements Annotator { } } } - final String tagName = tag instanceof HtmlTag ? tag.getName().toLowerCase() : tag.getName(); - final String endTokenText = tag instanceof HtmlTag ? end.getText().toLowerCase() : end.getText(); + final String tagName = tag.getName(); + final String endTokenText = end.getText(); final RenameTagBeginOrEndIntentionAction renameEndAction = new RenameTagBeginOrEndIntentionAction(tagName, endTokenText, false); final RenameTagBeginOrEndIntentionAction renameStartAction = new RenameTagBeginOrEndIntentionAction(endTokenText, tagName, true); @@ -129,8 +128,8 @@ public class XmlWrongClosingTagNameInspection implements Annotator { } } } - final String tagName = tag instanceof HtmlTag ? tag.getName().toLowerCase() : tag.getName(); - final String endTokenText = tag instanceof HtmlTag ? end.getText().toLowerCase() : end.getText(); + final String tagName = tag.getName(); + final String endTokenText = end.getText(); final RenameTagBeginOrEndIntentionAction renameEndAction = new RenameTagBeginOrEndIntentionAction(tagName, endTokenText, false); final RenameTagBeginOrEndIntentionAction renameStartAction = new RenameTagBeginOrEndIntentionAction(endTokenText, tagName, true); From 36633880217873c33d70147603f25a06b3786a4a Mon Sep 17 00:00:00 2001 From: "Egor.Ushakov" Date: Wed, 24 Dec 2014 15:59:20 +0300 Subject: [PATCH 026/137] fixed incorrect slots mapping (double and long slots were not checked in parameters) --- .../debugger/ui/impl/FrameVariablesTree.java | 2 +- .../watch/ArgumentValueDescriptorImpl.java | 37 +++++++++++++++++-- 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/FrameVariablesTree.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/FrameVariablesTree.java index 5d32e714ab89..379fcf0dcc18 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/impl/FrameVariablesTree.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/FrameVariablesTree.java @@ -241,7 +241,7 @@ public class FrameVariablesTree extends DebuggerTree { } final byte[] bytecodes = method.bytecodes(); if (bytecodes != null && bytecodes.length > 0) { - final int firstLocalVariableSlot = argumentCount + (method.isStatic()? 0 : 1); + final int firstLocalVariableSlot = ArgumentValueDescriptorImpl.getFirstLocalsSlot(method); final long instructionIndex = location.codeIndex(); final TIntObjectHashMap usedVars = new TIntObjectHashMap(); new InstructionParser(bytecodes, instructionIndex) { diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/ArgumentValueDescriptorImpl.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/ArgumentValueDescriptorImpl.java index a92abe492c45..2e3653afaf02 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/ArgumentValueDescriptorImpl.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/ArgumentValueDescriptorImpl.java @@ -27,6 +27,7 @@ import com.intellij.openapi.project.Project; import com.intellij.psi.*; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.IncorrectOperationException; +import com.sun.jdi.Method; import com.sun.jdi.PrimitiveValue; import com.sun.jdi.Value; @@ -78,8 +79,7 @@ public class ArgumentValueDescriptorImpl extends ValueDescriptorImpl{ if (body != null) { final StringBuilder nameBuilder = new StringBuilder(); try { - final int startSlot = params.getParametersCount() + (method.hasModifierProperty(PsiModifier.STATIC)? 0 : 1); - body.accept(new LocalVariableNameFinder(startSlot, nameBuilder)); + body.accept(new LocalVariableNameFinder(getFirstLocalsSlot(method), nameBuilder)); } finally { myName = nameBuilder.length() > 0? myDefaultName + ": " + nameBuilder.toString() : myDefaultName; @@ -93,6 +93,36 @@ public class ArgumentValueDescriptorImpl extends ValueDescriptorImpl{ return myValue; } + private static int getFirstLocalsSlot(PsiMethod method) { + int startSlot = method.hasModifierProperty(PsiModifier.STATIC) ? 0 : 1; + for (PsiParameter parameter : method.getParameterList().getParameters()) { + startSlot += getTypeSlotSize(parameter.getType()); + } + return startSlot; + } + + private static int getTypeSlotSize(PsiType varType) { + if (varType == PsiType.DOUBLE || varType == PsiType.LONG) { + return 2; + } + return 1; + } + + public static int getFirstLocalsSlot(Method method) { + int firstLocalVariableSlot = method.isStatic() ? 0 : 1; + for (String type : method.argumentTypeNames()) { + firstLocalVariableSlot += getTypeSlotSize(type); + } + return firstLocalVariableSlot; + } + + private static int getTypeSlotSize(String name) { + if (PsiKeyword.DOUBLE.equals(name) || PsiKeyword.LONG.equals(name)) { + return 2; + } + return 1; + } + public String getName() { return myName; } @@ -127,8 +157,7 @@ public class ArgumentValueDescriptorImpl extends ValueDescriptorImpl{ @Override public void visitLocalVariable(PsiLocalVariable variable) { appendName(variable.getName()); - final PsiType varType = variable.getType(); - myCurrentSlotIndex += (varType == PsiType.DOUBLE || varType == PsiType.LONG)? 2 : 1; + myCurrentSlotIndex += getTypeSlotSize(variable.getType()); } public void visitSynchronizedStatement(PsiSynchronizedStatement statement) { From 02e6f706156bd3aaf4a846272079721723f3a37e Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Wed, 24 Dec 2014 14:30:38 +0300 Subject: [PATCH 027/137] [vcs] Deprecate unused setter (later will make the field immutable) --- .../openapi/diff/impl/patch/TextFilePatch.java | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/platform/vcs-api/src/com/intellij/openapi/diff/impl/patch/TextFilePatch.java b/platform/vcs-api/src/com/intellij/openapi/diff/impl/patch/TextFilePatch.java index b6442a7c89a1..804b066b070a 100644 --- a/platform/vcs-api/src/com/intellij/openapi/diff/impl/patch/TextFilePatch.java +++ b/platform/vcs-api/src/com/intellij/openapi/diff/impl/patch/TextFilePatch.java @@ -15,6 +15,8 @@ */ package com.intellij.openapi.diff.impl.patch; +import org.jetbrains.annotations.Nullable; + import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Collections; @@ -24,7 +26,7 @@ import java.util.List; * @author yole */ public class TextFilePatch extends FilePatch { - private Charset myCharset; + @Nullable private Charset myCharset; private final List myHunks; public void addHunk(final PatchHunk hunk) { @@ -35,7 +37,7 @@ public class TextFilePatch extends FilePatch { return Collections.unmodifiableList(myHunks); } - public TextFilePatch(Charset charset) { + public TextFilePatch(@Nullable Charset charset) { myCharset = charset; myHunks = new ArrayList(); } @@ -65,11 +67,16 @@ public class TextFilePatch extends FilePatch { return myHunks.size() == 1 && myHunks.get(0).isDeletedContent(); } + @Nullable public Charset getCharset() { return myCharset; } - public void setCharset(Charset charset) { + /** + * To be removed in IDEA 15 + */ + @Deprecated + public void setCharset(@Nullable Charset charset) { myCharset = charset; } } From d9b886f191e2ed5064149ee30adf335361c022fc Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Wed, 24 Dec 2014 16:09:47 +0300 Subject: [PATCH 028/137] [vcs] IDEA-117448 Don't read & store patch text until really needed ShelvedChangeList doesn't need patch text itself to provide the changes, this texts are loaded and parsed in ShelvedChange#getChanges when needed => let read patch files in "ignore content" mode & use this mode when ShelveChangeLists are loaded. --- .../openapi/diff/impl/patch/PatchReader.java | 24 ++++++++++++++----- .../changes/shelf/ShelveChangesManager.java | 22 ++++++++++++++--- .../vcs/changes/shelf/ShelvedChangeList.java | 3 +-- 3 files changed, 38 insertions(+), 11 deletions(-) diff --git a/platform/vcs-api/src/com/intellij/openapi/diff/impl/patch/PatchReader.java b/platform/vcs-api/src/com/intellij/openapi/diff/impl/patch/PatchReader.java index 9a78602ac8de..236816854c8e 100644 --- a/platform/vcs-api/src/com/intellij/openapi/diff/impl/patch/PatchReader.java +++ b/platform/vcs-api/src/com/intellij/openapi/diff/impl/patch/PatchReader.java @@ -52,9 +52,13 @@ public class PatchReader { @NonNls private static final Pattern ourContextAfterHunkStartPattern = Pattern.compile("--- (\\d+),(\\d+) ----"); public PatchReader(CharSequence patchContent) { + this(patchContent, false); + } + + public PatchReader(CharSequence patchContent, boolean parseHunks) { myLines = LineTokenizer.tokenizeIntoList(patchContent, false); - myAdditionalInfoParser = new AdditionalInfoParser(); - myPatchContentParser = new PatchContentParser(); + myAdditionalInfoParser = new AdditionalInfoParser(!parseHunks); + myPatchContentParser = new PatchContentParser(parseHunks); } public List readAllPatches() throws PatchSyntaxException { @@ -169,10 +173,12 @@ public class PatchReader { private static class AdditionalInfoParser implements Parser { // first is path! private final Map> myResultMap; + private final boolean myIgnoreMode; private Map myAddMap; private PatchSyntaxException mySyntaxException; - private AdditionalInfoParser() { + private AdditionalInfoParser(boolean ignore) { + myIgnoreMode = ignore; myAddMap = new HashMap(); myResultMap = new HashMap>(); } @@ -194,12 +200,16 @@ public class PatchReader { @Override public boolean testIsStart(String start) { - if (mySyntaxException != null) return false; // stop on first error + if (myIgnoreMode || mySyntaxException != null) return false; // stop on first error return start != null && start.contains(UnifiedDiffWriter.ADDITIONAL_PREFIX); } @Override public void parse(String start, ListIterator iterator) { + if (myIgnoreMode) { + return; + } + if (! iterator.hasNext()) { mySyntaxException = new PatchSyntaxException(iterator.previousIndex(), "Empty additional info header"); return; @@ -244,13 +254,15 @@ public class PatchReader { private static class PatchContentParser implements Parser { + private final boolean myParseHunks; private DiffFormat myDiffFormat = null; private final List myPatches; private boolean myDiffCommandLike; private boolean myIndexLike; - private PatchContentParser() { + private PatchContentParser(boolean parseHunks) { + myParseHunks = parseHunks; myPatches = new SmartList(); } @@ -302,7 +314,7 @@ public class PatchReader { } extractFileName(curLine, curPatch, false, myDiffCommandLike && myIndexLike); - while (iterator.hasNext()) { + while (myParseHunks && iterator.hasNext()) { PatchHunk hunk; if (myDiffFormat == DiffFormat.UNIFIED) { hunk = readNextHunkUnified(iterator); diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/shelf/ShelveChangesManager.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/shelf/ShelveChangesManager.java index 96bb835bc086..461d58d52d48 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/shelf/ShelveChangesManager.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/shelf/ShelveChangesManager.java @@ -665,10 +665,26 @@ public class ShelveChangesManager extends AbstractProjectComponent implements JD notifyStateChanged(); } - // todo problem: control usage - public static List loadPatches(Project project, final String patchPath, CommitContext commitContext) throws IOException, PatchSyntaxException { + @NotNull + public static List loadPatches(Project project, + final String patchPath, + CommitContext commitContext) throws IOException, PatchSyntaxException { + return loadPatches(project, patchPath, commitContext, true); + } + + @NotNull + static List loadPatchesWithoutContent(Project project, + final String patchPath, + CommitContext commitContext) throws IOException, PatchSyntaxException { + return loadPatches(project, patchPath, commitContext, false); + } + + private static List loadPatches(Project project, + final String patchPath, + CommitContext commitContext, + boolean loadContent) throws IOException, PatchSyntaxException { char[] text = FileUtil.loadFileText(new File(patchPath), CharsetToolkit.UTF8); - PatchReader reader = new PatchReader(new CharArrayCharSequence(text)); + PatchReader reader = new PatchReader(new CharArrayCharSequence(text), loadContent); final List textFilePatches = reader.readAllPatches(); final TransparentlyFailedValueI>, PatchSyntaxException> additionalInfo = reader.getAdditionalInfo( null); diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/shelf/ShelvedChangeList.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/shelf/ShelvedChangeList.java index af3bb540d65e..e88ce0885733 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/shelf/ShelvedChangeList.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/shelf/ShelvedChangeList.java @@ -24,7 +24,6 @@ package com.intellij.openapi.vcs.changes.shelf; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.diff.impl.patch.FilePatch; -import com.intellij.openapi.diff.impl.patch.TextFilePatch; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.DefaultJDOMExternalizer; import com.intellij.openapi.util.InvalidDataException; @@ -109,7 +108,7 @@ public class ShelvedChangeList implements JDOMExternalizable { public List getChanges(Project project) { if (myChanges == null) { try { - final List list = ShelveChangesManager.loadPatches(project, PATH, null); + final List list = ShelveChangesManager.loadPatchesWithoutContent(project, PATH, null); myChanges = new ArrayList(); for (FilePatch patch : list) { FileStatus status; From ca5f32bc7ac131a7b8230b59018b2c5d8e756cd6 Mon Sep 17 00:00:00 2001 From: Dmitry Batrak Date: Wed, 24 Dec 2014 16:19:46 +0300 Subject: [PATCH 029/137] IDEA-126296, IDEA-130425 incorrect scrolling on undo/redo --- .../impl/text/TextEditorProvider.java | 37 ++----------------- .../fileEditor/impl/text/TextEditorState.java | 2 - 2 files changed, 3 insertions(+), 36 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/TextEditorProvider.java b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/TextEditorProvider.java index 14f0c95ec31b..67d7004e4874 100644 --- a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/TextEditorProvider.java +++ b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/TextEditorProvider.java @@ -20,7 +20,6 @@ import com.intellij.ide.structureView.StructureViewBuilder; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.*; -import com.intellij.openapi.editor.ex.EditorEx; import com.intellij.openapi.editor.ex.util.EditorUtil; import com.intellij.openapi.fileEditor.*; import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx; @@ -32,7 +31,6 @@ import com.intellij.openapi.project.ProjectManager; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.Key; import com.intellij.openapi.util.UserDataHolderBase; -import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.pom.Navigatable; import com.intellij.psi.SingleRootFileViewProvider; @@ -63,8 +61,6 @@ public class TextEditorProvider implements FileEditorProvider, DumbAware { @NonNls private static final String SELECTION_END_LINE_ATTR = "selection-end-line"; @NonNls private static final String SELECTION_END_COLUMN_ATTR = "selection-end-column"; @NonNls private static final String VERTICAL_SCROLL_PROPORTION_ATTR = "vertical-scroll-proportion"; - @NonNls private static final String VERTICAL_OFFSET_ATTR = "vertical-offset"; - @NonNls private static final String MAX_VERTICAL_OFFSET_ATTR = "max-vertical-offset"; @NonNls private static final String CARET_ELEMENT = "caret"; public static TextEditorProvider getInstance() { @@ -115,12 +111,6 @@ public class TextEditorProvider implements FileEditorProvider, DumbAware { String verticalScrollProportion = element.getAttributeValue(VERTICAL_SCROLL_PROPORTION_ATTR); state.VERTICAL_SCROLL_PROPORTION = verticalScrollProportion == null ? 0 : Float.parseFloat(verticalScrollProportion); - String verticalOffset = element.getAttributeValue(VERTICAL_OFFSET_ATTR); - String maxVerticalOffset = element.getAttributeValue(MAX_VERTICAL_OFFSET_ATTR); - if (!StringUtil.isEmpty(verticalOffset) && !StringUtil.isEmpty(maxVerticalOffset)) { - state.VERTICAL_SCROLL_OFFSET = Integer.parseInt(verticalOffset); - state.MAX_VERTICAL_SCROLL_OFFSET = Integer.parseInt(maxVerticalOffset); - } } catch (NumberFormatException ignored) { } @@ -149,8 +139,6 @@ public class TextEditorProvider implements FileEditorProvider, DumbAware { TextEditorState state = (TextEditorState)_state; element.setAttribute(VERTICAL_SCROLL_PROPORTION_ATTR, Float.toString(state.VERTICAL_SCROLL_PROPORTION)); - element.setAttribute(VERTICAL_OFFSET_ATTR, Integer.toString(state.VERTICAL_SCROLL_OFFSET)); - element.setAttribute(MAX_VERTICAL_OFFSET_ATTR, Integer.toString(state.MAX_VERTICAL_SCROLL_OFFSET)); if (state.CARETS != null) { for (TextEditorState.CaretState caretState : state.CARETS) { Element e = new Element(CARET_ELEMENT); @@ -249,11 +237,6 @@ public class TextEditorProvider implements FileEditorProvider, DumbAware { // Saving scrolling proportion on UNDO may cause undesirable results of undo action fails to perform since // scrolling proportion restored slightly differs from what have been saved. state.VERTICAL_SCROLL_PROPORTION = level == FileEditorStateLevel.UNDO ? -1 : EditorUtil.calcVerticalScrollProportion(editor); - if (editor instanceof EditorEx) { - state.VERTICAL_SCROLL_OFFSET = editor.getScrollingModel().getVerticalScrollOffset(); - JScrollBar scrollBar = ((EditorEx)editor).getScrollPane().getVerticalScrollBar(); - state.MAX_VERTICAL_SCROLL_OFFSET = scrollBar == null ? 0 : scrollBar.getMaximum(); - } return state; } @@ -295,21 +278,9 @@ public class TextEditorProvider implements FileEditorProvider, DumbAware { editor.getSelectionModel().removeSelection(); } } - EditorEx editorEx = editor instanceof EditorEx ? (EditorEx)editor : null; - boolean preciselyScrollVertically = - state.VERTICAL_SCROLL_OFFSET > 0 - && editorEx != null - && editorEx.getScrollPane().getVerticalScrollBar() != null - && editorEx.getScrollPane().getVerticalScrollBar().getMaximum() == state.MAX_VERTICAL_SCROLL_OFFSET; - if (preciselyScrollVertically) { - editor.getScrollingModel().scrollVertically(state.VERTICAL_SCROLL_OFFSET); - } - else { - editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE); - if (state.VERTICAL_SCROLL_PROPORTION != -1) { - EditorUtil.setVerticalScrollProportion(editor, state.VERTICAL_SCROLL_PROPORTION); - } + if (state.VERTICAL_SCROLL_PROPORTION != -1) { + EditorUtil.setVerticalScrollProportion(editor, state.VERTICAL_SCROLL_PROPORTION); } if (!editor.getCaretModel().supportsMultipleCarets()) { @@ -323,9 +294,7 @@ public class TextEditorProvider implements FileEditorProvider, DumbAware { editor.getSelectionModel().setSelection(startOffset, endOffset); } } - if (!preciselyScrollVertically) { - editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE); - } + editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE); } protected class EditorWrapper extends UserDataHolderBase implements TextEditor { diff --git a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/TextEditorState.java b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/TextEditorState.java index d4aca486c041..f8d176533f06 100644 --- a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/TextEditorState.java +++ b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/TextEditorState.java @@ -32,8 +32,6 @@ public final class TextEditorState implements FileEditorState { public CaretState[] CARETS; public float VERTICAL_SCROLL_PROPORTION; - public int VERTICAL_SCROLL_OFFSET; - public int MAX_VERTICAL_SCROLL_OFFSET; /** * State which describes how editor is folded. From 2493c99585e2cc48847533b1a43900e82d4117d7 Mon Sep 17 00:00:00 2001 From: Sergey Savenko Date: Wed, 24 Dec 2014 16:21:45 +0300 Subject: [PATCH 030/137] EA-63550: fix IAE in JBListTable row animation when animated row is deleted --- .../src/com/intellij/util/ui/table/JBListTable.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/platform/platform-impl/src/com/intellij/util/ui/table/JBListTable.java b/platform/platform-impl/src/com/intellij/util/ui/table/JBListTable.java index 89cd47453b92..86318c465072 100644 --- a/platform/platform-impl/src/com/intellij/util/ui/table/JBListTable.java +++ b/platform/platform-impl/src/com/intellij/util/ui/table/JBListTable.java @@ -483,10 +483,12 @@ public abstract class JBListTable { * @return whether this row animation is complete */ public boolean doAnimationStep(long currentTime) { + if (myTable.getRowCount() >= myRow) return true; + int currentRowHeight = myTable.getRowHeight(myRow); int resizeAbs = (int) (RESIZE_AMOUNT_PER_STEP * ((currentTime - myLastUpdateTime) / (double)ANIMATION_STEP_MILLIS)); int leftToAnimate = myTargetHeight - currentRowHeight; - int newHeight = Math.abs(leftToAnimate) <= Math.abs(resizeAbs) ? myTargetHeight : + int newHeight = Math.abs(leftToAnimate) <= resizeAbs ? myTargetHeight : currentRowHeight + (leftToAnimate < 0 ? -resizeAbs : resizeAbs); myTable.setRowHeight(myRow, newHeight); myLastUpdateTime = currentTime; From fc2f15f64e211b823a237726a6a02e362ee486b3 Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Wed, 24 Dec 2014 12:04:39 +0100 Subject: [PATCH 031/137] java 8 javadoc tags @apiNote, @implNote, @implSpec --- .../psi/impl/source/javadoc/JavadocManagerImpl.java | 3 +++ .../daemonCodeAnalyzer/javaDoc/Java18Tags.java | 8 ++++++++ .../codeInsight/daemon/JavadocHighlightingTest.java | 1 + 3 files changed, 12 insertions(+) create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/Java18Tags.java diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/javadoc/JavadocManagerImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/javadoc/JavadocManagerImpl.java index 9b4be9c071c9..882e6b68498f 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/javadoc/JavadocManagerImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/javadoc/JavadocManagerImpl.java @@ -44,6 +44,9 @@ public class JavadocManagerImpl implements JavadocManager { myInfos.add(new SimpleDocTagInfo("serialField", PsiField.class, false, LanguageLevel.JDK_1_3)); myInfos.add(new SimpleDocTagInfo("since", PsiElement.class, PsiPackage.class, LanguageLevel.JDK_1_3)); myInfos.add(new SimpleDocTagInfo("version", PsiClass.class, PsiPackage.class, LanguageLevel.JDK_1_3)); + myInfos.add(new SimpleDocTagInfo("apiNote", PsiElement.class, false, LanguageLevel.JDK_1_8)); + myInfos.add(new SimpleDocTagInfo("implNote", PsiElement.class, false, LanguageLevel.JDK_1_8)); + myInfos.add(new SimpleDocTagInfo("implSpec", PsiElement.class, false, LanguageLevel.JDK_1_8)); myInfos.add(new SimpleDocTagInfo("docRoot", PsiElement.class, true, LanguageLevel.JDK_1_3)); myInfos.add(new SimpleDocTagInfo("inheritDoc", PsiElement.class, true, LanguageLevel.JDK_1_4)); diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/Java18Tags.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/Java18Tags.java new file mode 100644 index 000000000000..80a6789e8f50 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/Java18Tags.java @@ -0,0 +1,8 @@ +class Test { + /** + * @apiNote note1 + * @implNote implNote + * @implSpec implSpec + */ + public void i() {} +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/JavadocHighlightingTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/JavadocHighlightingTest.java index 52c201d3cb54..ef47e405467a 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/JavadocHighlightingTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/JavadocHighlightingTest.java @@ -95,6 +95,7 @@ public class JavadocHighlightingTest extends LightDaemonAnalyzerTestCase { public void testValueNotOnField() throws Exception { doTestWithLangLevel(LanguageLevel.HIGHEST); } public void testValueNotOnStaticField() throws Exception { doTestWithLangLevel(LanguageLevel.HIGHEST); } public void testValueOnNotInitializedField() throws Exception { doTestWithLangLevel(LanguageLevel.HIGHEST); } + public void testJava18Tags() throws Exception { doTestWithLangLevel(LanguageLevel.JDK_1_8); } public void testUnknownInlineTag() throws Exception { doTest(); } public void testUnknownTags() throws Exception { doTest(); } From e130ff266923312d7c3c393b7d31a13a7ad63caf Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Wed, 24 Dec 2014 12:26:07 +0100 Subject: [PATCH 032/137] quick javadoc: include new javadoc tags in view (IDEA-128304) --- .../javadoc/JavaDocInfoGenerator.java | 16 ++++++++++++++++ .../testData/codeInsight/javadocIG/apiNotes.html | 1 + .../testData/codeInsight/javadocIG/apiNotes.java | 13 +++++++++++++ .../javadoc/JavaDocInfoGeneratorTest.java | 4 ++++ 4 files changed, 34 insertions(+) create mode 100644 java/java-tests/testData/codeInsight/javadocIG/apiNotes.html create mode 100644 java/java-tests/testData/codeInsight/javadocIG/apiNotes.java diff --git a/java/java-psi-impl/src/com/intellij/codeInsight/javadoc/JavaDocInfoGenerator.java b/java/java-psi-impl/src/com/intellij/codeInsight/javadoc/JavaDocInfoGenerator.java index 1c023d6f1797..f30ad7c999d6 100644 --- a/java/java-psi-impl/src/com/intellij/codeInsight/javadoc/JavaDocInfoGenerator.java +++ b/java/java-psi-impl/src/com/intellij/codeInsight/javadoc/JavaDocInfoGenerator.java @@ -585,11 +585,26 @@ public class JavaDocInfoGenerator { public void generateCommonSection(StringBuilder buffer, PsiDocComment docComment) { generateDescription(buffer, docComment); + generateApiSection(buffer, docComment); generateDeprecatedSection(buffer, docComment); generateSinceSection(buffer, docComment); generateSeeAlsoSection(buffer, docComment); } + private void generateApiSection(StringBuilder buffer, PsiDocComment comment) { + final String[] tagNames = {"apiNote", "implSpec", "implNote"}; + for (String tagName : tagNames) { + PsiDocTag tag = comment.findTagByName(tagName); + if (tag != null) { + buffer.append("
"); + buffer.append("
").append(tagName).append(""); + buffer.append("
"); + generateValue(buffer, tag.getDataElements(), ourEmptyElementsProvider); + buffer.append("
"); + } + } + } + private void generatePackageHtmlJavaDoc(final StringBuilder buffer, final PsiFile packageHtmlFile, boolean generatePrologueAndEpilogue) { String htmlText = packageHtmlFile.getText(); @@ -912,6 +927,7 @@ public class JavaDocInfoGenerator { generateThrowsSection(buffer, method, comment); if (comment != null) { + generateApiSection(buffer, comment); generateSinceSection(buffer, comment); generateSeeAlsoSection(buffer, comment); } diff --git a/java/java-tests/testData/codeInsight/javadocIG/apiNotes.html b/java/java-tests/testData/codeInsight/javadocIG/apiNotes.html new file mode 100644 index 000000000000..b731e4ecefcc --- /dev/null +++ b/java/java-tests/testData/codeInsight/javadocIG/apiNotes.html @@ -0,0 +1 @@ + Test
public void foo()
apiNote
my api note
implSpec
my impl spec
implNote
my impl note
\ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/javadocIG/apiNotes.java b/java/java-tests/testData/codeInsight/javadocIG/apiNotes.java new file mode 100644 index 000000000000..a0227cfd597e --- /dev/null +++ b/java/java-tests/testData/codeInsight/javadocIG/apiNotes.java @@ -0,0 +1,13 @@ +class Test { + /** + * @apiNote + * my api note + * + * @implSpec + * my impl spec + * + * @implNote + * my impl note + */ + public void foo(){} +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/javadoc/JavaDocInfoGeneratorTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/javadoc/JavaDocInfoGeneratorTest.java index bb132e19fd08..ef891b913836 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/javadoc/JavaDocInfoGeneratorTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/javadoc/JavaDocInfoGeneratorTest.java @@ -113,6 +113,10 @@ public class JavaDocInfoGeneratorTest extends CodeInsightTestCase { doTestMethod(); } + public void testApiNotes() throws Exception { + doTestMethod(); + } + public void testLiteral() throws Exception { doTestField(); } From 10c1ec502ca73ce47be83eb644f96309a83d696c Mon Sep 17 00:00:00 2001 From: Anton Makeev Date: Wed, 24 Dec 2014 14:37:07 +0100 Subject: [PATCH 033/137] SpellChecker now knows about CLion --- spellchecker/src/com/intellij/spellchecker/jetbrains.dic | 1 + 1 file changed, 1 insertion(+) diff --git a/spellchecker/src/com/intellij/spellchecker/jetbrains.dic b/spellchecker/src/com/intellij/spellchecker/jetbrains.dic index a5dd90c7896c..98ec7e480eda 100644 --- a/spellchecker/src/com/intellij/spellchecker/jetbrains.dic +++ b/spellchecker/src/com/intellij/spellchecker/jetbrains.dic @@ -68,6 +68,7 @@ checksum chmod classpath clazz +clion clob clojure cloneable From 3ddfd5e140110d2b7ebbed308ed52159f645b966 Mon Sep 17 00:00:00 2001 From: Sergey Ignatov Date: Wed, 24 Dec 2014 15:58:48 +0300 Subject: [PATCH 034/137] ObjectUtil.notNull for EA-63607 - IAE: ColorIcon. --- .../intellij/codeHighlighting/HighlightDisplayLevel.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/platform/analysis-api/src/com/intellij/codeHighlighting/HighlightDisplayLevel.java b/platform/analysis-api/src/com/intellij/codeHighlighting/HighlightDisplayLevel.java index 4455cf0d6767..e7198b5ac44b 100644 --- a/platform/analysis-api/src/com/intellij/codeHighlighting/HighlightDisplayLevel.java +++ b/platform/analysis-api/src/com/intellij/codeHighlighting/HighlightDisplayLevel.java @@ -21,6 +21,8 @@ import com.intellij.openapi.editor.colors.EditorColorsManager; import com.intellij.openapi.editor.colors.TextAttributesKey; import com.intellij.openapi.editor.markup.TextAttributes; import com.intellij.openapi.util.Comparing; +import com.intellij.ui.JBColor; +import com.intellij.util.ObjectUtils; import com.intellij.util.containers.HashMap; import com.intellij.util.ui.ColorIcon; import com.intellij.util.ui.JBUI; @@ -143,7 +145,13 @@ public class HighlightDisplayLevel { myKey = key; } + @NotNull public Color getColor() { + return ObjectUtils.notNull(getColorInner(), JBColor.GRAY); + } + + @Nullable + public Color getColorInner() { final EditorColorsManager manager = EditorColorsManager.getInstance(); if (manager != null) { TextAttributes attributes = manager.getGlobalScheme().getAttributes(myKey); From db2cb1bfddfbca3fed2ec5fa5b8f673acbf799bf Mon Sep 17 00:00:00 2001 From: Sergey Ignatov Date: Wed, 24 Dec 2014 16:37:23 +0300 Subject: [PATCH 035/137] update j2ee icons again --- .../src/javaee/persistenceEmbeddable.png | Bin 281 -> 311 bytes .../src/javaee/persistenceEmbeddable@2x.png | Bin 1242 -> 1258 bytes .../icons/src/javaee/persistenceEntity.png | Bin 286 -> 347 bytes .../icons/src/javaee/persistenceEntity@2x.png | Bin 1249 -> 1267 bytes .../javaee/persistenceMappedSuperclass.png | Bin 398 -> 453 bytes .../javaee/persistenceMappedSuperclass@2x.png | Bin 1462 -> 1485 bytes 6 files changed, 0 insertions(+), 0 deletions(-) diff --git a/platform/icons/src/javaee/persistenceEmbeddable.png b/platform/icons/src/javaee/persistenceEmbeddable.png index 03f46d92bc53a2988c9a7d29f749f3c4af57ec5a..ef5ac7d714139717eb1f0e1f895de63eb1332540 100755 GIT binary patch delta 284 zcmV+%0ptFe0=EK?B!B)%L_t(|+GF_t|33pI7)-40PUt^0FaO8MCB^?wEiJ)|L25v1 zL3;L1OM)11cwWx`6N?M~6KlYU#YO)Q&&~M{H{j^}-2Vq=rv2YHJvk95h!=y@fYgHY zzzx{YpA0tr^6okRA6!2T#vnGb%^N4A!7+#r(gQc3Ez3O-D1Vp;(u9oh7?9YW?VboX z;Kbr$mRvKpeQ0H78L+zbFtxbUYZX80000SU-@%ltt6z#?KnKtzvxt9%s@6%j%4qou30%{sjx=@!$(X6a_rrLIff zJul-h>(Naew!8RUz&Yo6f9H9g_jykSLMY>PlJUP0xM})^=6_9q1IU2@uns%{&>?w} zd^V7b#Yx6at+iX=1V91LkFeN5*-ox;!YR#rSzuxK>tBy?;g^85wy*%sLP{X0A)dj7 z<6oSrL{qAZzcU2FI=+2eQSx-Whl>KLQZ%b0(fm*aS_G*jL)D=d!p|%YSE2dA3Iwsy zbYB_r$%`>B;D7he41wrS#m!}-;Mt_A40+&2PdBCr-H;U`_q77#lI9`jA;8bzXK@TK z#2Z)e(2Vv{LJnSRlOX_RxnTX6euG=1ja&1kdbHr|MsuT56dvhBfdOF(|MiP0CX}UU z3f>Uo>ER{tDZWG#Dgp(yd=!B!&~X@rljdqog>(bT=rmY>yuw72g zIeIKJ#($<1J_T=2tZn%T%#u86xS1{2)O|s!YCq>1TXG0@cd<6q&tD1YE zw}2+uh*-s;DN3ZB7;X`J^^G;2fvW;H2+`QuE{I0jndn956AU%7It(qjN?Ut@9cN(4 zDA=as!#1p82tZ9TgKDC6Ie8;abGk}E_W(5cHh*mKTD%rRz$)RKCC-14i{EUfpNyqj zU|RiE)FR;s%Gn>WN82x)VU|Ec{#eUBCCBy0+~~hj6Ed~fZ%+=!Rzs%vy;<{S%q2|` z9je?D|8*k4cyHN;tD6_Y{m@^3PJm+?nps3E|1=fUk`EaIqtfCTy8gJCyt*qQ2Q;F6 zAAe}k-Qb4X30~X?y%10nAt=EXUc=H}I4KkgGcYLum|SOJPT!(aiPL`tm*T_LgS*0KbyRol=uUkbW)(VkVd$EdSKimH!q)01qNE z=fh%{Y+l@mbglm$M9xG{B>(5a!zdl31b_Ok=9oEI?-DqTmR61+WN!Ax++7>5Ody~p z*P~SBPu`vq$}DD+bgkXmI?_)yiKa}F4!^#E=6yOqJRUz13;};HuM|@M8{GrA))8B4 zXx`Op50A;H*%6sGKz&Q|aoPoN4~R-L>+x3Fa}WVL<^XrMK+zEEKZ0@tuQc_Z&FZ5`aK6;Bm`}e!(A- zuS4Js0Dr5QZ4&ka|6s$5IcqDr7f&{$2T}XK3jF77NS{tgk@p;(d4#QvV}tGay|IP$ z7*4Y1(42n&2si1m2`KMA{YU6SB<-X4prl*iPf)3zdO#E6KL7v#07*qoM6N<$f}Mh^byuLV5Q5@M1rzK#9vJ>NU$+;d+XAtdf)68FCmm}<#mynhD7pc(kU5_ky6Gx9LJ z))(GO9Ns$;YpcLMU;|Hf5p1Wdg=6e%Q6z5`@HAxqv4?>-fmo|lfMy{g;Lv6~p17K` z=fTIX(w(@BR)Kp;g-Wv57MX)?j0 z9dkpOg0-heJA&HOcqs@BH=Yj3-KvwU@C1~(M%~=HTOpb0sU=em9r4?> zWVGdc1o~Etp@wYYXwa#OyRCwCT zfPc@(tpTHEh_aL3&BbIJ@#ETLwT|=vpgj@( zox@@h3nBsy7m}Q!qi;!R8Zi&#-j1@7S%0T``GpDKGFn2Nenm6d99p4_)q2oWDjTs@ zsm8ms`r$SuD5dOY8w7*FUBMI3oJ+{ZwfiUQ0a|NcS4Cj@X1&|*(%bw_y?NZCWV|19 z0onr>B!|lW#@g?-4pfj5u!&zt5$_o|1q*}$89Dl)= zk&InNsI_jox861DzT%x7xEi4MLztwP3*gpTTA$Z>YjhNkw<}#9vqCpyR?7QZOQc%{ z(Hk)rkft59;Q9=197J2^z@C->H6ej-cF)5z;6xH=RSt)c7nt!;JpH2ygyW(|4DD-#p6G&R7 k{VVJeiTNnrDX|v#2k6&4#xr9~2mk;807*qoM6N<$g6IcNuK)l5 diff --git a/platform/icons/src/javaee/persistenceEntity.png b/platform/icons/src/javaee/persistenceEntity.png index 9f942f970782c919b1bac1fba3d1b7542cd1fe63..8ed614d96bf032049e4abf9034fabebf98152191 100755 GIT binary patch delta 321 zcmV-H0lxm80^0(RBYy!RNkl#cG{M`QsW~Tn%H$6EKD2Nw>)PU52 z^uP_+(4P!8{qpWP{~ugG4aOigvdtSOq`@(W57GlSpe@Ti5r1f6;^p15!5U#0n*kg8 z!L}#1XS*lD4LGs57#s!{cFagTzhgQaA6<|O$7_1x!FX+NVj@T_NDt6p%Dmt)X%Aj6 zBmxz}F;F8I1HAxJs|xgj>Y+o2@OnWNXv2R(7@rpsK?;Dj{D;x#7;XSAFMt$OF5UMZ zMx$f60rmbFYJ7xaklNkU@PfyrJ$Su< z&jqSLFQ^_mbO^5(RDm}9Cxr2NArYhiXv=>XjgH|4;PL`ULFLkY|6w#bh8uv-3q-kK zMQiv^TwWl`1uYpa@$0*zKb=^Q=>?)(F!kbR6by=AP!tgp3jms^qSu->C)5A{002ov JPDHLkV1j;WbDaPH diff --git a/platform/icons/src/javaee/persistenceEntity@2x.png b/platform/icons/src/javaee/persistenceEntity@2x.png index 8da8fa56771610359a5e97753b01508396e1666e..b752905a75bf6b0d66fe74102ef55e87e2537aee 100755 GIT binary patch delta 1247 zcmV<51R(q23G)e%B!9X|L_t(|+Rc{9Pa9_xz&W&kKu@{!+FR92tEyF{NUacUs-#jA z786$E2BwSy6qlX2EXFJ*#+caH#ux_gfVbGjfH!RR#Ayksn!*7otxzPQDlJi}(5U+Q zKG!oL9)ch;O%K1r*fa0@&3o^A-=rag(q1KL{~LiD#&2of0Dm}u4DbV+z(W8XlZT0C z{fStdL~LfQWPwuv1w46)#g58eVvSP{N#64UOJm>sae@m!2duS=1#lJ^fuNdr41b*b z;#3uyRbKjwB@of_C#U2kkEZ&$$geC#b6OHDj8>v$kXq4KAA2GE%<@<@S{SKB5E}&s z%aB)AjCl&zzkjg=7Dp>@tQrK5XOv~g4L7>`Fh%IPv=F(j79gi24>^tjeg;2_V|XCm zl$?h`n)0|Dyx0y)0L*g1`T_k0Hz!(l7mQ74$`S759Vc^1x(Iz6jrFQ`T^untDON(yfTtWYoO9 z-yAZuGJkmGyaTax=EpIK^Qf`59GSZDOHx_?1=rA?O}P4sHQ^!tT3CDeK1%?)R7k%C zG|6_sswZoK$Gvm7JskDYq10@V$M0@!uz@S%|b(DEY$)5 z)z^z=F-K65^I^_J*Tu6e0l%93rJnn-4A&oXeW;->Y;3pPni+|$hmBiz=1e;=r-Wf~ zwCX^7*N8Y%17+LJK3)v>!%)+C0gkC}%OX1XXQ-ftyvGulkQ9gL`r~HuXd8rfXhho! zpnpY^!40<`ytn~+!LK61P=Z~&hPkV7<}-O94Z{e)UQwt&p2uHryE1ErZ>z^5Q`XH{eoq@Rm{m~j?HDn51g=D*1jz=Md) z{-78pn+G={UF&Cq$Pw>}#P3{q7^MP6V1MXJwuzJR4uR8X?%)W*rZ!K^)w}(l3HVjz zo6tnRdiqN!lPHIzYwglBl0K?cIBOJl`*h7T@6iFG(I`Xm^{YxCZ#jE+jv|n<49saOb_eRtdyG(j`Y@W(HH+pQa`Uo#aAw7;4&(D7!I_i` z1XRRky!NmKLmDy`)VG+u+D4H}+a$0L))GmB=&h8O01gN(d;6zIR0&RfX zB`x|Le@MOxf!Bd-yClzK73bXbjaW24owszLI}sDQyJ$Q4T|l2sAn_XTuDvIZuy%5+ zuswe=v}Zlgw`D$o=KLE#xJgr<0a`$D`_ZA$he*mt@li>&z&|8Izpu$$c2fWV002ov JPDHLkV1mBXU8Mj3 delta 1229 zcmV;;1Ty>c3E>HlB!8$$L_t(|+Rc{9Pg_?M##yv~Kv&sx+g&HA8Bp3PRf__&2?XO2 zoWP?Bv2a9_n&Js;;~`*&DI|t?z+mtI31+Y{#`uA$)ub&!9ayx21yWj}NJLdyqEw+# zb$hPyeF8rRk<>I@{1zVWIo~_y-0!>`giy|lBB}y zvG2(vS1OQ4&-;rdz+>QzIMgK%`?aOWZxo=h%jGECc?LzVR-)K7>X{SGz!`it+;Ikt zx0a(JlK{CIIe*C6Q1ZlY68y#z5HOc5%v`H{6ofzfO?))a#6^7?4gyigraFas6h#OQ z?V0P!VmNyW^+Hm&4ju{wgxXIh#ocTXt+NCuE02kwJom{H#9bFRVvbrgKh%t7y+%ZP z3@F@vo&i4`Kdn^GRpMRnu zPXW`r7IUlPQ%;pV+}~sjIveFdhgyaO5n!k^nSh~90>fwS({ijJCIB~JiMCRkB>v^v z0y#^-InLp{t92(#v^D8g>>2nMEg&<1MYMiasDHq@SORKzM^1|J-xR?W)Zk&swg71H zEuWDuD=TJgCey19?y>}cL(P%?<6)Yx$u)Qop9T?{4j#De;N*A~ zz<-3|F)Ou!bJ&!{(Sj~I2g3-c6&^haiSLk7;xd2b({0|FcCCLCwl9AjvMtSfb<6Xf z##Mj|dm|%o-2f36rd>2@DX)N-6b51@8EzKlLknJI3BX1qE_}NZoNbbZwMlx-%m9FA zBK185hfy|Q1hic!^a+l?A;Dz?KafTHRDY8RpKk3x69CI-1^VeHIhZ0a=4w3+gM1mpx^KP&N=+EU zZSp6yy8$gs_oDA&gZqCA$aVq|FGd0H)bMg8y6TUH+b@3nQ;)LvKD6gCyyg6j-cgoCp-ei$Q8YYLCoE zGGJYABG~lHyXX9WaQ!qGgV@M6Z=8?@#~}WCpdPpZtyyk~M}Oz%CSKk>8>|tAu^F(T zKlMLIZCkc`;_8kFhylkI7Jvl*pW8Y$@$8lBnUfmh12~<1r z_@cs-Ur$dW=!H$k7Z>Gh?vG!yx+C%h(8k{&8pL1Un~(!H0EZV&0&U4%*ByNm6ksn8 zbo~E(aw3=p@gi5Xho1!+$c4`f=IgqmCLNxa{U2x(1_l`dG@t>W7qZuOlM4YJW9FKU zh=&ARa1U(2hQ6eqSiCS17}{%(;17dFm>1%=Pf7cPKNdRwe>pV~OhaSg3_KR5Ui^%L vK`9Ir#~=)3bAoIF;yWNeLunA76C@7+)K<8qtdH)P00000NkvXXu0mjfP<^zL delta 371 zcmV-(0gV2|1C9fbB!5*&L_t(|+GF_t|33pI7)&f~3hm!EG498nsY(C$PQ#BuYCvj1 zdVqY00lTIo64Z!}p?V+&?3oHTAdyJ?AF2mp!1C5`umLAG^#8wk@hBLB*vK|6Z4QHD z5Fe@sVn9o#3)p0kCS;7qfW+2Jw?w!ByP;kHYDz@LQ0Mvpv41&Gqb3k5gJ>XsB2drC z)g2K8y|4-B*PIPK(QAN;UjXrM5Dnr3_2hg#JqfQDP6BPoUE3LX^T_<1|1S@8{QrD% zBA5p8SG9+q1scYM&kN>jyCNqYo|pX}XcGno83Ht*0iPGL*K|g{0NIGm0FXG)fV=p- z5DoG($l2Ho0Bnf^<$vPyf+kSGLjo?i2R2|uYxqwrUYNMPJ8JC_{9(`t@j`}6{QBc6`#1&nZ(l~B7wF%66`oiraOxf_<#B_fpnU)^=X8v+fN4MsRTB?F}Mf!+7&$F z0DFUt8Dv72O^XY(=Pg7Da4PvJp!yzrg7bZ4i-GPEGG%KZ{ysVJo~b3S*8C7dKV*g& zZptE~nu9cURR)c-@jEiC7LsvY4)H-GS-Zi`V}HQG5`Uuvn50Pw`MjMXZ)?sxE}U~H z$edG2ew(r}SYJM4STFQ0ZO)qDJBYyS3EobDxr&nzC7}B7*RsU;4+I^j_6cnD=}ps? zn)!?20w()6EPzsGT(Zd1YS1?NkRRDq&Gv$oA~fXQ8P{fy_1Er~;zEl$UofC66p!`R zGY3;|6~ft=u_nFM`)N#7Tw_OhvQk_8tw>$?ji9R{Nk}#Db?%m&Ik*1s zohSignu8Md6i_6$eZ5lms8OOD?x>JD3}prO){|li1hJT_Qzd6)(HJCqY1+#YYdR}Z zn#{5^3r1kNOT5h5A5~`-__e$^BqYEl=f*=XsDGSc7GjuVOu;RHf{-hKd?1qne=G1E z6#4HibygwziW1OU#n~;~yFCR@Hqj!QjZpvvlmy!j)q1r8k6)X97mUAnN%~!U=Fw&p z_f&B{&Q1RGvp!ksuBG#hkpf&=(VvBaFO-;n`U1q|6@zmES47$mR4+svD3FWbW%*NLj51oX-I6Kwvmm>l{di4_XbvJQ;U z9V3lgE*N@@4uY)*$aQ-Wx$mnXkI$)S?)zlq+Swxd9V6uFpo(`qN&r=#wj28Nc{Z#V z=AZ0}<)6L13v=V0^FO+bmu778`59~N4S&RE$kqAu!aOjtgoZDh^T^_K0|CQpg70t* zBVrNQ79ju|ktpdCK6Ew*79yMLl}2QvYl3->1y>r-@vpJY*K@p@FcCpuOGrS=$s`je z;X@&Ywx^OKcALr_vsB&fbp%jQaB?>6uR8f!kqApi{7MlvXJ3Vay6I3IFq)*vB7Zj5 zl&)AbWIQDq?XIdBGL*9H@@RNAG=lkkQ|ByLCyW4HNWjqPj4TNK6SfBEJew=sfq~N& zZ@jRn0J*O)@Rspz& z5wIK*P<-Ia6F4Zk$`gfn4KEDTEq}a5z|)Nicr>Go7U0q6E}kyf&E%Oz=6#-Hz5VrSB6ou@G6~qxPlWp(d>96l`002ovPDHLkV1nN&&5!^9 delta 1444 zcmV;V1zY;f3$_c8B!7KLL_t(|+Rc~yPm^a9$1&Odfc@mZz>?jPO(4XDB_kjkf>cXe zE`_py1PtgvN(+<B!+c20fY zH@$#dg4urfgywyp=bZ0*&Uwyx@FRry{g?RtZv;#>q|m$raDRaszzW;}9s^{bJf`+q zDO+61Hsi}%z)?UCyf}cfy|PL9INBhL@)TgMO!)f^I`#m3t)T#n0wbWiGE3Iq&QCA!32lk--51c;JDco3dd`U~u>7uKvzS;Wy(PA0o$#MV_x zMjFmB;8)R@Diesg>J``ITo-+E9vM)^ks)|D3X!DkLVr|$&rSH0?IR#H=2%!7>sTg; zSj2_j8KvY#PYL;9vilXbF4r@fokEYP+YZY4t*@d#5u|}H9|2-Ph@2hzo&Z8GfDoze zokfct0<0Ye7SLP9S-4uxRiJJ3QIPUkIo%5w0mIda58))(dMxvGIMj0(A-pzgMw(Fs3h9~Me72JPtjJ)QiGU&H~|YbwP2IB zUy*e}=p*1PDLVp!-5lE%L-&ObyMEs`8j>tz}-)Q-M z2qPea9e9!#{s9k;pahF$p8`xkfkTt5v^OL=oQ?cH!T1(}zww!^o-a1YVgut&e0V&Q z9Te#!;JPyIkKBagHJE<{!Ys737xv#UYi`YsHZRYOHLXl{OBf(c$ReP!sgrWR(Jx?- zynl}A#>Cl{!l-zNNcqNmou>fkP*ZgNv6xI+p#%$YCn%x8mb&~h)S>$?033)!KRqH2iaKHd(t_O@F}fw%|KlgKHsLYw*|KLjX3Sgouxlp|cI! zU~JO4W@-SynxLLz!4*2S{3Y7?PL92yMF2Cv5k^4e`3M6i?EQ2ME%bvNOPhGuX^=kH zL4XMgu7VEx>%M%uNVugV)O{G;fnjkEic#NP%Fd*7J*dsk9BwU^jCGVMhMGh`K7SJF z&?F9^5zOyiozq~QPy%#}fReMJX)t!5(KUd1wssWSr>?5{ZAOLOW>DzHnng6>kjMLI z1dD9H0BuK*ZEYtSZ#;eTe7Ne?5)wQQ Date: Wed, 24 Dec 2014 16:58:45 +0300 Subject: [PATCH 036/137] IDEA-27486 Make file templates per-project: sharing default scheme --- .../ide/fileTemplates/impl/FTManager.java | 29 +++++++++---------- .../impl/FileTemplateManagerImpl.java | 1 - .../impl/FileTemplatesLoader.java | 4 +-- .../impl/LightFileTemplatesTest.java | 18 ++++++++++++ 4 files changed, 33 insertions(+), 19 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/ide/fileTemplates/impl/FTManager.java b/platform/lang-impl/src/com/intellij/ide/fileTemplates/impl/FTManager.java index 92085534bf98..b5aa184607e2 100644 --- a/platform/lang-impl/src/com/intellij/ide/fileTemplates/impl/FTManager.java +++ b/platform/lang-impl/src/com/intellij/ide/fileTemplates/impl/FTManager.java @@ -63,7 +63,7 @@ class FTManager { myOriginal = null; } - FTManager(FTManager original) { + FTManager(@NotNull FTManager original) { myOriginal = original; myName = original.getName(); myTemplatesDir = original.myTemplatesDir; @@ -77,15 +77,15 @@ class FTManager { } public void setScheme(FileTemplatesScheme scheme) { + mySortedTemplates = null; myScheme = scheme; - restoreDefaults(Collections.emptySet()); } @NotNull public Collection getAllTemplates(boolean includeDisabled) { List sorted = mySortedTemplates; if (sorted == null) { - sorted = new ArrayList(myTemplates.values()); + sorted = new ArrayList(getTemplates().values()); Collections.sort(sorted, new Comparator() { @Override public int compare(FileTemplateBase t1, FileTemplateBase t2) { @@ -115,7 +115,7 @@ class FTManager { */ @Nullable public FileTemplateBase getTemplate(@NotNull String templateQname) { - return myTemplates.get(templateQname); + return getTemplates().get(templateQname); } /** @@ -125,7 +125,7 @@ class FTManager { */ @Nullable public FileTemplateBase findTemplateByName(@NotNull String templateName) { - final FileTemplateBase template = myTemplates.get(templateName); + final FileTemplateBase template = getTemplates().get(templateName); if (template != null) { final boolean isEnabled = !(template instanceof BundledFileTemplate) || ((BundledFileTemplate)template).isEnabled(); if (isEnabled) { @@ -151,7 +151,7 @@ class FTManager { FileTemplateBase template = getTemplate(qName); if (template == null) { template = new CustomFileTemplate(name, extension); - myTemplates.put(qName, template); + getTemplates().put(qName, template); mySortedTemplates = null; } else { @@ -163,9 +163,9 @@ class FTManager { } public void removeTemplate(@NotNull String qName) { - final FileTemplateBase template = myTemplates.get(qName); + final FileTemplateBase template = getTemplates().get(qName); if (template instanceof CustomFileTemplate) { - myTemplates.remove(qName); + getTemplates().remove(qName); mySortedTemplates = null; } else if (template instanceof BundledFileTemplate){ @@ -190,7 +190,7 @@ class FTManager { } private void restoreDefaults(Set toDisable) { - myTemplates.clear(); + getTemplates().clear(); mySortedTemplates = null; for (DefaultTemplate template : myDefaultTemplates) { final BundledFileTemplate bundled = createAndStoreBundledTemplate(template); @@ -208,7 +208,7 @@ class FTManager { private BundledFileTemplate createAndStoreBundledTemplate(DefaultTemplate template) { final BundledFileTemplate bundled = new BundledFileTemplate(template, myInternal); final String qName = bundled.getQualifiedName(); - final FileTemplateBase previous = myTemplates.put(qName, bundled); + final FileTemplateBase previous = getTemplates().put(qName, bundled); mySortedTemplates = null; LOG.assertTrue(previous == null, "Duplicate bundled template " + qName + @@ -269,12 +269,6 @@ class FTManager { } public void saveTemplates() { - if (myOriginal != null) { - myOriginal.myDefaultTemplates.clear(); - myOriginal.myDefaultTemplates.addAll(myDefaultTemplates); - myOriginal.myTemplates.clear(); - myOriginal.myTemplates.putAll(myTemplates); - } final File configRoot = getConfigRoot(true); final File[] files = configRoot.listFiles(); @@ -399,4 +393,7 @@ class FTManager { return Pair.create(name, ext); } + public Map getTemplates() { + return myOriginal != null && myScheme == FileTemplatesScheme.DEFAULT ? myOriginal.myTemplates : myTemplates; + } } diff --git a/platform/lang-impl/src/com/intellij/ide/fileTemplates/impl/FileTemplateManagerImpl.java b/platform/lang-impl/src/com/intellij/ide/fileTemplates/impl/FileTemplateManagerImpl.java index 5776f4832645..aedc584d1a36 100644 --- a/platform/lang-impl/src/com/intellij/ide/fileTemplates/impl/FileTemplateManagerImpl.java +++ b/platform/lang-impl/src/com/intellij/ide/fileTemplates/impl/FileTemplateManagerImpl.java @@ -145,7 +145,6 @@ public class FileTemplateManagerImpl extends FileTemplateManager implements Pers myScheme = scheme; for (FTManager manager : myAllManagers) { manager.setScheme(scheme); - manager.loadCustomizedContent(); } } diff --git a/platform/lang-impl/src/com/intellij/ide/fileTemplates/impl/FileTemplatesLoader.java b/platform/lang-impl/src/com/intellij/ide/fileTemplates/impl/FileTemplatesLoader.java index 18188a7d3e04..a9423ad11f78 100644 --- a/platform/lang-impl/src/com/intellij/ide/fileTemplates/impl/FileTemplatesLoader.java +++ b/platform/lang-impl/src/com/intellij/ide/fileTemplates/impl/FileTemplatesLoader.java @@ -107,11 +107,11 @@ public class FileTemplatesLoader { return new FTManager(myPatternsManager); } - public FTManager getCodeTemplatesManager() { + FTManager getCodeTemplatesManager() { return new FTManager(myCodeTemplatesManager); } - public FTManager getJ2eeTemplatesManager() { + FTManager getJ2eeTemplatesManager() { return new FTManager(myJ2eeTemplatesManager); } diff --git a/platform/platform-tests/testSrc/com/intellij/ide/fileTemplates/impl/LightFileTemplatesTest.java b/platform/platform-tests/testSrc/com/intellij/ide/fileTemplates/impl/LightFileTemplatesTest.java index 3eba2bd1493e..ecce6a5ad2a7 100644 --- a/platform/platform-tests/testSrc/com/intellij/ide/fileTemplates/impl/LightFileTemplatesTest.java +++ b/platform/platform-tests/testSrc/com/intellij/ide/fileTemplates/impl/LightFileTemplatesTest.java @@ -117,6 +117,24 @@ public class LightFileTemplatesTest extends LightPlatformTestCase { } } + public void testRemoveTemplate() throws Exception { + FileTemplate[] before = myTemplateManager.getAllTemplates(); + try { + FileTemplate template = myTemplateManager.getTemplate(TEST_TEMPLATE_TXT); + myTemplateManager.removeTemplate(template); + assertNull(myTemplateManager.getTemplate(TEST_TEMPLATE_TXT)); + myTemplateManager.setCurrentScheme(myTemplateManager.getProjectScheme()); + assertNull(myTemplateManager.getTemplate(TEST_TEMPLATE_TXT)); + myTemplateManager.setCurrentScheme(FileTemplatesScheme.DEFAULT); + assertNull(myTemplateManager.getTemplate(TEST_TEMPLATE_TXT)); + } + finally { + myTemplateManager.setTemplates(FileTemplateManager.DEFAULT_TEMPLATES_CATEGORY, Arrays.asList(before)); + myTemplateManager.setCurrentScheme(myTemplateManager.getProjectScheme()); + myTemplateManager.setTemplates(FileTemplateManager.DEFAULT_TEMPLATES_CATEGORY, Arrays.asList(before)); + } + } + private FileTemplateManagerImpl myTemplateManager; @Override From 06dbabe0984a5ec955f8a0fe3b24af1cf536d052 Mon Sep 17 00:00:00 2001 From: Alexander Lobas Date: Wed, 24 Dec 2014 17:16:08 +0300 Subject: [PATCH 037/137] OC-11351 Parameter info for Swift --- .../codeInsight/ParameterInfoTest.java | 16 ++------------ .../MockUpdateParameterInfoContext.java | 21 ++++++++++++++++--- 2 files changed, 20 insertions(+), 17 deletions(-) diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/ParameterInfoTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/ParameterInfoTest.java index abf7f3880c9c..929c1463b979 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/ParameterInfoTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/ParameterInfoTest.java @@ -28,7 +28,6 @@ import com.intellij.testFramework.LightCodeInsightTestCase; import com.intellij.testFramework.utils.parameterInfo.MockCreateParameterInfoContext; import com.intellij.testFramework.utils.parameterInfo.MockParameterInfoUIContext; import com.intellij.testFramework.utils.parameterInfo.MockUpdateParameterInfoContext; -import com.intellij.util.ArrayUtilRt; import com.intellij.util.Function; import junit.framework.Assert; @@ -104,21 +103,10 @@ public class ParameterInfoTest extends LightCodeInsightTestCase { assertEquals(2, itemsToShow.length); assertTrue(itemsToShow[0] instanceof MethodCandidateInfo); final ParameterInfoUIContextEx parameterContext = ParameterInfoComponent.createContext(itemsToShow, myEditor, handler, -1); - final Boolean [] enabled = new Boolean[itemsToShow.length]; - final MockUpdateParameterInfoContext updateParameterInfoContext = new MockUpdateParameterInfoContext(myEditor, myFile){ - @Override - public Object[] getObjectsToView() { - return itemsToShow; - } - - @Override - public void setUIComponentEnabled(int index, boolean b) { - enabled[index] = b; - } - }; + final MockUpdateParameterInfoContext updateParameterInfoContext = new MockUpdateParameterInfoContext(myEditor, myFile, itemsToShow); updateParameterInfoContext.setParameterOwner(list); handler.updateParameterInfo(list, updateParameterInfoContext); - assertTrue(ArrayUtilRt.find(enabled, Boolean.TRUE) > -1); + assertTrue(updateParameterInfoContext.isUIComponentEnabled(0) || updateParameterInfoContext.isUIComponentEnabled(1)); } public void testAfterGenericsInsideCall() throws Exception { diff --git a/platform/testFramework/src/com/intellij/testFramework/utils/parameterInfo/MockUpdateParameterInfoContext.java b/platform/testFramework/src/com/intellij/testFramework/utils/parameterInfo/MockUpdateParameterInfoContext.java index 25679f485eb6..a1bfed07dc5b 100644 --- a/platform/testFramework/src/com/intellij/testFramework/utils/parameterInfo/MockUpdateParameterInfoContext.java +++ b/platform/testFramework/src/com/intellij/testFramework/utils/parameterInfo/MockUpdateParameterInfoContext.java @@ -22,6 +22,7 @@ import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.util.ArrayUtil; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; /** * @author gregsh @@ -32,10 +33,18 @@ public class MockUpdateParameterInfoContext implements UpdateParameterInfoContex private PsiElement myParameterOwner; private Object myHighlightedParameter; private int myCurrentParameter; + private final Object[] myItems; + private final boolean[] myCompEnabled; public MockUpdateParameterInfoContext(@NotNull Editor editor, @NotNull PsiFile file) { + this(editor, file, null); + } + + public MockUpdateParameterInfoContext(@NotNull Editor editor, @NotNull PsiFile file, @Nullable Object[] items) { myEditor = editor; myFile = file; + myItems = items == null ? ArrayUtil.EMPTY_OBJECT_ARRAY : items; + myCompEnabled = items == null ? null : new boolean[items.length]; } public void removeHint() {} @@ -58,16 +67,22 @@ public class MockUpdateParameterInfoContext implements UpdateParameterInfoContex return myCurrentParameter; } - public boolean isUIComponentEnabled(int index) { return false; } + public boolean isUIComponentEnabled(int index) { + return myCompEnabled != null && myCompEnabled[index]; + } - public void setUIComponentEnabled(int index, boolean b) {} + public void setUIComponentEnabled(int index, boolean b) { + if (myCompEnabled != null) { + myCompEnabled[index] = b; + } + } public int getParameterListStart() { return myEditor.getCaretModel().getOffset(); } public Object[] getObjectsToView() { - return ArrayUtil.EMPTY_OBJECT_ARRAY; + return myItems; } public Project getProject() { From cdddd873d9ae73f5a0c8f26214f78d1dcb325894 Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Wed, 24 Dec 2014 17:24:35 +0300 Subject: [PATCH 038/137] [vcs] IDEA-117448 Fix default PatchReader value --- .../src/com/intellij/openapi/diff/impl/patch/PatchReader.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/vcs-api/src/com/intellij/openapi/diff/impl/patch/PatchReader.java b/platform/vcs-api/src/com/intellij/openapi/diff/impl/patch/PatchReader.java index 236816854c8e..4c7031ffbc1b 100644 --- a/platform/vcs-api/src/com/intellij/openapi/diff/impl/patch/PatchReader.java +++ b/platform/vcs-api/src/com/intellij/openapi/diff/impl/patch/PatchReader.java @@ -52,7 +52,7 @@ public class PatchReader { @NonNls private static final Pattern ourContextAfterHunkStartPattern = Pattern.compile("--- (\\d+),(\\d+) ----"); public PatchReader(CharSequence patchContent) { - this(patchContent, false); + this(patchContent, true); } public PatchReader(CharSequence patchContent, boolean parseHunks) { From 0eedd3f0c93916a7afa3a283ffb0f4b9f8897d22 Mon Sep 17 00:00:00 2001 From: peter Date: Wed, 24 Dec 2014 15:09:40 +0100 Subject: [PATCH 039/137] EA-63629 - INRE: FileBasedIndexImpl.handleDumbMode --- .../com/intellij/execution/filters/ExceptionInfoCache.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/java/openapi/src/com/intellij/execution/filters/ExceptionInfoCache.java b/java/openapi/src/com/intellij/execution/filters/ExceptionInfoCache.java index e0ffc7fc9b40..7af2b2c1a3af 100644 --- a/java/openapi/src/com/intellij/execution/filters/ExceptionInfoCache.java +++ b/java/openapi/src/com/intellij/execution/filters/ExceptionInfoCache.java @@ -15,6 +15,7 @@ */ package com.intellij.execution.filters; +import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Pair; import com.intellij.psi.JavaPsiFacade; @@ -58,6 +59,10 @@ public class ExceptionInfoCache { return cached; } + if (DumbService.isDumb(myProject)) { + return Pair.create(PsiClass.EMPTY_ARRAY, PsiFile.EMPTY_ARRAY); + } + PsiClass[] classes = findClassesPreferringMyScope(className); if (classes.length == 0) { final int dollarIndex = className.indexOf('$'); From cf323744bfa85d115a0da289e7c7b33792a544cd Mon Sep 17 00:00:00 2001 From: peter Date: Wed, 24 Dec 2014 15:10:00 +0100 Subject: [PATCH 040/137] EA-63628 - INRE: FileBasedIndexImpl.handleDumbMode --- .../openapi/src/com/intellij/execution/JavaExecutionUtil.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/java/execution/openapi/src/com/intellij/execution/JavaExecutionUtil.java b/java/execution/openapi/src/com/intellij/execution/JavaExecutionUtil.java index 42ed3830364a..453cbcb0d6cd 100644 --- a/java/execution/openapi/src/com/intellij/execution/JavaExecutionUtil.java +++ b/java/execution/openapi/src/com/intellij/execution/JavaExecutionUtil.java @@ -26,6 +26,7 @@ import com.intellij.execution.util.ExecutionErrorDialog; import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleUtilCore; +import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.text.StringUtil; @@ -168,7 +169,7 @@ public class JavaExecutionUtil { @Nullable public static PsiClass findMainClass(final Project project, final String mainClassName, final GlobalSearchScope scope) { - if (project.isDefault()) return null; + if (project.isDefault() || DumbService.isDumb(project)) return null; final PsiManager psiManager = PsiManager.getInstance(project); final String shortName = StringUtil.getShortName(mainClassName); final String packageName = StringUtil.getPackageName(mainClassName); From 5f2b5a3363bcc614820cddda269ddc68a42f2924 Mon Sep 17 00:00:00 2001 From: peter Date: Wed, 24 Dec 2014 15:11:05 +0100 Subject: [PATCH 041/137] make ui form editor non-dumb-aware (EA-63630 - INRE: FileBasedIndexImpl.handleDumbMode) --- .../com/intellij/uiDesigner/editor/UIFormEditorProvider.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/plugins/ui-designer/src/com/intellij/uiDesigner/editor/UIFormEditorProvider.java b/plugins/ui-designer/src/com/intellij/uiDesigner/editor/UIFormEditorProvider.java index 1e043a3be4af..73f40c0aa8b2 100644 --- a/plugins/ui-designer/src/com/intellij/uiDesigner/editor/UIFormEditorProvider.java +++ b/plugins/ui-designer/src/com/intellij/uiDesigner/editor/UIFormEditorProvider.java @@ -22,7 +22,6 @@ import com.intellij.openapi.fileEditor.FileEditorProvider; import com.intellij.openapi.fileEditor.FileEditorState; import com.intellij.openapi.fileTypes.StdFileTypes; import com.intellij.openapi.module.ModuleUtil; -import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.vfs.VirtualFile; @@ -31,7 +30,7 @@ import com.intellij.util.ArrayUtil; import org.jdom.Element; import org.jetbrains.annotations.NotNull; -public final class UIFormEditorProvider implements FileEditorProvider, DumbAware { +public final class UIFormEditorProvider implements FileEditorProvider { private static final Logger LOG = Logger.getInstance("#com.intellij.uiDesigner.editor.UIFormEditorProvider"); public boolean accept(@NotNull final Project project, @NotNull final VirtualFile file){ From 546f255e28e751f9e9e95b99eecc5afe2a9202ca Mon Sep 17 00:00:00 2001 From: peter Date: Wed, 24 Dec 2014 15:14:38 +0100 Subject: [PATCH 042/137] no getOriginalClass in dumb mode (EA-63632 - INRE: FileBasedIndexImpl.handleDumbMode) --- .../com/intellij/psi/impl/JavaPsiImplementationHelperImpl.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/java/java-impl/src/com/intellij/psi/impl/JavaPsiImplementationHelperImpl.java b/java/java-impl/src/com/intellij/psi/impl/JavaPsiImplementationHelperImpl.java index 104546dd11e1..00d31a1f2dc7 100644 --- a/java/java-impl/src/com/intellij/psi/impl/JavaPsiImplementationHelperImpl.java +++ b/java/java-impl/src/com/intellij/psi/impl/JavaPsiImplementationHelperImpl.java @@ -26,6 +26,7 @@ import com.intellij.openapi.fileTypes.StdFileTypes; import com.intellij.openapi.module.EffectiveLanguageLevelUtil; import com.intellij.openapi.module.Module; import com.intellij.openapi.progress.ProcessCanceledException; +import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.*; import com.intellij.openapi.roots.impl.DirectoryIndex; @@ -69,6 +70,8 @@ public class JavaPsiImplementationHelperImpl extends JavaPsiImplementationHelper public PsiClass getOriginalClass(PsiClass psiClass) { PsiCompiledElement cls = psiClass.getUserData(ClsElementImpl.COMPILED_ELEMENT); if (cls != null && cls.isValid()) return (PsiClass)cls; + + if (DumbService.isDumb(myProject)) return psiClass; VirtualFile vFile = psiClass.getContainingFile().getVirtualFile(); final ProjectFileIndex idx = ProjectRootManager.getInstance(myProject).getFileIndex(); From 97d3accaee15b1e0736c004059055f83ade49a2e Mon Sep 17 00:00:00 2001 From: peter Date: Wed, 24 Dec 2014 15:17:47 +0100 Subject: [PATCH 043/137] AddModuleDependencyFix: add import only in non-dumb mode (EA-63633 - INRE: FileBasedIndexImpl.handleDumbMode) --- .../daemon/impl/quickfix/AddModuleDependencyFix.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/AddModuleDependencyFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/AddModuleDependencyFix.java index f3b95702eac7..e189374b2eb4 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/AddModuleDependencyFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/AddModuleDependencyFix.java @@ -24,6 +24,7 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleUtilCore; +import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.*; import com.intellij.openapi.ui.Messages; @@ -150,7 +151,9 @@ class AddModuleDependencyFix extends OrderEntryFix { targetClasses.add(psiClass); } } - new AddImportAction(project, myReference, editor, targetClasses.toArray(new PsiClass[targetClasses.size()])).execute(); + if (!DumbService.isDumb(project)) { + new AddImportAction(project, myReference, editor, targetClasses.toArray(new PsiClass[targetClasses.size()])).execute(); + } } } }; From a97424853f096cd181ec34c2961b1f136ead1e2c Mon Sep 17 00:00:00 2001 From: peter Date: Wed, 24 Dec 2014 15:22:01 +0100 Subject: [PATCH 044/137] allow to create Groovy classes in dumb mode (EA-63626 - INRE: FileBasedIndexImpl.handleDumbMode) --- .../plugins/groovy/util/LibrariesUtil.java | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/util/LibrariesUtil.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/util/LibrariesUtil.java index 398498f87e6a..32ede785af15 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/util/LibrariesUtil.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/util/LibrariesUtil.java @@ -19,6 +19,7 @@ package org.jetbrains.plugins.groovy.util; import com.intellij.openapi.application.AccessToken; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.module.Module; +import com.intellij.openapi.project.DumbService; import com.intellij.openapi.roots.*; import com.intellij.openapi.roots.libraries.Library; import com.intellij.openapi.roots.libraries.LibraryTable; @@ -132,14 +133,16 @@ public class LibrariesUtil { @Nullable public static String getGroovyHomePath(@NotNull Module module) { - final VirtualFile local = findJarWithClass(module, SOME_GROOVY_CLASS); - if (local != null) { - final VirtualFile parent = local.getParent(); - if (parent != null) { - if (("lib".equals(parent.getName()) || "embeddable".equals(parent.getName())) && parent.getParent() != null) { - return parent.getParent().getPath(); + if (!DumbService.isDumb(module.getProject())) { + final VirtualFile local = findJarWithClass(module, SOME_GROOVY_CLASS); + if (local != null) { + final VirtualFile parent = local.getParent(); + if (parent != null) { + if (("lib".equals(parent.getName()) || "embeddable".equals(parent.getName())) && parent.getParent() != null) { + return parent.getParent().getPath(); + } + return parent.getPath(); } - return parent.getPath(); } } From c4fb3e32ea98d3cece0ffbbeb9a295c3737c4911 Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Wed, 24 Dec 2014 12:20:22 +0100 Subject: [PATCH 045/137] restructure the code a bit to make it clearer and remove unnecessary use of reflection --- .../nodes/ProjectViewDirectoryHelper.java | 68 +++++++------------ 1 file changed, 26 insertions(+), 42 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/ide/projectView/impl/nodes/ProjectViewDirectoryHelper.java b/platform/lang-impl/src/com/intellij/ide/projectView/impl/nodes/ProjectViewDirectoryHelper.java index cfdde22d49f1..bd8ff2d059b9 100644 --- a/platform/lang-impl/src/com/intellij/ide/projectView/impl/nodes/ProjectViewDirectoryHelper.java +++ b/platform/lang-impl/src/com/intellij/ide/projectView/impl/nodes/ProjectViewDirectoryHelper.java @@ -133,21 +133,21 @@ public class ProjectViewDirectoryHelper { if (parentDir == null || skipDirectory(parentDir) && withSubDirectories) { addAllSubpackages(children, psiDirectory, moduleFileIndex, settings); } - PsiDirectory[] subdirs = psiDirectory.getSubdirectories(); - for (PsiDirectory subdir : subdirs) { - if (!skipDirectory(subdir)) { - continue; - } - VirtualFile directoryFile = subdir.getVirtualFile(); + if (withSubDirectories) { + PsiDirectory[] subdirs = psiDirectory.getSubdirectories(); + for (PsiDirectory subdir : subdirs) { + if (!skipDirectory(subdir)) { + continue; + } + VirtualFile directoryFile = subdir.getVirtualFile(); - if (Registry.is("ide.hide.excluded.files")) { - if (fileIndex.isExcluded(directoryFile)) continue; - } - else { - if (FileTypeRegistry.getInstance().isFileIgnored(directoryFile)) continue; - } + if (Registry.is("ide.hide.excluded.files")) { + if (fileIndex.isExcluded(directoryFile)) continue; + } + else { + if (FileTypeRegistry.getInstance().isFileIgnored(directoryFile)) continue; + } - if (withSubDirectories) { children.add(new PsiDirectoryNode(project, subdir, settings)); } } @@ -228,17 +228,23 @@ public class ProjectViewDirectoryHelper { for (PsiElement child : children) { LOG.assertTrue(child.isValid()); - final VirtualFile vFile; + if (!(child instanceof PsiFileSystemItem)) { + LOG.error("Either PsiFile or PsiDirectory expected as a child of " + child.getParent() + ", but was " + child); + continue; + } + final VirtualFile vFile = ((PsiFileSystemItem) child).getVirtualFile(); + if (vFile == null) { + continue; + } + if (moduleFileIndex != null && !moduleFileIndex.isInContent(vFile)) { + continue; + } if (child instanceof PsiFile) { - vFile = ((PsiFile)child).getVirtualFile(); - if (vFile != null) { - addNode(moduleFileIndex, vFile, container, PsiFileNode.class, child, viewSettings); - } + container.add(new PsiFileNode(child.getProject(), (PsiFile) child, viewSettings)); } else if (child instanceof PsiDirectory) { if (withSubDirectories) { PsiDirectory dir = (PsiDirectory)child; - vFile = dir.getVirtualFile(); if (!vFile.equals(projectFileIndex.getSourceRootForFile(vFile))) { // if is not a source root if (viewSettings.isHideEmptyMiddlePackages() && !skipDirectory(psiDir) && isEmptyMiddleDirectory(dir, true)) { processPsiDirectoryChildren(dir, directoryChildrenInProject(dir, viewSettings), @@ -246,31 +252,9 @@ public class ProjectViewDirectoryHelper { continue; } } - addNode(moduleFileIndex, vFile, container, PsiDirectoryNode.class, child, viewSettings); + container.add(new PsiDirectoryNode(child.getProject(), (PsiDirectory) child, viewSettings)); } } - else { - LOG.error("Either PsiFile or PsiDirectory expected as a child of " + child.getParent() + ", but was " + child); - } - } - } - - public void addNode(ModuleFileIndex moduleFileIndex, - VirtualFile vFile, - List container, - Class nodeClass, - PsiElement element, - final ViewSettings settings) { - // this check makes sense for classes not in library content only - if (moduleFileIndex != null && !moduleFileIndex.isInContent(vFile)) { - return; - } - - try { - container.add(ProjectViewNode.createTreeNode(nodeClass, element.getProject(), element, settings)); - } - catch (Exception e) { - LOG.error(e); } } From 5fb8cdf9c3f8b8e19d34653e91619d496a500c63 Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Wed, 24 Dec 2014 12:39:48 +0100 Subject: [PATCH 046/137] move PackagesTreeStructureTest to community --- .../PackagesTreeStructureTest.java | 221 ++++++++++++++++++ 1 file changed, 221 insertions(+) create mode 100644 java/java-tests/testSrc/com/intellij/projectView/PackagesTreeStructureTest.java diff --git a/java/java-tests/testSrc/com/intellij/projectView/PackagesTreeStructureTest.java b/java/java-tests/testSrc/com/intellij/projectView/PackagesTreeStructureTest.java new file mode 100644 index 000000000000..74c0a402d9fc --- /dev/null +++ b/java/java-tests/testSrc/com/intellij/projectView/PackagesTreeStructureTest.java @@ -0,0 +1,221 @@ +/* + * Copyright (c) 2004 JetBrains s.r.o. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * -Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * -Redistribution in binary form must reproduct the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the distribution. + * + * Neither the name of JetBrains or IntelliJ IDEA + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. JETBRAINS AND ITS LICENSORS SHALL NOT + * BE LIABLE FOR ANY DAMAGES OR LIABILITIES SUFFERED BY LICENSEE AS A RESULT + * OF OR RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL JETBRAINS OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE SOFTWARE, EVEN + * IF JETBRAINS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + */ +package com.intellij.projectView; + +import com.intellij.ide.projectView.ProjectView; +import com.intellij.ide.projectView.impl.AbstractProjectTreeStructure; +import com.intellij.ide.projectView.impl.PackageViewPane; +import com.intellij.ide.projectView.impl.ProjectViewImpl; +import com.intellij.testFramework.IdeaTestUtil; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.module.impl.ModuleManagerImpl; +import com.intellij.openapi.util.Disposer; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.testFramework.TestSourceBasedTestCase; +import com.intellij.util.ui.tree.TreeUtil; +import com.intellij.lang.properties.projectView.ResourceBundleGrouper; +import org.jetbrains.annotations.NonNls; + +import javax.swing.*; +import java.io.IOException; + +public class PackagesTreeStructureTest extends TestSourceBasedTestCase { + public void testPackageView() throws IOException { + ModuleManagerImpl.getInstanceImpl(myProject).setModuleGroupPath(myModule, new String[]{"Group"}); + final VirtualFile srcFile = getSrcDirectory().getVirtualFile(); + if (srcFile.findChild("empty") == null){ + ApplicationManager.getApplication().runWriteAction(new Runnable() { + @Override + public void run() { + try { + srcFile.createChildDirectory(this, "empty"); + } + catch (IOException e) { + fail(e.getLocalizedMessage()); + } + } + }); + } + + doTest(true, true, "-Project\n" + + " -Group: Group\n" + + " -Module\n" + + " -PsiPackage: com.package1\n" + + " Class1.java\n" + + " Class2.java\n" + + " Class4.java\n" + + " Form1.form\n" + + " Form1.java\n" + + " Form2.form\n" + + " PsiPackage: empty\n" + + " -PsiPackage: java\n" + + " Class1.java\n" + + " -PsiPackage: javax.servlet\n" + + " Class1.java\n" + + " -Libraries\n" + + " -PsiPackage: java\n" + + " +PsiPackage: awt\n" + + " +PsiPackage: beans.beancontext\n" + + " +PsiPackage: io\n" + + " +PsiPackage: lang\n" + + " +PsiPackage: net\n" + + " +PsiPackage: rmi\n" + + " +PsiPackage: security\n" + + " +PsiPackage: sql\n" + + " +PsiPackage: util\n" + + " -PsiPackage: javax.swing\n" + + " +PsiPackage: table\n" + + " AbstractButton.class\n" + + " Icon.class\n" + + " JButton.class\n" + + " JComponent.class\n" + + " JDialog.class\n" + + " JFrame.class\n" + + " JLabel.class\n" + + " JPanel.class\n" + + " JScrollPane.class\n" + + " JTable.class\n" + + " SwingConstants.class\n" + + " SwingUtilities.class\n" + + " -PsiPackage: META-INF\n" + + " MANIFEST.MF\n" + + " MANIFEST.MF\n" + + " -PsiPackage: org\n" + + " +PsiPackage: intellij.lang.annotations\n" + + " +PsiPackage: jetbrains.annotations\n" + + "" + , 5); + + doTest(false, true, "-Project\n" + + " -PsiPackage: com.package1\n" + + " Class1.java\n" + + " Class2.java\n" + + " Class4.java\n" + + " Form1.form\n" + + " Form1.java\n" + + " Form2.form\n" + + " PsiPackage: empty\n" + + " -PsiPackage: java\n" + + " Class1.java\n" + + " -PsiPackage: javax.servlet\n" + + " Class1.java\n" + + " -Libraries\n" + + " -PsiPackage: java\n" + + " +PsiPackage: awt\n" + + " +PsiPackage: beans.beancontext\n" + + " +PsiPackage: io\n" + + " +PsiPackage: lang\n" + + " +PsiPackage: net\n" + + " +PsiPackage: rmi\n" + + " +PsiPackage: security\n" + + " +PsiPackage: sql\n" + + " +PsiPackage: util\n" + + " -PsiPackage: javax.swing\n" + + " +PsiPackage: table\n" + + " AbstractButton.class\n" + + " Icon.class\n" + + " JButton.class\n" + + " JComponent.class\n" + + " JDialog.class\n" + + " JFrame.class\n" + + " JLabel.class\n" + + " JPanel.class\n" + + " JScrollPane.class\n" + + " JTable.class\n" + + " SwingConstants.class\n" + + " SwingUtilities.class\n" + + " -PsiPackage: META-INF\n" + + " MANIFEST.MF\n" + + " MANIFEST.MF\n" + + " -PsiPackage: org\n" + + " +PsiPackage: intellij.lang.annotations\n" + + " +PsiPackage: jetbrains.annotations\n" + , 3); + + doTest(true, false, "-Project\n" + + " -Group: Group\n" + + " -Module\n" + + " -PsiPackage: com.package1\n" + + " Class1.java\n" + + " Class2.java\n" + + " Class4.java\n" + + " Form1.form\n" + + " Form1.java\n" + + " Form2.form\n" + + " PsiPackage: empty\n" + + " -PsiPackage: java\n" + + " Class1.java\n" + + " -PsiPackage: javax.servlet\n" + + " Class1.java\n", 4); + + doTest(false, false, "-Project\n" + + " -PsiPackage: com.package1\n" + + " Class1.java\n" + + " Class2.java\n" + + " Class4.java\n" + + " Form1.form\n" + + " Form1.java\n" + + " Form2.form\n" + + " PsiPackage: empty\n" + + " -PsiPackage: java\n" + + " Class1.java\n" + + " -PsiPackage: javax.servlet\n" + + " Class1.java\n", 3); + + } + + private void doTest(final boolean showModules, final boolean showLibraryContents, @NonNls final String expected, final int levels) { + final ProjectViewImpl projectView = (ProjectViewImpl)ProjectView.getInstance(myProject); + + projectView.setShowModules(showModules, PackageViewPane.ID); + + projectView.setShowLibraryContents(showLibraryContents, PackageViewPane.ID); + + projectView.setFlattenPackages(false, PackageViewPane.ID); + projectView.setHideEmptyPackages(true, PackageViewPane.ID); + + PackageViewPane packageViewPane = new PackageViewPane(myProject); + packageViewPane.createComponent(); + ((AbstractProjectTreeStructure) packageViewPane.getTreeStructure()).setProviders(new ResourceBundleGrouper(myProject)); + packageViewPane.updateFromRoot(true); + JTree tree = packageViewPane.getTree(); + TreeUtil.expand(tree, levels); + IdeaTestUtil.assertTreeEqual(tree, expected); + BaseProjectViewTestCase.checkContainsMethod(packageViewPane.getTreeStructure().getRootElement(), packageViewPane.getTreeStructure()); + Disposer.dispose(packageViewPane); + } + + @Override + protected String getTestPath() { + return "projectView"; + } +} From c8055c9253100b0d77545c4f7bc970e215ab3e0d Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Wed, 24 Dec 2014 13:00:26 +0100 Subject: [PATCH 047/137] remove more gratuitous uses of reflection --- .../projectView/impl/nodes/PackageViewModuleGroupNode.java | 2 +- .../ide/projectView/impl/nodes/PackageViewProjectNode.java | 4 ++-- .../projectView/impl/nodes/ProjectViewModuleGroupNode.java | 4 ++-- .../ide/projectView/impl/nodes/ProjectViewProjectNode.java | 6 +++--- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/java/java-impl/src/com/intellij/ide/projectView/impl/nodes/PackageViewModuleGroupNode.java b/java/java-impl/src/com/intellij/ide/projectView/impl/nodes/PackageViewModuleGroupNode.java index 7416cd7ec6c5..0f1e1c9c9998 100644 --- a/java/java-impl/src/com/intellij/ide/projectView/impl/nodes/PackageViewModuleGroupNode.java +++ b/java/java-impl/src/com/intellij/ide/projectView/impl/nodes/PackageViewModuleGroupNode.java @@ -39,7 +39,7 @@ public class PackageViewModuleGroupNode extends ModuleGroupNode { @Override protected AbstractTreeNode createModuleNode(Module module) throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException { - return createTreeNode(PackageViewModuleNode.class, module.getProject(), module, getSettings()); + return new PackageViewModuleNode(module.getProject(), module, getSettings()); } @Override diff --git a/java/java-impl/src/com/intellij/ide/projectView/impl/nodes/PackageViewProjectNode.java b/java/java-impl/src/com/intellij/ide/projectView/impl/nodes/PackageViewProjectNode.java index 76946c41e999..1383ef400438 100644 --- a/java/java-impl/src/com/intellij/ide/projectView/impl/nodes/PackageViewProjectNode.java +++ b/java/java-impl/src/com/intellij/ide/projectView/impl/nodes/PackageViewProjectNode.java @@ -101,13 +101,13 @@ public class PackageViewProjectNode extends AbstractProjectNode { protected AbstractTreeNode createModuleGroup(final Module module) throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException { - return createTreeNode(PackageViewModuleNode.class, getProject(), module, getSettings()); + return new PackageViewModuleNode(getProject(), module, getSettings()); } @Override protected AbstractTreeNode createModuleGroupNode(final ModuleGroup moduleGroup) throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException { - return createTreeNode(PackageViewModuleGroupNode.class, getProject(), moduleGroup, getSettings()); + return new PackageViewModuleGroupNode(getProject(), moduleGroup, getSettings()); } @Override diff --git a/platform/lang-impl/src/com/intellij/ide/projectView/impl/nodes/ProjectViewModuleGroupNode.java b/platform/lang-impl/src/com/intellij/ide/projectView/impl/nodes/ProjectViewModuleGroupNode.java index d13d5e9c1fe0..b0a67ca578ae 100644 --- a/platform/lang-impl/src/com/intellij/ide/projectView/impl/nodes/ProjectViewModuleGroupNode.java +++ b/platform/lang-impl/src/com/intellij/ide/projectView/impl/nodes/ProjectViewModuleGroupNode.java @@ -48,11 +48,11 @@ public class ProjectViewModuleGroupNode extends ModuleGroupNode { if (roots.length == 1) { final PsiDirectory psi = PsiManager.getInstance(myProject).findDirectory(roots[0]); if (psi != null) { - return createTreeNode(PsiDirectoryNode.class, myProject, psi, getSettings()); + return new PsiDirectoryNode(myProject, psi, getSettings()); } } - return createTreeNode(ProjectViewModuleNode.class, getProject(), module, getSettings()); + return new ProjectViewModuleNode(getProject(), module, getSettings()); } @Override diff --git a/platform/lang-impl/src/com/intellij/ide/projectView/impl/nodes/ProjectViewProjectNode.java b/platform/lang-impl/src/com/intellij/ide/projectView/impl/nodes/ProjectViewProjectNode.java index c020db91e017..9f7cc2f7ac57 100644 --- a/platform/lang-impl/src/com/intellij/ide/projectView/impl/nodes/ProjectViewProjectNode.java +++ b/platform/lang-impl/src/com/intellij/ide/projectView/impl/nodes/ProjectViewProjectNode.java @@ -133,16 +133,16 @@ public class ProjectViewProjectNode extends AbstractProjectNode { if (roots.length == 1) { final PsiDirectory psi = PsiManager.getInstance(myProject).findDirectory(roots[0]); if (psi != null) { - return createTreeNode(PsiDirectoryNode.class, myProject, psi, getSettings()); + return new PsiDirectoryNode(myProject, psi, getSettings()); } } - return createTreeNode(ProjectViewModuleNode.class, getProject(), module, getSettings()); + return new ProjectViewModuleNode(getProject(), module, getSettings()); } @Override protected AbstractTreeNode createModuleGroupNode(final ModuleGroup moduleGroup) throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException { - return createTreeNode(ProjectViewModuleGroupNode.class, getProject(), moduleGroup, getSettings()); + return new ProjectViewModuleGroupNode(getProject(), moduleGroup, getSettings()); } } From d7e7555e7b4097773a916c4ad269656ae29bd5c2 Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Wed, 24 Dec 2014 13:22:40 +0100 Subject: [PATCH 048/137] remove a couple of unnecessary Project parameters --- .../ide/projectView/impl/nodes/PackageElement.java | 2 +- .../projectView/impl/nodes/PackageElementNode.java | 6 +++--- .../ide/projectView/impl/nodes/PackageUtil.java | 11 ++++------- 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/java/java-impl/src/com/intellij/ide/projectView/impl/nodes/PackageElement.java b/java/java-impl/src/com/intellij/ide/projectView/impl/nodes/PackageElement.java index ee64a3186f0e..8ecf509b0114 100644 --- a/java/java-impl/src/com/intellij/ide/projectView/impl/nodes/PackageElement.java +++ b/java/java-impl/src/com/intellij/ide/projectView/impl/nodes/PackageElement.java @@ -62,7 +62,7 @@ public final class PackageElement implements Queryable, RootsProvider { @Override public Collection getRoots() { Set roots= new HashSet(); - final PsiDirectory[] dirs = PackageUtil.getDirectories(getPackage(), myElement.getProject(), myModule, isLibraryElement()); + final PsiDirectory[] dirs = PackageUtil.getDirectories(getPackage(), myModule, isLibraryElement()); for (PsiDirectory each : dirs) { roots.add(each.getVirtualFile()); } diff --git a/java/java-impl/src/com/intellij/ide/projectView/impl/nodes/PackageElementNode.java b/java/java-impl/src/com/intellij/ide/projectView/impl/nodes/PackageElementNode.java index 1e09187d15c6..6568e2ff6e6b 100644 --- a/java/java-impl/src/com/intellij/ide/projectView/impl/nodes/PackageElementNode.java +++ b/java/java-impl/src/com/intellij/ide/projectView/impl/nodes/PackageElementNode.java @@ -87,13 +87,13 @@ public class PackageElementNode extends ProjectViewNode { if (!getSettings().isFlattenPackages()) { - final PsiPackage[] subpackages = PackageUtil.getSubpackages(aPackage, module, myProject, isLibraryElement()); + final PsiPackage[] subpackages = PackageUtil.getSubpackages(aPackage, module, isLibraryElement()); for (PsiPackage subpackage : subpackages) { PackageUtil.addPackageAsChild(children, subpackage, module, getSettings(), isLibraryElement()); } } // process only files in package's directories - final PsiDirectory[] dirs = PackageUtil.getDirectories(aPackage, myProject, module, isLibraryElement()); + final PsiDirectory[] dirs = PackageUtil.getDirectories(aPackage, module, isLibraryElement()); for (final PsiDirectory dir : dirs) { children.addAll(ProjectViewDirectoryHelper.getInstance(myProject).getDirectoryChildren(dir, getSettings(), false)); } @@ -163,7 +163,7 @@ public class PackageElementNode extends ProjectViewNode { if (value == null) { return VirtualFile.EMPTY_ARRAY; } - final PsiDirectory[] directories = PackageUtil.getDirectories(value.getPackage(), getProject(), value.getModule(), isLibraryElement()); + final PsiDirectory[] directories = PackageUtil.getDirectories(value.getPackage(), value.getModule(), isLibraryElement()); final VirtualFile[] result = new VirtualFile[directories.length]; for (int i = 0; i < directories.length; i++) { PsiDirectory directory = directories[i]; diff --git a/java/java-impl/src/com/intellij/ide/projectView/impl/nodes/PackageUtil.java b/java/java-impl/src/com/intellij/ide/projectView/impl/nodes/PackageUtil.java index bcb4b3d20319..28e3b85d3b7d 100644 --- a/java/java-impl/src/com/intellij/ide/projectView/impl/nodes/PackageUtil.java +++ b/java/java-impl/src/com/intellij/ide/projectView/impl/nodes/PackageUtil.java @@ -38,9 +38,8 @@ public class PackageUtil { @NotNull public static PsiPackage[] getSubpackages(@NotNull PsiPackage aPackage, @Nullable Module module, - @NotNull Project project, final boolean searchInLibraries) { - final PsiDirectory[] dirs = getDirectories(aPackage, project, module, searchInLibraries); + final PsiDirectory[] dirs = getDirectories(aPackage, module, searchInLibraries); final Set subpackages = new HashSet(); for (PsiDirectory dir : dirs) { final PsiDirectory[] subdirectories = dir.getSubdirectories(); @@ -70,7 +69,7 @@ public class PackageUtil { children.add(new PackageElementNode(project, new PackageElement(module, aPackage, inLibrary), settings)); } if (settings.isFlattenPackages() || shouldSkipPackage) { - final PsiPackage[] subpackages = getSubpackages(aPackage, module, project, inLibrary); + final PsiPackage[] subpackages = getSubpackages(aPackage, module, inLibrary); for (PsiPackage subpackage : subpackages) { addPackageAsChild(children, subpackage, module, settings, inLibrary); } @@ -81,8 +80,7 @@ public class PackageUtil { @Nullable Module module, boolean strictlyEmpty, final boolean inLibrary) { - final Project project = aPackage.getProject(); - final PsiDirectory[] dirs = getDirectories(aPackage, project, module, inLibrary); + final PsiDirectory[] dirs = getDirectories(aPackage, module, inLibrary); for (final PsiDirectory dir : dirs) { if (!TreeViewUtil.isEmptyMiddlePackage(dir, strictlyEmpty)) { return false; @@ -93,10 +91,9 @@ public class PackageUtil { @NotNull public static PsiDirectory[] getDirectories(@NotNull PsiPackage aPackage, - @NotNull Project project, @Nullable Module module, boolean inLibrary) { - final GlobalSearchScope scopeToShow = getScopeToShow(project, module, inLibrary); + final GlobalSearchScope scopeToShow = getScopeToShow(aPackage.getProject(), module, inLibrary); return aPackage.getDirectories(scopeToShow); } From fc00e89d0e12aeb9e38be9109275b18d14416b12 Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Wed, 24 Dec 2014 14:21:08 +0100 Subject: [PATCH 049/137] exception tolerance --- .../intellij/psi/impl/file/PsiPackageImpl.java | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/file/PsiPackageImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/file/PsiPackageImpl.java index d1b0a3553a13..2cda50ec8309 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/file/PsiPackageImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/file/PsiPackageImpl.java @@ -20,6 +20,8 @@ import com.intellij.lang.Language; import com.intellij.lang.java.JavaLanguage; import com.intellij.navigation.ItemPresentation; import com.intellij.navigation.ItemPresentationProviders; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.project.DumbService; import com.intellij.openapi.ui.Queryable; import com.intellij.openapi.util.Condition; @@ -46,6 +48,8 @@ import org.jetbrains.annotations.Nullable; import java.util.*; public class PsiPackageImpl extends PsiPackageBase implements PsiPackage, Queryable { + private static final Logger LOG = Logger.getInstance(PsiPackageImpl.class); + private volatile CachedValue myAnnotationList; private volatile CachedValue> myDirectories; private volatile CachedValue> myDirectoriesWithLibSources; @@ -321,7 +325,17 @@ public class PsiPackageImpl extends PsiPackageBase implements PsiPackage, Querya @NotNull Condition nameCondition) { for (PsiClass aClass : classes) { String name = aClass.getName(); - if (name != null && nameCondition.value(name) && !processor.execute(aClass, state)) return false; + if (name != null && nameCondition.value(name)) { + try { + if (!processor.execute(aClass, state)) return false; + } + catch (ProcessCanceledException e) { + throw e; + } + catch (Exception e) { + LOG.error(e); + } + } } return true; } From 60b8e7041b4090a3674b3f30a31a2bd4a4e23a0a Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Wed, 24 Dec 2014 15:26:50 +0100 Subject: [PATCH 050/137] replace PsiPackage.getChildren(scope) API with PsiPackage.getFiles(scope); use it for coverage and package view --- .../impl/nodes/PackageElementNode.java | 11 ++-- .../projectView/impl/nodes/PackageUtil.java | 50 ++++++++----------- .../com/intellij/psi/PsiElementFinder.java | 28 +++++------ .../src/com/intellij/psi/PsiPackage.java | 7 +-- .../intellij/psi/impl/JavaPsiFacadeImpl.java | 40 ++++++++------- .../psi/impl/file/PsiPackageImpl.java | 10 +--- .../view/JavaCoverageViewExtension.java | 33 +++++++----- 7 files changed, 92 insertions(+), 87 deletions(-) diff --git a/java/java-impl/src/com/intellij/ide/projectView/impl/nodes/PackageElementNode.java b/java/java-impl/src/com/intellij/ide/projectView/impl/nodes/PackageElementNode.java index 6568e2ff6e6b..3d73fdd48c0c 100644 --- a/java/java-impl/src/com/intellij/ide/projectView/impl/nodes/PackageElementNode.java +++ b/java/java-impl/src/com/intellij/ide/projectView/impl/nodes/PackageElementNode.java @@ -28,7 +28,9 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiDirectory; +import com.intellij.psi.PsiFile; import com.intellij.psi.PsiPackage; +import com.intellij.psi.search.GlobalSearchScope; import com.intellij.util.PlatformIcons; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -93,9 +95,12 @@ public class PackageElementNode extends ProjectViewNode { } } // process only files in package's directories - final PsiDirectory[] dirs = PackageUtil.getDirectories(aPackage, module, isLibraryElement()); - for (final PsiDirectory dir : dirs) { - children.addAll(ProjectViewDirectoryHelper.getInstance(myProject).getDirectoryChildren(dir, getSettings(), false)); + final GlobalSearchScope scopeToShow = PackageUtil.getScopeToShow(aPackage.getProject(), module, isLibraryElement()); + PsiFile[] packageChildren = aPackage.getFiles(scopeToShow); + for (PsiFile file : packageChildren) { + if (file.getVirtualFile() != null) { + children.add(new PsiFileNode(getProject(), file, getSettings())); + } } return children; } diff --git a/java/java-impl/src/com/intellij/ide/projectView/impl/nodes/PackageUtil.java b/java/java-impl/src/com/intellij/ide/projectView/impl/nodes/PackageUtil.java index 28e3b85d3b7d..885913402e80 100644 --- a/java/java-impl/src/com/intellij/ide/projectView/impl/nodes/PackageUtil.java +++ b/java/java-impl/src/com/intellij/ide/projectView/impl/nodes/PackageUtil.java @@ -23,12 +23,8 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.*; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.psi.JavaDirectoryService; -import com.intellij.psi.PsiDirectory; -import com.intellij.psi.PsiManager; -import com.intellij.psi.PsiPackage; +import com.intellij.psi.*; import com.intellij.psi.search.GlobalSearchScope; -import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -39,23 +35,17 @@ public class PackageUtil { public static PsiPackage[] getSubpackages(@NotNull PsiPackage aPackage, @Nullable Module module, final boolean searchInLibraries) { - final PsiDirectory[] dirs = getDirectories(aPackage, module, searchInLibraries); - final Set subpackages = new HashSet(); - for (PsiDirectory dir : dirs) { - final PsiDirectory[] subdirectories = dir.getSubdirectories(); - for (PsiDirectory subdirectory : subdirectories) { - final PsiPackage psiPackage = JavaDirectoryService.getInstance().getPackage(subdirectory); - if (psiPackage != null) { - final String name = psiPackage.getName(); - // skip "default" subpackages as they should be attributed to other modules - // this is the case when contents of one module is nested into contents of another - if (name != null && !name.isEmpty()) { - subpackages.add(psiPackage); - } - } + final GlobalSearchScope scopeToShow = getScopeToShow(aPackage.getProject(), module, searchInLibraries); + List result = new ArrayList(); + for (PsiPackage psiPackage : aPackage.getSubPackages(scopeToShow)) { + // skip "default" subpackages as they should be attributed to other modules + // this is the case when contents of one module is nested into contents of another + final String name = psiPackage.getName(); + if (name != null && !name.isEmpty()) { + result.add(psiPackage); } } - return subpackages.toArray(new PsiPackage[subpackages.size()]); + return result.toArray(new PsiPackage[result.size()]); } public static void addPackageAsChild(@NotNull Collection children, @@ -80,13 +70,17 @@ public class PackageUtil { @Nullable Module module, boolean strictlyEmpty, final boolean inLibrary) { - final PsiDirectory[] dirs = getDirectories(aPackage, module, inLibrary); - for (final PsiDirectory dir : dirs) { - if (!TreeViewUtil.isEmptyMiddlePackage(dir, strictlyEmpty)) { - return false; - } + final Project project = aPackage.getProject(); + final GlobalSearchScope scopeToShow = getScopeToShow(project, module, inLibrary); + PsiElement[] children = aPackage.getFiles(scopeToShow); + if (children.length > 0) { + return false; } - return true; + PsiPackage[] subPackages = aPackage.getSubPackages(scopeToShow); + if (strictlyEmpty) { + return subPackages.length == 1; + } + return subPackages.length > 0; } @NotNull @@ -98,7 +92,7 @@ public class PackageUtil { } @NotNull - private static GlobalSearchScope getScopeToShow(@NotNull Project project, @Nullable Module module, boolean forLibraries) { + public static GlobalSearchScope getScopeToShow(@NotNull Project project, @Nullable Module module, boolean forLibraries) { if (module == null) { if (forLibraries) { return new ProjectLibrariesSearchScope(project); @@ -239,7 +233,7 @@ public class PackageUtil { @Override public int compare(@NotNull VirtualFile file1, @NotNull VirtualFile file2) { - throw new IncorrectOperationException("not implemented"); + return 0; } @Override diff --git a/java/java-psi-api/src/com/intellij/psi/PsiElementFinder.java b/java/java-psi-api/src/com/intellij/psi/PsiElementFinder.java index 85b5cf1b6e42..b33600944ffa 100644 --- a/java/java-psi-api/src/com/intellij/psi/PsiElementFinder.java +++ b/java/java-psi-api/src/com/intellij/psi/PsiElementFinder.java @@ -101,33 +101,31 @@ public abstract class PsiElementFinder { } /** - * Returns a list of children (classes, subpackages and possibly other elements) belonging to the specified package. + * Returns a list of files belonging to the specified package which are not located in any of the package directories. * - * @param psiPackage the package to return the list of children for. - * @param scope the scope in which children are searched. - * @return the list of children. + * @param psiPackage the package to return the list of files for. + * @param scope the scope in which files are searched. + * @return the list of files. * @since 14.1 */ @NotNull - public PsiNamedElement[] getChildren(@NotNull PsiPackage psiPackage, @NotNull GlobalSearchScope scope) { - Set children = new HashSet(); - Collections.addAll(children, getSubPackages(psiPackage, scope)); - Collections.addAll(children, getClasses(psiPackage, scope)); - return children.toArray(new PsiNamedElement[children.size()]); + public PsiFile[] getPackageFiles(@NotNull PsiPackage psiPackage, @NotNull GlobalSearchScope scope) { + return PsiFile.EMPTY_ARRAY; } /** - * Returns the filter to use for filtering the list of children for a given package produced by other PsiElementFinder - * implementations. (For example, the list of children for a Kotlin package includes files directly, rather than classes, - * so the classes located by the standard Java package children finder need to be excluded.) + * Returns the filter to use for filtering the list of files in the directories belonging to a package to exclude files + * that actually belong to a different package. (For example, in Kotlin the package of a file is determined by its + * package statement and not by its location in the directory structure, so the files which have a differring package + * statement need to be excluded.) * - * @param psiPackage the package to return the list of children for. - * @param scope the scope in which children are searched. + * @param psiPackage the package for which the list of files is requested. + * @param scope the scope in which children are requested. * @return the filter to use, or null if no additional filtering is necessary. * @since 14.1 */ @Nullable - public Predicate getPackageChildrenFilter(@NotNull PsiPackage psiPackage, @NotNull GlobalSearchScope scope) { + public Predicate getPackageFilesFilter(@NotNull PsiPackage psiPackage, @NotNull GlobalSearchScope scope) { return null; } diff --git a/java/java-psi-api/src/com/intellij/psi/PsiPackage.java b/java/java-psi-api/src/com/intellij/psi/PsiPackage.java index cab1728ad650..1a3db4d1301b 100644 --- a/java/java-psi-api/src/com/intellij/psi/PsiPackage.java +++ b/java/java-psi-api/src/com/intellij/psi/PsiPackage.java @@ -84,12 +84,13 @@ public interface PsiPackage extends PsiCheckedRenameElement, NavigationItem, Psi PsiClass[] getClasses(@NotNull GlobalSearchScope scope); /** - * Returns the list of all elements (classes, subpackages and potentially other elements) belonging to this package - * (non-recursively), restricted by the specified scope. + * Returns the list of all files in the package, restricted by the specified scope. (This is + * normally the list of all files in all directories corresponding to the package, but it can + * be modified by custom language plugins which have a different notion of packages.) * * @since 14.1 */ - PsiElement[] getChildren(@NotNull GlobalSearchScope scope); + PsiFile[] getFiles(@NotNull GlobalSearchScope scope); /** * Returns the list of package-level annotations for the package. diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/JavaPsiFacadeImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/JavaPsiFacadeImpl.java index 028e067666fc..a99550bad82c 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/JavaPsiFacadeImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/JavaPsiFacadeImpl.java @@ -243,17 +243,17 @@ public class JavaPsiFacadeImpl extends JavaPsiFacadeEx { return result == null ? PsiClass.EMPTY_ARRAY : result.toArray(new PsiClass[result.size()]); } - private static class AndPredicate implements Predicate { - private final List> myComponents = new SmartList>(); + private static class AndPredicate implements Predicate { + private final List> myComponents = new SmartList>(); - public AndPredicate(Predicate filter1, Predicate filter2) { + public AndPredicate(Predicate filter1, Predicate filter2) { myComponents.add(filter1); myComponents.add(filter2); } @Override - public boolean apply(@Nullable PsiNamedElement input) { - for (Predicate component : myComponents) { + public boolean apply(@Nullable T input) { + for (Predicate component : myComponents) { if (!component.apply(input)) { return false; } @@ -263,34 +263,38 @@ public class JavaPsiFacadeImpl extends JavaPsiFacadeEx { } @NotNull - public PsiElement[] getPackageChildren(@NotNull PsiPackage psiPackage, @NotNull GlobalSearchScope scope) { - Map result = new HashMap(); - Predicate filter = null; + public PsiFile[] getPackageFiles(@NotNull PsiPackage psiPackage, @NotNull GlobalSearchScope scope) { + Predicate filter = null; for (PsiElementFinder finder : filteredFinders()) { - Predicate finderFilter = finder.getPackageChildrenFilter(psiPackage, scope); + Predicate finderFilter = finder.getPackageFilesFilter(psiPackage, scope); if (finderFilter != null) { if (filter == null) { filter = finderFilter; } else if (filter instanceof AndPredicate) { - ((AndPredicate) filter).myComponents.add(finderFilter); + ((AndPredicate) filter).myComponents.add(finderFilter); } else { - filter = new AndPredicate(filter, finderFilter); + filter = new AndPredicate(filter, finderFilter); + } + } + } + + Set result = new HashSet(); + PsiDirectory[] directories = psiPackage.getDirectories(scope); + for (PsiDirectory directory : directories) { + for (PsiFile file : directory.getFiles()) { + if (filter == null || filter.apply(file)) { + result.add(file); } } } for (PsiElementFinder finder : filteredFinders()) { - PsiNamedElement[] children = finder.getChildren(psiPackage, scope); - for (PsiNamedElement child : children) { - if (!result.containsKey(child.getName()) && (filter == null || filter.apply(child))) { - result.put(child.getName(), child); - } - } + Collections.addAll(result, finder.getPackageFiles(psiPackage, scope)); } - return result.values().toArray(new PsiElement[result.size()]); + return result.toArray(new PsiFile[result.size()]); } public boolean processPackageDirectories(@NotNull PsiPackage psiPackage, diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/file/PsiPackageImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/file/PsiPackageImpl.java index 2cda50ec8309..1915df3b09c8 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/file/PsiPackageImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/file/PsiPackageImpl.java @@ -157,15 +157,9 @@ public class PsiPackageImpl extends PsiPackageBase implements PsiPackage, Querya return getFacade().getClasses(this, scope); } - @NotNull @Override - public PsiElement[] getChildren() { - return getChildren(allScope()); - } - - @Override - public PsiElement[] getChildren(@NotNull GlobalSearchScope scope) { - return getFacade().getPackageChildren(this, scope); + public PsiFile[] getFiles(@NotNull GlobalSearchScope scope) { + return getFacade().getPackageFiles(this, scope); } @Override diff --git a/plugins/coverage/src/com/intellij/coverage/view/JavaCoverageViewExtension.java b/plugins/coverage/src/com/intellij/coverage/view/JavaCoverageViewExtension.java index 19b2f20d7054..2d858e573247 100644 --- a/plugins/coverage/src/com/intellij/coverage/view/JavaCoverageViewExtension.java +++ b/plugins/coverage/src/com/intellij/coverage/view/JavaCoverageViewExtension.java @@ -217,22 +217,31 @@ public class JavaCoverageViewExtension extends CoverageViewExtension { return isInCoverageScope(psiPackage); } })) { - final PsiElement[] childElements = ApplicationManager.getApplication().runReadAction(new Computable() { - public PsiElement[] compute() { - return psiPackage.getChildren(mySuitesBundle.getSearchScope(node.getProject())); + final PsiPackage[] subPackages = ApplicationManager.getApplication().runReadAction(new Computable() { + public PsiPackage[] compute() { + return psiPackage.getSubPackages(mySuitesBundle.getSearchScope(node.getProject())); } }); - for (PsiElement element : childElements) { - if (element instanceof PsiClass) { - PsiClass aClass = (PsiClass) element; - if (!(node instanceof CoverageListRootNode) && getClassCoverageInfo(aClass) == null) continue; - children.add(new CoverageListNode(myProject, aClass, mySuitesBundle, myStateBean)); + for (PsiPackage subPackage: subPackages) { + processSubPackage(subPackage, children); + } + + final PsiFile[] childFiles = ApplicationManager.getApplication().runReadAction(new Computable() { + public PsiFile[] compute() { + return psiPackage.getFiles(mySuitesBundle.getSearchScope(node.getProject())); } - else if (element instanceof PsiPackage) { - processSubPackage((PsiPackage) element, children); + }); + for (PsiFile file : childFiles) { + if (file instanceof PsiJavaFile) { + PsiClass[] classes = ((PsiJavaFile)file).getClasses(); + if (classes.length > 0) { + PsiClass aClass = classes[0]; + if (!(node instanceof CoverageListRootNode) && getClassCoverageInfo(aClass) == null) continue; + children.add(new CoverageListNode(myProject, aClass, mySuitesBundle, myStateBean)); + } } - else if (element instanceof PsiNamedElement) { - children.add(new CoverageListNode(myProject, (PsiNamedElement) element, mySuitesBundle, myStateBean)); + else { + children.add(new CoverageListNode(myProject, file, mySuitesBundle, myStateBean)); } } } From 7f7d10857cf92e415a91f941aef29785c6e5020a Mon Sep 17 00:00:00 2001 From: "Vladimir.Orlov" Date: Wed, 24 Dec 2014 17:35:47 +0300 Subject: [PATCH 051/137] added PE code to the ApplicationInfo.xml for PyCharm EDU. --- python/edu/build/pycharm_edu_build.gant | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/edu/build/pycharm_edu_build.gant b/python/edu/build/pycharm_edu_build.gant index 85889184ab09..59e240f8be06 100644 --- a/python/edu/build/pycharm_edu_build.gant +++ b/python/edu/build/pycharm_edu_build.gant @@ -170,7 +170,7 @@ public layoutEducational(String classesPath, Set usedJars) { def appInfo = appInfoFile() if (!dryRun) { - wireBuildDate(buildNumber, appInfo) + wireBuildDate("PE-${buildNumber}", appInfo) } Map args = [ From b4e905df62866ca351dbd417f84cb290c889cb08 Mon Sep 17 00:00:00 2001 From: Sergey Savenko Date: Wed, 24 Dec 2014 17:45:14 +0300 Subject: [PATCH 052/137] DBE-1035: fix JBTable not using column margin when expanding/collapsing columns --- platform/platform-api/src/com/intellij/ui/table/JBTable.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/platform/platform-api/src/com/intellij/ui/table/JBTable.java b/platform/platform-api/src/com/intellij/ui/table/JBTable.java index 919317277b8a..9b6201ecf345 100644 --- a/platform/platform-api/src/com/intellij/ui/table/JBTable.java +++ b/platform/platform-api/src/com/intellij/ui/table/JBTable.java @@ -741,7 +741,8 @@ public class JBTable extends JTable implements ComponentWithEmptyText, Component TableColumn column = getColumnModel().getColumn(columnToPack); int currentWidth = column.getWidth(); int expandedWidth = getExpandedColumnWidth(columnToPack); - int newWidth = currentWidth >= expandedWidth ? getPreferredHeaderWidth(columnToPack) : expandedWidth; + int newWidth = getColumnModel().getColumnMargin() + + (currentWidth >= expandedWidth ? getPreferredHeaderWidth(columnToPack) : expandedWidth); setResizingColumn(column); column.setWidth(newWidth); From 9ef51730195a8ab0a30d510b4aa54518afe6ecef Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Wed, 24 Dec 2014 17:44:28 +0300 Subject: [PATCH 053/137] [git] IDEA-134721 Don't let fixup at the first position in rebase editor --- plugins/git4idea/src/git4idea/i18n/GitBundle.properties | 2 +- plugins/git4idea/src/git4idea/rebase/GitRebaseEditor.java | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/plugins/git4idea/src/git4idea/i18n/GitBundle.properties b/plugins/git4idea/src/git4idea/i18n/GitBundle.properties index a2937584ec39..a48c05400bf3 100644 --- a/plugins/git4idea/src/git4idea/i18n/GitBundle.properties +++ b/plugins/git4idea/src/git4idea/i18n/GitBundle.properties @@ -256,7 +256,7 @@ rebase.editor.button=Start Rebasing rebase.editor.comment.column=Comment rebase.editor.commit.column=Commit rebase.editor.invalid.entryset=No commits found to rebase -rebase.editor.invalid.squash=The first non-skip commit could not be marked as squashed since squash merges commit with the previous commit. +rebase.editor.invalid.squash=The first non-skip commit can't be marked as {0} since it merges commit with the previous commit. rebase.editor.message=Reorder and edit &rebased commits rebase.editor.move.down.tooltip=Move commit down (commit will be applied later) rebase.editor.move.down=Move &Down diff --git a/plugins/git4idea/src/git4idea/rebase/GitRebaseEditor.java b/plugins/git4idea/src/git4idea/rebase/GitRebaseEditor.java index e3c9a1aa80c2..e0c9aa035257 100644 --- a/plugins/git4idea/src/git4idea/rebase/GitRebaseEditor.java +++ b/plugins/git4idea/src/git4idea/rebase/GitRebaseEditor.java @@ -19,6 +19,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.ArrayUtil; import com.intellij.util.ListWithSelection; @@ -167,8 +168,9 @@ public class GitRebaseEditor extends DialogWrapper { while (i < entries.size() && entries.get(i).getAction() == GitRebaseEntry.Action.skip) { i++; } - if (i < entries.size() && entries.get(i).getAction() == GitRebaseEntry.Action.squash) { - setErrorText(GitBundle.getString("rebase.editor.invalid.squash")); + GitRebaseEntry.Action action = entries.get(i).getAction(); + if (i < entries.size() && (action == GitRebaseEntry.Action.squash || action == GitRebaseEntry.Action.fixup)) { + setErrorText(GitBundle.message("rebase.editor.invalid.squash", StringUtil.toLowerCase(action.name()))); setOKActionEnabled(false); return; } From 2abf5c025566d05ceb64d4f858ded63a44897e37 Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Wed, 24 Dec 2014 17:45:00 +0300 Subject: [PATCH 054/137] [git] IDEA-134721 Better detect rebase failures It can start with e.g. "Cannot fixup". --- plugins/git4idea/src/git4idea/rebase/GitRebaseLineListener.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/git4idea/src/git4idea/rebase/GitRebaseLineListener.java b/plugins/git4idea/src/git4idea/rebase/GitRebaseLineListener.java index 62aabee3a3bc..941c39357fb7 100644 --- a/plugins/git4idea/src/git4idea/rebase/GitRebaseLineListener.java +++ b/plugins/git4idea/src/git4idea/rebase/GitRebaseLineListener.java @@ -69,7 +69,7 @@ public class GitRebaseLineListener extends GitLineHandlerAdapter { assert myStatus == null; myStatus = myProgressLine == null ? Status.CANCELLED : Status.ERROR; } - else if (line.startsWith("fatal") || line.startsWith("error: ") || line.startsWith("Cannot rebase")) { + else if (line.startsWith("fatal") || line.startsWith("error: ") || line.startsWith("Cannot")) { if (myStatus != Status.CONFLICT) { myStatus = Status.ERROR; } From cf9b96253bb8cc8db4a1371302700ae9390df3e0 Mon Sep 17 00:00:00 2001 From: "Egor.Ushakov" Date: Wed, 24 Dec 2014 17:57:40 +0300 Subject: [PATCH 055/137] IDEA-85298 When stopped at breakpoint, line should be highlighted in all panels containing that file --- .../xdebugger/impl/ui/ExecutionPointHighlighter.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/ExecutionPointHighlighter.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/ExecutionPointHighlighter.java index 65a6fa82f5f9..6e33a76aecff 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/ExecutionPointHighlighter.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/ExecutionPointHighlighter.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. @@ -21,6 +21,7 @@ import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.colors.EditorColorsListener; import com.intellij.openapi.editor.colors.EditorColorsManager; import com.intellij.openapi.editor.colors.EditorColorsScheme; +import com.intellij.openapi.editor.impl.DocumentMarkupModel; import com.intellij.openapi.editor.impl.EditorImpl; import com.intellij.openapi.editor.markup.GutterIconRenderer; import com.intellij.openapi.editor.markup.RangeHighlighter; @@ -194,7 +195,7 @@ public class ExecutionPointHighlighter { if (myRangeHighlighter != null) return; EditorColorsScheme scheme = EditorColorsManager.getInstance().getGlobalScheme(); - myRangeHighlighter = myEditor.getMarkupModel().addLineHighlighter(line, DebuggerColors.EXECUTION_LINE_HIGHLIGHTERLAYER, + myRangeHighlighter = DocumentMarkupModel.forDocument(document, myProject, true).addLineHighlighter(line, DebuggerColors.EXECUTION_LINE_HIGHLIGHTERLAYER, myNotTopFrame ? scheme.getAttributes(DebuggerColors.NOT_TOP_FRAME_ATTRIBUTES) : scheme.getAttributes(DebuggerColors.EXECUTIONPOINT_ATTRIBUTES)); From 94d1d2a57455aa5501d87dad9f0328baf61421a1 Mon Sep 17 00:00:00 2001 From: peter Date: Wed, 24 Dec 2014 16:21:08 +0100 Subject: [PATCH 056/137] [^cdr] let findMethodsByName not load fields and inner classes and vice versa --- .../intellij/psi/impl/PsiClassImplUtil.java | 96 ++++++++----------- 1 file changed, 42 insertions(+), 54 deletions(-) diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/PsiClassImplUtil.java b/java/java-psi-impl/src/com/intellij/psi/impl/PsiClassImplUtil.java index 7e12adac007d..c410b37dcb91 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/PsiClassImplUtil.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/PsiClassImplUtil.java @@ -23,7 +23,6 @@ import com.intellij.openapi.util.*; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.pom.java.LanguageLevel; import com.intellij.psi.*; -import com.intellij.psi.filters.OrFilter; import com.intellij.psi.impl.source.ClassInnerStuffCache; import com.intellij.psi.impl.source.PsiImmediateClassType; import com.intellij.psi.impl.source.resolve.graphInference.InferenceSession; @@ -45,6 +44,7 @@ import com.intellij.util.Function; import com.intellij.util.IncorrectOperationException; import com.intellij.util.NullableFunction; import com.intellij.util.SmartList; +import com.intellij.util.containers.ConcurrentFactoryMap; import com.intellij.util.containers.HashSet; import gnu.trove.THashMap; import gnu.trove.THashSet; @@ -214,54 +214,6 @@ public class PsiClassImplUtil { public enum MemberType {CLASS, FIELD, METHOD} - @NotNull - private static MembersMap buildAllMaps(@NotNull PsiClass psiClass) { - final List> classes = new ArrayList>(); - final List> fields = new ArrayList>(); - final List> methods = new ArrayList>(); - - FilterScopeProcessor processor = new FilterScopeProcessor( - new OrFilter(ElementClassFilter.METHOD, ElementClassFilter.FIELD, ElementClassFilter.CLASS)) { - @Override - protected void add(@NotNull PsiElement element, @NotNull PsiSubstitutor substitutor) { - if (element instanceof PsiMethod) { - methods.add(Pair.create((PsiMember)element, substitutor)); - } - else if (element instanceof PsiField) { - fields.add(Pair.create((PsiMember)element, substitutor)); - } - else if (element instanceof PsiClass) { - classes.add(Pair.create((PsiMember)element, substitutor)); - } - } - }; - processDeclarationsInClassNotCached(psiClass, processor, ResolveState.initial(), null, null, psiClass, false, - PsiUtil.getLanguageLevel(psiClass)); - - MembersMap result = new MembersMap(MemberType.class); - result.put(MemberType.CLASS, generateMapByList(classes)); - result.put(MemberType.METHOD, generateMapByList(methods)); - result.put(MemberType.FIELD, generateMapByList(fields)); - return result; - } - - @NotNull - private static Map>> generateMapByList(@NotNull final List> list) { - Map>> map = new THashMap>>(); - map.put(ALL, list); - for (final Pair info : list) { - PsiMember element = info.getFirst(); - String currentName = element.getName(); - List> listByName = map.get(currentName); - if (listByName == null) { - listByName = new ArrayList>(1); - map.put(currentName, listByName); - } - listByName.add(info); - } - return map; - } - private static Map>> getMap(@NotNull PsiClass aClass, @NotNull MemberType type) { ParameterizedCachedValue value = getValues(aClass); return value.getValue(aClass).get(type); @@ -407,9 +359,46 @@ public class PsiClassImplUtil { return factory.createMethodFromText(text, null).getSignature(PsiSubstitutor.EMPTY); } - private static class MembersMap extends EnumMap>>> { - public MembersMap(@NotNull Class keyType) { - super(keyType); + private static class MembersMap extends ConcurrentFactoryMap>>> { + private final PsiClass myPsiClass; + + public MembersMap(PsiClass psiClass) { + myPsiClass = psiClass; + } + + @Nullable + @Override + protected Map>> create(final MemberType key) { + final Map>> map = new THashMap>>(); + + final List> allMembers = new ArrayList>(); + map.put(ALL, allMembers); + + ElementClassFilter filter = key == MemberType.CLASS ? ElementClassFilter.CLASS : + key == MemberType.METHOD ? ElementClassFilter.METHOD : + ElementClassFilter.FIELD; + FilterScopeProcessor processor = new FilterScopeProcessor(filter) { + @Override + protected void add(@NotNull PsiElement element, @NotNull PsiSubstitutor substitutor) { + if (key == MemberType.CLASS && element instanceof PsiClass || + key == MemberType.METHOD && element instanceof PsiMethod || + key == MemberType.FIELD && element instanceof PsiField) { + Pair info = Pair.create((PsiMember)element, substitutor); + allMembers.add(info); + String currentName = ((PsiMember)element).getName(); + List> listByName = map.get(currentName); + if (listByName == null) { + listByName = new ArrayList>(1); + map.put(currentName, listByName); + } + listByName.add(info); + } + } + }; + + processDeclarationsInClassNotCached(myPsiClass, processor, ResolveState.initial(), null, null, myPsiClass, false, + PsiUtil.getLanguageLevel(myPsiClass)); + return map; } } @@ -418,8 +407,7 @@ public class PsiClassImplUtil { @Override public CachedValueProvider.Result compute(@NotNull PsiClass myClass) { - MembersMap map = buildAllMaps(myClass); - return new CachedValueProvider.Result(map, PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT); + return new CachedValueProvider.Result(new MembersMap(myClass), PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT); } } From 3bd310b1d3e52f722ba7dab344aa9308861813b9 Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Wed, 24 Dec 2014 18:27:10 +0300 Subject: [PATCH 057/137] [git] IDEA-115780 Let branch and tag with same name in the log The purpose of the special refs hashing strategy is to make sure we don't receive the same reference pointing to different hashes. However, type is still important, since we don't store "refs/tags" prefixes in the name. --- .../src/git4idea/history/GitHistoryUtils.java | 9 ++------ .../src/git4idea/log/GitLogProvider.java | 8 +++---- .../git4idea/log/GitLogProviderTest.java | 23 +++++++++++++++++++ 3 files changed, 29 insertions(+), 11 deletions(-) diff --git a/plugins/git4idea/src/git4idea/history/GitHistoryUtils.java b/plugins/git4idea/src/git4idea/history/GitHistoryUtils.java index 9d1e27395ca0..c9824aeec26f 100644 --- a/plugins/git4idea/src/git4idea/history/GitHistoryUtils.java +++ b/plugins/git4idea/src/git4idea/history/GitHistoryUtils.java @@ -40,12 +40,7 @@ import com.intellij.vcs.log.*; import com.intellij.vcs.log.impl.HashImpl; import com.intellij.vcs.log.impl.LogDataImpl; import com.intellij.vcs.log.util.StopWatch; -import git4idea.GitBranch; -import git4idea.GitCommit; -import git4idea.GitFileRevision; -import git4idea.GitRevisionNumber; -import git4idea.GitUtil; -import git4idea.GitVcs; +import git4idea.*; import git4idea.branch.GitBranchUtil; import git4idea.commands.*; import git4idea.config.GitVersionSpecialty; @@ -740,7 +735,7 @@ public class GitHistoryUtils { if (factory == null) { return LogDataImpl.empty(); } - final Set refs = new OpenTHashSet(GitLogProvider.REF_ONLY_NAME_STRATEGY); + final Set refs = new OpenTHashSet(GitLogProvider.DONT_CONSIDER_SHA); final List commits = loadDetails(project, root, withRefs, false, new NullableFunction() { @Nullable diff --git a/plugins/git4idea/src/git4idea/log/GitLogProvider.java b/plugins/git4idea/src/git4idea/log/GitLogProvider.java index 59e3babe372d..3c4e0a3034c7 100644 --- a/plugins/git4idea/src/git4idea/log/GitLogProvider.java +++ b/plugins/git4idea/src/git4idea/log/GitLogProvider.java @@ -55,15 +55,15 @@ public class GitLogProvider implements VcsLogProvider { return ref.getType() == GitRefManager.TAG ? ref.getName() : null; } }; - public static final TObjectHashingStrategy REF_ONLY_NAME_STRATEGY = new TObjectHashingStrategy() { + public static final TObjectHashingStrategy DONT_CONSIDER_SHA = new TObjectHashingStrategy() { @Override public int computeHashCode(@NotNull VcsRef ref) { - return ref.getName().hashCode(); + return 31 * ref.getName().hashCode() + ref.getType().hashCode(); } @Override public boolean equals(@NotNull VcsRef ref1, @NotNull VcsRef ref2) { - return ref1.getName().equals(ref2.getName()); + return ref1.getName().equals(ref2.getName()) && ref1.getType().equals(ref2.getType()); } }; @@ -104,7 +104,7 @@ public class GitLogProvider implements VcsLogProvider { DetailedLogData data = GitHistoryUtils.loadMetadata(myProject, root, true, params); Set safeRefs = data.getRefs(); - Set allRefs = new OpenTHashSet(safeRefs, REF_ONLY_NAME_STRATEGY); + Set allRefs = new OpenTHashSet(safeRefs, DONT_CONSIDER_SHA); Set branches = readBranches(repository); addNewElements(allRefs, branches); diff --git a/plugins/git4idea/tests/git4idea/log/GitLogProviderTest.java b/plugins/git4idea/tests/git4idea/log/GitLogProviderTest.java index f4afb51a8e21..2b086f459cf1 100644 --- a/plugins/git4idea/tests/git4idea/log/GitLogProviderTest.java +++ b/plugins/git4idea/tests/git4idea/log/GitLogProviderTest.java @@ -136,6 +136,29 @@ public class GitLogProviderTest extends GitSingleRepoTest { })); } + public void test_support_equally_named_branch_and_tag() throws Exception { + prepareSomeHistory(); + git("branch build"); + git("tag build"); + + VcsLogProvider.DetailedLogData data = myLogProvider.readFirstBlock(myProjectRoot, + new RequirementsImpl(1000, true, Collections.emptySet())); + List expectedLog = log(); + assertOrderedEquals(data.getCommits(), expectedLog); + assertTrue(ContainerUtil.exists(data.getRefs(), new Condition() { + @Override + public boolean value(VcsRef ref) { + return ref.getName().equals("build") && ref.getType() == GitRefManager.LOCAL_BRANCH; + } + })); + assertTrue(ContainerUtil.exists(data.getRefs(), new Condition() { + @Override + public boolean value(VcsRef ref) { + return ref.getName().equals("build") && ref.getType() == GitRefManager.TAG; + } + })); + } + private static void prepareSomeHistory() { tac("a.txt"); git("tag ATAG"); From 0d9d93fe2b2bdf0d348e36a8860f4dd98a8effb4 Mon Sep 17 00:00:00 2001 From: "Egor.Ushakov" Date: Wed, 24 Dec 2014 19:02:42 +0300 Subject: [PATCH 058/137] IDEA-85298 When stopped at breakpoint, line should be highlighted in all panels containing that file - fixed hover color --- .../navigation/NavigationUtil.java | 45 ++++++++++--------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInsight/navigation/NavigationUtil.java b/platform/lang-impl/src/com/intellij/codeInsight/navigation/NavigationUtil.java index 3617c944e888..e8774cedeeb8 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/navigation/NavigationUtil.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/navigation/NavigationUtil.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,8 +24,11 @@ import com.intellij.navigation.GotoRelatedProvider; import com.intellij.navigation.NavigationItem; import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.editor.ex.MarkupModelEx; +import com.intellij.openapi.editor.ex.RangeHighlighterEx; +import com.intellij.openapi.editor.impl.DocumentMarkupModel; import com.intellij.openapi.editor.markup.HighlighterTargetArea; -import com.intellij.openapi.editor.markup.RangeHighlighter; +import com.intellij.openapi.editor.markup.MarkupModel; import com.intellij.openapi.editor.markup.TextAttributes; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.fileEditor.FileEditor; @@ -214,24 +217,26 @@ public final class NavigationUtil { */ @SuppressWarnings("UseJBColor") public static TextAttributes patchAttributesColor(TextAttributes attributes, @NotNull TextRange range, @NotNull Editor editor) { - int lineStart = editor.offsetToLogicalPosition(range.getStartOffset()).line; - int lineEnd = editor.offsetToLogicalPosition(range.getEndOffset()).line; - for (RangeHighlighter highlighter : editor.getMarkupModel().getAllHighlighters()) { - if (!highlighter.isValid()) continue; - if (highlighter.getTargetArea() == HighlighterTargetArea.LINES_IN_RANGE) { - int line = editor.offsetToLogicalPosition(highlighter.getStartOffset()).line; - if (line >= lineStart && line <= lineEnd) { - TextAttributes textAttributes = highlighter.getTextAttributes(); - if (textAttributes != null) { - Color color = textAttributes.getBackgroundColor(); - if (color != null && color.getBlue() > 128 && color.getRed() < 128 && color.getGreen() < 128) { - TextAttributes clone = attributes.clone(); - clone.setForegroundColor(Color.orange); - clone.setEffectColor(Color.orange); - return clone; - } - } - } + MarkupModel model = DocumentMarkupModel.forDocument(editor.getDocument(), editor.getProject(), false); + if (model != null) { + if (!((MarkupModelEx)model).processRangeHighlightersOverlappingWith(range.getStartOffset(), range.getEndOffset(), + new Processor() { + @Override + public boolean process(RangeHighlighterEx highlighter) { + if (highlighter.isValid() && highlighter.getTargetArea() == HighlighterTargetArea.LINES_IN_RANGE) { + TextAttributes textAttributes = highlighter.getTextAttributes(); + if (textAttributes != null) { + Color color = textAttributes.getBackgroundColor(); + return !(color != null && color.getBlue() > 128 && color.getRed() < 128 && color.getGreen() < 128); + } + } + return true; + } + })) { + TextAttributes clone = attributes.clone(); + clone.setForegroundColor(Color.orange); + clone.setEffectColor(Color.orange); + return clone; } } return attributes; From 074abb049edb9d1869f77c923ca2804b2f3d1f9e Mon Sep 17 00:00:00 2001 From: Dmitry Batrak Date: Wed, 24 Dec 2014 19:09:52 +0300 Subject: [PATCH 059/137] IDEA-134720 Reorganize UI for editor soft wraps settings --- .../options/editor/EditorOptionsPanel.form | 158 +++++++++--------- .../options/editor/EditorOptionsPanel.java | 12 +- .../src/messages/ApplicationBundle.properties | 7 +- 3 files changed, 90 insertions(+), 87 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/application/options/editor/EditorOptionsPanel.form b/platform/lang-impl/src/com/intellij/application/options/editor/EditorOptionsPanel.form index 89e8e9fcc7c9..fe82b9dea740 100644 --- a/platform/lang-impl/src/com/intellij/application/options/editor/EditorOptionsPanel.form +++ b/platform/lang-impl/src/com/intellij/application/options/editor/EditorOptionsPanel.form @@ -2,7 +2,7 @@
- + @@ -15,7 +15,7 @@ - + @@ -65,7 +65,7 @@ - + @@ -103,7 +103,7 @@ - + @@ -170,16 +170,16 @@ - + - + - + @@ -189,7 +189,7 @@ - + @@ -197,7 +197,7 @@ - + @@ -205,83 +205,19 @@ - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + @@ -318,7 +254,7 @@ - + @@ -347,7 +283,7 @@ - + @@ -384,7 +320,7 @@ - + @@ -411,7 +347,7 @@ - + @@ -483,6 +419,70 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/platform/lang-impl/src/com/intellij/application/options/editor/EditorOptionsPanel.java b/platform/lang-impl/src/com/intellij/application/options/editor/EditorOptionsPanel.java index 19f7c804d3d6..84c44a22ab82 100644 --- a/platform/lang-impl/src/com/intellij/application/options/editor/EditorOptionsPanel.java +++ b/platform/lang-impl/src/com/intellij/application/options/editor/EditorOptionsPanel.java @@ -94,7 +94,7 @@ public class EditorOptionsPanel { private JCheckBox myCbUseSoftWrapsAtConsole; private JCheckBox myCbUseCustomSoftWrapIndent; private JTextField myCustomSoftWrapIndent; - private JCheckBox myCbShowAllSoftWraps; + private JCheckBox myCbShowSoftWrapsOnlyOnCaretLine; private JCheckBox myPreselectCheckBox; private JBCheckBox myCbShowQuickDocOnMouseMove; private JBLabel myQuickDocDelayLabel; @@ -177,7 +177,7 @@ public class EditorOptionsPanel { myCbUseSoftWrapsAtConsole.setSelected(editorSettings.isUseSoftWraps(SoftWrapAppliancePlaces.CONSOLE)); myCbUseCustomSoftWrapIndent.setSelected(editorSettings.isUseCustomSoftWrapIndent()); myCustomSoftWrapIndent.setText(Integer.toString(editorSettings.getCustomSoftWrapIndent())); - myCbShowAllSoftWraps.setSelected(editorSettings.isAllSoftWrapsShown()); + myCbShowSoftWrapsOnlyOnCaretLine.setSelected(!editorSettings.isAllSoftWrapsShown()); updateSoftWrapSettingsRepresentation(); myCbVirtualSpace.setSelected(editorSettings.isVirtualSpace()); @@ -282,7 +282,7 @@ public class EditorOptionsPanel { editorSettings.setUseSoftWraps(myCbUseSoftWrapsAtConsole.isSelected(), SoftWrapAppliancePlaces.CONSOLE); editorSettings.setUseCustomSoftWrapIndent(myCbUseCustomSoftWrapIndent.isSelected()); editorSettings.setCustomSoftWrapIndent(getCustomSoftWrapIndent()); - editorSettings.setAllSoftwrapsShown(myCbShowAllSoftWraps.isSelected()); + editorSettings.setAllSoftwrapsShown(!myCbShowSoftWrapsOnlyOnCaretLine.isSelected()); editorSettings.setVirtualSpace(myCbVirtualSpace.isSelected()); editorSettings.setCaretInsideTabs(myCbCaretInsideTabs.isSelected()); editorSettings.setAdditionalPageAtBottom(myCbVirtualPageAtBottom.isSelected()); @@ -443,7 +443,7 @@ public class EditorOptionsPanel { isModified |= isModified(myCbUseSoftWrapsAtConsole, editorSettings.isUseSoftWraps(SoftWrapAppliancePlaces.CONSOLE)); isModified |= isModified(myCbUseCustomSoftWrapIndent, editorSettings.isUseCustomSoftWrapIndent()); isModified |= editorSettings.getCustomSoftWrapIndent() != getCustomSoftWrapIndent(); - isModified |= isModified(myCbShowAllSoftWraps, editorSettings.isAllSoftWrapsShown()); + isModified |= isModified(myCbShowSoftWrapsOnlyOnCaretLine, !editorSettings.isAllSoftWrapsShown()); isModified |= isModified(myCbVirtualSpace, editorSettings.isVirtualSpace()); isModified |= isModified(myCbCaretInsideTabs, editorSettings.isCaretInsideTabs()); isModified |= isModified(myCbVirtualPageAtBottom, editorSettings.isAdditionalPageAtBottom()); @@ -555,8 +555,10 @@ public class EditorOptionsPanel { } private void updateSoftWrapSettingsRepresentation() { - myCbUseCustomSoftWrapIndent.setEnabled(myCbUseSoftWrapsAtEditor.isSelected() || myCbUseSoftWrapsAtConsole.isSelected()); + boolean softWrapsEnabled = myCbUseSoftWrapsAtEditor.isSelected() || myCbUseSoftWrapsAtConsole.isSelected(); + myCbUseCustomSoftWrapIndent.setEnabled(softWrapsEnabled); myCustomSoftWrapIndent.setEnabled(myCbUseCustomSoftWrapIndent.isEnabled() && myCbUseCustomSoftWrapIndent.isSelected()); + myCbShowSoftWrapsOnlyOnCaretLine.setEnabled(softWrapsEnabled); } public JComponent getComponent() { diff --git a/platform/platform-resources-en/src/messages/ApplicationBundle.properties b/platform/platform-resources-en/src/messages/ApplicationBundle.properties index 725bd00182a7..6a1baadbfc2f 100644 --- a/platform/platform-resources-en/src/messages/ApplicationBundle.properties +++ b/platform/platform-resources-en/src/messages/ApplicationBundle.properties @@ -344,7 +344,6 @@ checkbox.show.whitespaces=Show whitespaces checkbox.show.leading.whitespaces=Leading checkbox.show.inner.whitespaces=Inner checkbox.show.trailing.whitespaces=Trailing -checkbox.show.all.softwraps=Show all soft wraps checkbox.show.method.separators=Show method separators checkbox.show.small.icons.in.gutter=Show icons preview in gutter for small icons (Java) checkbox.show.line.numbers=Show line numbers @@ -387,10 +386,12 @@ label.when.closing.active.editor=When closing active editor: radio.close.less.frequently.used.files=Close less frequently used files radio.close.non.modified.files.first=Close non-modified files first label.when.number.of.opened.editors.exceeds.tab.limit=When number of opened editors exceeds tab limit: -group.virtual.space=Virtual Space +group.soft.wraps=Soft Wraps checkbox.use.soft.wraps.at.editor=Use soft wraps in editor checkbox.use.soft.wraps.at.console=Use soft wraps in console -checkbox.use.custom.soft.wraps.indent=Use custom soft wraps indent +checkbox.use.custom.soft.wraps.indent=Use original line's indent for wrapped parts. Additional shift: +checkbox.show.softwraps.only.for.caret.line=Show soft wrap symbols only for current line +group.virtual.space=Virtual Space checkbox.allow.placement.of.caret.after.end.of.line=Allow placement of caret after end of line checkbox.allow.placement.of.caret.inside.tabs=Allow placement of caret inside tabs checkbox.show.virtual.space.at.file.bottom=Show virtual space at file bottom From 394f55fe6f4b34481ca602372f611f7e34bf5544 Mon Sep 17 00:00:00 2001 From: Sergey Simonchik Date: Wed, 24 Dec 2014 19:33:22 +0300 Subject: [PATCH 060/137] WEB-14686 Run Configurations: "CreateProcess error=87, The parameter is incorrect" error on invalid environment variable --- .../configurations/GeneralCommandLine.java | 5 +++++ .../execution/GeneralCommandLineTest.java | 17 ++++++++++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/platform/platform-api/src/com/intellij/execution/configurations/GeneralCommandLine.java b/platform/platform-api/src/com/intellij/execution/configurations/GeneralCommandLine.java index cd9d1fcf49e2..5598abe47742 100644 --- a/platform/platform-api/src/com/intellij/execution/configurations/GeneralCommandLine.java +++ b/platform/platform-api/src/com/intellij/execution/configurations/GeneralCommandLine.java @@ -333,6 +333,11 @@ public class GeneralCommandLine implements UserDataHolder { environment.putAll(myEnvParams); } } + if (SystemInfo.isWindows) { + // (Windows) An environment variable with empty name is incorrect. + // It'll end up in "CreateProcess error=87, The parameter is incorrect". + environment.remove(""); + } } /** diff --git a/platform/platform-tests/testSrc/com/intellij/execution/GeneralCommandLineTest.java b/platform/platform-tests/testSrc/com/intellij/execution/GeneralCommandLineTest.java index 8fe3951dcd11..095cb524d801 100644 --- a/platform/platform-tests/testSrc/com/intellij/execution/GeneralCommandLineTest.java +++ b/platform/platform-tests/testSrc/com/intellij/execution/GeneralCommandLineTest.java @@ -17,6 +17,7 @@ package com.intellij.execution; import com.intellij.execution.configurations.GeneralCommandLine; import com.intellij.execution.util.ExecUtil; +import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; @@ -239,6 +240,13 @@ public class GeneralCommandLineTest { checkEnvPassing(commandLine, testEnv, false); } + @Test + public void emptyEnvironmentPassing() throws Exception { + Pair nonEmpty = Pair.create("a", "b"); + Map inputEnv = newHashMap(Pair.create("", "c"), nonEmpty); + GeneralCommandLine commandLine = makeJavaCommand(EnvPassingTest.class, null); + checkEnvPassing(commandLine, inputEnv, SystemInfo.isWindows ? newHashMap(nonEmpty) : inputEnv, false); + } private static String execAndGetOutput(GeneralCommandLine commandLine, @Nullable String encoding) throws Exception { Process process = commandLine.createProcess(); @@ -284,6 +292,13 @@ public class GeneralCommandLineTest { } private static void checkEnvPassing(GeneralCommandLine commandLine, Map testEnv, boolean passParentEnv) throws Exception { + checkEnvPassing(commandLine, testEnv, testEnv, passParentEnv); + } + + private static void checkEnvPassing(GeneralCommandLine commandLine, + Map testEnv, + Map expectedOutputEnv, + boolean passParentEnv) throws Exception { commandLine.getEnvironment().putAll(testEnv); commandLine.setPassParentEnvironment(passParentEnv); String output = execAndGetOutput(commandLine, null); @@ -291,7 +306,7 @@ public class GeneralCommandLineTest { Set lines = new HashSet(Arrays.asList(StringUtil.convertLineSeparators(output).split("\n"))); lines.remove("====="); - for (Map.Entry entry : testEnv.entrySet()) { + for (Map.Entry entry : expectedOutputEnv.entrySet()) { String str = EnvPassingTest.format(entry); assertTrue("\"" + str + "\" should be in " + lines, lines.contains(str)); From b06f6e4d014bfa938d3e8f7688f314e3f38e0aab Mon Sep 17 00:00:00 2001 From: nik Date: Wed, 24 Dec 2014 19:40:20 +0300 Subject: [PATCH 061/137] project structure dialog: keep changes made in newly added SDK --- .../roots/ui/configuration/projectRoot/ProjectSdksModel.java | 1 + 1 file changed, 1 insertion(+) diff --git a/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/projectRoot/ProjectSdksModel.java b/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/projectRoot/ProjectSdksModel.java index d67c251e8fe0..e2738c3e021e 100644 --- a/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/projectRoot/ProjectSdksModel.java +++ b/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/projectRoot/ProjectSdksModel.java @@ -163,6 +163,7 @@ public class ProjectSdksModel implements SdkModel { LOG.assertTrue(projectJdk != null); if (ArrayUtilRt.find(allJdks, projectJdk) == -1) { jdkTable.addJdk(projectJdk); + jdkTable.updateJdk(projectJdk, myProjectSdks.get(projectJdk)); } } } From 73a01d8eecb7393c83bce187745791499e70805b Mon Sep 17 00:00:00 2001 From: Alexander Zolotov Date: Tue, 23 Dec 2014 19:48:43 +0300 Subject: [PATCH 062/137] HTML: extract common 'unknown element inspection' --- .../HtmlUnknownAttributeInspection.java | 3 - .../HtmlUnknownTagInspection.java | 24 ++++--- ... AddCustomHtmlElementIntentionAction.java} | 13 ++-- .../HtmlUnknownAttributeInspectionBase.java | 35 +++-------- .../HtmlUnknownTagInspectionBase.java | 62 +++---------------- 5 files changed, 32 insertions(+), 105 deletions(-) rename xml/xml-analysis-impl/src/com/intellij/codeInspection/htmlInspections/{AddCustomTagOrAttributeIntentionAction.java => AddCustomHtmlElementIntentionAction.java} (82%) diff --git a/xml/impl/src/com/intellij/codeInspection/htmlInspections/HtmlUnknownAttributeInspection.java b/xml/impl/src/com/intellij/codeInspection/htmlInspections/HtmlUnknownAttributeInspection.java index 6aebe4c74716..320467e48052 100644 --- a/xml/impl/src/com/intellij/codeInspection/htmlInspections/HtmlUnknownAttributeInspection.java +++ b/xml/impl/src/com/intellij/codeInspection/htmlInspections/HtmlUnknownAttributeInspection.java @@ -20,9 +20,6 @@ import org.jetbrains.annotations.Nullable; import javax.swing.*; -/** - * @author spleaner - */ public class HtmlUnknownAttributeInspection extends HtmlUnknownAttributeInspectionBase { public HtmlUnknownAttributeInspection() { super(""); diff --git a/xml/impl/src/com/intellij/codeInspection/htmlInspections/HtmlUnknownTagInspection.java b/xml/impl/src/com/intellij/codeInspection/htmlInspections/HtmlUnknownTagInspection.java index f44eaf7f2f08..1b12d947a4ca 100644 --- a/xml/impl/src/com/intellij/codeInspection/htmlInspections/HtmlUnknownTagInspection.java +++ b/xml/impl/src/com/intellij/codeInspection/htmlInspections/HtmlUnknownTagInspection.java @@ -36,16 +36,13 @@ import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.List; -/** - * @author spleaner - */ public class HtmlUnknownTagInspection extends HtmlUnknownTagInspectionBase { public HtmlUnknownTagInspection() { super(); } - protected HtmlUnknownTagInspection(@NonNls @NotNull final String defaultValues) { + public HtmlUnknownTagInspection(@NonNls @NotNull final String defaultValues) { super(defaultValues); } @@ -56,7 +53,7 @@ public class HtmlUnknownTagInspection extends HtmlUnknownTagInspectionBase { } @NotNull - protected static JComponent createOptionsPanel(@NotNull final HtmlUnknownTagInspectionBase inspection) { + protected static JComponent createOptionsPanel(@NotNull final HtmlUnknownElementInspection inspection) { final JPanel result = new JPanel(new BorderLayout()); final JPanel internalPanel = new JPanel(new BorderLayout()); @@ -66,7 +63,8 @@ public class HtmlUnknownTagInspection extends HtmlUnknownTagInspectionBase { final FieldPanel additionalAttributesPanel = new FieldPanel(null, null, new ActionListener() { @Override public void actionPerformed(ActionEvent event) { - Messages.showTextAreaDialog(panelRef.get().getTextField(), StringUtil.wordsToBeginFromUpperCase(inspection.getPanelTitle()), "HtmlUnknownTagInspection", + Messages.showTextAreaDialog(panelRef.get().getTextField(), StringUtil.wordsToBeginFromUpperCase(inspection.getPanelTitle()), + inspection.getClass().getSimpleName(), new Function>() { @Override public List fun(String s) { @@ -90,7 +88,7 @@ public class HtmlUnknownTagInspection extends HtmlUnknownTagInspectionBase { try { final String text = document.getText(0, document.getLength()); if (text != null) { - inspection.myValues = reparseProperties(text.trim()); + inspection.updateAdditionalEntries(text.trim()); } } catch (BadLocationException e1) { @@ -100,14 +98,14 @@ public class HtmlUnknownTagInspection extends HtmlUnknownTagInspectionBase { }); final JCheckBox checkBox = new JCheckBox(inspection.getCheckboxTitle()); - checkBox.setSelected(inspection.myCustomValuesEnabled); + checkBox.setSelected(inspection.isCustomValuesEnabled()); checkBox.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { final boolean b = checkBox.isSelected(); - if (b != inspection.myCustomValuesEnabled) { - inspection.myCustomValuesEnabled = b; - additionalAttributesPanel.setEnabled(inspection.myCustomValuesEnabled); + if (b != inspection.isCustomValuesEnabled()) { + inspection.enableCustomValues(b); + additionalAttributesPanel.setEnabled(inspection.isCustomValuesEnabled()); } } }); @@ -116,8 +114,8 @@ public class HtmlUnknownTagInspection extends HtmlUnknownTagInspectionBase { internalPanel.add(additionalAttributesPanel, BorderLayout.CENTER); additionalAttributesPanel.setPreferredSize(new Dimension(150, additionalAttributesPanel.getPreferredSize().height)); - additionalAttributesPanel.setEnabled(inspection.myCustomValuesEnabled); - additionalAttributesPanel.setText(inspection.createPropertiesString()); + additionalAttributesPanel.setEnabled(inspection.isCustomValuesEnabled()); + additionalAttributesPanel.setText(inspection.getAdditionalEntries()); return result; } diff --git a/xml/xml-analysis-impl/src/com/intellij/codeInspection/htmlInspections/AddCustomTagOrAttributeIntentionAction.java b/xml/xml-analysis-impl/src/com/intellij/codeInspection/htmlInspections/AddCustomHtmlElementIntentionAction.java similarity index 82% rename from xml/xml-analysis-impl/src/com/intellij/codeInspection/htmlInspections/AddCustomTagOrAttributeIntentionAction.java rename to xml/xml-analysis-impl/src/com/intellij/codeInspection/htmlInspections/AddCustomHtmlElementIntentionAction.java index 49ca50204152..2820af06bc65 100644 --- a/xml/xml-analysis-impl/src/com/intellij/codeInspection/htmlInspections/AddCustomTagOrAttributeIntentionAction.java +++ b/xml/xml-analysis-impl/src/com/intellij/codeInspection/htmlInspections/AddCustomHtmlElementIntentionAction.java @@ -27,15 +27,12 @@ import com.intellij.util.Consumer; import com.intellij.xml.XmlBundle; import org.jetbrains.annotations.NotNull; -/** - * @author spleaner - */ -public class AddCustomTagOrAttributeIntentionAction implements LocalQuickFix { +public class AddCustomHtmlElementIntentionAction implements LocalQuickFix { private final String myName; private final String myText; - @NotNull private final Key myInspectionKey; + @NotNull private final Key myInspectionKey; - public AddCustomTagOrAttributeIntentionAction(@NotNull Key inspectionKey, String name, String text) { + public AddCustomHtmlElementIntentionAction(@NotNull Key inspectionKey, String name, String text) { myInspectionKey = inspectionKey; myName = name; myText = text; @@ -58,9 +55,9 @@ public class AddCustomTagOrAttributeIntentionAction implements LocalQuickFix { final PsiElement element = descriptor.getPsiElement(); InspectionProfile profile = InspectionProjectProfileManager.getInstance(project).getInspectionProfile(); - profile.modifyToolSettings(myInspectionKey, element, new Consumer() { + profile.modifyToolSettings(myInspectionKey, element, new Consumer() { @Override - public void consume(HtmlUnknownTagInspectionBase tool) { + public void consume(HtmlUnknownElementInspection tool) { tool.addEntry(myName); } }); diff --git a/xml/xml-analysis-impl/src/com/intellij/codeInspection/htmlInspections/HtmlUnknownAttributeInspectionBase.java b/xml/xml-analysis-impl/src/com/intellij/codeInspection/htmlInspections/HtmlUnknownAttributeInspectionBase.java index ea9f3e0aeffa..0acd0691a447 100644 --- a/xml/xml-analysis-impl/src/com/intellij/codeInspection/htmlInspections/HtmlUnknownAttributeInspectionBase.java +++ b/xml/xml-analysis-impl/src/com/intellij/codeInspection/htmlInspections/HtmlUnknownAttributeInspectionBase.java @@ -17,15 +17,11 @@ package com.intellij.codeInspection.htmlInspections; import com.intellij.codeInsight.daemon.XmlErrorMessages; import com.intellij.codeInspection.LocalQuickFix; -import com.intellij.codeInspection.ProblemHighlightType; import com.intellij.codeInspection.ProblemsHolder; -import com.intellij.lang.ASTNode; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.Key; -import com.intellij.psi.PsiElement; import com.intellij.psi.html.HtmlTag; import com.intellij.psi.xml.XmlAttribute; -import com.intellij.psi.xml.XmlChildRole; import com.intellij.psi.xml.XmlTag; import com.intellij.xml.XmlAttributeDescriptor; import com.intellij.xml.XmlBundle; @@ -37,18 +33,14 @@ import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; -public class HtmlUnknownAttributeInspectionBase extends HtmlUnknownTagInspectionBase { - public static final Key ATTRIBUTE_KEY = Key.create(ATTRIBUTE_SHORT_NAME); +public class HtmlUnknownAttributeInspectionBase extends HtmlUnknownElementInspection { + private static final Key ATTRIBUTE_KEY = Key.create(ATTRIBUTE_SHORT_NAME); private static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.htmlInspections.HtmlUnknownAttributeInspection"); public HtmlUnknownAttributeInspectionBase(String defaultValues) { super(defaultValues); } - public HtmlUnknownAttributeInspectionBase() { - super(); - } - @Override @Nls @NotNull @@ -68,6 +60,7 @@ public class HtmlUnknownAttributeInspectionBase extends HtmlUnknownTagInspection return XmlBundle.message("html.inspections.unknown.tag.attribute.checkbox.title"); } + @NotNull @Override protected String getPanelTitle() { return XmlBundle.message("html.inspections.unknown.tag.attribute.title"); @@ -79,11 +72,6 @@ public class HtmlUnknownAttributeInspectionBase extends HtmlUnknownTagInspection return LOG; } - @Override - protected void checkTag(@NotNull final XmlTag tag, @NotNull final ProblemsHolder holder, final boolean isOnTheFly) { - // does nothing! this method should be overridden empty! - } - @Override protected void checkAttribute(@NotNull final XmlAttribute attribute, @NotNull final ProblemsHolder holder, final boolean isOnTheFly) { final XmlTag tag = attribute.getParent(); @@ -96,26 +84,19 @@ public class HtmlUnknownAttributeInspectionBase extends HtmlUnknownTagInspection XmlAttributeDescriptor attributeDescriptor = elementDescriptor.getAttributeDescriptor(attribute); - final String name = attribute.getName(); - if (attributeDescriptor == null && !attribute.isNamespaceDeclaration()) { - if (!XmlUtil.attributeFromTemplateFramework(name, tag) && - (!isCustomValuesEnabled() || !isCustomValue(name))) { - final ASTNode node = attribute.getNode(); - assert node != null; - final PsiElement nameElement = XmlChildRole.ATTRIBUTE_NAME_FINDER.findChild(node).getPsi(); - + final String name = attribute.getName(); + if (!XmlUtil.attributeFromTemplateFramework(name, tag) && (!isCustomValuesEnabled() || !isCustomValue(name))) { boolean maySwitchToHtml5 = HtmlUtil.isCustomHtml5Attribute(name) && !HtmlUtil.hasNonHtml5Doctype(tag); LocalQuickFix[] quickfixes = new LocalQuickFix[maySwitchToHtml5 ? 3 : 2]; - quickfixes[0] = new AddCustomTagOrAttributeIntentionAction(ATTRIBUTE_KEY, name, XmlBundle.message("add.custom.html.attribute", name)); + quickfixes[0] = new AddCustomHtmlElementIntentionAction(ATTRIBUTE_KEY, name, XmlBundle.message("add.custom.html.attribute", name)); quickfixes[1] = new RemoveAttributeIntentionAction(name); if (maySwitchToHtml5) { quickfixes[2] = new SwitchToHtml5WithHighPriorityAction(); } - if (nameElement.getTextLength() > 0) - holder.registerProblem(nameElement, XmlErrorMessages.message("attribute.is.not.allowed.here", name), - ProblemHighlightType.GENERIC_ERROR_OR_WARNING, quickfixes); + registerProblemOnAttributeName(attribute, XmlErrorMessages.message("attribute.is.not.allowed.here", attribute.getName()), holder, + quickfixes); } } } diff --git a/xml/xml-analysis-impl/src/com/intellij/codeInspection/htmlInspections/HtmlUnknownTagInspectionBase.java b/xml/xml-analysis-impl/src/com/intellij/codeInspection/htmlInspections/HtmlUnknownTagInspectionBase.java index 2cc788d50c06..1da21a1b73a9 100644 --- a/xml/xml-analysis-impl/src/com/intellij/codeInspection/htmlInspections/HtmlUnknownTagInspectionBase.java +++ b/xml/xml-analysis-impl/src/com/intellij/codeInspection/htmlInspections/HtmlUnknownTagInspectionBase.java @@ -22,9 +22,7 @@ import com.intellij.codeInspection.ProblemHighlightType; import com.intellij.codeInspection.ProblemsHolder; import com.intellij.codeInspection.XmlQuickFixFactory; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.util.JDOMExternalizableStringList; import com.intellij.openapi.util.Key; -import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiElement; import com.intellij.psi.html.HtmlTag; import com.intellij.psi.impl.source.html.dtd.HtmlElementDescriptorImpl; @@ -43,33 +41,19 @@ import org.jetbrains.annotations.NotNull; import java.util.ArrayList; import java.util.List; -import java.util.StringTokenizer; -public class HtmlUnknownTagInspectionBase extends HtmlLocalInspectionTool implements XmlEntitiesInspection { - public static final Key TAG_KEY = Key.create(TAG_SHORT_NAME); +public class HtmlUnknownTagInspectionBase extends HtmlUnknownElementInspection { + public static final Key TAG_KEY = Key.create(TAG_SHORT_NAME); private static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.htmlInspections.HtmlUnknownTagInspection"); - public JDOMExternalizableStringList myValues; - public boolean myCustomValuesEnabled = true; - public HtmlUnknownTagInspectionBase(String defaultValues) { - myValues = reparseProperties(defaultValues); + public HtmlUnknownTagInspectionBase(@NotNull String defaultValues) { + super(defaultValues); } public HtmlUnknownTagInspectionBase() { this("nobr,noembed,comment,noscript,embed,script"); } - protected static JDOMExternalizableStringList reparseProperties(@NotNull final String properties) { - final JDOMExternalizableStringList result = new JDOMExternalizableStringList(); - - final StringTokenizer tokenizer = new StringTokenizer(properties, ","); - while (tokenizer.hasMoreTokens()) { - result.add(tokenizer.nextToken().toLowerCase().trim()); - } - - return result; - } - private static boolean isAbstractDescriptor(XmlElementDescriptor descriptor) { return descriptor == null || descriptor instanceof AnyXmlElementDescriptor; } @@ -88,52 +72,23 @@ public class HtmlUnknownTagInspectionBase extends HtmlLocalInspectionTool implem return TAG_SHORT_NAME; } + @Override @NotNull protected Logger getLogger() { return LOG; } - protected String createPropertiesString() { - return StringUtil.join(myValues, ","); - } - @Override - public String getAdditionalEntries() { - return createPropertiesString(); - } - protected String getCheckboxTitle() { return XmlBundle.message("html.inspections.unknown.tag.checkbox.title"); } - public void setAdditionalValues(@NotNull final String values) { - myValues = reparseProperties(values); - } - + @Override + @NotNull protected String getPanelTitle() { return XmlBundle.message("html.inspections.unknown.tag.title"); } - protected boolean isCustomValue(@NotNull final String value) { - return myValues.contains(value.toLowerCase()); - } - - @Override - public void addEntry(@NotNull final String text) { - final String s = text.trim().toLowerCase(); - if (!isCustomValue(s)) { - myValues.add(s); - } - - if (!isCustomValuesEnabled()) { - myCustomValuesEnabled = true; - } - } - - public boolean isCustomValuesEnabled() { - return myCustomValuesEnabled; - } - @Override protected void checkTag(@NotNull final XmlTag tag, @NotNull final ProblemsHolder holder, final boolean isOnTheFly) { if (!(tag instanceof HtmlTag) || !XmlHighlightVisitor.shouldBeValidated(tag)) { @@ -157,8 +112,7 @@ public class HtmlUnknownTagInspectionBase extends HtmlLocalInspectionTool implem final String name = tag.getName(); if (!isCustomValuesEnabled() || !isCustomValue(name)) { - final AddCustomTagOrAttributeIntentionAction action = - new AddCustomTagOrAttributeIntentionAction(TAG_KEY, name, XmlBundle.message("add.custom.html.tag", name)); + final AddCustomHtmlElementIntentionAction action = new AddCustomHtmlElementIntentionAction(TAG_KEY, name, XmlBundle.message("add.custom.html.tag", name)); // todo: support "element is not allowed" message for html5 // some tags in html5 cannot be found in xhtml5.xsd if they are located in incorrect context, so they get any-element descriptor (ex. "canvas: tag) From c488d3e992d55b9b24e3d82455ee58265fd86b77 Mon Sep 17 00:00:00 2001 From: Alexander Zolotov Date: Tue, 23 Dec 2014 19:52:41 +0300 Subject: [PATCH 063/137] HTML: extract common 'unknown element inspection' --- .../model/descriptors/AttributeFinder.java | 4 +- .../relaxNG/RngHtml5CompletionTest.java | 4 + .../html5_overwritten_attributes.xml | 8 ++ .../html5_overwritten_attributes_after.xml | 8 ++ .../HtmlUnknownElementInspection.java | 90 +++++++++++++++++++ 5 files changed, 113 insertions(+), 1 deletion(-) create mode 100644 xml/relaxng/testData/completion/html5_overwritten_attributes.xml create mode 100644 xml/relaxng/testData/completion/html5_overwritten_attributes_after.xml create mode 100644 xml/xml-analysis-impl/src/com/intellij/codeInspection/htmlInspections/HtmlUnknownElementInspection.java diff --git a/xml/relaxng/src/org/intellij/plugins/relaxNG/model/descriptors/AttributeFinder.java b/xml/relaxng/src/org/intellij/plugins/relaxNG/model/descriptors/AttributeFinder.java index 32830be50fcc..5f2b13a1bee4 100644 --- a/xml/relaxng/src/org/intellij/plugins/relaxNG/model/descriptors/AttributeFinder.java +++ b/xml/relaxng/src/org/intellij/plugins/relaxNG/model/descriptors/AttributeFinder.java @@ -66,7 +66,9 @@ class AttributeFinder extends RecursionSaveWalker { if (depth == 1 && (myQname == null || p.getName().contains(myQname))) { myLastAttr = p; - myAttributes.put(p, Pair.create(new LinkedHashMap(), optional > 0)); + if (!myAttributes.containsKey(p)) { + myAttributes.put(p, Pair.create(new LinkedHashMap(), optional > 0)); + } return super.onAttribute(p); } return null; diff --git a/xml/relaxng/test/org/intellij/plugins/relaxNG/RngHtml5CompletionTest.java b/xml/relaxng/test/org/intellij/plugins/relaxNG/RngHtml5CompletionTest.java index 55db78a3dd8b..fce0d34c1709 100644 --- a/xml/relaxng/test/org/intellij/plugins/relaxNG/RngHtml5CompletionTest.java +++ b/xml/relaxng/test/org/intellij/plugins/relaxNG/RngHtml5CompletionTest.java @@ -93,4 +93,8 @@ public class RngHtml5CompletionTest extends HighlightingTestBase { public void testHtml5_17() throws Throwable { doTestCompletion("html5_17"); } + + public void testHtml5_overwritten_attributes() throws Throwable { + myTestFixture.testCompletionTyping("html5_overwritten_attributes.xml", "a\n", "html5_overwritten_attributes_after.xml"); + } } diff --git a/xml/relaxng/testData/completion/html5_overwritten_attributes.xml b/xml/relaxng/testData/completion/html5_overwritten_attributes.xml new file mode 100644 index 000000000000..effe54541449 --- /dev/null +++ b/xml/relaxng/testData/completion/html5_overwritten_attributes.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/xml/relaxng/testData/completion/html5_overwritten_attributes_after.xml b/xml/relaxng/testData/completion/html5_overwritten_attributes_after.xml new file mode 100644 index 000000000000..0d77c11e273e --- /dev/null +++ b/xml/relaxng/testData/completion/html5_overwritten_attributes_after.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/xml/xml-analysis-impl/src/com/intellij/codeInspection/htmlInspections/HtmlUnknownElementInspection.java b/xml/xml-analysis-impl/src/com/intellij/codeInspection/htmlInspections/HtmlUnknownElementInspection.java new file mode 100644 index 000000000000..e00aebcf5069 --- /dev/null +++ b/xml/xml-analysis-impl/src/com/intellij/codeInspection/htmlInspections/HtmlUnknownElementInspection.java @@ -0,0 +1,90 @@ +package com.intellij.codeInspection.htmlInspections; + +import com.intellij.codeInspection.LocalQuickFix; +import com.intellij.codeInspection.ProblemHighlightType; +import com.intellij.codeInspection.ProblemsHolder; +import com.intellij.lang.ASTNode; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.util.JDOMExternalizableStringList; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.psi.PsiElement; +import com.intellij.psi.xml.XmlAttribute; +import com.intellij.psi.xml.XmlChildRole; +import org.jetbrains.annotations.NotNull; + +import java.util.StringTokenizer; + +abstract public class HtmlUnknownElementInspection extends HtmlLocalInspectionTool implements XmlEntitiesInspection { + public boolean myCustomValuesEnabled = true; + public JDOMExternalizableStringList myValues; + + public HtmlUnknownElementInspection(@NotNull String defaultValues) { + myValues = reparseProperties(defaultValues); + } + + protected static JDOMExternalizableStringList reparseProperties(@NotNull final String properties) { + final JDOMExternalizableStringList result = new JDOMExternalizableStringList(); + + final StringTokenizer tokenizer = new StringTokenizer(properties, ","); + while (tokenizer.hasMoreTokens()) { + result.add(tokenizer.nextToken().toLowerCase().trim()); + } + + return result; + } + + protected static void registerProblemOnAttributeName(@NotNull XmlAttribute attribute, + String message, @NotNull ProblemsHolder holder, + LocalQuickFix... quickfixes) { + final ASTNode node = attribute.getNode(); + assert node != null; + final ASTNode nameNode = XmlChildRole.ATTRIBUTE_NAME_FINDER.findChild(node); + if (nameNode != null) { + final PsiElement nameElement = nameNode.getPsi(); + if (nameElement.getTextLength() > 0) { + holder.registerProblem(nameElement, message, ProblemHighlightType.GENERIC_ERROR_OR_WARNING, quickfixes); + } + } + } + + protected boolean isCustomValue(@NotNull final String value) { + return myValues.contains(value.toLowerCase()); + } + + @Override + public void addEntry(@NotNull final String text) { + final String s = text.trim().toLowerCase(); + if (!isCustomValue(s)) { + myValues.add(s); + } + + if (!isCustomValuesEnabled()) { + myCustomValuesEnabled = true; + } + } + + public boolean isCustomValuesEnabled() { + return myCustomValuesEnabled; + } + + @Override + public String getAdditionalEntries() { + return StringUtil.join(myValues, ","); + } + + public void enableCustomValues(boolean customValuesEnabled) { + myCustomValuesEnabled = customValuesEnabled; + } + + public void updateAdditionalEntries(@NotNull final String values) { + myValues = reparseProperties(values); + } + + protected abstract String getCheckboxTitle(); + + @NotNull + protected abstract String getPanelTitle(); + + @NotNull + protected abstract Logger getLogger(); +} From 4ca9b677e59f149df17999569587a3a36c0ba4e7 Mon Sep 17 00:00:00 2001 From: Alexander Zolotov Date: Tue, 23 Dec 2014 20:35:24 +0300 Subject: [PATCH 064/137] HTML: add unknown boolean attribute inspection --- .../src/messages/XmlBundle.properties | 4 + .../src/META-INF/XmlPlugin.xml | 3 + .../XmlQuickFixFactoryImpl.java | 8 ++ .../AddAttributeValueIntentionFix.java | 84 ++++++++++++++ ...HtmlUnknownBooleanAttributeInspection.java | 34 ++++++ .../codeInspection/XmlQuickFixFactory.java | 4 + .../HtmlUnknownBooleanAttribute.html | 6 + .../EmptyXmlQuickFixFactory.java | 7 ++ ...UnknownBooleanAttributeInspectionBase.java | 103 ++++++++++++++++++ .../messages/XmlErrorMessages.properties | 2 + .../XmlEntitiesInspection.java | 1 + .../src/com/intellij/xml/util/HtmlUtil.java | 32 ++++-- 12 files changed, 278 insertions(+), 10 deletions(-) create mode 100644 xml/impl/src/com/intellij/codeInspection/htmlInspections/AddAttributeValueIntentionFix.java create mode 100644 xml/impl/src/com/intellij/codeInspection/htmlInspections/HtmlUnknownBooleanAttributeInspection.java create mode 100644 xml/xml-analysis-impl/resources/inspectionDescriptions/HtmlUnknownBooleanAttribute.html create mode 100644 xml/xml-analysis-impl/src/com/intellij/codeInspection/htmlInspections/HtmlUnknownBooleanAttributeInspectionBase.java diff --git a/platform/platform-resources-en/src/messages/XmlBundle.properties b/platform/platform-resources-en/src/messages/XmlBundle.properties index 53c4fc55aa1f..139f86b8521b 100644 --- a/platform/platform-resources-en/src/messages/XmlBundle.properties +++ b/platform/platform-resources-en/src/messages/XmlBundle.properties @@ -71,10 +71,13 @@ html.inspections.non.existent.internet.resource.name=Non-existent web resource html.inspections.unknown.tag=Unknown HTML tag html.inspections.unknown.attribute=Unknown HTML tag attribute +html.inspections.unknown.boolean.attribute=Unknown HTML boolean tag attribute html.inspections.unknown.tag.checkbox.title=Custom HTML tags: html.inspections.unknown.tag.title=Edit custom tags html.inspections.unknown.tag.attribute.checkbox.title=Custom HTML tag attributes: +html.inspections.unknown.tag.boolean.attribute.checkbox.title=Custom HTML boolean tag attributes: html.inspections.unknown.tag.attribute.title=Edit custom attributes +html.inspections.unknown.tag.boolean.attribute.title=Edit custom boolean attributes xml.schema.create.complex.type.intention.name=Create Complex Type {0} xml.schema.create.attribute.intention.name=Create Attribute {0} xml.schema.create.element.intention.name=Create Element {0} @@ -130,6 +133,7 @@ no.ignored.resources=No ignored resources custom.html.tag=Custom Html Tag add.custom.html.tag=Add {0} to custom html tags add.custom.html.attribute=Add {0} to custom html attributes +add.custom.html.boolean.attribute=Add {0} to custom html boolean attributes add.optional.html.attribute=Add {0} to not required html attributes fix.html.family=Fix Html diff --git a/platform/platform-resources/src/META-INF/XmlPlugin.xml b/platform/platform-resources/src/META-INF/XmlPlugin.xml index cf0e8e7b97c8..3ada69d17e89 100644 --- a/platform/platform-resources/src/META-INF/XmlPlugin.xml +++ b/platform/platform-resources/src/META-INF/XmlPlugin.xml @@ -421,6 +421,9 @@ + diff --git a/xml/impl/src/com/intellij/codeInspection/XmlQuickFixFactoryImpl.java b/xml/impl/src/com/intellij/codeInspection/XmlQuickFixFactoryImpl.java index c095bd1cf49f..4c647c6e0c01 100644 --- a/xml/impl/src/com/intellij/codeInspection/XmlQuickFixFactoryImpl.java +++ b/xml/impl/src/com/intellij/codeInspection/XmlQuickFixFactoryImpl.java @@ -17,7 +17,9 @@ package com.intellij.codeInspection; import com.intellij.codeInsight.daemon.impl.analysis.CreateNSDeclarationIntentionFix; import com.intellij.codeInsight.daemon.impl.analysis.InsertRequiredAttributeFix; +import com.intellij.codeInspection.htmlInspections.AddAttributeValueIntentionFix; import com.intellij.psi.PsiElement; +import com.intellij.psi.xml.XmlAttribute; import com.intellij.psi.xml.XmlTag; import com.intellij.psi.xml.XmlToken; import org.jetbrains.annotations.NotNull; @@ -35,4 +37,10 @@ public class XmlQuickFixFactoryImpl extends XmlQuickFixFactory { public LocalQuickFix createNSDeclarationIntentionFix(@NotNull PsiElement element, @NotNull String namespacePrefix, @Nullable XmlToken token) { return new CreateNSDeclarationIntentionFix(element, namespacePrefix, token); } + + @NotNull + @Override + public LocalQuickFixAndIntentionActionOnPsiElement addAttributeValueFix(@NotNull XmlAttribute attribute) { + return new AddAttributeValueIntentionFix(attribute); + } } diff --git a/xml/impl/src/com/intellij/codeInspection/htmlInspections/AddAttributeValueIntentionFix.java b/xml/impl/src/com/intellij/codeInspection/htmlInspections/AddAttributeValueIntentionFix.java new file mode 100644 index 000000000000..500fdc4f4c8b --- /dev/null +++ b/xml/impl/src/com/intellij/codeInspection/htmlInspections/AddAttributeValueIntentionFix.java @@ -0,0 +1,84 @@ +/* + * Copyright 2000-2013 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.htmlInspections; + +import com.intellij.codeInsight.AutoPopupController; +import com.intellij.codeInsight.FileModificationService; +import com.intellij.codeInsight.daemon.XmlErrorMessages; +import com.intellij.codeInspection.LocalQuickFixAndIntentionActionOnPsiElement; +import com.intellij.openapi.application.Result; +import com.intellij.openapi.command.WriteCommandAction; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.psi.XmlElementFactory; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.psi.xml.XmlAttribute; +import com.intellij.psi.xml.XmlAttributeValue; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class AddAttributeValueIntentionFix extends LocalQuickFixAndIntentionActionOnPsiElement { + public AddAttributeValueIntentionFix(@Nullable PsiElement element) { + super(element); + } + + @NotNull + @Override + public String getText() { + return XmlErrorMessages.message("add.attribute.value.quickfix.text"); + } + + @Override + @NotNull + public String getFamilyName() { + return getName(); + } + + @Override + public void invoke(@NotNull Project project, + @NotNull PsiFile file, + @Nullable("is null when called from inspection") final Editor editor, + @NotNull PsiElement startElement, + @NotNull PsiElement endElement) { + final XmlAttribute attribute = PsiTreeUtil.getNonStrictParentOfType(startElement, XmlAttribute.class); + if (attribute == null || attribute.getValue() != null) { + return; + } + + if (!FileModificationService.getInstance().prepareFileForWrite(attribute.getContainingFile())) { + return; + } + + new WriteCommandAction(project) { + @Override + protected void run(@NotNull final Result result) { + final XmlAttribute attributeWithValue = XmlElementFactory.getInstance(getProject()).createXmlAttribute(attribute.getName(), ""); + final PsiElement newAttribute = attribute.replace(attributeWithValue); + + if (editor != null && newAttribute != null && newAttribute instanceof XmlAttribute && newAttribute.isValid()) { + final XmlAttributeValue valueElement = ((XmlAttribute)newAttribute).getValueElement(); + if (valueElement != null) { + editor.getCaretModel().moveToOffset(valueElement.getTextOffset()); + AutoPopupController.getInstance(newAttribute.getProject()).scheduleAutoPopup(editor); + } + } + } + }.execute(); + } +} diff --git a/xml/impl/src/com/intellij/codeInspection/htmlInspections/HtmlUnknownBooleanAttributeInspection.java b/xml/impl/src/com/intellij/codeInspection/htmlInspections/HtmlUnknownBooleanAttributeInspection.java new file mode 100644 index 000000000000..478669ea418f --- /dev/null +++ b/xml/impl/src/com/intellij/codeInspection/htmlInspections/HtmlUnknownBooleanAttributeInspection.java @@ -0,0 +1,34 @@ +/* + * Copyright 2000-2013 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.htmlInspections; + +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; + +public class HtmlUnknownBooleanAttributeInspection extends HtmlUnknownBooleanAttributeInspectionBase { + + public HtmlUnknownBooleanAttributeInspection() { + super(""); + } + + @Nullable + @Override + public JComponent createOptionsPanel() { + return HtmlUnknownTagInspection.createOptionsPanel(this); + } +} diff --git a/xml/xml-analysis-api/src/com/intellij/codeInspection/XmlQuickFixFactory.java b/xml/xml-analysis-api/src/com/intellij/codeInspection/XmlQuickFixFactory.java index c0c5b1081785..3037760dc98a 100644 --- a/xml/xml-analysis-api/src/com/intellij/codeInspection/XmlQuickFixFactory.java +++ b/xml/xml-analysis-api/src/com/intellij/codeInspection/XmlQuickFixFactory.java @@ -17,6 +17,7 @@ package com.intellij.codeInspection; import com.intellij.openapi.components.ServiceManager; import com.intellij.psi.PsiElement; +import com.intellij.psi.xml.XmlAttribute; import com.intellij.psi.xml.XmlTag; import com.intellij.psi.xml.XmlToken; import org.jetbrains.annotations.NotNull; @@ -34,4 +35,7 @@ public abstract class XmlQuickFixFactory { public abstract LocalQuickFix createNSDeclarationIntentionFix(@NotNull final PsiElement element, @NotNull String namespacePrefix, @Nullable final XmlToken token); + + @NotNull + public abstract LocalQuickFixAndIntentionActionOnPsiElement addAttributeValueFix(@NotNull XmlAttribute attribute); } diff --git a/xml/xml-analysis-impl/resources/inspectionDescriptions/HtmlUnknownBooleanAttribute.html b/xml/xml-analysis-impl/resources/inspectionDescriptions/HtmlUnknownBooleanAttribute.html new file mode 100644 index 000000000000..d926ffab1cc0 --- /dev/null +++ b/xml/xml-analysis-impl/resources/inspectionDescriptions/HtmlUnknownBooleanAttribute.html @@ -0,0 +1,6 @@ + + +This inspection highlights HTML none-boolean tag attributes without value as invalid, and lets mark such attributes as Custom to avoid highlighting them as +invalid.
+ + \ No newline at end of file diff --git a/xml/xml-analysis-impl/src/com/intellij/codeInspection/EmptyXmlQuickFixFactory.java b/xml/xml-analysis-impl/src/com/intellij/codeInspection/EmptyXmlQuickFixFactory.java index ce56f3923abc..3c019d890e3c 100644 --- a/xml/xml-analysis-impl/src/com/intellij/codeInspection/EmptyXmlQuickFixFactory.java +++ b/xml/xml-analysis-impl/src/com/intellij/codeInspection/EmptyXmlQuickFixFactory.java @@ -17,6 +17,7 @@ package com.intellij.codeInspection; import com.intellij.codeInsight.intention.QuickFixes; import com.intellij.psi.PsiElement; +import com.intellij.psi.xml.XmlAttribute; import com.intellij.psi.xml.XmlTag; import com.intellij.psi.xml.XmlToken; import org.jetbrains.annotations.NotNull; @@ -38,4 +39,10 @@ public class EmptyXmlQuickFixFactory extends XmlQuickFixFactory { @Nullable XmlToken token) { return QuickFixes.EMPTY_ACTION; } + + @NotNull + @Override + public LocalQuickFixAndIntentionActionOnPsiElement addAttributeValueFix(@NotNull XmlAttribute attribute) { + return QuickFixes.EMPTY_FIX; + } } diff --git a/xml/xml-analysis-impl/src/com/intellij/codeInspection/htmlInspections/HtmlUnknownBooleanAttributeInspectionBase.java b/xml/xml-analysis-impl/src/com/intellij/codeInspection/htmlInspections/HtmlUnknownBooleanAttributeInspectionBase.java new file mode 100644 index 000000000000..b7fb7f2a0870 --- /dev/null +++ b/xml/xml-analysis-impl/src/com/intellij/codeInspection/htmlInspections/HtmlUnknownBooleanAttributeInspectionBase.java @@ -0,0 +1,103 @@ +/* + * Copyright 2000-2013 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.htmlInspections; + +import com.intellij.codeInsight.daemon.XmlErrorMessages; +import com.intellij.codeInspection.LocalQuickFix; +import com.intellij.codeInspection.ProblemsHolder; +import com.intellij.codeInspection.XmlQuickFixFactory; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.util.Key; +import com.intellij.psi.html.HtmlTag; +import com.intellij.psi.xml.XmlAttribute; +import com.intellij.psi.xml.XmlTag; +import com.intellij.xml.XmlAttributeDescriptor; +import com.intellij.xml.XmlBundle; +import com.intellij.xml.XmlElementDescriptor; +import com.intellij.xml.impl.schema.AnyXmlElementDescriptor; +import com.intellij.xml.util.HtmlUtil; +import org.jetbrains.annotations.Nls; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; + +public abstract class HtmlUnknownBooleanAttributeInspectionBase extends HtmlUnknownElementInspection { + private static final Key BOOLEAN_ATTRIBUTE_KEY = Key.create(BOOLEAN_ATTRIBUTE_SHORT_NAME); + private static final Logger LOG = Logger.getInstance(HtmlUnknownBooleanAttributeInspectionBase.class); + + public HtmlUnknownBooleanAttributeInspectionBase(String defaultValues) { + super(defaultValues); + } + + @Override + @Nls + @NotNull + public String getDisplayName() { + return XmlBundle.message("html.inspections.unknown.boolean.attribute"); + } + + @Override + @NonNls + @NotNull + public String getShortName() { + return BOOLEAN_ATTRIBUTE_SHORT_NAME; + } + + @Override + protected String getCheckboxTitle() { + return XmlBundle.message("html.inspections.unknown.tag.boolean.attribute.checkbox.title"); + } + + @NotNull + @Override + protected String getPanelTitle() { + return XmlBundle.message("html.inspections.unknown.tag.boolean.attribute.title"); + } + + @Override + @NotNull + protected Logger getLogger() { + return LOG; + } + + @Override + protected void checkAttribute(@NotNull final XmlAttribute attribute, @NotNull final ProblemsHolder holder, final boolean isOnTheFly) { + if (attribute.getValueElement() == null) { + final XmlTag tag = attribute.getParent(); + + if (tag instanceof HtmlTag) { + XmlElementDescriptor elementDescriptor = tag.getDescriptor(); + if (elementDescriptor == null || elementDescriptor instanceof AnyXmlElementDescriptor) { + return; + } + + XmlAttributeDescriptor attributeDescriptor = elementDescriptor.getAttributeDescriptor(attribute); + if (attributeDescriptor != null) { + String name = attribute.getName(); + if (!HtmlUtil.isBooleanAttribute(attributeDescriptor) && (!isCustomValuesEnabled() || !isCustomValue(name))) { + LocalQuickFix[] quickFixes = new LocalQuickFix[]{ + new AddCustomHtmlElementIntentionAction(BOOLEAN_ATTRIBUTE_KEY, name, XmlBundle.message("add.custom.html.boolean.attribute", name)), + XmlQuickFixFactory.getInstance().addAttributeValueFix(attribute), + new RemoveAttributeIntentionAction(name), + }; + + registerProblemOnAttributeName(attribute, XmlErrorMessages.message("attribute.is.not.boolean", attribute.getName()), holder, + quickFixes); + } + } + } + } + } +} diff --git a/xml/xml-psi-impl/resources/messages/XmlErrorMessages.properties b/xml/xml-psi-impl/resources/messages/XmlErrorMessages.properties index 1eaa0cecc989..aad82b2ed52b 100644 --- a/xml/xml-psi-impl/resources/messages/XmlErrorMessages.properties +++ b/xml/xml-psi-impl/resources/messages/XmlErrorMessages.properties @@ -14,6 +14,7 @@ wrong.root.element=Wrong root element unbound.namespace=Namespace ''{0}'' is not bound unbound.namespace.no.param=Namespace is not bound attribute.is.not.allowed.here=Attribute {0} is not allowed here +attribute.is.not.boolean=Attribute {0} is not boolean empty.attribute.is.not.allowed=Empty attribute {0} is not allowed duplicate.attribute=Duplicate attribute {0} duplicate.id.reference=Duplicate id reference @@ -27,6 +28,7 @@ insert.required.attribute.quickfix.text=Insert required attribute {0} insert.required.attribute.quickfix.family=Insert required attribute remove.attribute.quickfix.text=Remove attribute {0} remove.attribute.quickfix.family=Remove attribute +add.attribute.value.quickfix.text=Add attribute value remove.extra.closing.tag.quickfix=Remove extra closing tag create.namespace.declaration.quickfix=Create {0} declaration select.namespace.title={0} To Import diff --git a/xml/xml-psi-impl/src/com/intellij/codeInspection/htmlInspections/XmlEntitiesInspection.java b/xml/xml-psi-impl/src/com/intellij/codeInspection/htmlInspections/XmlEntitiesInspection.java index 1143b7bd05dc..109dd2cab802 100644 --- a/xml/xml-psi-impl/src/com/intellij/codeInspection/htmlInspections/XmlEntitiesInspection.java +++ b/xml/xml-psi-impl/src/com/intellij/codeInspection/htmlInspections/XmlEntitiesInspection.java @@ -7,6 +7,7 @@ import org.jetbrains.annotations.NonNls; * Date: 16-Dec-2005 */ public interface XmlEntitiesInspection { + @NonNls String BOOLEAN_ATTRIBUTE_SHORT_NAME = "HtmlUnknownBooleanAttribute"; @NonNls String ATTRIBUTE_SHORT_NAME = "HtmlUnknownAttribute"; @NonNls String TAG_SHORT_NAME = "HtmlUnknownTag"; @NonNls String REQUIRED_ATTRIBUTES_SHORT_NAME = "RequiredAttributes"; diff --git a/xml/xml-psi-impl/src/com/intellij/xml/util/HtmlUtil.java b/xml/xml-psi-impl/src/com/intellij/xml/util/HtmlUtil.java index 3c3221b92b9e..1e90360c24a4 100644 --- a/xml/xml-psi-impl/src/com/intellij/xml/util/HtmlUtil.java +++ b/xml/xml-psi-impl/src/com/intellij/xml/util/HtmlUtil.java @@ -57,10 +57,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.nio.charset.Charset; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.StringTokenizer; +import java.util.*; /** * @author Maxim.Mossienko @@ -140,7 +137,7 @@ public class HtmlUtil { static { for (HTMLControls.Control control : HTMLControls.getControls()) { - final String tagName = control.name.toLowerCase(); + final String tagName = control.name.toLowerCase(Locale.US); if (control.endTag == HTMLControls.TagState.FORBIDDEN) EMPTY_TAGS_MAP.add(tagName); AUTO_CLOSE_BY_MAP.put(tagName, new THashSet(control.autoClosedBy)); } @@ -153,7 +150,7 @@ public class HtmlUtil { } public static boolean isSingleHtmlTag(String tagName) { - return EMPTY_TAGS_MAP.contains(tagName.toLowerCase()); + return EMPTY_TAGS_MAP.contains(tagName.toLowerCase(Locale.US)); } public static boolean isSingleHtmlTagL(String tagName) { @@ -161,7 +158,7 @@ public class HtmlUtil { } public static boolean isOptionalEndForHtmlTag(String tagName) { - return OPTIONAL_END_TAGS_MAP.contains(tagName.toLowerCase()); + return OPTIONAL_END_TAGS_MAP.contains(tagName.toLowerCase(Locale.US)); } public static boolean isOptionalEndForHtmlTagL(String tagName) { @@ -174,11 +171,11 @@ public class HtmlUtil { } public static boolean isSingleHtmlAttribute(String attrName) { - return EMPTY_ATTRS_MAP.contains(attrName.toLowerCase()); + return EMPTY_ATTRS_MAP.contains(attrName.toLowerCase(Locale.US)); } public static boolean isHtmlBlockTag(String tagName) { - return BLOCK_TAGS_MAP.contains(tagName.toLowerCase()); + return BLOCK_TAGS_MAP.contains(tagName.toLowerCase(Locale.US)); } public static boolean isPossiblyInlineTag(String tagName) { @@ -190,7 +187,7 @@ public class HtmlUtil { } public static boolean isInlineTagContainer(String tagName) { - return INLINE_ELEMENTS_CONTAINER_MAP.contains(tagName.toLowerCase()); + return INLINE_ELEMENTS_CONTAINER_MAP.contains(tagName.toLowerCase(Locale.US)); } public static boolean isInlineTagContainerL(String tagName) { @@ -241,6 +238,21 @@ public class HtmlUtil { return HtmlDescriptorsTable.getHtmlTagNames(); } + public static boolean isBooleanAttribute(@NotNull XmlAttributeDescriptor descriptor) { + final String[] values = descriptor.getEnumeratedValues(); + if (values == null) { + return false; + } + if (values.length == 2) { + return values[0].isEmpty() && values[1].equals(descriptor.getName()) + || values[1].isEmpty() && values[0].equals(descriptor.getName()); + } + else if (values.length == 1) { + return descriptor.getName().equals(values[0]); + } + return false; + } + public static XmlAttributeDescriptor[] getCustomAttributeDescriptors(XmlElement context) { String entitiesString = getEntitiesString(context, XmlEntitiesInspection.ATTRIBUTE_SHORT_NAME); if (entitiesString == null) return XmlAttributeDescriptor.EMPTY; From b29d17908fbf003bb0c499549e858d0ef3c6cbf7 Mon Sep 17 00:00:00 2001 From: Alexander Zolotov Date: Tue, 23 Dec 2014 20:37:12 +0300 Subject: [PATCH 065/137] Remove trailing space --- .../platform-resources-en/src/messages/XmlBundle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/platform-resources-en/src/messages/XmlBundle.properties b/platform/platform-resources-en/src/messages/XmlBundle.properties index 139f86b8521b..928d26855bf0 100644 --- a/platform/platform-resources-en/src/messages/XmlBundle.properties +++ b/platform/platform-resources-en/src/messages/XmlBundle.properties @@ -204,7 +204,7 @@ xmlbeans.particle.valid.tooltip=Enable particle valid (restriction) rule xmlbeans.unique.particle.tooltip=Enable unique particle rule xmlbeans.designtype.tooltip=XMLSchema design type xmlbeans.simplecontenttype.tooltip=Simple content types detection (leaf text) -xmlbeans.enumerations.tooltip=Detection enumeration from following count +xmlbeans.enumerations.tooltip=Detection enumeration from following count webservice.status.tooltip=Status of current settings, input errors, etc xmlbeans.instance2schema.result.schema.name=Result schema file name browse.button.tooltip=Browse for local file From b2e27cfbfc26fdf3602b01b7dd447896663decbe Mon Sep 17 00:00:00 2001 From: Alexander Zolotov Date: Wed, 24 Dec 2014 17:14:40 +0300 Subject: [PATCH 066/137] Avoid IOOBE in Registry --- .../openapi/util/registry/RegistryUi.java | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/openapi/util/registry/RegistryUi.java b/platform/lang-impl/src/com/intellij/openapi/util/registry/RegistryUi.java index e0fcb7440100..0433c92ebf5b 100644 --- a/platform/lang-impl/src/com/intellij/openapi/util/registry/RegistryUi.java +++ b/platform/lang-impl/src/com/intellij/openapi/util/registry/RegistryUi.java @@ -142,13 +142,15 @@ public class RegistryUi implements Disposable { public void keyPressed(@NotNull KeyEvent e) { if (e.getKeyCode() == KeyEvent.VK_SPACE) { int row = myTable.getSelectedRow(); - RegistryValue rv = myModel.getRegistryValue(row); - if (rv.isBoolean()) { - rv.setValue(!rv.asBoolean()); - keyChanged(rv.getKey()); - for (int i : new int[]{0, 1, 2}) myModel.fireTableCellUpdated(row, i); - revaliateActions(); - if (search.isPopupActive()) search.hidePopup(); + if (row != -1) { + RegistryValue rv = myModel.getRegistryValue(row); + if (rv.isBoolean()) { + rv.setValue(!rv.asBoolean()); + keyChanged(rv.getKey()); + for (int i : new int[]{0, 1, 2}) myModel.fireTableCellUpdated(row, i); + revaliateActions(); + if (search.isPopupActive()) search.hidePopup(); + } } } } From 22f3dc074e2cadf870e9018786ee38dd95e57248 Mon Sep 17 00:00:00 2001 From: Alexander Zolotov Date: Wed, 24 Dec 2014 17:46:45 +0300 Subject: [PATCH 067/137] Emmet: use html settings on handling boolean attribute --- .../util/resources/misc/registry.properties | 1 + xml/impl/resources/liveTemplates/zen_html.xml | 45 +++++------ .../options/emmet/EmmetOptions.java | 18 ----- .../options/emmet/XmlEmmetConfigurable.form | 12 +-- .../options/emmet/XmlEmmetConfigurable.java | 6 -- .../template/emmet/nodes/GenerationNode.java | 74 +++++++++++-------- ...UnknownBooleanAttributeInspectionBase.java | 2 +- .../src/com/intellij/xml/util/HtmlUtil.java | 37 +++++++++- 8 files changed, 102 insertions(+), 93 deletions(-) diff --git a/platform/util/resources/misc/registry.properties b/platform/util/resources/misc/registry.properties index c27a3f1b19ea..cd86bd76f7f3 100644 --- a/platform/util/resources/misc/registry.properties +++ b/platform/util/resources/misc/registry.properties @@ -470,6 +470,7 @@ spy.js.realtime.evaluation=false spy.js.realtime.evaluation.description=Enables spy-js autocomplete and realtime evaluation new.css.schema.enabled=true +html.prefer.short.notation.of.boolean.attributes=true editor.disable.rtl=false editor.disable.rtl.description=Disables RTL support in editor (which is broken now anyway) diff --git a/xml/impl/resources/liveTemplates/zen_html.xml b/xml/impl/resources/liveTemplates/zen_html.xml index ec5a2d388562..50c8714e5bc0 100644 --- a/xml/impl/resources/liveTemplates/zen_html.xml +++ b/xml/impl/resources/liveTemplates/zen_html.xml @@ -655,20 +655,18 @@