mirror of
https://gitflic.ru/project/openide/openide.git
synced 2025-12-14 18:05:27 +07:00
RegExp: new "Unnecessary non-capturing group" inspection (IDEA-228664)
GitOrigin-RevId: d6288b1241bf4253030c6f91ecb73f17a6ea4710
This commit is contained in:
committed by
intellij-monorepo-bot
parent
75339de4c1
commit
143337cad9
@@ -74,6 +74,9 @@
|
||||
<localInspection language="RegExp" shortName="RegExpRedundantNestedCharacterClass" enabledByDefault="true" level="WARNING"
|
||||
bundle="messages.RegExpBundle" groupKey="inspection.group.name.regexp" key="inspection.name.redundant.nested.character.class"
|
||||
implementationClass="org.intellij.lang.regexp.inspection.RedundantNestedCharacterClassInspection"/>
|
||||
<localInspection language="RegExp" shortName="RegExpUnnecessaryNonCapturingGroup" enabledByDefault="true" level="WARNING"
|
||||
bundle="messages.RegExpBundle" groupKey="inspection.group.name.regexp" key="inspection.name.unnecessary.non.capturing.group"
|
||||
implementationClass="org.intellij.lang.regexp.inspection.UnnecessaryNonCapturingGroupInspection"/>
|
||||
|
||||
</extensions>
|
||||
</idea-plugin>
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
<html>
|
||||
<body>
|
||||
Reports unnecessary non-capturing groups.
|
||||
For example<br>
|
||||
<code>Everybody be cool, (?:this) is a robbery!</code><br>
|
||||
is equivalent too<br>
|
||||
<code>Everybody be cool, this is a robbery!</code>.
|
||||
<!-- tooltip end -->
|
||||
<p><small>New in 2021.1</small>
|
||||
</body>
|
||||
</html>
|
||||
@@ -73,11 +73,13 @@ inspection.name.octal.escape=Octal escape
|
||||
inspection.name.redundant.character.escape=Redundant character escape
|
||||
inspection.name.redundant.nested.character.class=Redundant nested character class
|
||||
inspection.name.single.character.alternation=Single character alternation
|
||||
inspection.name.unnecessary.non.capturing.group=Unnecessary non-capturing group
|
||||
inspection.quick.fix.remove.duplicate.0.from.character.class=Remove duplicate ''{0}'' from character class
|
||||
inspection.quick.fix.remove.duplicate.branch=Remove duplicate branch
|
||||
inspection.quick.fix.remove.duplicate.element.from.character.class=Remove duplicate element from character class
|
||||
inspection.quick.fix.remove.empty.branch=Remove empty branch
|
||||
inspection.quick.fix.remove.redundant.escape=Remove redundant escape
|
||||
inspection.quick.fix.remove.unnecessary.non.capturing.group=Unwrap unnecessary non-capturing group
|
||||
inspection.quick.fix.replace.alternation.with.character.class=Replace alternation with character class
|
||||
inspection.quick.fix.replace.redundant.character.class.with.contents=Replace redundant character class with contents
|
||||
inspection.quick.fix.replace.with.character.inside.class=Replace with character inside class
|
||||
@@ -95,6 +97,7 @@ inspection.warning.potential.exponential.backtracking=Potential exponential back
|
||||
inspection.warning.redundant.character.escape.0.in.regexp=Redundant character escape <code>{0}</code> in RegExp
|
||||
inspection.warning.redundant.nested.character.class=Redundant nested character class
|
||||
inspection.warning.single.character.alternation.in.regexp=Single character alternation in RegExp
|
||||
inspection.warning.unnecessary.non.capturing.group=Unnecessary non-capturing group <code>{0}</code>
|
||||
intention.name.check.regexp=Check RegExp
|
||||
intention.name.simplify.quantifier=Simplify quantifier
|
||||
label.regexp=&RegExp:
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
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.codeInspection.util.IntentionFamilyName;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiElementVisitor;
|
||||
import org.intellij.lang.regexp.RegExpBundle;
|
||||
import org.intellij.lang.regexp.psi.RegExpBranch;
|
||||
import org.intellij.lang.regexp.psi.RegExpElementVisitor;
|
||||
import org.intellij.lang.regexp.psi.RegExpGroup;
|
||||
import org.intellij.lang.regexp.psi.RegExpPattern;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* @author Bas Leijdekkers
|
||||
*/
|
||||
public class UnnecessaryNonCapturingGroupInspection extends LocalInspectionTool {
|
||||
|
||||
@Override
|
||||
public @NotNull PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder, boolean isOnTheFly) {
|
||||
return new UnnecessaryNonCapturingGroupVisitor(holder);
|
||||
}
|
||||
|
||||
private static class UnnecessaryNonCapturingGroupVisitor extends RegExpElementVisitor {
|
||||
|
||||
private final ProblemsHolder myHolder;
|
||||
|
||||
private UnnecessaryNonCapturingGroupVisitor(ProblemsHolder holder) {
|
||||
myHolder = holder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitRegExpGroup(RegExpGroup group) {
|
||||
super.visitRegExpGroup(group);
|
||||
if (group.getType() != RegExpGroup.Type.NON_CAPTURING) {
|
||||
return;
|
||||
}
|
||||
final PsiElement parent = group.getParent();
|
||||
if (parent instanceof RegExpBranch) {
|
||||
if (hasOneBranch(group.getPattern())) {
|
||||
registerProblem(group);
|
||||
}
|
||||
else {
|
||||
final PsiElement grandParent = parent.getParent();
|
||||
if (grandParent instanceof RegExpPattern && hasSingleAtom((RegExpPattern)grandParent)) {
|
||||
registerProblem(group);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (hasSingleAtom(group.getPattern())) {
|
||||
registerProblem(group);
|
||||
}
|
||||
}
|
||||
|
||||
void registerProblem(RegExpGroup group) {
|
||||
myHolder.registerProblem(group.getFirstChild(),
|
||||
RegExpBundle.message("inspection.warning.unnecessary.non.capturing.group", group.getText()),
|
||||
new UnnecessaryNonCapturingGroupFix());
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean hasOneBranch(RegExpPattern pattern) {
|
||||
return pattern != null && pattern.getBranches().length == 1;
|
||||
}
|
||||
|
||||
private static boolean hasSingleAtom(RegExpPattern pattern) {
|
||||
if (pattern == null) {
|
||||
return false;
|
||||
}
|
||||
final RegExpBranch[] branches = pattern.getBranches();
|
||||
return branches.length == 1 && branches[0].getAtoms().length == 1;
|
||||
}
|
||||
|
||||
private static class UnnecessaryNonCapturingGroupFix implements LocalQuickFix {
|
||||
@Override
|
||||
public @IntentionFamilyName @NotNull String getFamilyName() {
|
||||
return RegExpBundle.message("inspection.quick.fix.remove.unnecessary.non.capturing.group");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
|
||||
final PsiElement element = descriptor.getPsiElement().getParent();
|
||||
if (!(element instanceof RegExpGroup)) {
|
||||
return;
|
||||
}
|
||||
final RegExpGroup group = (RegExpGroup)element;
|
||||
RegExpReplacementUtil.replaceInContext(group, group.getPattern().getUnescapedText());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package org.intellij.lang.regexp.inspection;
|
||||
|
||||
import com.intellij.codeInspection.LocalInspectionTool;
|
||||
import org.intellij.lang.regexp.RegExpBundle;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* @author Bas Leijdekkers
|
||||
*/
|
||||
public class UnnecessaryNonCapturingGroupInspectionTest extends RegExpInspectionTestCase {
|
||||
|
||||
public void testSimple() {
|
||||
quickfixTest("abc <warning descr=\"Unnecessary non-capturing group '(?:def)'\"><caret>(?:</warning>def) ghi",
|
||||
"abc def ghi",
|
||||
RegExpBundle.message("inspection.quick.fix.remove.unnecessary.non.capturing.group"));
|
||||
}
|
||||
|
||||
public void testNoWarnOnRegularGroup() {
|
||||
highlightTest("abc (def) ghi");
|
||||
}
|
||||
|
||||
public void testNoWarnOnAlternation() {
|
||||
highlightTest("aa(?:bb|bbb)cccc");
|
||||
}
|
||||
|
||||
public void testTopLevelAlternation() {
|
||||
quickfixTest("<warning descr=\"Unnecessary non-capturing group '(?:xx|xy)'\">(?:</warning>xx|xy)", "xx|xy",
|
||||
RegExpBundle.message("inspection.quick.fix.remove.unnecessary.non.capturing.group"));
|
||||
}
|
||||
|
||||
public void testSingleAtom() {
|
||||
quickfixTest("aaa<warning descr=\"Unnecessary non-capturing group '(?:b)'\">(?:<caret></warning>b)+aaa",
|
||||
"aaab+aaa",
|
||||
RegExpBundle.message("inspection.quick.fix.remove.unnecessary.non.capturing.group"));
|
||||
}
|
||||
|
||||
public void testCorrectEscaping() {
|
||||
quickfixTest("<warning descr=\"Unnecessary non-capturing group '(?:[\\w-]+:)'\"><caret>(?:</warning>[\\w-]+:)[\\w-]+",
|
||||
"[\\w-]+:[\\w-]+",
|
||||
RegExpBundle.message("inspection.quick.fix.remove.unnecessary.non.capturing.group"));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @NotNull LocalInspectionTool getInspection() {
|
||||
return new UnnecessaryNonCapturingGroupInspection();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user