Bug 560065 - Quickfix to open colliding managed version's location.

Change-Id: I92b2fd65fb97ef633a12cda5c5a3a267d12699ee
Signed-off-by: Till Brychcy <register.eclipse@brychcy.de>
diff --git a/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/PomHyperlinkDetector.java b/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/PomHyperlinkDetector.java
index 95633fd..ce06e0e 100644
--- a/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/PomHyperlinkDetector.java
+++ b/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/PomHyperlinkDetector.java
@@ -24,17 +24,11 @@
 import static org.eclipse.m2e.core.ui.internal.editing.PomEdits.VERSION;
 
 import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Iterator;
 import java.util.List;
 
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
 import org.w3c.dom.Element;
 import org.w3c.dom.Node;
 import org.w3c.dom.NodeList;
@@ -51,7 +45,6 @@
 import org.eclipse.core.runtime.Path;
 import org.eclipse.core.runtime.Status;
 import org.eclipse.core.runtime.jobs.Job;
-import org.eclipse.jface.dialogs.MessageDialog;
 import org.eclipse.jface.text.BadLocationException;
 import org.eclipse.jface.text.IDocument;
 import org.eclipse.jface.text.IRegion;
@@ -64,19 +57,8 @@
 import org.eclipse.jface.text.source.IAnnotationModel;
 import org.eclipse.jface.text.source.ISourceViewer;
 import org.eclipse.osgi.util.NLS;
-import org.eclipse.swt.widgets.Display;
-import org.eclipse.ui.IEditorInput;
-import org.eclipse.ui.IEditorPart;
-import org.eclipse.ui.IWorkbenchPage;
-import org.eclipse.ui.IWorkbenchWindow;
-import org.eclipse.ui.PartInitException;
-import org.eclipse.ui.PlatformUI;
-import org.eclipse.ui.forms.editor.FormEditor;
-import org.eclipse.ui.ide.IDE;
 import org.eclipse.ui.texteditor.MarkerAnnotation;
 import org.eclipse.wst.sse.core.internal.provisional.IndexedRegion;
-import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocument;
-import org.eclipse.wst.sse.ui.StructuredTextEditor;
 
 import org.apache.maven.model.Build;
 import org.apache.maven.model.Dependency;
@@ -89,7 +71,7 @@
 
 import org.eclipse.m2e.core.internal.IMavenConstants;
 import org.eclipse.m2e.core.ui.internal.actions.OpenPomAction;
-import org.eclipse.m2e.core.ui.internal.actions.OpenPomAction.MavenPathStorageEditorInput;
+import org.eclipse.m2e.editor.xml.internal.XMLEditorUtility;
 import org.eclipse.m2e.editor.xml.internal.Messages;
 import org.eclipse.m2e.editor.xml.internal.XmlUtils;
 
@@ -99,8 +81,6 @@
  * @author Milos Kleint
  */
 public class PomHyperlinkDetector implements IHyperlinkDetector {
-  private static final Logger log = LoggerFactory.getLogger(PomHyperlinkDetector.class);
-
   public IHyperlink[] detectHyperlinks(final ITextViewer textViewer, final IRegion region,
       boolean canShowMultipleHyperlinks) {
     if(region == null || textViewer == null) {
@@ -256,7 +236,7 @@
             File file = XmlUtils.fileForInputLocation(openLocation, mavprj);
             if(file != null) {
               IFileStore fileStore = EFS.getLocalFileSystem().getStore(file.toURI());
-              openXmlEditor(fileStore, openLocation.getLineNumber(), openLocation.getColumnNumber(),
+              XMLEditorUtility.openXmlEditor(fileStore, openLocation.getLineNumber(), openLocation.getColumnNumber(),
                   openLocation.getSource().getModelId());
             }
           }
@@ -394,7 +374,7 @@
             File file = XmlUtils.fileForInputLocation(location, mavprj);
             if(file != null) {
               IFileStore fileStore = EFS.getLocalFileSystem().getStore(file.toURI());
-              openXmlEditor(fileStore, location.getLineNumber(), location.getColumnNumber(),
+              XMLEditorUtility.openXmlEditor(fileStore, location.getLineNumber(), location.getColumnNumber(),
                   location.getSource().getModelId());
             }
           }
@@ -472,7 +452,7 @@
 //          String hint = marker.getAttribute(IMavenConstants.MARKER_ATTR_EDITOR_HINT, null);
 //          if (IMavenConstants.EDITOR_HINT_NOT_COVERED_MOJO_EXECUTION.equals(hint)) {
 //          }
-          openXmlEditor(fileStore, row, column, name);
+          XMLEditorUtility.openXmlEditor(fileStore, row, column, name);
         }
       }
     };
