From bc01db0fe2ad88bc2de0ef06a5183166b8065da3 Mon Sep 17 00:00:00 2001 From: Andrey Loskutov Date: Sat, 6 Jun 2015 23:12:24 +0200 Subject: [PATCH] Bug 468906 - NullPointerException in OpenWithMenu$1.compare (92), part 1 Make sure EditorRegistry.getEditors(String) and IDE.overrideEditorAssociations() never return null editor descriptors. Change-Id: I7e995138715fb746cf9cd673400d220e0f58b5be Signed-off-by: Andrey Loskutov --- .../src/org/eclipse/ui/ide/IDE.java | 26 ++++- .../ui/internal/registry/EditorRegistry.java | 81 +++++++------- .../org/eclipse/ui/tests/api/ApiTestSuite.java | 8 +- .../org/eclipse/ui/tests/ide/api/IDETest.java | 122 +++++++++++++++++++++ tests/org.eclipse.ui.tests/plugin.xml | 7 ++ 5 files changed, 196 insertions(+), 48 deletions(-) create mode 100644 tests/org.eclipse.ui.tests/Eclipse UI Tests/org/eclipse/ui/tests/ide/api/IDETest.java diff --git a/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/ide/IDE.java b/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/ide/IDE.java index 4aa1db2..c29e168 100644 --- a/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/ide/IDE.java +++ b/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/ide/IDE.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2003, 2013 IBM Corporation and others. + * Copyright (c) 2003, 2015 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -845,7 +845,7 @@ public final class IDE { for (int i = 0; i < overrides.length; i++) { editorDescriptors = overrides[i].overrideEditors(editorInput, contentType, editorDescriptors); } - return editorDescriptors; + return removeNullEntries(editorDescriptors); } /** @@ -866,7 +866,27 @@ public final class IDE { for (int i = 0; i < overrides.length; i++) { editorDescriptors = overrides[i].overrideEditors(fileName, contentType, editorDescriptors); } - return editorDescriptors; + return removeNullEntries(editorDescriptors); + } + + private static IEditorDescriptor[] removeNullEntries(IEditorDescriptor[] editorDescriptors) { + boolean nullDescriptorFound = false; + for (IEditorDescriptor d : editorDescriptors) { + if (d == null) { + nullDescriptorFound = true; + break; + } + } + if (!nullDescriptorFound) { + return editorDescriptors; + } + List nonNullDescriptors = new ArrayList<>(editorDescriptors.length); + for (IEditorDescriptor d : editorDescriptors) { + if (d != null) { + nonNullDescriptors.add(d); + } + } + return nonNullDescriptors.toArray(new IEditorDescriptor[nonNullDescriptors.size()]); } /** diff --git a/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/registry/EditorRegistry.java b/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/registry/EditorRegistry.java index 4d2dd97..fd1a838 100644 --- a/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/registry/EditorRegistry.java +++ b/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/registry/EditorRegistry.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2012 IBM Corporation and others. + * Copyright (c) 2000, 2015 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -1030,37 +1030,37 @@ public class EditorRegistry extends EventManager implements IEditorRegistry, editorMemento.putString(IWorkbenchConstants.TAG_EXTENSION, type .getExtension()); IEditorDescriptor[] editorArray = type.getEditors(); - for (int i = 0; i < editorArray.length; i++) { - EditorDescriptor editor = (EditorDescriptor) editorArray[i]; - if (!editors.contains(editor)) { + for (IEditorDescriptor editor : editorArray) { + if (editor == null) { + continue; + } + if (!editors.contains(editor)) { editors.add(editor); } - IMemento idMemento = editorMemento - .createChild(IWorkbenchConstants.TAG_EDITOR); - idMemento.putString(IWorkbenchConstants.TAG_ID, editorArray[i] - .getId()); + IMemento idMemento = editorMemento.createChild(IWorkbenchConstants.TAG_EDITOR); + idMemento.putString(IWorkbenchConstants.TAG_ID, editor.getId()); } editorArray = type.getDeletedEditors(); - for (int i = 0; i < editorArray.length; i++) { - EditorDescriptor editor = (EditorDescriptor) editorArray[i]; - if (!editors.contains(editor)) { + for (IEditorDescriptor editor : editorArray) { + if (editor == null) { + continue; + } + if (!editors.contains(editor)) { editors.add(editor); } - IMemento idMemento = editorMemento - .createChild(IWorkbenchConstants.TAG_DELETED_EDITOR); - idMemento.putString(IWorkbenchConstants.TAG_ID, editorArray[i] - .getId()); + IMemento idMemento = editorMemento.createChild(IWorkbenchConstants.TAG_DELETED_EDITOR); + idMemento.putString(IWorkbenchConstants.TAG_ID, editor.getId()); } editorArray = type.getDeclaredDefaultEditors(); - for (int i = 0; i < editorArray.length; i++) { - EditorDescriptor editor = (EditorDescriptor) editorArray[i]; - if (!editors.contains(editor)) { + for (IEditorDescriptor editor : editorArray) { + if (editor == null) { + continue; + } + if (!editors.contains(editor)) { editors.add(editor); } - IMemento idMemento = editorMemento - .createChild(IWorkbenchConstants.TAG_DEFAULT_EDITOR); - idMemento.putString(IWorkbenchConstants.TAG_ID, editorArray[i] - .getId()); + IMemento idMemento = editorMemento.createChild(IWorkbenchConstants.TAG_DEFAULT_EDITOR); + idMemento.putString(IWorkbenchConstants.TAG_ID, editor.getId()); } } Writer writer = null; @@ -1521,21 +1521,20 @@ public class EditorRegistry extends EventManager implements IEditorRegistry, */ private IEditorDescriptor [] findRelatedObjects(IContentType type, String fileName, RelatedRegistry registry) { - List allRelated = new ArrayList(); - List nonDefaultFileEditors = new ArrayList(); - IEditorDescriptor [] related; + List allRelated = new ArrayList(); + List nonDefaultFileEditors = new ArrayList(); if (fileName != null) { FileEditorMapping mapping = getMappingFor(fileName); if (mapping != null) { // backwards compatibility - add editors flagged as "default" - related = mapping.getDeclaredDefaultEditors(); - for (int i = 0; i < related.length; i++) { + IEditorDescriptor[] related = mapping.getDeclaredDefaultEditors(); + for (IEditorDescriptor editor : related) { // we don't want to return duplicates - if (!allRelated.contains(related[i])) { + if (editor != null && !allRelated.contains(editor)) { // if it's not filtered, add it to the list - if (!WorkbenchActivityHelper.filterItem(related[i])) { - allRelated.add(related[i]); + if (!WorkbenchActivityHelper.filterItem(editor)) { + allRelated.add(editor); } } } @@ -1551,13 +1550,13 @@ public class EditorRegistry extends EventManager implements IEditorRegistry, String extension = "*" + fileName.substring(index); //$NON-NLS-1$ mapping = getMappingFor(extension); if (mapping != null) { - related = mapping.getDeclaredDefaultEditors(); - for (int i = 0; i < related.length; i++) { + IEditorDescriptor[] related = mapping.getDeclaredDefaultEditors(); + for (IEditorDescriptor editor : related) { // we don't want to return duplicates - if (!allRelated.contains(related[i])) { + if (editor != null && !allRelated.contains(editor)) { // if it's not filtered, add it to the list - if (!WorkbenchActivityHelper.filterItem(related[i])) { - allRelated.add(related[i]); + if (!WorkbenchActivityHelper.filterItem(editor)) { + allRelated.add(editor); } } } @@ -1568,7 +1567,7 @@ public class EditorRegistry extends EventManager implements IEditorRegistry, if (type != null) { // now add any objects directly related to the content type - related = registry.getRelatedObjects(type); + IEditorDescriptor[] related = registry.getRelatedObjects(type); for (int i = 0; i < related.length; i++) { // we don't want to return duplicates if (!allRelated.contains(related[i])) { @@ -1584,7 +1583,7 @@ public class EditorRegistry extends EventManager implements IEditorRegistry, if (type != null) { // now add any indirectly related objects, walking up the content type hierarchy while ((type = type.getBaseType()) != null) { - related = registry.getRelatedObjects(type); + IEditorDescriptor[] related = registry.getRelatedObjects(type); for (int i = 0; i < related.length; i++) { // we don't want to return duplicates if (!allRelated.contains(related[i])) { @@ -1598,15 +1597,13 @@ public class EditorRegistry extends EventManager implements IEditorRegistry, } // add all non-default editors to the list - for (Iterator i = nonDefaultFileEditors.iterator(); i.hasNext();) { - IEditorDescriptor editor = (IEditorDescriptor) i.next(); - if (!allRelated.contains(editor) && !WorkbenchActivityHelper.filterItem(editor)) { + for (IEditorDescriptor editor : nonDefaultFileEditors) { + if (editor != null && !allRelated.contains(editor) && !WorkbenchActivityHelper.filterItem(editor)) { allRelated.add(editor); } } - return (IEditorDescriptor []) allRelated.toArray(new IEditorDescriptor [allRelated - .size()]); + return allRelated.toArray(new IEditorDescriptor[allRelated.size()]); } /** diff --git a/tests/org.eclipse.ui.tests/Eclipse UI Tests/org/eclipse/ui/tests/api/ApiTestSuite.java b/tests/org.eclipse.ui.tests/Eclipse UI Tests/org/eclipse/ui/tests/api/ApiTestSuite.java index 0e92aac..b71b14e 100644 --- a/tests/org.eclipse.ui.tests/Eclipse UI Tests/org/eclipse/ui/tests/api/ApiTestSuite.java +++ b/tests/org.eclipse.ui.tests/Eclipse UI Tests/org/eclipse/ui/tests/api/ApiTestSuite.java @@ -10,15 +10,16 @@ *******************************************************************************/ package org.eclipse.ui.tests.api; -import junit.framework.Test; -import junit.framework.TestSuite; - import org.eclipse.ui.tests.api.workbenchpart.ArbitraryPropertyTest; import org.eclipse.ui.tests.api.workbenchpart.LifecycleViewTest; import org.eclipse.ui.tests.api.workbenchpart.OverriddenTitleTest; import org.eclipse.ui.tests.api.workbenchpart.RawIViewPartTest; import org.eclipse.ui.tests.api.workbenchpart.ViewPartTitleTest; import org.eclipse.ui.tests.ide.api.FileEditorInputTest; +import org.eclipse.ui.tests.ide.api.IDETest; + +import junit.framework.Test; +import junit.framework.TestSuite; /** * Test all areas of the UI API. @@ -76,6 +77,7 @@ public class ApiTestSuite extends TestSuite { addTest(new TestSuite(UIJobTest.class)); addTest(new TestSuite(Bug75118Test.class)); addTest(new TestSuite(FileEditorInputTest.class)); + addTest(new TestSuite(IDETest.class)); addTest(new TestSuite(IEditorMatchingStrategyTest.class)); addTest(new TestSuite(XMLMementoTest.class)); //addTest(new TestSuite(IWorkbenchPartTestableTests.class)); diff --git a/tests/org.eclipse.ui.tests/Eclipse UI Tests/org/eclipse/ui/tests/ide/api/IDETest.java b/tests/org.eclipse.ui.tests/Eclipse UI Tests/org/eclipse/ui/tests/ide/api/IDETest.java new file mode 100644 index 0000000..d4c574f --- /dev/null +++ b/tests/org.eclipse.ui.tests/Eclipse UI Tests/org/eclipse/ui/tests/ide/api/IDETest.java @@ -0,0 +1,122 @@ +/******************************************************************************* + * Copyright (c) 2015 Andrey Loskutov. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Andrey Loskutov - initial API and implementation + *******************************************************************************/ +package org.eclipse.ui.tests.ide.api; + +import java.util.Arrays; + +import org.eclipse.core.runtime.content.IContentType; +import org.eclipse.ui.IEditorDescriptor; +import org.eclipse.ui.IEditorInput; +import org.eclipse.ui.ide.IDE; +import org.eclipse.ui.ide.IEditorAssociationOverride; +import org.eclipse.ui.internal.registry.EditorDescriptor; +import org.eclipse.ui.tests.harness.util.UITestCase; + +/** + * Tests the IDE API and behaviour. + * + * @since 3.5 + */ +public class IDETest extends UITestCase { + + public IDETest(String testName) { + super(testName); + } + + static EditorDescriptor descriptor1 = EditorDescriptor.createForProgram("echo"); + static EditorDescriptor descriptor2 = EditorDescriptor.createForProgram("ps"); + + public void testOverrideEditorAssociations() throws Exception { + IEditorDescriptor[] descriptors = new IEditorDescriptor[] { descriptor1 }; + IEditorDescriptor[] descriptors2 = IDE.overrideEditorAssociations((IEditorInput) null, null, descriptors); + assertNoNullEntries(descriptors2); + assertArrayContains(descriptors2, descriptor1, descriptor2); + + descriptors = new IEditorDescriptor[] { descriptor1 }; + descriptors2 = IDE.overrideEditorAssociations((String) null, null, descriptors); + assertNoNullEntries(descriptors2); + assertArrayContains(descriptors2, descriptor1, descriptor2); + } + + void assertNoNullEntries(Object[] arr) { + for (Object object : arr) { + assertNotNull("Null entry found in the array: " + Arrays.toString(arr), object); + } + } + + void assertArrayContains(Object[] arr, Object... entries) { + for (Object entry : entries) { + boolean found = false; + for (Object object : arr) { + if (entry == object) { + found = true; + break; + } + } + assertTrue("Entry " + entry + " is missing in the array: " + Arrays.toString(arr), found); + } + } + + @Override + protected void doSetUp() throws Exception { + super.doSetUp(); + TestOverride.returnNullEntries = true; + } + + @Override + protected void doTearDown() throws Exception { + TestOverride.returnNullEntries = false; + super.doTearDown(); + } + + public static class TestOverride implements IEditorAssociationOverride { + static boolean returnNullEntries; + + @Override + public IEditorDescriptor[] overrideEditors(IEditorInput editorInput, IContentType contentType, + IEditorDescriptor[] editorDescriptors) { + if (returnNullEntries) { + IEditorDescriptor[] descriptors = new IEditorDescriptor[editorDescriptors.length + 2]; + System.arraycopy(editorDescriptors, 0, descriptors, 2, editorDescriptors.length); + descriptors[0] = null; + descriptors[1] = descriptor2; + return descriptors; + } + return editorDescriptors; + } + + @Override + public IEditorDescriptor[] overrideEditors(String fileName, IContentType contentType, + IEditorDescriptor[] editorDescriptors) { + if (returnNullEntries) { + IEditorDescriptor[] descriptors = new IEditorDescriptor[editorDescriptors.length + 2]; + System.arraycopy(editorDescriptors, 0, descriptors, 2, editorDescriptors.length); + descriptors[1] = descriptor2; + descriptors[0] = null; + return descriptors; + } + return editorDescriptors; + } + + @Override + public IEditorDescriptor overrideDefaultEditor(IEditorInput editorInput, IContentType contentType, + IEditorDescriptor editorDescriptor) { + return editorDescriptor; + } + + @Override + public IEditorDescriptor overrideDefaultEditor(String fileName, IContentType contentType, + IEditorDescriptor editorDescriptor) { + return editorDescriptor; + } + + } +} diff --git a/tests/org.eclipse.ui.tests/plugin.xml b/tests/org.eclipse.ui.tests/plugin.xml index f3a0910..7378dbf 100644 --- a/tests/org.eclipse.ui.tests/plugin.xml +++ b/tests/org.eclipse.ui.tests/plugin.xml @@ -4386,5 +4386,12 @@ + + + + -- 2.7.4