Attempt to make PythonRegexpInjector more readable

This commit is contained in:
Semyon Proshev
2016-07-15 19:16:08 +03:00
parent 513f21de26
commit 8640a09ed0
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
* Copyright 2000-2016 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.
@@ -21,7 +21,6 @@ import com.intellij.lang.injection.MultiHostRegistrar;
import com.intellij.openapi.util.Pair;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiPolyVariantReference;
import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil;
import com.intellij.psi.impl.source.tree.injected.MultiHostRegistrarImpl;
import com.intellij.psi.impl.source.tree.injected.Place;
@@ -72,33 +71,40 @@ public class PythonRegexpInjector implements MultiHostInjector {
@Override
public void getLanguagesToInject(@NotNull MultiHostRegistrar registrar, @NotNull PsiElement context) {
final PsiElement contextParent = context.getParent();
if (PyInjectionUtil.getLargestStringLiteral(context) == context && contextParent instanceof PyArgumentList) {
final PyExpression[] args = ((PyArgumentList)contextParent).getArguments();
int index = ArrayUtil.indexOf(args, context);
PyCallExpression call = PsiTreeUtil.getParentOfType(context, PyCallExpression.class);
final PyArgumentList argumentList = PyUtil.as(context.getParent(), PyArgumentList.class);
if (PyInjectionUtil.getLargestStringLiteral(context) == context && argumentList != null) {
final PyCallExpression call = PsiTreeUtil.getParentOfType(context, PyCallExpression.class);
if (call != null) {
final PyExpression callee = call.getCallee();
if (callee instanceof PyReferenceExpression && canBeRegexpCall(callee)) {
final PsiPolyVariantReference ref = ((PyReferenceExpression)callee).getReference(PyResolveContext.noImplicits());
if (ref != null) {
final PsiElement element = ref.resolve();
if (element != null && ScopeUtil.getScopeOwner(element) instanceof PyFile &&
element.getContainingFile().getName().equals("re.py") && isRegexpMethod(element, index)) {
final Language language = isVerbose(call) ? PythonVerboseRegexpLanguage.INSTANCE : PythonRegexpLanguage.INSTANCE;
registrar.startInjecting(language);
final PyInjectionUtil.InjectionResult result = PyInjectionUtil.registerStringLiteralInjection(context, registrar);
if (result.isInjected()) {
registrar.doneInjecting();
if (!result.isStrict()) {
final PsiFile file = getInjectedFile(registrar);
if (file != null) {
file.putUserData(InjectedLanguageUtil.FRANKENSTEIN_INJECTION, Boolean.TRUE);
}
}
}
}
}
final RegexpMethodDescriptor methodDescriptor = findRegexpMethodDescriptor(resolvePossibleRegexpCall(call));
if (methodDescriptor != null && methodDescriptor.argIndex == ArrayUtil.indexOf(argumentList.getArguments(), context)) {
injectRegexpLanguage(registrar, context, isVerbose(call));
}
}
}
}
@Nullable
private PsiElement resolvePossibleRegexpCall(@NotNull PyCallExpression call) {
final PyExpression callee = call.getCallee();
if (callee instanceof PyReferenceExpression && canBeRegexpCall(callee)) {
final PyReferenceExpression referenceExpression = (PyReferenceExpression)callee;
return referenceExpression.getReference(PyResolveContext.noImplicits()).resolve();
}
return null;
}
private static void injectRegexpLanguage(@NotNull MultiHostRegistrar registrar, @NotNull PsiElement context, boolean verbose) {
final Language language = verbose ? PythonVerboseRegexpLanguage.INSTANCE : PythonRegexpLanguage.INSTANCE;
registrar.startInjecting(language);
final PyInjectionUtil.InjectionResult result = PyInjectionUtil.registerStringLiteralInjection(context, registrar);
if (result.isInjected()) {
registrar.doneInjecting();
if (!result.isStrict()) {
final PsiFile file = getInjectedFile(registrar);
if (file != null) {
file.putUserData(InjectedLanguageUtil.FRANKENSTEIN_INJECTION, Boolean.TRUE);
}
}
}
@@ -107,7 +113,7 @@ public class PythonRegexpInjector implements MultiHostInjector {
@Nullable
private static PsiFile getInjectedFile(@NotNull MultiHostRegistrar registrar) {
// Don't add a dependency on IntelliLang here now, but this injector should become IntelliLang-based in the future
final List<Pair<Place,PsiFile>> result = ((MultiHostRegistrarImpl)registrar).getResult();
final List<Pair<Place, PsiFile>> result = ((MultiHostRegistrarImpl)registrar).getResult();
return result == null || result.isEmpty() ? null : result.get(result.size() - 1).second;
}
@@ -119,51 +125,47 @@ public class PythonRegexpInjector implements MultiHostInjector {
}
private static boolean isVerbose(@NotNull PyCallExpression call) {
PyExpression[] arguments = call.getArguments();
if (arguments.length <= 1) {
return false;
}
return isVerbose(arguments[arguments.length-1]);
final PyExpression[] arguments = call.getArguments();
return arguments.length > 1 && isVerbose(arguments[arguments.length - 1]);
}
private static boolean isVerbose(@Nullable PyExpression expr) {
if (expr instanceof PyKeywordArgument) {
PyKeywordArgument keywordArgument = (PyKeywordArgument)expr;
if (!"flags".equals(keywordArgument.getName())) {
return false;
}
return isVerbose(keywordArgument.getValueExpression());
private static boolean isVerbose(@Nullable PyExpression expression) {
if (expression instanceof PyKeywordArgument) {
final PyKeywordArgument keywordArgument = (PyKeywordArgument)expression;
return "flags".equals(keywordArgument.getName()) && isVerbose(keywordArgument.getValueExpression());
}
if (expr instanceof PyReferenceExpression) {
final String flagName = ((PyReferenceExpression)expr).getReferencedName();
if (expression instanceof PyReferenceExpression) {
final String flagName = ((PyReferenceExpression)expression).getReferencedName();
return "VERBOSE".equals(flagName) || "X".equals(flagName);
}
if (expr instanceof PyBinaryExpression) {
return isVerbose(((PyBinaryExpression)expr).getLeftExpression()) || isVerbose(((PyBinaryExpression)expr).getRightExpression());
if (expression instanceof PyBinaryExpression) {
final PyBinaryExpression binaryExpression = (PyBinaryExpression)expression;
return isVerbose(binaryExpression.getLeftExpression()) || isVerbose(binaryExpression.getRightExpression());
}
return false;
}
private boolean isRegexpMethod(@NotNull PsiElement element, int index) {
if (!(element instanceof PyFunction)) {
return false;
@Nullable
private RegexpMethodDescriptor findRegexpMethodDescriptor(@Nullable PsiElement element) {
if (element == null ||
!(ScopeUtil.getScopeOwner(element) instanceof PyFile) ||
!element.getContainingFile().getName().equals("re.py") ||
!(element instanceof PyFunction)) {
return null;
}
final String name = ((PyFunction)element).getName();
for (RegexpMethodDescriptor descriptor : myDescriptors) {
if (descriptor.methodName.equals(name) && descriptor.argIndex == index) {
return true;
}
}
return false;
final String functionName = ((PyFunction)element).getName();
return myDescriptors
.stream()
.filter(descriptor -> descriptor.methodName.equals(functionName))
.findAny()
.orElse(null);
}
private boolean canBeRegexpCall(@NotNull PyExpression callee) {
String text = callee.getText();
for (RegexpMethodDescriptor descriptor : myDescriptors) {
if (text.endsWith(descriptor.methodName)) {
return true;
}
}
return false;
final String text = callee.getText();
return myDescriptors
.stream()
.anyMatch(descriptor -> text.endsWith(descriptor.methodName));
}
}