blob: 84acd78f35120431aa301986a49bd265d5339db6 [file] [log] [blame]
/*******************************************************************************
* 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);
}
}