PY-30825 Remove the controversial logic regarding annotating of a reference qualifier

Otherwise, we can't really tell whether the use wants to annotate the return type
of the method or the type of the qualifier in cases like the "param.met<caret>hod()".
It's better to be more explicit and ask them to invoke the intention on the right
element directly.

Handle the cases when the caret is at the end of an identifier using
TargetElementUtil#adjustOffset.
This commit is contained in:
Mikhail Golubev
2018-08-06 19:13:21 +03:00
parent 3f724495b2
commit 618921d8bc
7 changed files with 41 additions and 15 deletions
@@ -18,6 +18,7 @@ package com.jetbrains.python.codeInsight.intentions;
import com.google.common.collect.Lists;
import com.intellij.codeInsight.CodeInsightUtilCore;
import com.intellij.codeInsight.FileModificationService;
import com.intellij.codeInsight.TargetElementUtil;
import com.intellij.codeInsight.template.*;
import com.intellij.openapi.application.WriteAction;
import com.intellij.openapi.editor.Document;
@@ -54,7 +55,8 @@ public class PyAnnotateTypesIntention extends PyBaseIntentionAction {
public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
if (!(file instanceof PyFile) || file instanceof PyDocstringFile) return false;
final PsiElement elementAt = PyUtil.findNonWhitespaceAtOffset(file, editor.getCaretModel().getOffset());
final int offset = TargetElementUtil.adjustOffset(file, editor.getDocument(), editor.getCaretModel().getOffset());
final PsiElement elementAt = PyUtil.findNonWhitespaceAtOffset(file, offset);
if (elementAt == null) return false;
final PyFunction function = findSuitableFunction(elementAt);
@@ -77,7 +79,8 @@ public class PyAnnotateTypesIntention extends PyBaseIntentionAction {
@Override
public void doInvoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException {
final PsiElement elementAt = PyUtil.findNonWhitespaceAtOffset(file, editor.getCaretModel().getOffset());
final int offset = TargetElementUtil.adjustOffset(file, editor.getDocument(), editor.getCaretModel().getOffset());
final PsiElement elementAt = PyUtil.findNonWhitespaceAtOffset(file, offset);
if (elementAt != null) {
final PyFunction function = findSuitableFunction(elementAt);
if (function != null) {
@@ -16,6 +16,7 @@
package com.jetbrains.python.codeInsight.intentions;
import com.intellij.codeInsight.FileModificationService;
import com.intellij.codeInsight.TargetElementUtil;
import com.intellij.openapi.application.WriteAction;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
@@ -57,7 +58,8 @@ public class SpecifyTypeInDocstringIntention extends TypeIntention {
@Override
public void doInvoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException {
final PsiElement elementAt = PyUtil.findNonWhitespaceAtOffset(file, editor.getCaretModel().getOffset());
final int offset = TargetElementUtil.adjustOffset(file, editor.getDocument(), editor.getCaretModel().getOffset());
final PsiElement elementAt = PyUtil.findNonWhitespaceAtOffset(file, offset);
final PyExpression problemElement = getProblemElement(elementAt);
final PsiReference reference = problemElement == null ? null : problemElement.getReference();
@@ -17,6 +17,7 @@ package com.jetbrains.python.codeInsight.intentions;
import com.intellij.codeInsight.CodeInsightUtilCore;
import com.intellij.codeInsight.FileModificationService;
import com.intellij.codeInsight.TargetElementUtil;
import com.intellij.codeInsight.template.*;
import com.intellij.openapi.application.WriteAction;
import com.intellij.openapi.editor.Editor;
@@ -68,7 +69,8 @@ public class SpecifyTypeInPy3AnnotationsIntention extends TypeIntention {
@Override
public void doInvoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException {
final PsiElement elementAt = PyUtil.findNonWhitespaceAtOffset(file, editor.getCaretModel().getOffset());
final int offset = TargetElementUtil.adjustOffset(file, editor.getDocument(), editor.getCaretModel().getOffset());
final PsiElement elementAt = PyUtil.findNonWhitespaceAtOffset(file, offset);
final PyExpression problemElement = getProblemElement(elementAt);
final PsiReference reference = problemElement == null ? null : problemElement.getReference();
@@ -15,6 +15,7 @@
*/
package com.jetbrains.python.codeInsight.intentions;
import com.intellij.codeInsight.TargetElementUtil;
import com.intellij.lang.ASTNode;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
@@ -24,7 +25,6 @@ import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.containers.ContainerUtil;
import com.jetbrains.python.PyNames;
import com.jetbrains.python.documentation.doctest.PyDocstringFile;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.resolve.PyResolveContext;
@@ -49,7 +49,8 @@ public abstract class TypeIntention extends PyBaseIntentionAction {
if (!(file instanceof PyFile) || file instanceof PyDocstringFile) return false;
updateText(false);
final PsiElement elementAt = PyUtil.findNonWhitespaceAtOffset(file, editor.getCaretModel().getOffset());
final int offset = TargetElementUtil.adjustOffset(file, editor.getDocument(), editor.getCaretModel().getOffset());
final PsiElement elementAt = PyUtil.findNonWhitespaceAtOffset(file, offset);
if (elementAt == null) return false;
if (isAvailableForParameter(project, elementAt)) {
return true;
@@ -86,15 +87,7 @@ public abstract class TypeIntention extends PyBaseIntentionAction {
@Nullable
public static PyExpression getProblemElement(@Nullable PsiElement elementAt) {
PyExpression problemElement = PsiTreeUtil.getParentOfType(elementAt, PyNamedParameter.class, PyReferenceExpression.class);
if (problemElement == null) return null;
if (problemElement instanceof PyQualifiedExpression) {
final PyExpression qualifier = ((PyQualifiedExpression)problemElement).getQualifier();
if (qualifier != null && !qualifier.getText().equals(PyNames.CANONICAL_SELF)) {
problemElement = qualifier;
}
}
return problemElement;
return PsiTreeUtil.getParentOfType(elementAt, PyNamedParameter.class, PyReferenceExpression.class);
}
protected abstract void updateText(boolean isReturn);
@@ -0,0 +1,10 @@
class MyClass:
def __init__(self):
pass
def method(self, x):
pass
x = MyClass()
foo = x.met<caret>hod(42)
@@ -0,0 +1,11 @@
class MyClass:
def __init__(self):
pass
def method(self, x):
# type: (object) -> object
pass
x = MyClass()
foo = x.method(42)
@@ -46,6 +46,11 @@ public class PyAnnotateTypesIntentionTest extends PyIntentionTestCase {
doNegativeTest(PyBundle.message("INTN.add.type.hints.for.function.family"));
}
// PY-30825
public void testMethodAfterConstructorCall() {
doIntentionTest(PyBundle.message("INTN.add.type.hints.for.function", "method"));
}
private void doTest() {
doTest(PyBundle.message("INTN.add.type.hints.for.function.family"), LanguageLevel.PYTHON34);
}