[275733] Markup Validation for JSPs is strict on HTML attributes
diff --git a/bundles/org.eclipse.jst.jsp.ui/plugin.xml b/bundles/org.eclipse.jst.jsp.ui/plugin.xml index 17b97dd..32449c6 100644 --- a/bundles/org.eclipse.jst.jsp.ui/plugin.xml +++ b/bundles/org.eclipse.jst.jsp.ui/plugin.xml
@@ -150,7 +150,7 @@ <extension point="org.eclipse.wst.sse.ui.sourcevalidation"> <validator scope="total" - class="org.eclipse.wst.xml.ui.internal.validation.MarkupValidator" + class="org.eclipse.jst.jsp.ui.internal.validation.JSPMarkupValidator" id="org.eclipse.jst.jsp.ui.internal.validation.markupvalidator"> <contentTypeIdentifier id="org.eclipse.jst.jsp.core.jspsource">
diff --git a/bundles/org.eclipse.jst.jsp.ui/src/org/eclipse/jst/jsp/ui/internal/validation/JSPMarkupValidator.java b/bundles/org.eclipse.jst.jsp.ui/src/org/eclipse/jst/jsp/ui/internal/validation/JSPMarkupValidator.java new file mode 100644 index 0000000..84acd78 --- /dev/null +++ b/bundles/org.eclipse.jst.jsp.ui/src/org/eclipse/jst/jsp/ui/internal/validation/JSPMarkupValidator.java
@@ -0,0 +1,163 @@ +/******************************************************************************* + * Copyright (c) 2009 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 + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * + *******************************************************************************/ +package org.eclipse.jst.jsp.ui.internal.validation; + +import org.eclipse.jst.jsp.core.internal.regions.DOMJSPRegionContexts; +import org.eclipse.osgi.util.NLS; +import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocumentRegion; +import org.eclipse.wst.sse.core.internal.provisional.text.ITextRegion; +import org.eclipse.wst.sse.core.internal.provisional.text.ITextRegionContainer; +import org.eclipse.wst.sse.core.internal.provisional.text.ITextRegionList; +import org.eclipse.wst.sse.ui.internal.reconcile.AbstractStructuredTextReconcilingStrategy; +import org.eclipse.wst.validation.internal.provisional.core.IReporter; +import org.eclipse.wst.xml.core.internal.regions.DOMRegionContext; +import org.eclipse.wst.xml.ui.internal.XMLUIMessages; +import org.eclipse.wst.xml.ui.internal.correction.ProblemIDsXML; +import org.eclipse.wst.xml.ui.internal.validation.MarkupValidator; + +public class JSPMarkupValidator extends MarkupValidator { + + private boolean hasXMLAttributes(IStructuredDocumentRegion structuredDocumentRegion) { + ITextRegionList regions = structuredDocumentRegion.getRegions(); + + if (regions.size() > 1 && regions.get(0).getType() == DOMRegionContext.XML_TAG_OPEN) { + ITextRegion region = regions.get(1); + if (region.getType() == DOMRegionContext.XML_TAG_NAME || region.getType() == DOMJSPRegionContexts.JSP_DIRECTIVE_NAME) { + // Tag name has a prefix, be strict about requiring quotes + if (structuredDocumentRegion.getText(region).indexOf(":") != -1) //$NON-NLS-1$ + return true; + } + } + return false; + } + + protected void checkForAttributeValue(IStructuredDocumentRegion structuredDocumentRegion, IReporter reporter) { + + if (structuredDocumentRegion.isDeleted()) { + return; + } + + if (hasXMLAttributes(structuredDocumentRegion)) + super.checkForAttributeValue(structuredDocumentRegion, reporter); + + // check for attributes without a value + // track the attribute/equals/value sequence using a state of 0, 1 ,2 + // representing the name, =, and value, respectively + int attrState = 0; + ITextRegionList textRegions = structuredDocumentRegion.getRegions(); + + int errorCount = 0; + for (int i = 0; (i < textRegions.size()) && (errorCount < AbstractStructuredTextReconcilingStrategy.ELEMENT_ERROR_LIMIT); i++) { + ITextRegion textRegion = textRegions.get(i); + if ((textRegion.getType() == DOMRegionContext.XML_TAG_ATTRIBUTE_NAME) || isTagCloseTextRegion(textRegion)) { + // dangling name and '=' + if ((attrState == 2) && (i >= 2)) { + // create annotation + ITextRegion nameRegion = textRegions.get(i - 2); + if (!(nameRegion instanceof ITextRegionContainer)) { + Object[] args = {structuredDocumentRegion.getText(nameRegion)}; + String messageText = NLS.bind(XMLUIMessages.Attribute__is_missing_a_value, args); + + int start = structuredDocumentRegion.getStartOffset(nameRegion); + int end = structuredDocumentRegion.getEndOffset(); + int textLength = structuredDocumentRegion.getText(nameRegion).trim().length(); + + // quick fix info + ITextRegion equalsRegion = textRegions.get(i - 2 + 1); + int insertOffset = structuredDocumentRegion.getTextEndOffset(equalsRegion) - end; + Object[] additionalFixInfo = {structuredDocumentRegion.getText(nameRegion), new Integer(insertOffset)}; + + addAttributeError(messageText, additionalFixInfo, start, textLength, ProblemIDsXML.MissingAttrValue, structuredDocumentRegion, reporter); + // annotation.setAdditionalFixInfo(additionalFixInfo); + // results.add(annotation); + errorCount++; + } + } + attrState = 1; + } + else if (textRegion.getType() == DOMRegionContext.XML_TAG_ATTRIBUTE_EQUALS) { + attrState = 2; + } + else if (textRegion.getType() == DOMRegionContext.XML_TAG_ATTRIBUTE_VALUE) { + attrState = 0; + } + } + + } + + protected void checkQuotesForAttributeValues(IStructuredDocumentRegion structuredDocumentRegion, IReporter reporter) { + ITextRegionList regions = structuredDocumentRegion.getRegions(); + ITextRegion r = null; + String attrValueText = ""; //$NON-NLS-1$ + int errorCount = 0; + + if (hasXMLAttributes(structuredDocumentRegion)) + super.checkQuotesForAttributeValues(structuredDocumentRegion, reporter); + + for (int i = 0; (i < regions.size()) && (errorCount < AbstractStructuredTextReconcilingStrategy.ELEMENT_ERROR_LIMIT); i++) { + r = regions.get(i); + if (r.getType() != DOMRegionContext.XML_TAG_ATTRIBUTE_VALUE) { + continue; + } + + attrValueText = structuredDocumentRegion.getText(r); + // attribute value includes quotes in the string + // split up attribute value on quotes + /* + * WORKAROUND till + * http://dev.icu-project.org/cgi-bin/icu-bugs/incoming?findid=5207 + * is fixed. (Also see BUG143628) + */ + + java.util.StringTokenizer st = new java.util.StringTokenizer(attrValueText, "\"'", true); //$NON-NLS-1$ + int size = st.countTokens(); + // get the pieces of the attribute value + String one = "", two = ""; //$NON-NLS-1$ //$NON-NLS-2$ + if (size > 0) { + one = st.nextToken(); + } + if (size > 1) { + two = st.nextToken(); + } + if (size > 2) { + // should be handled by parsing... + // as in we can't have an attribute value like: <element + // attr="a"b"c"/> + // and <element attr='a"b"c' /> is legal + continue; + } + + + if (size == 1) { + if (one.equals(DQUOTE) || one.equals(SQUOTE)) { + // missing closing quote + String message = XMLUIMessages.ReconcileStepForMarkup_0; + addAttributeError(message, attrValueText, structuredDocumentRegion.getStartOffset(r), attrValueText.trim().length(), ProblemIDsXML.Unclassified, structuredDocumentRegion, reporter); + errorCount++; + } + } + else if (size == 2) { + if ((one.equals(SQUOTE) && !two.equals(SQUOTE)) || (one.equals(DQUOTE) && !two.equals(DQUOTE))) { + // missing closing quote + String message = XMLUIMessages.ReconcileStepForMarkup_0; + addAttributeError(message, attrValueText, structuredDocumentRegion.getStartOffset(r), attrValueText.trim().length(), ProblemIDsXML.Unclassified, structuredDocumentRegion, reporter); + errorCount++; + } + } + } + // end of region for loop + } + + private boolean isTagCloseTextRegion(ITextRegion textRegion) { + return (textRegion.getType() == DOMRegionContext.XML_TAG_CLOSE) || (textRegion.getType() == DOMRegionContext.XML_EMPTY_TAG_CLOSE); + } +}
diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/internal/validation/MarkupValidator.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/internal/validation/MarkupValidator.java index 9979f54..d0ee221 100644 --- a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/internal/validation/MarkupValidator.java +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/internal/validation/MarkupValidator.java
@@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2001, 2008 IBM Corporation and others. + * Copyright (c) 2001, 2009 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 @@ -51,7 +51,7 @@ * @author pavery */ public class MarkupValidator implements IValidator, ISourceValidator { - private String DQUOTE = "\""; //$NON-NLS-1$ + protected final static String DQUOTE = "\""; //$NON-NLS-1$ protected String SEVERITY_ATTR_MISSING_VALUE = TemporaryAnnotation.ANNOT_ERROR; protected String SEVERITY_ATTR_NO_VALUE = TemporaryAnnotation.ANNOT_ERROR; @@ -61,12 +61,12 @@ protected String SEVERITY_STRUCTURE = TemporaryAnnotation.ANNOT_ERROR; protected String SEVERITY_SYNTAX_ERROR = TemporaryAnnotation.ANNOT_ERROR; // used for attribute quote checking - private String SQUOTE = "'"; //$NON-NLS-1$ + protected final static String SQUOTE = "'"; //$NON-NLS-1$ private final String QUICKASSISTPROCESSOR = IQuickAssistProcessor.class.getName(); private IDocument fDocument; - private void addAttributeError(String messageText, String attributeValueText, int start, int length, int problemId, IStructuredDocumentRegion sdRegion, IReporter reporter) { + protected final void addAttributeError(String messageText, String attributeValueText, int start, int length, int problemId, IStructuredDocumentRegion sdRegion, IReporter reporter) { if (sdRegion.isDeleted()) { return; @@ -87,6 +87,27 @@ ((IncrementalReporter) reporter).addAnnotationInfo(this, info); } + protected final void addAttributeError(String messageText, Object[] additionalInfo, int start, int length, int problemId, IStructuredDocumentRegion sdRegion, IReporter reporter) { + + if (sdRegion.isDeleted()) { + return; + } + + int lineNo = getLineNumber(start); + LocalizedMessage message = new LocalizedMessage(IMessage.HIGH_SEVERITY, messageText); + message.setOffset(start); + message.setLength(length); + message.setLineNo(lineNo); + + MarkupQuickAssistProcessor processor = new MarkupQuickAssistProcessor(); + processor.setProblemId(problemId); + processor.setAdditionalFixInfo(additionalInfo); + message.setAttribute(QUICKASSISTPROCESSOR, processor); + + AnnotationInfo info = new AnnotationInfo(message); + ((IncrementalReporter) reporter).addAnnotationInfo(this, info); + } + private void checkAttributesInEndTag(IStructuredDocumentRegion structuredDocumentRegion, IReporter reporter) { if (structuredDocumentRegion.isDeleted()) { @@ -205,7 +226,7 @@ return lineNo; } - private void checkForAttributeValue(IStructuredDocumentRegion structuredDocumentRegion, IReporter reporter) { + protected void checkForAttributeValue(IStructuredDocumentRegion structuredDocumentRegion, IReporter reporter) { if (structuredDocumentRegion.isDeleted()) { return; @@ -233,28 +254,14 @@ int start = structuredDocumentRegion.getStartOffset(nameRegion); int end = structuredDocumentRegion.getEndOffset(); - int lineNo = getLineNumber(start); int textLength = structuredDocumentRegion.getText(nameRegion).trim().length(); - LocalizedMessage message = new LocalizedMessage(IMessage.HIGH_SEVERITY, messageText); - message.setOffset(start); - message.setLength(textLength); - message.setLineNo(lineNo); - // quick fix info ITextRegion equalsRegion = textRegions.get(i - 2 + 1); int insertOffset = structuredDocumentRegion.getTextEndOffset(equalsRegion) - end; Object[] additionalFixInfo = {structuredDocumentRegion.getText(nameRegion), new Integer(insertOffset)}; - MarkupQuickAssistProcessor processor = new MarkupQuickAssistProcessor(); - processor.setProblemId(ProblemIDsXML.MissingAttrValue); - processor.setAdditionalFixInfo(additionalFixInfo); - message.setAttribute(QUICKASSISTPROCESSOR, processor); - - AnnotationInfo info = new AnnotationInfo(message); - - ((IncrementalReporter) reporter).addAnnotationInfo(this, info); - + addAttributeError(messageText, additionalFixInfo, start, textLength, ProblemIDsXML.MissingAttrValue, structuredDocumentRegion, reporter); // annotation.setAdditionalFixInfo(additionalFixInfo); // results.add(annotation); errorCount++; @@ -269,22 +276,8 @@ String messageText = NLS.bind(XMLUIMessages.Attribute__has_no_value, args); int start = structuredDocumentRegion.getStartOffset(previousRegion); int textLength = structuredDocumentRegion.getText(previousRegion).trim().length(); - int lineNo = getLineNumber(start); - LocalizedMessage message = new LocalizedMessage(IMessage.HIGH_SEVERITY, messageText); - message.setOffset(start); - message.setLength(textLength); - message.setLineNo(lineNo); - - MarkupQuickAssistProcessor processor = new MarkupQuickAssistProcessor(); - processor.setProblemId(ProblemIDsXML.NoAttrValue); - processor.setAdditionalFixInfo(structuredDocumentRegion.getText(previousRegion)); - message.setAttribute(QUICKASSISTPROCESSOR, processor); - - AnnotationInfo info = new AnnotationInfo(message); - - ((IncrementalReporter) reporter).addAnnotationInfo(this, info); - + addAttributeError(messageText, structuredDocumentRegion.getText(previousRegion), start, textLength, ProblemIDsXML.NoAttrValue, structuredDocumentRegion, reporter); errorCount++; } } @@ -372,7 +365,7 @@ } } - private void checkQuotesForAttributeValues(IStructuredDocumentRegion structuredDocumentRegion, IReporter reporter) { + protected void checkQuotesForAttributeValues(IStructuredDocumentRegion structuredDocumentRegion, IReporter reporter) { ITextRegionList regions = structuredDocumentRegion.getRegions(); ITextRegion r = null; String attrValueText = ""; //$NON-NLS-1$