/*
* Copyright 2000-2017 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 org.intellij.lang.regexp.inspection;
import com.intellij.codeInspection.LocalInspectionTool;
import com.intellij.codeInspection.LocalQuickFix;
import com.intellij.codeInspection.ProblemDescriptor;
import com.intellij.codeInspection.ProblemsHolder;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiElementVisitor;
import com.intellij.psi.PsiWhiteSpace;
import org.intellij.lang.regexp.psi.*;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
/**
* @author Bas Leijdekkers
*/
public class RepeatedSpaceInspection extends LocalInspectionTool {
@Nls
@NotNull
@Override
public String getDisplayName() {
return "Consecutive spaces";
}
@NotNull
@Override
public PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder, boolean isOnTheFly) {
return new RepeatedSpaceVisitor(holder);
}
private static class RepeatedSpaceVisitor extends RegExpElementVisitor {
private final ProblemsHolder myHolder;
private int myCount = 0;
private RegExpChar myFirstChar = null;
private boolean quoted = false;
public RepeatedSpaceVisitor(ProblemsHolder holder) {
myHolder = holder;
}
@Override
public void visitRegExpChar(RegExpChar aChar) {
if (!quoted && !(aChar.getParent() instanceof RegExpClass) && aChar.getType() == RegExpChar.Type.CHAR && aChar.getValue() == ' ') {
if (myFirstChar == null) {
myFirstChar = aChar;
}
myCount++;
}
else {
super.visitRegExpChar(aChar);
}
}
@Override
public void visitWhiteSpace(PsiWhiteSpace space) {
super.visitWhiteSpace(space);
final String text = space.getText();
if (text.equals("\\Q")) {
quoted = true;
}
else if (text.equals("\\E")) {
quoted = false;
}
myFirstChar = null;
myCount = 0;
}
@Override
public void visitRegExpClass(RegExpClass expClass) {
super.visitRegExpClass(expClass);
myFirstChar = null;
myCount = 0;
}
@Override
public void visitRegExpElement(RegExpElement element) {
super.visitRegExpElement(element);
if (myFirstChar != null && myCount > 1) {
final int offset = myFirstChar.getStartOffsetInParent();
final String message = myCount + " consecutive spaces in RegExp";
myHolder.registerProblem(myFirstChar.getParent(), new TextRange(offset, offset + myCount), message,
new RepeatedSpaceFix(myCount));
}
myFirstChar = null;
myCount = 0;
}
}
private static class RepeatedSpaceFix implements LocalQuickFix {
private final int myCount;
public RepeatedSpaceFix(int count) {
myCount = count;
}
@Nls
@NotNull
@Override
public String getName() {
return "Replace with ' {" + myCount + "}'";
}
@Nls
@NotNull
@Override
public String getFamilyName() {
return "Replace with space and repeated quantifier";
}
@Override
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
final PsiElement element = descriptor.getPsiElement();
if (!(element instanceof RegExpBranch)) {
return;
}
final TextRange range = descriptor.getTextRangeInElement();
final StringBuilder text = new StringBuilder();
final PsiElement[] children = element.getChildren();
boolean inserted = false;
for (PsiElement child : children) {
if (!range.contains(child.getStartOffsetInParent())) {
text.append(child.getText());
}
else if (!inserted) {
text.append(" {").append(range.getLength()).append('}');
inserted = true;
}
}
element.replace(RegExpFactory.createBranchFromText(text, element));
}
}
}