@@ -541,7 +521,7 @@
       }
 
       public void open() {
-        openXmlEditor(fileStore);
+        XMLEditorUtility.openXmlEditor(fileStore);
       }
     };
   }
@@ -629,102 +609,6 @@
     return null;
   }
 
-  private void openXmlEditor(final IFileStore fileStore) {
-    openXmlEditor(fileStore, -1, -1, fileStore.getName());
-  }
-
-  private static void openXmlEditor(final IFileStore fileStore, int line, int column, String name) {
-    assert fileStore != null;
-    IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
-    if(window != null) {
-      IWorkbenchPage page = window.getActivePage();
-      if(page != null) {
-        try {
-          if(!fileStore.getName().endsWith(".pom")) { //.pom means stuff from local repository?
-            IEditorPart part = IDE.openEditorOnFileStore(page, fileStore);
-            reveal(selectEditorPage(part), line, column);
-          } else {
-            //we need special EditorInput for stuff from repository
-            name = name + ".pom"; //$NON-NLS-1$
-            File file = new File(fileStore.toURI());
-            try {
-              IEditorInput input = new MavenPathStorageEditorInput(name, name, file.getAbsolutePath(),
-                  readStream(new FileInputStream(file)));
-              IEditorPart part = OpenPomAction.openEditor(input, name);
-              reveal(selectEditorPage(part), line, column);
-            } catch(IOException e) {
-              log.error("failed opening editor", e);
-            }
-          }
-        } catch(PartInitException e) {
-          MessageDialog.openInformation(Display.getDefault().getActiveShell(), //
-              Messages.PomHyperlinkDetector_error_title,
-              NLS.bind(Messages.PomHyperlinkDetector_error_message, fileStore, e.toString()));
-
-        }
-      }
-    }
-  }
-
-  private static StructuredTextEditor selectEditorPage(IEditorPart part) {
-    if(part == null) {
-      return null;
-    }
-    if(part instanceof FormEditor) {
-      FormEditor ed = (FormEditor) part;
-      ed.setActivePage(null); //null means source, always or just in the case of MavenPomEditor?
-      if(ed.getActiveEditor() instanceof StructuredTextEditor) {
-        return (StructuredTextEditor) ed.getActiveEditor();
-      }
-    }
-    return null;
-  }
-
-  private static void reveal(StructuredTextEditor structured, int line, int column) {
-    if(structured == null || line < 0 || column < 0) {
-      return;
-    }
-    IDocument doc = structured.getTextViewer().getDocument();
-    if(doc instanceof IStructuredDocument) {
-      IStructuredDocument document = (IStructuredDocument) doc;
-      try {
-        int offset = document.getLineOffset(line - 1);
-        structured.selectAndReveal(offset + column - 1, 0);
-      } catch(BadLocationException e) {
-        log.error("failed selecting part of editor", e);
-      }
-    }
-  }
-
-  /**
-   * duplicate of OpenPomAction method
-   * 
-   * @param is
-   * @return
-   * @throws IOException
-   */
-  private static byte[] readStream(InputStream is) throws IOException {
-    byte[] b = new byte[is.available()];
-    int len = 0;
-    while(true) {
-      int n = is.read(b, len, b.length - len);
-      if(n == -1) {
-        if(len < b.length) {
-          byte[] c = new byte[len];
-          System.arraycopy(b, 0, c, 0, len);
-          b = c;
-        }
-        return b;
-      }
-      len += n;
-      if(len == b.length) {
-        byte[] c = new byte[b.length + 1000];
-        System.arraycopy(b, 0, c, 0, len);
-        b = c;
-      }
-    }
-  }
-
   public static class ExpressionRegion implements IRegion {
 
     final String property;
diff --git a/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/internal/MarkerLocationService.java b/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/internal/MarkerLocationService.java
index 6d1ed6f..d90bb27 100644
--- a/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/internal/MarkerLocationService.java
+++ b/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/internal/MarkerLocationService.java
@@ -21,6 +21,7 @@
 import static org.eclipse.m2e.core.ui.internal.editing.PomEdits.getTextValue;
 import static org.eclipse.m2e.core.ui.internal.editing.PomEdits.textEquals;
 
+import java.io.File;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -53,6 +54,7 @@
 import org.apache.maven.model.Dependency;
 import org.apache.maven.model.DependencyManagement;
 import org.apache.maven.model.InputLocation;
+import org.apache.maven.model.InputLocationTracker;
 import org.apache.maven.model.Plugin;
 import org.apache.maven.model.PluginManagement;
 import org.apache.maven.project.MavenProject;
@@ -345,7 +347,7 @@
       }
     }
     //collect the managed dep ids
