regexp: fix a case of "good code is red"

This commit is contained in:
Bas Leijdekkers
2016-12-05 11:44:40 +01:00
parent ae2f20b889
commit 16ec0170f6
5 changed files with 45 additions and 33 deletions
@@ -217,7 +217,8 @@ public class RegExpParser implements PsiParser {
// DEFLIST
if (parseClassIntersection(builder)) {
while (RegExpTT.CHARACTERS2.contains(builder.getTokenType()) ||
while (RegExpTT.CHARACTERS.contains(builder.getTokenType()) ||
builder.getTokenType() == RegExpTT.CHAR_CLASS ||
builder.getTokenType() == RegExpTT.CLASS_BEGIN ||
builder.getTokenType() == RegExpTT.PROPERTY ||
builder.getTokenType() == RegExpTT.BRACKET_EXPRESSION_BEGIN) {
@@ -257,9 +258,14 @@ public class RegExpParser implements PsiParser {
else if (token == RegExpTT.BRACKET_EXPRESSION_BEGIN) {
parseBracketExpression(builder);
}
else if (RegExpTT.CHARACTERS2.contains(token)) {
else if (RegExpTT.CHARACTERS.contains(token)) {
parseSimpleClassdef(builder);
}
else if (token == RegExpTT.CHAR_CLASS) {
final PsiBuilder.Marker m = builder.mark();
builder.advanceLexer();
m.done(RegExpElementTypes.SIMPLE_CLASS);
}
else if (token == RegExpTT.PROPERTY) {
parseProperty(builder);
}
@@ -291,7 +297,7 @@ public class RegExpParser implements PsiParser {
}
private void parseSimpleClassdef(PsiBuilder builder) {
assert RegExpTT.CHARACTERS2.contains(builder.getTokenType());
assert RegExpTT.CHARACTERS.contains(builder.getTokenType());
final PsiBuilder.Marker marker = builder.mark();
makeChar(builder);
@@ -301,7 +307,7 @@ public class RegExpParser implements PsiParser {
builder.advanceLexer();
final IElementType t = builder.getTokenType();
if (RegExpTT.CHARACTERS2.contains(t)) {
if (RegExpTT.CHARACTERS.contains(t) || t == RegExpTT.CHAR_CLASS) {
m.drop();
makeChar(builder);
marker.done(RegExpElementTypes.CHAR_RANGE);
@@ -449,7 +455,7 @@ public class RegExpParser implements PsiParser {
marker.drop();
parseNamedCharacter(builder);
}
else if (RegExpTT.SIMPLE_CLASSES.contains(type)) {
else if (type == RegExpTT.DOT || type == RegExpTT.CHAR_CLASS) {
builder.advanceLexer();
marker.done(RegExpElementTypes.SIMPLE_CLASS);
}
@@ -135,22 +135,17 @@ public interface RegExpTT {
IElementType RUBY_QUOTED_NAMED_GROUP_CALL = new RegExpElementType("RUBY_QUOTED_NAMED_GROUP_CALL");
TokenSet CHARACTERS = TokenSet.create(CHARACTER,
ESC_CTRL_CHARACTER,
ESC_CHARACTER,
CTRL_CHARACTER,
CTRL,
UNICODE_CHAR,
HEX_CHAR, BAD_HEX_VALUE,
OCT_CHAR, BAD_OCT_VALUE,
REDUNDANT_ESCAPE,
MINUS,
StringEscapesTokenTypes.INVALID_UNICODE_ESCAPE_TOKEN,
StringEscapesTokenTypes.INVALID_CHARACTER_ESCAPE_TOKEN);
TokenSet SIMPLE_CLASSES = TokenSet.create(DOT, CHAR_CLASS);
// caret is just a character in classes after the first position: [a^] matches "a" or "^"
TokenSet CHARACTERS2 = TokenSet.orSet(CHARACTERS, SIMPLE_CLASSES);
ESC_CTRL_CHARACTER,
ESC_CHARACTER,
CTRL_CHARACTER,
CTRL,
UNICODE_CHAR,
HEX_CHAR, BAD_HEX_VALUE,
OCT_CHAR, BAD_OCT_VALUE,
REDUNDANT_ESCAPE,
MINUS,
StringEscapesTokenTypes.INVALID_UNICODE_ESCAPE_TOKEN,
StringEscapesTokenTypes.INVALID_CHARACTER_ESCAPE_TOKEN);
TokenSet QUANTIFIERS = TokenSet.create(QUEST, PLUS, STAR, LBRACE);
@@ -84,9 +84,7 @@ public final class RegExpAnnotator extends RegExpElementVisitor implements Annot
public void visitRegExpCharRange(RegExpCharRange range) {
final RegExpCharRange.Endpoint from = range.getFrom();
final RegExpCharRange.Endpoint to = range.getTo();
final boolean a = from instanceof RegExpChar;
final boolean b = to instanceof RegExpChar;
if (a && b) {
if (from instanceof RegExpChar && to instanceof RegExpChar) {
final Character t = ((RegExpChar)to).getValue();
final Character f = ((RegExpChar)from).getValue();
if (t != null && f != null) {
@@ -99,8 +97,8 @@ public final class RegExpAnnotator extends RegExpElementVisitor implements Annot
}
}
}
else if (a != b) {
myHolder.createErrorAnnotation(range, "Character class (e.g. '\\\\w') may not be used inside character range");
else if (to instanceof RegExpSimpleClass) {
myHolder.createErrorAnnotation(to, "Character class not allowed inside character range");
}
else if (from.getText().equals(to.getText())) {
myHolder.createWarningAnnotation(range, "Redundant character range");
@@ -151,12 +149,20 @@ public final class RegExpAnnotator extends RegExpElementVisitor implements Annot
}
}
private void checkForDuplicates(RegExpClassElement element, Set<Character> seen) {
private void checkForDuplicates(RegExpClassElement element, Set<Object> seen) {
if (element instanceof RegExpChar) {
final RegExpChar regExpChar = (RegExpChar)element;
final Character value = regExpChar.getValue();
if (value != null && !seen.add(value)) {
myHolder.createWarningAnnotation(regExpChar, "Duplicate character '" + regExpChar.getText() + "' in character class");
myHolder.createWarningAnnotation(regExpChar, "Duplicate character '" + regExpChar.getText() + "' inside character class");
}
}
else if (element instanceof RegExpSimpleClass) {
final RegExpSimpleClass regExpSimpleClass = (RegExpSimpleClass)element;
final RegExpSimpleClass.Kind kind = regExpSimpleClass.getKind();
if (!seen.add(kind)) {
myHolder.createWarningAnnotation(regExpSimpleClass, "Duplicate predefined character class '" + regExpSimpleClass.getText() +
"' inside character class");
}
}
else if (element instanceof RegExpClass) {
+7 -3
View File
@@ -37,7 +37,11 @@
</quantifiers>
<charclasses>
<test verify="false">
<pattern><![CDATA[[<warning descr="Redundant character range">\w-\w</warning>]]]></pattern>
<pattern><![CDATA[[\w-<warning descr="Duplicate predefined character class '\w' inside character class">\w</warning>]]]></pattern>
<expected>OK</expected>
</test>
<test>
<pattern>[\w-a]</pattern>
<expected>OK</expected>
</test>
<test host="com.intellij.psi.impl.JavaRegExpHost">
@@ -106,7 +110,7 @@
<expected>OK</expected>
</test>
<test>
<pattern><![CDATA[[\Qabc?*+.)<warning descr="Duplicate character ')' in character class">)</warning>]<warning descr="Duplicate character ']' in character class">]</warning>[<warning descr="Duplicate character ']' in character class">]</warning>\E]]]></pattern>
<pattern><![CDATA[[\Qabc?*+.)<warning descr="Duplicate character ')' inside character class">)</warning>]<warning descr="Duplicate character ']' inside character class">]</warning>[<warning descr="Duplicate character ']' inside character class">]</warning>\E]]]></pattern>
<expected>OK</expected>
</test>
<test host="com.intellij.psi.impl.JavaRegExpHost">
@@ -133,7 +137,7 @@
<expected>OK</expected>
</test>
<test>
<pattern><![CDATA[[:xdig<warning descr="Duplicate character 'i' in character class">i</warning>t<warning descr="Duplicate character ':' in character class">:</warning>]+]]></pattern>
<pattern><![CDATA[[:xdig<warning descr="Duplicate character 'i' inside character class">i</warning>t<warning descr="Duplicate character ':' inside character class">:</warning>]+]]></pattern>
<expected>OK</expected>
</test>
</namedchars>
+3 -2
View File
@@ -3,10 +3,11 @@ REGEXP_FILE
RegExpBranchImpl: <[\w-\w]>
RegExpClassImpl: <[\w-\w]>
PsiElement(CLASS_BEGIN)('[')
RegExpCharRangeImpl: <\w-\w>
RegExpUnionImpl: <\w-\w>
RegExpSimpleClassImpl: <\w>
PsiElement(CHAR_CLASS)('\w')
PsiElement(MINUS)('-')
RegExpCharImpl: <->
PsiElement(MINUS)('-')
RegExpSimpleClassImpl: <\w>
PsiElement(CHAR_CLASS)('\w')
PsiElement(CLASS_END)(']')