[221762] GoTo Matching Tag throws NPE with mismatched tags.
diff --git a/bundles/org.eclipse.wst.xml.ui/plugin.properties b/bundles/org.eclipse.wst.xml.ui/plugin.properties
index 8007594..c529b7f 100644
--- a/bundles/org.eclipse.wst.xml.ui/plugin.properties
+++ b/bundles/org.eclipse.wst.xml.ui/plugin.properties
@@ -90,4 +90,5 @@
 ActionDefinition.previousSibling.name=Go to Previous Sibling
 ActionDefinition.previousSibling.description=Go to Previous Sibling
 ActionDefinition.gotoMatchingTag.name=Go to Matching Tag
-ActionDefinition.gotoMatchingTag.description=Go to Matching Tag
\ No newline at end of file
+ActionDefinition.gotoMatchingTag.description=Go to Matching Tag
+MatchingTagPreference.label=Matching Tags
\ No newline at end of file
diff --git a/bundles/org.eclipse.wst.xml.ui/plugin.xml b/bundles/org.eclipse.wst.xml.ui/plugin.xml
index 73a7a58..0780f9d 100644
--- a/bundles/org.eclipse.wst.xml.ui/plugin.xml
+++ b/bundles/org.eclipse.wst.xml.ui/plugin.xml
@@ -387,6 +387,31 @@
 		</validator>
 	</extension>
 	
+   <extension point="org.eclipse.ui.editors.annotationTypes">
+      <type name="org.eclipse.wst.xml.ui.matching.tag"/>
+   </extension>
+   <extension point="org.eclipse.ui.editors.markerAnnotationSpecification">
+      <specification
+      		includeOnPreferencePage="false"
+            colorPreferenceValue="212,212,212"
+            annotationType="org.eclipse.wst.xml.ui.matching.tag"
+            colorPreferenceKey="matchingTagIndicationColor"
+            presentationLayer="4"
+            label="%MatchingTagPreference.label"
+            icon="icons/full/obj16/tag-generic.gif"
+            textPreferenceValue="false"
+            textPreferenceKey="matchingTagIndication"
+            highlightPreferenceKey="matchingTagHighlight"
+            highlightPreferenceValue="true"
+            verticalRulerPreferenceKey="matchingTagVerticalRuler"
+            verticalRulerPreferenceValue="false"
+            overviewRulerPreferenceKey="matchingTagIndicationInOverviewRuler"
+            overviewRulerPreferenceValue="true"
+            textStylePreferenceKey="matchingTagTextStyle"
+			textStylePreferenceValue="NONE">
+      </specification>
+   </extension>
+
 	<!--======================================================================================-->
 	<!-- Document provider for ExternalFileEditorInput                                        -->
 	<!--======================================================================================-->
diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/internal/actions/GoToMatchingTagAction.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/internal/actions/GoToMatchingTagAction.java
index 3651e64..c0ae763 100644
--- a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/internal/actions/GoToMatchingTagAction.java
+++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/internal/actions/GoToMatchingTagAction.java
@@ -11,28 +11,57 @@
 
 package org.eclipse.wst.xml.ui.internal.actions;
 
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
 import java.util.ResourceBundle;
 
 import org.eclipse.jface.text.ITextSelection;
+import org.eclipse.jface.text.Position;
 import org.eclipse.jface.text.TextSelection;
+import org.eclipse.jface.text.source.Annotation;
+import org.eclipse.jface.text.source.IAnnotationModel;
+import org.eclipse.jface.text.source.IAnnotationModelExtension;
+import org.eclipse.jface.viewers.IPostSelectionProvider;
 import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.ISelectionProvider;
 import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
 import org.eclipse.swt.widgets.Event;
+import org.eclipse.ui.texteditor.IDocumentProvider;
 import org.eclipse.ui.texteditor.ITextEditor;
 import org.eclipse.ui.texteditor.TextEditorAction;
 import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocumentRegion;