-    Map<String, String> managed = new HashMap<String, String>();
+    Map<String, Dependency> managed = new HashMap<String, Dependency>();
     DependencyManagement dm = mavenproject.getDependencyManagement();
     if(dm != null) {
       List<Dependency> deps = dm.getDependencies();
@@ -354,7 +356,7 @@
           if(dep.getVersion() != null) { //#335366
             //355882 use dep.getManagementKey() to prevent false positives
             //when type or classifier doesn't match 
-            managed.put(dep.getManagementKey(), dep.getVersion());
+            managed.put(dep.getManagementKey(), dep);
           }
         }
       }
@@ -371,7 +373,8 @@
         String classifier = getTextValue(findChild(dep, PomEdits.CLASSIFIER));
         String id = getDependencyKey(grpString, artString, typeString, classifier);
         if(managed.containsKey(id)) {
-          String managedVersion = managed.get(id);
+          Dependency managedDep = managed.get(id);
+          String managedVersion = managedDep == null ? null : managedDep.getVersion();
           if(version instanceof IndexedRegion) {
             IndexedRegion off = (IndexedRegion) version;
             if(lookForIgnoreMarker(document, version, off, IMavenConstants.MARKER_IGNORE_MANAGED)) {
@@ -390,6 +393,7 @@
             //add these attributes to easily and deterministically find the declaration in question
             mark.setAttribute("groupId", grpString); //$NON-NLS-1$
             mark.setAttribute("artifactId", artString); //$NON-NLS-1$
+            setManagedVersionAttributes(mark, mavenproject, managedDep);
             String profile = candidateProfile.get(dep);
             if(profile != null) {
               mark.setAttribute("profile", profile); //$NON-NLS-1$
@@ -400,6 +404,24 @@
     }
   }
 
+  private static void setManagedVersionAttributes(IMarker mark, MavenProject mavenproject,
+      InputLocationTracker dependencyOrPlugin) throws CoreException {
+    InputLocation loc = dependencyOrPlugin == null ? null : dependencyOrPlugin.getLocation("version");
+    File file = loc == null ? null : XmlUtils.fileForInputLocation(loc, mavenproject);
+
+    if(file != null) {
+      mark.setAttribute("managedVersionLocation", file.toURI().toString());
+      int lineNumber = loc != null ? loc.getLineNumber() : -1;
+      if(lineNumber > 0) {
+        mark.setAttribute("managedVersionLine", lineNumber);
+      }
+      int columnNumber = loc != null ? loc.getColumnNumber() : -1;
+      if(columnNumber > 0) {
+        mark.setAttribute("managedVersionColumn", columnNumber);
+      }
+    }
+  }
+
   private static String getDependencyKey(String groupId, String artifactId, String type, String classifier) {
     StringBuilder key = new StringBuilder(groupId).append(":").append(artifactId).append(":") //$NON-NLS-1$ //$NON-NLS-2$
         .append(type == null ? "jar" : type);//$NON-NLS-1$
@@ -460,7 +482,7 @@
       }
     }
     //collect the managed plugin ids
-    Map<String, String> managed = new HashMap<String, String>();
+    Map<String, Plugin> managed = new HashMap<String, Plugin>();
     PluginManagement pm = mavenproject.getPluginManagement();
     if(pm != null) {
       List<Plugin> plgs = pm.getPlugins();
@@ -471,7 +493,7 @@
           String modelID = loc == null ? null : (loc.getSource() == null ? null : loc.getSource().getModelId());
           if(loc != null && (modelID == null
               || !(modelID.startsWith("org.apache.maven:maven-model-builder:") && modelID.endsWith(":super-pom")))) {
-            managed.put(plg.getKey(), plg.getVersion());
+            managed.put(plg.getKey(), plg);
           }
         }
       }
