RUBY-13071: (refactoring) work with RegExpLanguageHost encapsulated into RegExpLanguageHosts

This commit is contained in:
Oleg Sukhodolsky
2013-02-11 23:58:20 +04:00
parent 05e9d28982
commit bfff38cf9d
2 changed files with 76 additions and 39 deletions
@@ -15,15 +15,79 @@
*/
package org.intellij.lang.regexp;
import com.intellij.lang.injection.InjectedLanguageManager;
import com.intellij.openapi.util.ClassExtension;
import com.intellij.psi.PsiComment;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiLanguageInjectionHost;
import org.intellij.lang.regexp.psi.RegExpChar;
import org.intellij.lang.regexp.psi.RegExpGroup;
import org.intellij.lang.regexp.psi.RegExpPyCondRef;
import org.intellij.lang.regexp.psi.RegExpQuantifier;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* @author yole
*/
public class RegExpLanguageHosts extends ClassExtension<RegExpLanguageHost> {
public static final RegExpLanguageHosts INSTANCE = new RegExpLanguageHosts();
public final class RegExpLanguageHosts extends ClassExtension<RegExpLanguageHost> {
private static final RegExpLanguageHosts INSTANCE = new RegExpLanguageHosts();
public static RegExpLanguageHosts getInstance() {
return INSTANCE;
}
private RegExpLanguageHosts() {
super("com.intellij.regExpLanguageHost");
}
@Nullable
private static RegExpLanguageHost findRegExpHost(@Nullable final PsiElement element) {
if (element == null) {
return null;
}
PsiLanguageInjectionHost host = InjectedLanguageManager.getInstance(element.getProject()).getInjectionHost(element);
if (host instanceof RegExpLanguageHost) {
return (RegExpLanguageHost)host;
}
if (host != null) {
return INSTANCE.forClass(host.getClass());
}
return null;
}
public boolean isRedundantEscape(@NotNull final RegExpChar ch, @NotNull final String text) {
if (text.length() <= 1) {
return false;
}
final RegExpLanguageHost host = findRegExpHost(ch);
if (host != null) {
final char c = text.charAt(1);
final boolean needsEscaping = host.characterNeedsEscaping(c);
return !needsEscaping;
}
else {
return !("\\]".equals(text) || "\\}".equals(text));
}
}
public boolean supportsNamedGroupSyntax(@Nullable final RegExpGroup group) {
final RegExpLanguageHost host = findRegExpHost(group);
return host != null && host.supportsNamedGroupSyntax(group);
}
public boolean supportsPerl5EmbeddedComments(@Nullable final PsiComment comment) {
final RegExpLanguageHost host = findRegExpHost(comment);
return host != null && host.supportsPerl5EmbeddedComments();
}
public boolean supportsPythonConditionalRefs(@Nullable final RegExpPyCondRef condRef) {
final RegExpLanguageHost host = findRegExpHost(condRef);
return host != null && host.supportsPythonConditionalRefs();
}
public boolean supportsPossessiveQuantifiers(@Nullable final RegExpQuantifier quantifier) {
final RegExpLanguageHost host = findRegExpHost(quantifier);
return host != null && host.supportsPossessiveQuantifiers();
}
}
@@ -21,20 +21,22 @@ import com.intellij.lang.ASTNode;
import com.intellij.lang.annotation.Annotation;
import com.intellij.lang.annotation.AnnotationHolder;
import com.intellij.lang.annotation.Annotator;
import com.intellij.lang.injection.InjectedLanguageManager;
import com.intellij.psi.PsiComment;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiLanguageInjectionHost;
import com.intellij.psi.util.PsiTreeUtil;
import org.intellij.lang.regexp.*;
import org.intellij.lang.regexp.psi.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.math.BigInteger;
public final class RegExpAnnotator extends RegExpElementVisitor implements Annotator {
private AnnotationHolder myHolder;
private final RegExpLanguageHosts myLanguageHosts;
public RegExpAnnotator() {
myLanguageHosts = RegExpLanguageHosts.getInstance();
}
public void annotate(@NotNull PsiElement psiElement, @NotNull AnnotationHolder holder) {
assert myHolder == null : "unsupported concurrent annotator invocation";
@@ -95,7 +97,7 @@ public final class RegExpAnnotator extends RegExpElementVisitor implements Annot
}
else {
final String text = ch.getUnescapedText();
if (text.startsWith("\\") && isRedundantEscape(ch, text)) {
if (text.startsWith("\\") && myLanguageHosts.isRedundantEscape(ch, text)) {
final ASTNode astNode = ch.getNode().getFirstChildNode();
if (astNode != null && astNode.getElementType() == RegExpTT.REDUNDANT_ESCAPE) {
final Annotation a = myHolder.createWeakWarningAnnotation(ch, "Redundant character escape");
@@ -105,31 +107,6 @@ public final class RegExpAnnotator extends RegExpElementVisitor implements Annot
}
}
private static boolean isRedundantEscape(RegExpChar ch, String text) {
if (text.length() <= 1) return false;
RegExpLanguageHost host = findRegExpHost(ch);
if (host != null) {
final char c = text.charAt(1);
final boolean needsEscaping = host.characterNeedsEscaping(c);
return !needsEscaping;
}
else {
return !("\\]".equals(text) || "\\}".equals(text));
}
}
@Nullable
private static RegExpLanguageHost findRegExpHost(PsiElement element) {
PsiLanguageInjectionHost host = InjectedLanguageManager.getInstance(element.getProject()).getInjectionHost(element);
if (host instanceof RegExpLanguageHost) {
return (RegExpLanguageHost)host;
}
if (host != null) {
return RegExpLanguageHosts.INSTANCE.forClass(host.getClass());
}
return null;
}
public void visitRegExpProperty(RegExpProperty property) {
final ASTNode category = property.getCategoryNode();
if (category == null) {
@@ -180,8 +157,7 @@ public final class RegExpAnnotator extends RegExpElementVisitor implements Annot
}
}
if (group.isPythonNamedGroup() || group.isRubyNamedGroup()) {
RegExpLanguageHost host = findRegExpHost(group);
if (host == null || !host.supportsNamedGroupSyntax(group)) {
if (!myLanguageHosts.supportsNamedGroupSyntax(group)) {
myHolder.createErrorAnnotation(group, "This named group syntax is not supported");
}
}
@@ -212,8 +188,7 @@ public final class RegExpAnnotator extends RegExpElementVisitor implements Annot
@Override
public void visitComment(PsiComment comment) {
if (comment.getText().startsWith("(?#")) {
RegExpLanguageHost host = findRegExpHost(comment);
if (host == null || !host.supportsPerl5EmbeddedComments()) {
if (!myLanguageHosts.supportsPerl5EmbeddedComments(comment)) {
myHolder.createErrorAnnotation(comment, "Embedded comments are not supported");
}
}
@@ -221,8 +196,7 @@ public final class RegExpAnnotator extends RegExpElementVisitor implements Annot
@Override
public void visitRegExpPyCondRef(RegExpPyCondRef condRef) {
RegExpLanguageHost host = findRegExpHost(condRef);
if (host == null || !host.supportsPythonConditionalRefs()) {
if (!myLanguageHosts.supportsPythonConditionalRefs(condRef)) {
myHolder.createErrorAnnotation(condRef, "Conditional references are not supported");
}
}
@@ -280,8 +254,7 @@ public final class RegExpAnnotator extends RegExpElementVisitor implements Annot
}
}
if (quantifier.getType() == RegExpQuantifier.Type.POSSESSIVE) {
RegExpLanguageHost host = findRegExpHost(quantifier);
if (host != null && !host.supportsPossessiveQuantifiers()) {
if (!myLanguageHosts.supportsPossessiveQuantifiers(quantifier)) {
myHolder.createErrorAnnotation(quantifier, "Nested quantifier in regexp");
}
}