update copyright
[fedora-idea.git] / xml / impl / src / com / intellij / xml / util / CheckValidXmlInScriptBodyInspection.java
blob5487ef1161fd18773fa32a72b0da7ad824e50069
1 /*
2 * Copyright 2000-2009 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 * Created by IntelliJ IDEA.
19 * User: Maxim.Mossienko
20 * Date: Jun 29, 2006
21 * Time: 6:09:35 PM
23 package com.intellij.xml.util;
25 import com.intellij.codeHighlighting.HighlightDisplayLevel;
26 import com.intellij.codeInsight.CodeInsightUtilBase;
27 import com.intellij.codeInspection.*;
28 import com.intellij.lexer.Lexer;
29 import com.intellij.lexer.XmlLexer;
30 import com.intellij.openapi.editor.Editor;
31 import com.intellij.openapi.fileEditor.FileEditorManager;
32 import com.intellij.openapi.fileEditor.OpenFileDescriptor;
33 import com.intellij.openapi.fileTypes.FileType;
34 import com.intellij.openapi.fileTypes.StdFileTypes;
35 import com.intellij.openapi.project.Project;
36 import com.intellij.openapi.util.TextRange;
37 import com.intellij.psi.PsiElement;
38 import com.intellij.psi.PsiElementVisitor;
39 import com.intellij.psi.PsiFile;
40 import com.intellij.psi.XmlElementVisitor;
41 import com.intellij.psi.html.HtmlTag;
42 import com.intellij.psi.impl.source.tree.TreeUtil;
43 import com.intellij.psi.tree.IElementType;
44 import com.intellij.psi.xml.XmlTag;
45 import com.intellij.psi.xml.XmlTagValue;
46 import com.intellij.psi.xml.XmlTokenType;
47 import com.intellij.xml.XmlBundle;
48 import org.jetbrains.annotations.NonNls;
49 import org.jetbrains.annotations.NotNull;
51 /**
52 * @author Maxim Mossienko
54 public class CheckValidXmlInScriptBodyInspection extends XmlSuppressableInspectionTool {
55 @NonNls
56 private static final String SCRIPT_TAG_NAME = "script";
57 private Lexer myXmlLexer;
58 @NonNls
59 private static final String AMP_ENTITY_REFERENCE = "&";
60 @NonNls
61 private static final String LT_ENTITY_REFERENCE = "<";
63 public boolean isEnabledByDefault() {
64 return true;
67 @NotNull
68 public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, boolean isOnTheFly) {
69 return new XmlElementVisitor() {
70 @Override public void visitXmlTag(final XmlTag tag) {
71 if (SCRIPT_TAG_NAME.equals(tag.getName()) ||
72 (tag instanceof HtmlTag && SCRIPT_TAG_NAME.equalsIgnoreCase(tag.getName()))
73 ) {
74 final PsiFile psiFile = tag.getContainingFile();
75 final FileType fileType = psiFile.getFileType();
77 if (fileType == StdFileTypes.XHTML || fileType == StdFileTypes.JSPX) {
78 synchronized(CheckValidXmlInScriptBodyInspection.class) {
79 if (myXmlLexer == null) myXmlLexer = new XmlLexer();
80 final XmlTagValue tagValue = tag.getValue();
81 final String tagBodyText = tagValue.getText();
83 if (tagBodyText.length() > 0) {
84 myXmlLexer.start(tagBodyText);
86 while(myXmlLexer.getTokenType() != null) {
87 IElementType tokenType = myXmlLexer.getTokenType();
89 if (tokenType == XmlTokenType.XML_CDATA_START) {
90 while(tokenType != null && tokenType != XmlTokenType.XML_CDATA_END) {
91 myXmlLexer.advance();
92 tokenType = myXmlLexer.getTokenType();
94 if (tokenType == null) break;
96 if (( tokenType == XmlTokenType.XML_BAD_CHARACTER &&
97 "&".equals(TreeUtil.getTokenText(myXmlLexer))
98 ) ||
99 tokenType == XmlTokenType.XML_START_TAG_START
101 final int valueStart = tagValue.getTextRange().getStartOffset();
102 final int offset = valueStart + myXmlLexer.getTokenStart();
103 final PsiElement psiElement = psiFile.findElementAt(offset);
104 final TextRange elementRange = psiElement.getTextRange();
106 final int offsetInElement = offset - elementRange.getStartOffset();
107 holder.registerProblem(
108 psiElement,
109 XmlBundle.message("unescaped.xml.character"),
110 ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
111 new InsertQuotedCharacterQuickFix(
112 psiFile,
113 psiElement,
114 offsetInElement
118 int endOfElementInScriptTag = elementRange.getEndOffset() - valueStart;
119 while(myXmlLexer.getTokenEnd() < endOfElementInScriptTag) {
120 myXmlLexer.advance();
121 if (myXmlLexer.getTokenType() == null) break;
124 myXmlLexer.advance();
134 @NotNull
135 public String getGroupDisplayName() {
136 return XmlInspectionGroupNames.HTML_INSPECTIONS;
139 @NotNull
140 public String getDisplayName() {
141 return XmlBundle.message("html.inspections.check.valid.script.tag");
144 @NotNull
145 @NonNls
146 public String getShortName() {
147 return "CheckValidXmlInScriptTagBody";
150 private static class InsertQuotedCharacterQuickFix implements LocalQuickFix {
151 private final PsiFile psiFile;
152 private final PsiElement psiElement;
153 private final int startInElement;
155 public InsertQuotedCharacterQuickFix(PsiFile psiFile, PsiElement psiElement, int startInElement) {
156 this.psiFile = psiFile;
157 this.psiElement = psiElement;
158 this.startInElement = startInElement;
161 @NotNull
162 public String getName() {
163 final String character = getXmlCharacter();
165 return XmlBundle.message(
166 "unescaped.xml.character.fix.message",
167 character.equals("&") ?
168 XmlBundle.message("unescaped.xml.character.fix.message.parameter"):
169 character
173 @NotNull
174 public String getFamilyName() {
175 return getName();
178 public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor problemDescriptor) {
179 if ( !CodeInsightUtilBase.prepareFileForWrite(psiFile)) return;
180 final TextRange range = psiElement.getTextRange();
181 OpenFileDescriptor descriptor = new OpenFileDescriptor(
182 project,
183 psiFile.getVirtualFile(),
184 range.getStartOffset() + startInElement
187 final Editor editor = FileEditorManager.getInstance(project).openTextEditor(descriptor, true);
188 if (editor == null) return;
190 final String xmlCharacter = getXmlCharacter();
191 String replacement = xmlCharacter.equals("&") ? AMP_ENTITY_REFERENCE : LT_ENTITY_REFERENCE;
192 replacement = psiElement.getText().replace(xmlCharacter,replacement);
194 editor.getDocument().replaceString(
195 range.getStartOffset(),
196 range.getEndOffset(),
197 replacement
201 private String getXmlCharacter() {
202 return psiElement.getText().substring(startInElement, startInElement + 1);
206 @NotNull
207 public HighlightDisplayLevel getDefaultLevel() {
208 return HighlightDisplayLevel.ERROR;