regexp: non-capturing group with closure on both inside and outside is not unnecessary (IDEA-262576)

GitOrigin-RevId: 26d0f01e218065b5203363edfda98f967aa1cadb
This commit is contained in:
Bas Leijdekkers
2021-02-20 14:42:25 +01:00
committed by intellij-monorepo-bot
parent 6429f60f86
commit 262fba73d0
2 changed files with 23 additions and 16 deletions

View File

@@ -1,4 +1,4 @@
// 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. // Copyright 2000-2021 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; package org.intellij.lang.regexp.inspection;
import com.intellij.codeInspection.LocalInspectionTool; import com.intellij.codeInspection.LocalInspectionTool;
@@ -10,10 +10,7 @@ import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiElementVisitor; import com.intellij.psi.PsiElementVisitor;
import org.intellij.lang.regexp.RegExpBundle; import org.intellij.lang.regexp.RegExpBundle;
import org.intellij.lang.regexp.psi.RegExpBranch; import org.intellij.lang.regexp.psi.*;
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; import org.jetbrains.annotations.NotNull;
/** /**
@@ -41,20 +38,23 @@ public class UnnecessaryNonCapturingGroupInspection extends LocalInspectionTool
return; return;
} }
final PsiElement parent = group.getParent(); final PsiElement parent = group.getParent();
if (parent instanceof RegExpBranch) { final RegExpAtom atom = getSingleAtom(group.getPattern());
if (atom != null) {
if (!(parent instanceof RegExpClosure) || !(atom instanceof RegExpClosure)) {
registerProblem(group);
}
}
else if (parent instanceof RegExpBranch) {
if (hasOneBranch(group.getPattern())) { if (hasOneBranch(group.getPattern())) {
registerProblem(group); registerProblem(group);
} }
else { else {
final PsiElement grandParent = parent.getParent(); final PsiElement grandParent = parent.getParent();
if (grandParent instanceof RegExpPattern && hasSingleAtom((RegExpPattern)grandParent)) { if (grandParent instanceof RegExpPattern && getSingleAtom((RegExpPattern)grandParent) != null) {
registerProblem(group); registerProblem(group);
} }
} }
} }
else if (hasSingleAtom(group.getPattern())) {
registerProblem(group);
}
} }
void registerProblem(RegExpGroup group) { void registerProblem(RegExpGroup group) {
@@ -68,12 +68,12 @@ public class UnnecessaryNonCapturingGroupInspection extends LocalInspectionTool
return pattern != null && pattern.getBranches().length == 1; return pattern != null && pattern.getBranches().length == 1;
} }
private static boolean hasSingleAtom(RegExpPattern pattern) { private static RegExpAtom getSingleAtom(RegExpPattern pattern) {
if (pattern == null) { if (pattern == null) return null;
return false;
}
final RegExpBranch[] branches = pattern.getBranches(); final RegExpBranch[] branches = pattern.getBranches();
return branches.length == 1 && branches[0].getAtoms().length == 1; if (branches.length != 1) return null;
final RegExpAtom[] atoms = branches[0].getAtoms();
return atoms.length != 1 ? null : atoms[0];
} }
private static class UnnecessaryNonCapturingGroupFix implements LocalQuickFix { private static class UnnecessaryNonCapturingGroupFix implements LocalQuickFix {

View File

@@ -1,4 +1,4 @@
// 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. // Copyright 2000-2021 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; package org.intellij.lang.regexp.inspection;
import com.intellij.codeInspection.LocalInspectionTool; import com.intellij.codeInspection.LocalInspectionTool;
@@ -24,6 +24,13 @@ public class UnnecessaryNonCapturingGroupInspectionTest extends RegExpInspection
highlightTest("aa(?:bb|bbb)cccc"); highlightTest("aa(?:bb|bbb)cccc");
} }
public void testNoWarnOnNestedClosure() {
highlightTest("\\d{2}(?:\\d{3})?");
highlightTest("\\d{2}(?:\\d{3}){2}");
highlightTest("\\d{2}(?:\\d{3})+");
highlightTest("\\d{2}(?:\\d{3})*");
}
public void testTopLevelAlternation() { public void testTopLevelAlternation() {
quickfixTest("<warning descr=\"Unnecessary non-capturing group '(?:xx|xy)'\">(?:</warning>xx|xy)", "xx|xy", quickfixTest("<warning descr=\"Unnecessary non-capturing group '(?:xx|xy)'\">(?:</warning>xx|xy)", "xx|xy",
RegExpBundle.message("inspection.quick.fix.remove.unnecessary.non.capturing.group")); RegExpBundle.message("inspection.quick.fix.remove.unnecessary.non.capturing.group"));