@@ -489,7 +511,8 @@
       if(artString != null && versionString != null) {
         String id = Plugin.constructKey(grpString, artString);
         if(managed.containsKey(id)) {
-          String managedVersion = managed.get(id);
+          Plugin managedPlugin = managed.get(id);
+          String managedVersion = managedPlugin == null ? null : managedPlugin.getVersion();
           if(version instanceof IndexedRegion) {
             IndexedRegion off = (IndexedRegion) version;
             if(lookForIgnoreMarker(document, version, off, IMavenConstants.MARKER_IGNORE_MANAGED)) {
@@ -509,6 +532,7 @@
             //add these attributes to easily and deterministicaly find the declaration in question
             mark.setAttribute("groupId", grpString); //$NON-NLS-1$
             mark.setAttribute("artifactId", artString); //$NON-NLS-1$
+            setManagedVersionAttributes(mark, mavenproject, managedPlugin);
             String profile = candidateProfile.get(dep);
             if(profile != null) {
               mark.setAttribute("profile", profile); //$NON-NLS-1$
diff --git a/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/internal/Messages.java b/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/internal/Messages.java
index 584bdb9..3a3403b 100644
--- a/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/internal/Messages.java
+++ b/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/internal/Messages.java
@@ -70,6 +70,10 @@
 
   public static String MavenMarkerResolution_schema_label;
 
+  public static String MavenMarkerResolution_openManaged_label;
+
+  public static String MavenMarkerResolution_openManaged_description;
+
   public static String PomContentAssistProcessor_insert_relPath_title;
 
   public static String PomContentAssistProcessor_set_relPath_title;
diff --git a/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/internal/XMLEditorUtility.java b/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/internal/XMLEditorUtility.java
new file mode 100644
index 0000000..fe2e92b
--- /dev/null
+++ b/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/internal/XMLEditorUtility.java
@@ -0,0 +1,145 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2020 Sonatype, Inc. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *      Sonatype, Inc. - initial API and implementation (code moved here from PomHyperlinkDetector).
+ * 
+ *******************************************************************************/
+
+package org.eclipse.m2e.editor.xml.internal;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.eclipse.core.filesystem.IFileStore;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.forms.editor.FormEditor;
+import org.eclipse.ui.ide.IDE;
+import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocument;
+import org.eclipse.wst.sse.ui.StructuredTextEditor;
+
+import org.eclipse.m2e.core.ui.internal.actions.OpenPomAction;
+import org.eclipse.m2e.core.ui.internal.actions.OpenPomAction.MavenPathStorageEditorInput;
+
+
+public class XMLEditorUtility {
+  private static final Logger log = LoggerFactory.getLogger(XMLEditorUtility.class);
+
+  public static void openXmlEditor(final IFileStore fileStore) {
+    openXmlEditor(fileStore, -1, -1, fileStore.getName());
+  }
+
+  public static void openXmlEditor(final IFileStore fileStore, int line, int column, String name) {
+    assert fileStore != null;
+    IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
+    if(window != null) {
+      IWorkbenchPage page = window.getActivePage();
+      if(page != null) {
+        try {
+          if(!fileStore.getName().endsWith(".pom")) { //.pom means stuff from local repository?
+            IEditorPart part = IDE.openEditorOnFileStore(page, fileStore);
+            reveal(selectEditorPage(part), line, column);
+          } else {
+            //we need special EditorInput for stuff from repository
+            name = name + ".pom"; //$NON-NLS-1$
+            File file = new File(fileStore.toURI());
+            try {
+              IEditorInput input = new MavenPathStorageEditorInput(name, name, file.getAbsolutePath(),
+                  readStream(new FileInputStream(file)));
+              IEditorPart part = OpenPomAction.openEditor(input, name);
+              reveal(selectEditorPage(part), line, column);
+            } catch(IOException e) {
+              log.error("failed opening editor", e);
+            }
+          }
+        } catch(PartInitException e) {
+          MessageDialog.openInformation(Display.getDefault().getActiveShell(), //
+              Messages.PomHyperlinkDetector_error_title,
+              NLS.bind(Messages.PomHyperlinkDetector_error_message, fileStore, e.toString()));
+
+        }
+      }
+    }
+  }
+
+  private static StructuredTextEditor selectEditorPage(IEditorPart part) {
+    if(part == null) {
+      return null;
+    }
+    if(part instanceof FormEditor) {
+      FormEditor ed = (FormEditor) part;
+      ed.setActivePage(null); //null means source, always or just in the case of MavenPomEditor?
+      if(ed.getActiveEditor() instanceof StructuredTextEditor) {
+        return (StructuredTextEditor) ed.getActiveEditor();
+      }
+    }
+    return null;
+  }
+
+  private static void reveal(StructuredTextEditor structured, int line, int column) {
+    if(structured == null || line < 0 || column < 0) {
+      return;
+    }
+    IDocument doc = structured.getTextViewer().getDocument();
+    if(doc instanceof IStructuredDocument) {
+      IStructuredDocument document = (IStructuredDocument) doc;
+      try {
+        int offset = document.getLineOffset(line - 1);
+        structured.selectAndReveal(offset + column - 1, 0);
+      } catch(BadLocationException e) {
+        log.error("failed selecting part of editor", e);
+      }
+    }
+  }
+
+  /**
+   * duplicate of OpenPomAction method
+   * 
+   * @param is
+   * @return
+   * @throws IOException
+   */
+  private static byte[] readStream(InputStream is) throws IOException {
+    byte[] b = new byte[is.available()];
+    int len = 0;
+    while(true) {
+      int n = is.read(b, len, b.length - len);
+      if(n == -1) {
+        if(len < b.length) {
+          byte[] c = new byte[len];
+          System.arraycopy(b, 0, c, 0, len);
+          b = c;
+        }
+        return b;
+      }
+      len += n;
+      if(len == b.length) {
+        byte[] c = new byte[b.length + 1000];
+        System.arraycopy(b, 0, c, 0, len);
+        b = c;
+      }
+    }
+  }
+
+}
diff --git a/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/internal/markers/MavenMarkerResolutionGenerator.java b/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/internal/markers/MavenMarkerResolutionGenerator.java
index 8c743f0..d8ae650 100644
--- a/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/internal/markers/MavenMarkerResolutionGenerator.java
+++ b/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/internal/markers/MavenMarkerResolutionGenerator.java
@@ -50,11 +50,13 @@
       }
       if(isDependencyVersionOverride(hint)) {
         return new IMarkerResolution[] {new ManagedVersionRemovalResolution(marker, true),
-            new IgnoreWarningResolution(marker, IMavenConstants.MARKER_IGNORE_MANAGED)};
+            new IgnoreWarningResolution(marker, IMavenConstants.MARKER_IGNORE_MANAGED),
+            new OpenManagedVersionDefinitionResolution(marker)};
       }
       if(isPluginVersionOverride(hint)) {
         return new IMarkerResolution[] {new ManagedVersionRemovalResolution(marker, false),
-            new IgnoreWarningResolution(marker, IMavenConstants.MARKER_IGNORE_MANAGED)};
+            new IgnoreWarningResolution(marker, IMavenConstants.MARKER_IGNORE_MANAGED),
+            new OpenManagedVersionDefinitionResolution(marker)};
       }
       if(hint.equals(IMavenConstants.EDITOR_HINT_NOT_COVERED_MOJO_EXECUTION)) {
         return new IMarkerResolution[] {new LifecycleMappingResolution(marker, PluginExecutionAction.ignore),
diff --git a/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/internal/markers/OpenManagedVersionDefinitionResolution.java b/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/internal/markers/OpenManagedVersionDefinitionResolution.java
new file mode 100644
index 0000000..8dea3e5
--- /dev/null
+++ b/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/internal/markers/OpenManagedVersionDefinitionResolution.java
@@ -0,0 +1,89 @@
+/*******************************************************************************
+ * Copyright (c) 2020 Till Brychcy 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
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *      Till Brychcy - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.editor.xml.internal.markers;
+
+import java.net.URI;
+import java.util.List;
+
+import org.w3c.dom.Element;
+
+import org.eclipse.core.filesystem.EFS;
+import org.eclipse.core.filesystem.IFileStore;
+import org.eclipse.core.resources.IMarker;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.ide.IDE.SharedImages;
+import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocument;
+
+import org.eclipse.m2e.editor.xml.internal.XMLEditorUtility;
+import org.eclipse.m2e.editor.xml.internal.Messages;
+
+
+@SuppressWarnings("restriction")
+public class OpenManagedVersionDefinitionResolution extends AbstractPomProblemResolution {
+
+  public OpenManagedVersionDefinitionResolution(IMarker marker) {
+    super(marker);
+  }
+
+  @Override
+  public int getOrder() {
+    return 90;
+  }
+
+  @Override
+  public boolean canFix(String editorHint) {
+    try {
+      return getMarker().getAttribute("managedVersionLocation") != null;
+    } catch(CoreException ex) {
+      return false;
+    }
+  }
+
+  @Override
+  public String getLabel() {
+    return Messages.MavenMarkerResolution_openManaged_label;
+  }
+
+  @Override
+  public Image getImage() {
+    return PlatformUI.getWorkbench().getSharedImages().getImage(SharedImages.IMG_OPEN_MARKER);
+  }
+
+  @Override
+  public String getDescription() {
+    try {
+      String locationURIString = (String) getMarker().getAttribute("managedVersionLocation");
+      return NLS.bind(Messages.MavenMarkerResolution_openManaged_description, locationURIString);
+    } catch(CoreException ex) {
+      // ignore
+    }
+    return null;
+  }
+
+  @Override
+  protected void processFix(IStructuredDocument doc, Element root, List<IMarker> markers) {
+    try {
+      String locationURIString = (String) getMarker().getAttribute("managedVersionLocation");
+      if(locationURIString != null) {
+        IFileStore fileStore = EFS.getLocalFileSystem().getStore(new URI(locationURIString));
+        int lineNumber = getMarker().getAttribute("managedVersionLine", -1);
+        int columnNumber = Math.max(1, getMarker().getAttribute("managedVersionColumn", -1));
+        XMLEditorUtility.openXmlEditor(fileStore, lineNumber, columnNumber, fileStore.getName());
+      }
+    } catch(Exception ex) {
+      // ignore
+    }
+  }
+}
diff --git a/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/internal/messages.properties b/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/internal/messages.properties
index 989081e..effc6e2 100644
--- a/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/internal/messages.properties
+++ b/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/internal/messages.properties
@@ -23,6 +23,8 @@
 MavenMarkerResolution_error=Unable to apply the quick fix. The file may have unsaved changes that invalidate the current quick fix.
 MavenMarkerResolution_error_title=Error
 MavenMarkerResolution_schema_label=Add Schema information to the specified pom.xml
+MavenMarkerResolution_openManaged_label=Open declaration of managed version
+MavenMarkerResolution_openManaged_description=Open {0}
 PomContentAssistProcessor_insert_relPath_title=Insert relativePath pointing to {0}
 PomContentAssistProcessor_set_relPath_title=Set relativePath to {0}
 PomHyperlinkDetector_error_message=Can't open editor for {0}\n{1}