+import org.eclipse.wst.sse.core.internal.provisional.text.ITextRegion;
 import org.eclipse.wst.xml.core.internal.provisional.document.IDOMNode;
 import org.w3c.dom.Attr;
 import org.w3c.dom.Node;
 
 /**
  * Moves the cursor to the end tag if it is in a start tag, and vice versa.
+ * Also updates the matching tag annotation using the active editor.
  * 
  * @author nitin
  * 
  */
 class GoToMatchingTagAction extends TextEditorAction {
 
+	private class UpdateListener implements ISelectionChangedListener {
+		public void selectionChanged(SelectionChangedEvent event) {
+			updateFor(event.getSelection());
+		}
+	}
+
+	/**
+	 * 
+	 */
+	private static final String ANNOTATION_TYPE = "org.eclipse.wst.xml.ui.matching.tag";
+	private ISelectionChangedListener fUpdateListener = null;
+	boolean DEBUG = false;
+
 	/**
 	 * @param bundle
 	 * @param prefix
@@ -41,6 +70,45 @@
 	 */
 	GoToMatchingTagAction(ResourceBundle bundle, String prefix, ITextEditor editor) {
 		super(bundle, prefix, editor);
+		fUpdateListener = new UpdateListener();
+	}
+
+	void removeAnnotation(boolean allMatching) {
+		ITextEditor textEditor = getTextEditor();
+		if (textEditor == null) {
+			if (DEBUG) {
+				System.out.println("no editor");
+			}
+			return;
+		}
+		IDocumentProvider documentProvider = textEditor.getDocumentProvider();
+		if (documentProvider == null) {
+			if (DEBUG) {
+				System.out.println("no document provider");
+			}
+			return;
+		}
+		IAnnotationModel annotationModel = documentProvider.getAnnotationModel(textEditor.getEditorInput());
+		if (annotationModel == null) {
+			if (DEBUG) {
+				System.out.println("no annotation model");
+			}
+			return;
+		}
+
+		Iterator annotationIterator = annotationModel.getAnnotationIterator();
+		while (annotationIterator.hasNext()) {
+			Annotation annotation = (Annotation) annotationIterator.next();
+			if (ANNOTATION_TYPE.equals(annotation.getType())) {
+				annotation.markDeleted(true);
+				annotationIterator.remove();
+				if (DEBUG) {
+					System.out.println("removed " + annotation);
+				}
+				if (!allMatching)
+					break;
+			}
+		}
 	}
 
 	/*
@@ -66,15 +134,19 @@
 				int targetOffset = -1;
 				if (o instanceof IDOMNode) {
 					IDOMNode node = (IDOMNode) o;
-					if (node.getStartStructuredDocumentRegion().containsOffset(offset)) {
+					IStructuredDocumentRegion startStructuredDocumentRegion = node.getStartStructuredDocumentRegion();
+					if (startStructuredDocumentRegion != null && startStructuredDocumentRegion.containsOffset(offset)) {
 						matchRegion = ((IDOMNode) o).getEndStructuredDocumentRegion();
 						if (matchRegion != null)
 							targetOffset = matchRegion.getStartOffset() + 2;
 					}
-					else if (node.getEndStructuredDocumentRegion().containsOffset(offset)) {
-						matchRegion = ((IDOMNode) o).getStartStructuredDocumentRegion();
-						if (matchRegion != null)
-							targetOffset = matchRegion.getStartOffset() + 1;
+					else {
+						IStructuredDocumentRegion endStructuredDocumentRegion = node.getEndStructuredDocumentRegion();
+						if (endStructuredDocumentRegion != null && endStructuredDocumentRegion.containsOffset(offset)) {
+							matchRegion = ((IDOMNode) o).getStartStructuredDocumentRegion();
+							if (matchRegion != null)
+								targetOffset = matchRegion.getStartOffset() + 1;
+						}
 					}
 				}
 
@@ -85,8 +157,131 @@
 		}
 	}
 
-	public void update() {
-		setEnabled(true);
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see org.eclipse.ui.texteditor.TextEditorAction#setEditor(org.eclipse.ui.texteditor.ITextEditor)
+	 */
+	public void setEditor(ITextEditor editor) {
+		ITextEditor textEditor = getTextEditor();
+		if (textEditor != null) {
+			removeAnnotation(true);
+
+			ISelectionProvider selectionProvider = textEditor.getSelectionProvider();
+			if (selectionProvider instanceof IPostSelectionProvider) {
+				((IPostSelectionProvider) selectionProvider).removePostSelectionChangedListener(fUpdateListener);
+			}
+		}
+		super.setEditor(editor);
+		if (editor != null) {
+			ISelectionProvider selectionProvider = editor.getSelectionProvider();
+			if (selectionProvider instanceof IPostSelectionProvider) {
+				((IPostSelectionProvider) selectionProvider).addPostSelectionChangedListener(fUpdateListener);
+			}
+
+			updateFor(selectionProvider.getSelection());
+		}
 	}
 
+	public void update() {
+		setEnabled(true);
+
+	}
+
+	void updateFor(ISelection selection) {
+		ITextEditor textEditor = getTextEditor();
+		if (textEditor == null) {
+			if (DEBUG) {
+				System.out.println("no editor");
+			}
+			return;
+		}
+		IDocumentProvider documentProvider = textEditor.getDocumentProvider();
+		if (documentProvider == null) {
+			if (DEBUG) {
+				System.out.println("no document provider");
+			}
+			return;
+		}
+		IAnnotationModel annotationModel = documentProvider.getAnnotationModel(textEditor.getEditorInput());
+		if (annotationModel == null || !(annotationModel instanceof IAnnotationModelExtension)) {
+			if (DEBUG) {
+				System.out.println("no annotation model");
+			}
+			return;
+		}
+
+		List oldAnnotations = new ArrayList(2);
+		Iterator annotationIterator = annotationModel.getAnnotationIterator();
+		while (annotationIterator.hasNext()) {
+			Annotation annotation = (Annotation) annotationIterator.next();
+			if (ANNOTATION_TYPE.equals(annotation.getType())) {
+				annotation.markDeleted(true);
+				if (DEBUG) {
+					System.out.println("removing " + annotation);
+				}
+				oldAnnotations.add(annotation);
+			}
+		}
+
+		Map newAnnotations = new HashMap();
+		if (!selection.isEmpty() && selection instanceof IStructuredSelection && selection instanceof ITextSelection) {
+			Object o = ((IStructuredSelection) selection).getFirstElement();
+			if (o instanceof IDOMNode) {
+				int offset = ((ITextSelection) selection).getOffset();
+				IStructuredDocumentRegion matchRegion = null;
+				if (((Node) o).getNodeType() == Node.ATTRIBUTE_NODE) {
+					o = ((Attr) o).getOwnerElement();
+				}
+
+				Position pStart = null;
+				Position pEnd = null;
+				if (o instanceof IDOMNode) {
+					IDOMNode node = (IDOMNode) o;
+					IStructuredDocumentRegion startStructuredDocumentRegion = node.getStartStructuredDocumentRegion();
+					if (startStructuredDocumentRegion != null && startStructuredDocumentRegion.containsOffset(offset)) {
+						if (startStructuredDocumentRegion.getNumberOfRegions() > 1) {
+							ITextRegion nameRegion = startStructuredDocumentRegion.getRegions().get(1);
+							pStart = new Position(startStructuredDocumentRegion.getStartOffset(nameRegion), nameRegion.getTextLength());
+						}
+						matchRegion = ((IDOMNode) o).getEndStructuredDocumentRegion();
+						if (matchRegion != null && matchRegion.getNumberOfRegions() > 1) {
+							ITextRegion nameRegion = matchRegion.getRegions().get(1);
+							pEnd = new Position(matchRegion.getStartOffset(nameRegion), nameRegion.getTextLength());
+						}
+					}
+					else {
+						IStructuredDocumentRegion endStructuredDocumentRegion = node.getEndStructuredDocumentRegion();
+						if (endStructuredDocumentRegion != null && endStructuredDocumentRegion.containsOffset(offset)) {
+							if (endStructuredDocumentRegion.getNumberOfRegions() > 1) {
+								ITextRegion nameRegion = endStructuredDocumentRegion.getRegions().get(1);
+								pEnd = new Position(endStructuredDocumentRegion.getStartOffset(nameRegion), nameRegion.getTextLength());
+							}
+							matchRegion = ((IDOMNode) o).getStartStructuredDocumentRegion();
+							if (matchRegion != null && matchRegion.getNumberOfRegions() > 1) {
+								ITextRegion nameRegion = matchRegion.getRegions().get(1);
+								pStart = new Position(matchRegion.getStartOffset(nameRegion), nameRegion.getTextLength());
+							}
+						}
+					}
+				}
+				if (pStart != null && pEnd != null) {
+					Annotation annotation = new Annotation(false);
+					annotation.setType(ANNOTATION_TYPE);
+					newAnnotations.put(annotation, pStart);
+					if (DEBUG) {
+						System.out.println("adding " + annotation);
+					}
+
+					annotation = new Annotation(false);
+					annotation.setType(ANNOTATION_TYPE);
+					newAnnotations.put(annotation, pEnd);
+					if (DEBUG) {
+						System.out.println("adding " + annotation);
+					}
+				}
+			}
+		}
+		((IAnnotationModelExtension) annotationModel).replaceAnnotations((Annotation[]) oldAnnotations.toArray(new Annotation[oldAnnotations.size()]), newAnnotations);
+	}
 }