blob: bf80b8cb71b60fad5e8f2b968698402d5918f551 [file] [log] [blame]
/*
* Copyright 2000-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.xml.util;
import com.intellij.codeHighlighting.HighlightDisplayLevel;
import com.intellij.codeInspection.*;
import com.intellij.ide.highlighter.XmlLikeFileType;
import com.intellij.lexer.Lexer;
import com.intellij.lexer.XmlLexer;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiElementVisitor;
import com.intellij.psi.PsiFile;
import com.intellij.psi.XmlElementVisitor;
import com.intellij.psi.html.HtmlTag;
import com.intellij.psi.impl.source.tree.TreeUtil;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.xml.XmlTag;
import com.intellij.psi.xml.XmlTagValue;
import com.intellij.psi.xml.XmlTokenType;
import com.intellij.xml.XmlBundle;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
public class CheckValidXmlInScriptBodyInspectionBase extends XmlSuppressableInspectionTool {
@NonNls
protected static final String AMP_ENTITY_REFERENCE = "&";
@NonNls
protected static final String LT_ENTITY_REFERENCE = "<";
private Lexer myXmlLexer;
@Override
public boolean isEnabledByDefault() {
return true;
}
@Override
@NotNull
public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, boolean isOnTheFly) {
return new XmlElementVisitor() {
@Override public void visitXmlTag(final XmlTag tag) {
if (HtmlUtil.isHtmlTag(tag)) return;
if (HtmlUtil.SCRIPT_TAG_NAME.equals(tag.getName()) ||
tag instanceof HtmlTag && HtmlUtil.SCRIPT_TAG_NAME.equalsIgnoreCase(tag.getName())) {
final PsiFile psiFile = tag.getContainingFile();
final FileType fileType = psiFile.getFileType();
if (fileType instanceof XmlLikeFileType) {
synchronized(CheckValidXmlInScriptBodyInspectionBase.class) {
if (myXmlLexer == null) myXmlLexer = new XmlLexer();
final XmlTagValue tagValue = tag.getValue();
final String tagBodyText = tagValue.getText();
if (!tagBodyText.isEmpty()) {
myXmlLexer.start(tagBodyText);
while(myXmlLexer.getTokenType() != null) {
IElementType tokenType = myXmlLexer.getTokenType();
if (tokenType == XmlTokenType.XML_CDATA_START) {
while(tokenType != null && tokenType != XmlTokenType.XML_CDATA_END) {
myXmlLexer.advance();
tokenType = myXmlLexer.getTokenType();
}
if (tokenType == null) break;
}
if (tokenType == XmlTokenType.XML_BAD_CHARACTER &&
"&".equals(TreeUtil.getTokenText(myXmlLexer)) ||
tokenType == XmlTokenType.XML_START_TAG_START
) {
final int valueStart = tagValue.getTextRange().getStartOffset();
final int offset = valueStart + myXmlLexer.getTokenStart();
final PsiElement psiElement = psiFile.findElementAt(offset);
final TextRange elementRange = psiElement.getTextRange();
final int offsetInElement = offset - elementRange.getStartOffset();
holder.registerProblem(
psiElement,
XmlBundle.message("unescaped.xml.character"),
ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
createFix(psiFile, psiElement, offsetInElement)
);
int endOfElementInScriptTag = elementRange.getEndOffset() - valueStart;
while(myXmlLexer.getTokenEnd() < endOfElementInScriptTag) {
myXmlLexer.advance();
if (myXmlLexer.getTokenType() == null) break;
}
}
myXmlLexer.advance();
}
}
}
}
}
}
};
}
protected LocalQuickFix createFix(PsiFile psiFile, PsiElement psiElement, int offsetInElement) {
return null;
}
@Override
@NotNull
public String getGroupDisplayName() {
return XmlInspectionGroupNames.HTML_INSPECTIONS;
}
@Override
@NotNull
public String getDisplayName() {
return XmlBundle.message("html.inspections.check.valid.script.tag");
}
@Override
@NotNull
@NonNls
public String getShortName() {
return "CheckValidXmlInScriptTagBody";
}
@Override
@NotNull
public HighlightDisplayLevel getDefaultLevel() {
return HighlightDisplayLevel.ERROR;
}
}