mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
PY-2821: Support "reverse" and Co reference injection
* Drop Django 1.5 style {% url %} tag support
* Provide view name references for reverse etc
* Improve DjangoFQNamesProvider API to support "package/name only" check
This commit is contained in:
@@ -15,10 +15,20 @@
|
||||
*/
|
||||
package com.jetbrains.python.nameResolver;
|
||||
|
||||
import com.intellij.navigation.NavigationItem;
|
||||
import com.intellij.psi.util.QualifiedName;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.jetbrains.python.psi.PyQualifiedNameOwner;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* Some enum value that represents one or more fully qualified names for some function
|
||||
*
|
||||
* @author Ilya.Kazakevich
|
||||
*/
|
||||
public interface FQNamesProvider {
|
||||
@@ -28,8 +38,73 @@ public interface FQNamesProvider {
|
||||
@NotNull
|
||||
String[] getNames();
|
||||
|
||||
@NotNull
|
||||
default QualifiedName[] getQualifiedNames() {
|
||||
return Arrays.stream(getNames()).map(QualifiedName::fromDottedString).toArray(QualifiedName[]::new);
|
||||
}
|
||||
|
||||
|
||||
@NotNull
|
||||
default String getFirstName() {
|
||||
return getNames()[0];
|
||||
}
|
||||
|
||||
default boolean isShortNameMatches(@NotNull final NavigationItem item) {
|
||||
final String name = item.getName();
|
||||
if (name == null) {
|
||||
return false;
|
||||
}
|
||||
return getShortNames().contains(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return all names in unqualified ("after last dot") format
|
||||
*/
|
||||
@NotNull
|
||||
default List<String> getShortNames() {
|
||||
return Arrays.stream(getQualifiedNames()).map(QualifiedName::getLastComponent).filter(o -> o != null).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return is name of class (true) or function (false)
|
||||
*/
|
||||
boolean isClass();
|
||||
|
||||
/**
|
||||
* @return if element should be checked by full name conformity by {@link #isNameMatches(PyQualifiedNameOwner)}
|
||||
* or only name and package should be checked
|
||||
* @see #isNameMatches(PyQualifiedNameOwner)
|
||||
*/
|
||||
default boolean alwaysCheckQualifiedName() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if element name matches. {@link #alwaysCheckQualifiedName()} controls if full name should be checked, or only last and first
|
||||
* parts (name and package) are enough. It may be used for cases when physical FQN is not documented.
|
||||
*/
|
||||
default boolean isNameMatches(@NotNull final PyQualifiedNameOwner qualifiedNameOwner) {
|
||||
final String qualifiedName = qualifiedNameOwner.getQualifiedName();
|
||||
if (qualifiedName == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Only check qualified name
|
||||
if (alwaysCheckQualifiedName()) {
|
||||
return ArrayUtil.contains(qualifiedName, getNames());
|
||||
}
|
||||
|
||||
// Relaxed check: package and name
|
||||
final QualifiedName elementQualifiedName = QualifiedName.fromDottedString(qualifiedName);
|
||||
final Stream<QualifiedName> nameStream = Arrays.stream(getQualifiedNames());
|
||||
return nameStream.anyMatch((name) -> {
|
||||
final String first = name.getFirstComponent();
|
||||
final String last = name.getLastComponent();
|
||||
return first != null
|
||||
&& last != null
|
||||
&& first.equals(elementQualifiedName.getFirstComponent())
|
||||
&& last.equals(elementQualifiedName.getLastComponent());
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ public abstract class PyElementGenerator {
|
||||
|
||||
public abstract PyStringLiteralExpression createStringLiteralFromString(@NotNull String unescaped);
|
||||
|
||||
public abstract PyStringLiteralExpression createStringLiteral(@NotNull PyStringLiteralExpression oldElement, @NotNull String unescaped);
|
||||
public abstract PyStringLiteralExpression createStringLiteral(@NotNull StringLiteralExpression oldElement, @NotNull String unescaped);
|
||||
|
||||
public abstract PyListLiteralExpression createListLiteral();
|
||||
|
||||
|
||||
@@ -18,7 +18,6 @@ package com.jetbrains.python;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.jetbrains.python.psi.PyElementGenerator;
|
||||
import com.jetbrains.python.psi.PyStringLiteralUtil;
|
||||
import com.jetbrains.python.psi.StringLiteralExpression;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@@ -39,12 +38,12 @@ public abstract class PyStringLiteralReference extends BaseReference {
|
||||
@SuppressWarnings("RefusedBequest") // 1 instead of 1 in range and "-1" at the end because we do not need quotes
|
||||
@Override
|
||||
public final TextRange getRangeInElement() {
|
||||
return PyStringLiteralUtil.getTextRange(myElement);
|
||||
return myStringLiteral.getStringValueTextRange();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PsiElement handleElementRename(@NotNull final String newElementName) {
|
||||
final PsiElement newString = PyElementGenerator.getInstance(myElement.getProject()).createStringLiteralFromString(newElementName);
|
||||
final PsiElement newString = PyElementGenerator.getInstance(myElement.getProject()).createStringLiteral(myStringLiteral, newElementName);
|
||||
myStringLiteral.replace(newString);
|
||||
return newString;
|
||||
}
|
||||
|
||||
@@ -1708,7 +1708,10 @@ public class PyUtil {
|
||||
* @param expectedPackage package like "django"
|
||||
* @param expectedName expected name (i.e. AppConfig)
|
||||
* @return true if element in package
|
||||
* @deprecated use {@link com.jetbrains.python.nameResolver.FQNamesProvider#isNameMatches(PyQualifiedNameOwner)}
|
||||
* Remove in 2018
|
||||
*/
|
||||
@Deprecated
|
||||
public static boolean isSymbolInPackage(@NotNull final PyQualifiedNameOwner symbol,
|
||||
@NotNull final String expectedPackage,
|
||||
@NotNull final String expectedName) {
|
||||
|
||||
@@ -108,7 +108,8 @@ public class PyElementGeneratorImpl extends PyElementGenerator {
|
||||
return createStringLiteralFromString(null, unescaped, true);
|
||||
}
|
||||
|
||||
public PyStringLiteralExpression createStringLiteral(@NotNull PyStringLiteralExpression oldElement, @NotNull String unescaped) {
|
||||
@Override
|
||||
public PyStringLiteralExpression createStringLiteral(@NotNull StringLiteralExpression oldElement, @NotNull String unescaped) {
|
||||
Pair<String, String> quotes = PyStringLiteralUtil.getQuotes(oldElement.getText());
|
||||
if (quotes != null) {
|
||||
return createStringLiteralAlreadyEscaped(quotes.first + unescaped + quotes.second);
|
||||
|
||||
Reference in New Issue
Block a user