mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
improve interaction of Find Usages and global statements (PY-1167); changed PSI so that names declared in global statement are now PyTargetExpression rather than PyReferenceExpression instances
This commit is contained in:
@@ -14,6 +14,7 @@ import com.jetbrains.python.codeInsight.dataflow.scope.ScopeVariable;
|
||||
import com.jetbrains.python.psi.PyGlobalStatement;
|
||||
import com.jetbrains.python.psi.PyRecursiveElementVisitor;
|
||||
import com.jetbrains.python.psi.PyReferenceExpression;
|
||||
import com.jetbrains.python.psi.PyTargetExpression;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.*;
|
||||
@@ -98,7 +99,7 @@ public class ScopeImpl implements Scope {
|
||||
owner.accept(new PyRecursiveElementVisitor(){
|
||||
@Override
|
||||
public void visitPyGlobalStatement(final PyGlobalStatement node) {
|
||||
for (PyReferenceExpression expression : node.getGlobals()) {
|
||||
for (PyTargetExpression expression : node.getGlobals()) {
|
||||
names.add(expression.getReferencedName());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package com.jetbrains.python.inspections;
|
||||
|
||||
import com.intellij.codeHighlighting.HighlightDisplayLevel;
|
||||
import com.intellij.codeInspection.LocalInspectionTool;
|
||||
import com.intellij.codeInspection.ProblemHighlightType;
|
||||
import com.intellij.codeInspection.ProblemsHolder;
|
||||
import com.intellij.psi.PsiElement;
|
||||
@@ -17,7 +15,6 @@ import com.jetbrains.python.console.PydevConsoleRunner;
|
||||
import com.jetbrains.python.psi.*;
|
||||
import com.jetbrains.python.psi.impl.*;
|
||||
import org.jetbrains.annotations.Nls;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
@@ -43,7 +40,7 @@ public class PyUnboundLocalVariableInspection extends PyInspection {
|
||||
return;
|
||||
}
|
||||
// Ignore global statements arguments
|
||||
if (PyGlobalStatementNavigator.getPyGlobalStatementByArgument(node) != null){
|
||||
if (PyGlobalStatementNavigator.getByArgument(node) != null){
|
||||
return;
|
||||
}
|
||||
// Ignore qualifier inspections
|
||||
|
||||
@@ -500,10 +500,10 @@ public class StatementParsing extends Parsing implements ITokenTypeRemapper {
|
||||
private void parseNameDefiningStatement(boolean inSuite, final PyElementType elementType) {
|
||||
final PsiBuilder.Marker globalStatement = myBuilder.mark();
|
||||
myBuilder.advanceLexer();
|
||||
parseIdentifier(PyElementTypes.REFERENCE_EXPRESSION);
|
||||
parseIdentifier(PyElementTypes.TARGET_EXPRESSION);
|
||||
while (myBuilder.getTokenType() == PyTokenTypes.COMMA) {
|
||||
myBuilder.advanceLexer();
|
||||
parseIdentifier(PyElementTypes.REFERENCE_EXPRESSION);
|
||||
parseIdentifier(PyElementTypes.TARGET_EXPRESSION);
|
||||
}
|
||||
checkEndOfStatement(inSuite);
|
||||
globalStatement.done(elementType);
|
||||
|
||||
@@ -6,7 +6,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
* @author yole
|
||||
*/
|
||||
public interface PyGlobalStatement extends PyStatement, NameDefiner {
|
||||
@NotNull PyReferenceExpression[] getGlobals();
|
||||
@NotNull PyTargetExpression[] getGlobals();
|
||||
|
||||
void addGlobal(String name);
|
||||
}
|
||||
|
||||
@@ -2,9 +2,11 @@ package com.jetbrains.python.psi;
|
||||
|
||||
import com.intellij.psi.PsiNameIdentifierOwner;
|
||||
import com.intellij.psi.PsiNamedElement;
|
||||
import com.intellij.psi.PsiReference;
|
||||
import com.intellij.psi.StubBasedPsiElement;
|
||||
import com.jetbrains.python.psi.impl.PyQualifiedName;
|
||||
import com.jetbrains.python.psi.stubs.PyTargetExpressionStub;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
@@ -24,4 +26,7 @@ public interface PyTargetExpression extends PyQualifiedExpression, PsiNamedEleme
|
||||
|
||||
@Nullable
|
||||
PyQualifiedName getAssignedQName();
|
||||
|
||||
@NotNull
|
||||
PsiReference getReference();
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import com.intellij.lang.ASTNode;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.ResolveState;
|
||||
import com.intellij.psi.scope.PsiScopeProcessor;
|
||||
import com.intellij.psi.tree.TokenSet;
|
||||
import com.jetbrains.python.PyElementTypes;
|
||||
import com.jetbrains.python.psi.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -14,6 +15,8 @@ import java.util.Arrays;
|
||||
* @author yole
|
||||
*/
|
||||
public class PyGlobalStatementImpl extends PyElementImpl implements PyGlobalStatement {
|
||||
private static final TokenSet TARGET_EXPRESSION_SET = TokenSet.create(PyElementTypes.TARGET_EXPRESSION);
|
||||
|
||||
public PyGlobalStatementImpl(ASTNode astNode) {
|
||||
super(astNode);
|
||||
}
|
||||
@@ -24,8 +27,8 @@ public class PyGlobalStatementImpl extends PyElementImpl implements PyGlobalStat
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public PyReferenceExpression[] getGlobals() {
|
||||
return childrenToPsi(PyElementTypes.REFERENCE_EXPRESSION_SET, PyReferenceExpression.EMPTY_ARRAY);
|
||||
public PyTargetExpression[] getGlobals() {
|
||||
return childrenToPsi(TARGET_EXPRESSION_SET, PyTargetExpression.EMPTY_ARRAY);
|
||||
}
|
||||
|
||||
public boolean processDeclarations(@NotNull PsiScopeProcessor processor,
|
||||
|
||||
@@ -13,7 +13,7 @@ public class PyGlobalStatementNavigator {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static PyGlobalStatement getPyGlobalStatementByArgument(final PsiElement element){
|
||||
public static PyGlobalStatement getByArgument(final PsiElement element){
|
||||
final PsiElement parent = element.getParent();
|
||||
if (parent instanceof PyGlobalStatement){
|
||||
final PyGlobalStatement statement = (PyGlobalStatement)parent;
|
||||
|
||||
@@ -283,7 +283,24 @@ public class PyReferenceImpl implements PsiReferenceEx, PsiPolyVariantReference
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return resolve() == element; // TODO: handle multi-resolve
|
||||
final PsiElement resolveResult = resolve();
|
||||
if (resolveResult == element) {
|
||||
return true;
|
||||
}
|
||||
// TODO support nonlocal statement
|
||||
final PyGlobalStatement ourGlobal = PyGlobalStatementNavigator.getByArgument(resolveResult);
|
||||
final PyGlobalStatement theirGlobal = PyGlobalStatementNavigator.getByArgument(element);
|
||||
if (ourGlobal != null || theirGlobal != null) {
|
||||
PsiElement ourContainer = PsiTreeUtil.getParentOfType(getElement(), PsiNamedElement.class);
|
||||
PsiElement theirContainer = PsiTreeUtil.getParentOfType(element, PsiNamedElement.class);
|
||||
if (ourGlobal != null && ourContainer != null && PsiTreeUtil.isAncestor(theirContainer, ourContainer, false)) {
|
||||
return true;
|
||||
}
|
||||
if (theirGlobal != null && theirContainer != null && PsiTreeUtil.isAncestor(ourContainer, theirContainer, false)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false; // TODO: handle multi-resolve
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -208,6 +208,7 @@ public class PyTargetExpressionImpl extends PyPresentableElementImpl<PyTargetExp
|
||||
return value instanceof PyReferenceExpression ? ((PyReferenceExpression) value).asQualifiedName() : null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiReference getReference() {
|
||||
if (getQualifier() != null) {
|
||||
@@ -219,6 +220,11 @@ public class PyTargetExpressionImpl extends PyPresentableElementImpl<PyTargetExp
|
||||
@NotNull
|
||||
@Override
|
||||
public SearchScope getUseScope() {
|
||||
final PyGlobalStatement globalStatement = PyGlobalStatementNavigator.getByArgument(this);
|
||||
if (globalStatement != null) {
|
||||
return super.getUseScope();
|
||||
}
|
||||
|
||||
// find highest level function containing our var
|
||||
PyElement container = this;
|
||||
while(true) {
|
||||
|
||||
@@ -34,13 +34,13 @@ public class GlobalAnnotator extends PyAnnotator {
|
||||
|
||||
// check globals
|
||||
final AnnotationHolder holder = getHolder();
|
||||
for (PyReferenceExpression expr : node.getGlobals()) {
|
||||
for (PyTargetExpression expr : node.getGlobals()) {
|
||||
final String expr_name = expr.getReferencedName();
|
||||
if (paramNames.contains(expr_name)) {
|
||||
holder.createErrorAnnotation(expr.getTextRange(), PyBundle.message("ANN.$0.both.global.and.param", expr_name));
|
||||
}
|
||||
PsiElement resolvedElement = expr.getReference().resolve();
|
||||
if (resolvedElement != null && PsiTreeUtil.isAncestor(function, resolvedElement, true)) {
|
||||
if (resolvedElement != null && resolvedElement != expr && PsiTreeUtil.isAncestor(function, resolvedElement, true)) {
|
||||
getHolder().createWarningAnnotation(expr.getTextRange(),PyBundle.message("ANN.$0.both.global.and.param", expr_name));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
<caret>search_variable = 1
|
||||
|
||||
def function():
|
||||
global search_variable
|
||||
search_variable = 2
|
||||
@@ -0,0 +1,5 @@
|
||||
search_variable = 1
|
||||
|
||||
def function():
|
||||
global search_variable
|
||||
<caret>search_variable = 2
|
||||
@@ -2,9 +2,9 @@ PyFile:Nonlocal.py
|
||||
PyNonlocalStatement
|
||||
PsiElement(Py:NONLOCAL_KEYWORD)('nonlocal')
|
||||
PsiWhiteSpace(' ')
|
||||
PyReferenceExpression: a
|
||||
PyTargetExpression: a
|
||||
PsiElement(Py:IDENTIFIER)('a')
|
||||
PsiElement(Py:COMMA)(',')
|
||||
PsiWhiteSpace(' ')
|
||||
PyReferenceExpression: b
|
||||
PyTargetExpression: b
|
||||
PsiElement(Py:IDENTIFIER)('b')
|
||||
@@ -33,4 +33,15 @@ public class PyFindUsagesTest extends PyLightFixtureTestCase {
|
||||
final Collection<UsageInfo> usages = myFixture.testFindUsages("findUsages/QualifiedVsUnqualifiedUsages.py");
|
||||
assertEquals(1, usages.size());
|
||||
}
|
||||
}
|
||||
|
||||
public void testGlobalUsages() { // PY-1167
|
||||
final Collection<UsageInfo> usages = myFixture.testFindUsages("findUsages/GlobalUsages.py");
|
||||
assertEquals(3, usages.size());
|
||||
}
|
||||
|
||||
public void testGlobalUsages2() { // PY-1167
|
||||
// same text as GlobalUsages, different caret location
|
||||
final Collection<UsageInfo> usages = myFixture.testFindUsages("findUsages/GlobalUsages2.py");
|
||||
assertEquals(3, usages.size());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user