blob: 2560b065301e824937bed1c71e2df3bed85293cd [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.codeInspection.htmlInspections;
import com.intellij.codeHighlighting.HighlightDisplayLevel;
import com.intellij.codeInsight.FileModificationService;
import com.intellij.codeInsight.daemon.XmlErrorMessages;
import com.intellij.codeInsight.daemon.impl.analysis.XmlHighlightVisitor;
import com.intellij.codeInspection.*;
import com.intellij.lang.ASTNode;
import com.intellij.openapi.application.Result;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiFile;
import com.intellij.psi.html.HtmlTag;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.xml.*;
import com.intellij.xml.XmlBundle;
import com.intellij.xml.util.XmlUtil;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
/**
* @author spleaner
*/
public class XmlWrongRootElementInspection extends HtmlLocalInspectionTool {
@Override
@Nls
@NotNull
public String getGroupDisplayName() {
return XmlInspectionGroupNames.XML_INSPECTIONS;
}
@Override
@Nls
@NotNull
public String getDisplayName() {
return XmlBundle.message("xml.inspection.wrong.root.element");
}
@Override
@NonNls
@NotNull
public String getShortName() {
return "XmlWrongRootElement";
}
@Override
@NotNull
public HighlightDisplayLevel getDefaultLevel() {
return HighlightDisplayLevel.ERROR;
}
@Override
protected void checkTag(@NotNull final XmlTag tag, @NotNull final ProblemsHolder holder, final boolean isOnTheFly) {
if (!(tag.getParent() instanceof XmlTag)) {
final PsiFile psiFile = tag.getContainingFile();
if (!(psiFile instanceof XmlFile)) {
return;
}
XmlFile xmlFile = (XmlFile) psiFile;
final XmlDocument document = xmlFile.getDocument();
if (document == null) {
return;
}
XmlProlog prolog = document.getProlog();
if (prolog == null || XmlHighlightVisitor.skipValidation(prolog)) {
return;
}
final XmlDoctype doctype = prolog.getDoctype();
if (doctype == null) {
return;
}
XmlElement nameElement = doctype.getNameElement();
if (nameElement == null) {
return;
}
String name = tag.getName();
String text = nameElement.getText();
if (tag instanceof HtmlTag) {
name = name.toLowerCase();
text = text.toLowerCase();
}
if (!name.equals(text)) {
name = XmlUtil.findLocalNameByQualifiedName(name);
if (!name.equals(text)) {
if (tag instanceof HtmlTag) {
return; // it is legal to have html / head / body omitted
}
final LocalQuickFix localQuickFix = new MyLocalQuickFix(doctype.getNameElement().getText());
holder.registerProblem(XmlChildRole.START_TAG_NAME_FINDER.findChild(tag.getNode()).getPsi(),
XmlErrorMessages.message("wrong.root.element"),
ProblemHighlightType.LIKE_UNKNOWN_SYMBOL, localQuickFix
);
final ASTNode astNode = XmlChildRole.CLOSING_TAG_NAME_FINDER.findChild(tag.getNode());
if (astNode != null) {
holder.registerProblem(astNode.getPsi(),
XmlErrorMessages.message("wrong.root.element"),
ProblemHighlightType.LIKE_UNKNOWN_SYMBOL, localQuickFix
);
}
}
}
}
}
private static class MyLocalQuickFix implements LocalQuickFix {
private final String myText;
public MyLocalQuickFix(String text) {
myText = text;
}
@Override
@NotNull
public String getName() {
return XmlBundle.message("change.root.element.to", myText);
}
@Override
@NotNull
public String getFamilyName() {
return getName();
}
@Override
public void applyFix(@NotNull final Project project, @NotNull final ProblemDescriptor descriptor) {
final XmlTag myTag = PsiTreeUtil.getParentOfType(descriptor.getPsiElement(), XmlTag.class);
if (!FileModificationService.getInstance().prepareFileForWrite(myTag.getContainingFile())) {
return;
}
new WriteCommandAction(project) {
@Override
protected void run(final Result result) throws Throwable {
myTag.setName(myText);
}
}.execute();
}
}
}