diff options
Diffstat (limited to 'python/src/com/jetbrains/python/codeInsight')
5 files changed, 458 insertions, 72 deletions
diff --git a/python/src/com/jetbrains/python/codeInsight/PyTypingTypeProvider.java b/python/src/com/jetbrains/python/codeInsight/PyTypingTypeProvider.java new file mode 100644 index 000000000000..f03befac6c14 --- /dev/null +++ b/python/src/com/jetbrains/python/codeInsight/PyTypingTypeProvider.java @@ -0,0 +1,375 @@ +/* + * Copyright 2000-2014 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.jetbrains.python.codeInsight; + +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiPolyVariantReference; +import com.intellij.psi.util.QualifiedName; +import com.jetbrains.python.PyNames; +import com.jetbrains.python.psi.*; +import com.jetbrains.python.psi.impl.PyExpressionCodeFragmentImpl; +import com.jetbrains.python.psi.impl.PyPsiUtils; +import com.jetbrains.python.psi.resolve.PyResolveContext; +import com.jetbrains.python.psi.types.*; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * @author vlan + */ +public class PyTypingTypeProvider extends PyTypeProviderBase { + private static ImmutableMap<String, String> BUILTIN_COLLECTIONS = ImmutableMap.<String, String>builder() + .put("typing.List", "list") + .put("typing.Dict", "dict") + .put("typing.Set", PyNames.SET) + .put("typing.Tuple", PyNames.TUPLE) + .build(); + + private static ImmutableSet<String> GENERIC_CLASSES = ImmutableSet.<String>builder() + .add("typing.Generic") + .add("typing.AbstractGeneric") + .add("typing.Protocol") + .build(); + + public PyType getParameterType(@NotNull PyNamedParameter param, @NotNull PyFunction func, @NotNull TypeEvalContext context) { + final PyAnnotation annotation = param.getAnnotation(); + if (annotation != null) { + // XXX: Requires switching from stub to AST + final PyExpression value = annotation.getValue(); + if (value != null) { + return getTypingType(value, context); + } + } + return null; + } + + @Nullable + @Override + public PyType getReturnType(@NotNull Callable callable, @NotNull TypeEvalContext context) { + if (callable instanceof PyFunction) { + final PyFunction function = (PyFunction)callable; + final PyAnnotation annotation = function.getAnnotation(); + if (annotation != null) { + // XXX: Requires switching from stub to AST + final PyExpression value = annotation.getValue(); + if (value != null) { + return getTypingType(value, context); + } + } + final PyType constructorType = getGenericConstructorType(function, context); + if (constructorType != null) { + return constructorType; + } + } + return null; + } + + @Nullable + private static PyType getGenericConstructorType(@NotNull PyFunction function, @NotNull TypeEvalContext context) { + if (PyUtil.isInit(function)) { + final PyClass cls = function.getContainingClass(); + if (cls != null) { + final List<PyGenericType> genericTypes = collectGenericTypes(cls, context); + + final PyType elementType; + if (genericTypes.size() == 1) { + elementType = genericTypes.get(0); + } + else if (genericTypes.size() > 1) { + elementType = PyTupleType.create(cls, genericTypes.toArray(new PyType[genericTypes.size()])); + } + else { + elementType = null; + } + + if (elementType != null) { + return new PyCollectionTypeImpl(cls, false, elementType); + } + } + } + return null; + } + + @NotNull + private static List<PyGenericType> collectGenericTypes(@NotNull PyClass cls, @NotNull TypeEvalContext context) { + boolean isGeneric = false; + for (PyClass ancestor : cls.getAncestorClasses(context)) { + if (GENERIC_CLASSES.contains(ancestor.getQualifiedName())) { + isGeneric = true; + break; + } + } + if (isGeneric) { + final ArrayList<PyGenericType> results = new ArrayList<PyGenericType>(); + // XXX: Requires switching from stub to AST + for (PyExpression expr : cls.getSuperClassExpressions()) { + if (expr instanceof PySubscriptionExpression) { + final PyExpression indexExpr = ((PySubscriptionExpression)expr).getIndexExpression(); + if (indexExpr != null) { + final PyGenericType genericType = getGenericType(indexExpr, context); + if (genericType != null) { + results.add(genericType); + } + } + } + } + return results; + } + return Collections.emptyList(); + } + + @Nullable + private static PyType getTypingType(@NotNull PyExpression expression, @NotNull TypeEvalContext context) { + final PyType unionType = getUnionType(expression, context); + if (unionType != null) { + return unionType; + } + final PyType parameterizedType = getParameterizedType(expression, context); + if (parameterizedType != null) { + return parameterizedType; + } + final PyType builtinCollection = getBuiltinCollection(expression, context); + if (builtinCollection != null) { + return builtinCollection; + } + final PyType genericType = getGenericType(expression, context); + if (genericType != null) { + return genericType; + } + final PyType functionType = getFunctionType(expression, context); + if (functionType != null) { + return functionType; + } + final PyType stringBasedType = getStringBasedType(expression, context); + if (stringBasedType != null) { + return stringBasedType; + } + return null; + } + + @Nullable + private static PyType getStringBasedType(@NotNull PyExpression expression, @NotNull TypeEvalContext context) { + if (expression instanceof PyStringLiteralExpression) { + // XXX: Requires switching from stub to AST + final String contents = ((PyStringLiteralExpression)expression).getStringValue(); + final Project project = expression.getProject(); + final PyExpressionCodeFragmentImpl codeFragment = new PyExpressionCodeFragmentImpl(project, "dummy.py", contents, false); + codeFragment.setContext(expression.getContainingFile()); + final PsiElement element = codeFragment.getFirstChild(); + if (element instanceof PyExpressionStatement) { + final PyExpression dummyExpr = ((PyExpressionStatement)element).getExpression(); + return getType(dummyExpr, context); + } + } + return null; + } + + @Nullable + private static PyType getFunctionType(@NotNull PyExpression expression, @NotNull TypeEvalContext context) { + if (expression instanceof PySubscriptionExpression) { + final PySubscriptionExpression subscriptionExpr = (PySubscriptionExpression)expression; + final PyExpression operand = subscriptionExpr.getOperand(); + final String operandName = resolveToQualifiedName(operand, context); + if ("typing.Function".equals(operandName)) { + final PyExpression indexExpr = subscriptionExpr.getIndexExpression(); + if (indexExpr instanceof PyTupleExpression) { + final PyTupleExpression tupleExpr = (PyTupleExpression)indexExpr; + final PyExpression[] elements = tupleExpr.getElements(); + if (elements.length == 2) { + final PyExpression parametersExpr = elements[0]; + if (parametersExpr instanceof PyListLiteralExpression) { + final List<PyCallableParameter> parameters = new ArrayList<PyCallableParameter>(); + final PyListLiteralExpression listExpr = (PyListLiteralExpression)parametersExpr; + for (PyExpression argExpr : listExpr.getElements()) { + parameters.add(new PyCallableParameterImpl(null, getType(argExpr, context))); + } + final PyExpression returnTypeExpr = elements[1]; + final PyType returnType = getType(returnTypeExpr, context); + return new PyCallableTypeImpl(parameters, returnType); + } + } + } + } + } + return null; + } + + @Nullable + private static PyType getUnionType(@NotNull PyExpression expression, @NotNull TypeEvalContext context) { + if (expression instanceof PySubscriptionExpression) { + final PySubscriptionExpression subscriptionExpr = (PySubscriptionExpression)expression; + final PyExpression operand = subscriptionExpr.getOperand(); + final String operandName = resolveToQualifiedName(operand, context); + if ("typing.Union".equals(operandName)) { + return PyUnionType.union(getIndexTypes(subscriptionExpr, context)); + } + } + return null; + } + + @Nullable + private static PyGenericType getGenericType(@NotNull PyExpression expression, @NotNull TypeEvalContext context) { + final PsiElement resolved = resolve(expression, context); + if (resolved instanceof PyTargetExpression) { + final PyTargetExpression targetExpr = (PyTargetExpression)resolved; + final QualifiedName calleeName = targetExpr.getCalleeName(); + if (calleeName != null && "typevar".equals(calleeName.toString())) { + // XXX: Requires switching from stub to AST + final PyExpression assigned = targetExpr.findAssignedValue(); + if (assigned instanceof PyCallExpression) { + final PyCallExpression assignedCall = (PyCallExpression)assigned; + final PyExpression callee = assignedCall.getCallee(); + if (callee != null) { + final String calleeQName = resolveToQualifiedName(callee, context); + if ("typing.typevar".equals(calleeQName)) { + final PyExpression[] arguments = assignedCall.getArguments(); + if (arguments.length > 0) { + final PyExpression firstArgument = arguments[0]; + if (firstArgument instanceof PyStringLiteralExpression) { + final String name = ((PyStringLiteralExpression)firstArgument).getStringValue(); + if (name != null) { + return new PyGenericType(name, getGenericTypeBound(arguments, context)); + } + } + } + } + + } + } + } + } + return null; + } + + @Nullable + private static PyType getGenericTypeBound(@NotNull PyExpression[] typeVarArguments, @NotNull TypeEvalContext context) { + final List<PyType> types = new ArrayList<PyType>(); + if (typeVarArguments.length > 1) { + final PyExpression secondArgument = typeVarArguments[1]; + if (secondArgument instanceof PyKeywordArgument) { + final PyKeywordArgument valuesArgument = (PyKeywordArgument)secondArgument; + final PyExpression valueExpr = PyPsiUtils.flattenParens(valuesArgument.getValueExpression()); + if (valueExpr instanceof PyTupleExpression) { + final PyTupleExpression tupleExpr = (PyTupleExpression)valueExpr; + for (PyExpression expr : tupleExpr.getElements()) { + types.add(getType(expr, context)); + } + } + } + } + return PyUnionType.union(types); + } + + @NotNull + private static List<PyType> getIndexTypes(@NotNull PySubscriptionExpression expression, @NotNull TypeEvalContext context) { + final List<PyType> types = new ArrayList<PyType>(); + final PyExpression indexExpr = expression.getIndexExpression(); + if (indexExpr instanceof PyTupleExpression) { + final PyTupleExpression tupleExpr = (PyTupleExpression)indexExpr; + for (PyExpression expr : tupleExpr.getElements()) { + types.add(getType(expr, context)); + } + } + return types; + } + + @Nullable + private static PyType getParameterizedType(@NotNull PyExpression expression, @NotNull TypeEvalContext context) { + if (expression instanceof PySubscriptionExpression) { + final PySubscriptionExpression subscriptionExpr = (PySubscriptionExpression)expression; + final PyExpression operand = subscriptionExpr.getOperand(); + final PyExpression indexExpr = subscriptionExpr.getIndexExpression(); + final PyType operandType = getType(operand, context); + if (operandType instanceof PyClassType) { + final PyClass cls = ((PyClassType)operandType).getPyClass(); + if (PyNames.TUPLE.equals(cls.getQualifiedName())) { + final List<PyType> indexTypes = getIndexTypes(subscriptionExpr, context); + return PyTupleType.create(expression, indexTypes.toArray(new PyType[indexTypes.size()])); + } + else if (indexExpr != null) { + final PyType indexType = context.getType(indexExpr); + return new PyCollectionTypeImpl(cls, false, indexType); + } + } + } + return null; + } + + @Nullable + private static PyType getBuiltinCollection(@NotNull PyExpression expression, @NotNull TypeEvalContext context) { + final String collectionName = resolveToQualifiedName(expression, context); + final String builtinName = BUILTIN_COLLECTIONS.get(collectionName); + return builtinName != null ? PyTypeParser.getTypeByName(expression, builtinName) : null; + } + + @Nullable + private static PyType getType(@NotNull PyExpression expression, @NotNull TypeEvalContext context) { + // It is possible to replace PyAnnotation.getType() with this implementation + final PyType typingType = getTypingType(expression, context); + if (typingType != null) { + return typingType; + } + final PyType type = context.getType(expression); + if (type instanceof PyClassLikeType) { + final PyClassLikeType classType = (PyClassLikeType)type; + if (classType.isDefinition()) { + return classType.toInstance(); + } + } + else if (type instanceof PyNoneType) { + return type; + } + return null; + } + + @Nullable + private static PsiElement resolve(@NotNull PyExpression expression, @NotNull TypeEvalContext context) { + if (expression instanceof PyReferenceOwner) { + final PyReferenceOwner referenceOwner = (PyReferenceOwner)expression; + final PyResolveContext resolveContext = PyResolveContext.noImplicits().withTypeEvalContext(context); + final PsiPolyVariantReference reference = referenceOwner.getReference(resolveContext); + final PsiElement element = reference.resolve(); + if (element instanceof PyFunction) { + final PyFunction function = (PyFunction)element; + if (PyUtil.isInit(function)) { + final PyClass cls = function.getContainingClass(); + if (cls != null) { + return cls; + } + } + } + return element; + } + return null; + } + + @Nullable + private static String resolveToQualifiedName(@NotNull PyExpression expression, @NotNull TypeEvalContext context) { + final PsiElement element = resolve(expression, context); + if (element instanceof PyQualifiedNameOwner) { + final PyQualifiedNameOwner qualifiedNameOwner = (PyQualifiedNameOwner)element; + return qualifiedNameOwner.getQualifiedName(); + } + return null; + } +} diff --git a/python/src/com/jetbrains/python/codeInsight/highlighting/PyHighlightExitPointsHandlerFactory.java b/python/src/com/jetbrains/python/codeInsight/highlighting/PyHighlightExitPointsHandlerFactory.java index d0bc9dcbc7ca..27522d6e7f53 100644 --- a/python/src/com/jetbrains/python/codeInsight/highlighting/PyHighlightExitPointsHandlerFactory.java +++ b/python/src/com/jetbrains/python/codeInsight/highlighting/PyHighlightExitPointsHandlerFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -15,30 +15,26 @@ */ package com.jetbrains.python.codeInsight.highlighting; -import com.intellij.codeInsight.TargetElementUtilBase; import com.intellij.codeInsight.highlighting.HighlightUsagesHandlerBase; -import com.intellij.codeInsight.highlighting.HighlightUsagesHandlerFactory; +import com.intellij.codeInsight.highlighting.HighlightUsagesHandlerFactoryBase; import com.intellij.openapi.editor.Editor; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.util.PsiTreeUtil; import com.jetbrains.python.psi.PyExpression; import com.jetbrains.python.psi.PyReturnStatement; +import org.jetbrains.annotations.NotNull; /** * @author oleg */ -public class PyHighlightExitPointsHandlerFactory implements HighlightUsagesHandlerFactory { - public HighlightUsagesHandlerBase createHighlightUsagesHandler(final Editor editor, final PsiFile file) { - int offset = TargetElementUtilBase.adjustOffset(file, editor.getDocument(), editor.getCaretModel().getOffset()); - PsiElement target = file.findElementAt(offset); - if (target != null) { - final PyReturnStatement returnStatement = PsiTreeUtil.getParentOfType(target, PyReturnStatement.class); - if (returnStatement != null) { - final PyExpression returnExpr = returnStatement.getExpression(); - if (returnExpr == null || !PsiTreeUtil.isAncestor(returnExpr, target, false)) { - return new PyHighlightExitPointsHandler(editor, file, target); - } +public class PyHighlightExitPointsHandlerFactory extends HighlightUsagesHandlerFactoryBase { + public HighlightUsagesHandlerBase createHighlightUsagesHandler(@NotNull Editor editor, @NotNull PsiFile file, @NotNull PsiElement target) { + final PyReturnStatement returnStatement = PsiTreeUtil.getParentOfType(target, PyReturnStatement.class); + if (returnStatement != null) { + final PyExpression returnExpr = returnStatement.getExpression(); + if (returnExpr == null || !PsiTreeUtil.isAncestor(returnExpr, target, false)) { + return new PyHighlightExitPointsHandler(editor, file, target); } } return null; diff --git a/python/src/com/jetbrains/python/codeInsight/intentions/ImportToImportFromIntention.java b/python/src/com/jetbrains/python/codeInsight/intentions/ImportToImportFromIntention.java index fc35833473f8..e76240cefb1f 100644 --- a/python/src/com/jetbrains/python/codeInsight/intentions/ImportToImportFromIntention.java +++ b/python/src/com/jetbrains/python/codeInsight/intentions/ImportToImportFromIntention.java @@ -57,10 +57,11 @@ public class ImportToImportFromIntention implements IntentionAction { private PsiElement myReferee = null; private PyImportElement myImportElement = null; private Collection<PsiReference> myReferences = null; - private boolean myHasModuleReference = false; // is anything that resolves to our imported module is just an exact reference to that module + private boolean myHasModuleReference = false; + // is anything that resolves to our imported module is just an exact reference to that module private int myRelativeLevel; // true if "from ... import" - public IntentionState(Editor editor, PsiFile file) { + public IntentionState(@NotNull Editor editor, @NotNull PsiFile file) { boolean available = false; myImportElement = findImportElement(editor, file); if (myImportElement != null) { @@ -70,10 +71,10 @@ public class ImportToImportFromIntention implements IntentionAction { available = true; } else if (parent instanceof PyFromImportStatement) { - PyFromImportStatement from_import = (PyFromImportStatement)parent; - final int relative_level = from_import.getRelativeLevel(); - if (from_import.isValid() && relative_level > 0 && from_import.getImportSource() == null) { - myRelativeLevel = relative_level; + final PyFromImportStatement fromImport = (PyFromImportStatement)parent; + final int relativeLevel = fromImport.getRelativeLevel(); + if (fromImport.isValid() && relativeLevel > 0 && fromImport.getImportSource() == null) { + myRelativeLevel = relativeLevel; available = true; } } @@ -92,25 +93,27 @@ public class ImportToImportFromIntention implements IntentionAction { assert myImportElement != null : "isAvailable() must have returned true, but myImportElement is null"; // usages of imported name are qualifiers; what they refer to? - PyReferenceExpression reference = myImportElement.getImportReferenceExpression(); - if (reference != null) { - myModuleName = PyPsiUtils.toPath(reference); + final PyReferenceExpression importReference = myImportElement.getImportReferenceExpression(); + if (importReference != null) { + myModuleName = PyPsiUtils.toPath(importReference); myQualifierName = myImportElement.getVisibleName(); - myReferee = reference.getReference().resolve(); + myReferee = importReference.getReference().resolve(); myHasModuleReference = false; if (myReferee != null && myModuleName != null && myQualifierName != null) { final Collection<PsiReference> references = new ArrayList<PsiReference>(); PsiTreeUtil.processElements(file, new PsiElementProcessor() { public boolean execute(@NotNull PsiElement element) { if (element instanceof PyReferenceExpression && PsiTreeUtil.getParentOfType(element, PyImportElement.class) == null) { - PyReferenceExpression ref = (PyReferenceExpression)element; + final PyReferenceExpression ref = (PyReferenceExpression)element; if (myQualifierName.equals(PyPsiUtils.toPath(ref))) { // filter out other names that might resolve to our target - PsiElement parent_elt = ref.getParent(); - if (parent_elt instanceof PyQualifiedExpression) { // really qualified by us, not just referencing? - PsiElement resolved = ref.getReference().resolve(); + final PsiElement parentElt = ref.getParent(); + if (parentElt instanceof PyQualifiedExpression) { // really qualified by us, not just referencing? + final PsiElement resolved = ref.getReference().resolve(); if (resolved == myReferee) references.add(ref.getReference()); } - else myHasModuleReference = true; + else { + myHasModuleReference = true; + } } } return true; @@ -123,68 +126,70 @@ public class ImportToImportFromIntention implements IntentionAction { public void invoke() { assert myImportElement != null : "isAvailable() must have returned true, but myImportElement is null"; - PyUtil.sure(myImportElement.getImportReferenceExpression()); - Project project = myImportElement.getProject(); + sure(myImportElement.getImportReferenceExpression()); + final Project project = myImportElement.getProject(); + + final PyElementGenerator generator = PyElementGenerator.getInstance(project); + final LanguageLevel languageLevel = LanguageLevel.forElement(myImportElement); // usages of imported name are qualifiers; what they refer to? try { // remember names and make them drop qualifiers - Set<String> used_names = new HashSet<String>(); + final Set<String> usedNames = new HashSet<String>(); for (PsiReference ref : myReferences) { - PsiElement elt = ref.getElement(); - PsiElement parent_elt = elt.getParent(); - used_names.add(sure(PyUtil.sure(parent_elt).getLastChild()).getText()); // TODO: find ident node more properly + final PsiElement elt = ref.getElement(); + final PsiElement parentElt = elt.getParent(); + // TODO: find ident node more properly + final String nameUsed = sure(sure(parentElt).getLastChild()).getText(); + usedNames.add(nameUsed); if (!FileModificationService.getInstance().preparePsiElementForWrite(elt)) { return; } - PsiElement next_elt = elt.getNextSibling(); - if (next_elt != null && ".".equals(next_elt.getText())) next_elt.delete(); - elt.delete(); + assert parentElt instanceof PyReferenceExpression; + final PyElement newReference = generator.createExpressionFromText(languageLevel, nameUsed); + parentElt.replace(newReference); } // create a separate import stmt for the module - PsiElement importer = myImportElement.getParent(); - PyStatement import_statement; - PyImportElement[] import_elements; + final PsiElement importer = myImportElement.getParent(); + final PyStatement importStatement; + final PyImportElement[] importElements; if (importer instanceof PyImportStatement) { - import_statement = (PyImportStatement)importer; - import_elements = ((PyImportStatement)import_statement).getImportElements(); + importStatement = (PyImportStatement)importer; + importElements = ((PyImportStatement)importStatement).getImportElements(); } else if (importer instanceof PyFromImportStatement) { - import_statement = (PyFromImportStatement)importer; - import_elements = ((PyFromImportStatement)import_statement).getImportElements(); + importStatement = (PyFromImportStatement)importer; + importElements = ((PyFromImportStatement)importStatement).getImportElements(); } else { throw new IncorrectOperationException("Not an import at all"); } - PyElementGenerator generator = PyElementGenerator.getInstance(project); - StringBuilder builder = new StringBuilder("from ").append(getDots()).append(myModuleName).append(" import "); - builder.append(StringUtil.join(used_names, ", ")); - PyFromImportStatement from_import_stmt = - generator.createFromText(LanguageLevel.getDefault(), PyFromImportStatement.class, builder.toString()); - PsiElement parent = import_statement.getParent(); + final PyFromImportStatement newImportStatement = + generator.createFromImportStatement(languageLevel, getDots() + myModuleName, StringUtil.join(usedNames, ", "), null); + final PsiElement parent = importStatement.getParent(); sure(parent); sure(parent.isValid()); - if (import_elements.length == 1) { + if (importElements.length == 1) { if (myHasModuleReference) { - parent.addAfter(from_import_stmt, import_statement); // add 'import from': we need the module imported as is + parent.addAfter(newImportStatement, importStatement); // add 'import from': we need the module imported as is } else { // replace entire existing import - sure(parent.getNode()).replaceChild(sure(import_statement.getNode()), sure(from_import_stmt.getNode())); + sure(parent.getNode()).replaceChild(sure(importStatement.getNode()), sure(newImportStatement.getNode())); // import_statement.replace(from_import_stmt); } } else { if (!myHasModuleReference) { // cut the module out of import, add a from-import. - for (PyImportElement pie : import_elements) { + for (PyImportElement pie : importElements) { if (pie == myImportElement) { PyUtil.removeListNode(pie); break; } } } - parent.addAfter(from_import_stmt, import_statement); + parent.addAfter(newImportStatement, importStatement); } } catch (IncorrectOperationException ignored) { @@ -193,18 +198,24 @@ public class ImportToImportFromIntention implements IntentionAction { } + @NotNull public String getText() { - String module_name = "?"; + String moduleName = "?"; if (myImportElement != null) { - PyReferenceExpression reference = myImportElement.getImportReferenceExpression(); - if (reference != null) module_name = PyPsiUtils.toPath(reference); + final PyReferenceExpression reference = myImportElement.getImportReferenceExpression(); + if (reference != null) { + moduleName = PyPsiUtils.toPath(reference); + } } - return PyBundle.message("INTN.convert.to.from.$0.import.$1", getDots()+module_name, "..."); + return PyBundle.message("INTN.convert.to.from.$0.import.$1", getDots() + moduleName, "..."); } + @NotNull private String getDots() { String dots = ""; - for (int i=0; i<myRelativeLevel; i+=1) dots += "."; // this generally runs 1-2 times, so it's cheaper than allocating a StringBuilder + for (int i = 0; i < myRelativeLevel; i += 1) { + dots += "."; // this generally runs 1-2 times, so it's cheaper than allocating a StringBuilder + } return dots; } } @@ -222,10 +233,15 @@ public class ImportToImportFromIntention implements IntentionAction { } @Nullable - private static PyImportElement findImportElement(Editor editor, PsiFile file) { - PyImportElement import_elt = PsiTreeUtil.getParentOfType(file.findElementAt(editor.getCaretModel().getOffset()), PyImportElement.class); - if (import_elt != null && import_elt.isValid()) return import_elt; - else return null; + private static PyImportElement findImportElement(@NotNull Editor editor, @NotNull PsiFile file) { + final PsiElement elementAtCaret = file.findElementAt(editor.getCaretModel().getOffset()); + final PyImportElement importElement = PsiTreeUtil.getParentOfType(elementAtCaret, PyImportElement.class); + if (importElement != null && importElement.isValid()) { + return importElement; + } + else { + return null; + } } public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { @@ -233,7 +249,7 @@ public class ImportToImportFromIntention implements IntentionAction { return false; } - IntentionState state = new IntentionState(editor, file); + final IntentionState state = new IntentionState(editor, file); if (state.isAvailable()) { myText = state.getText(); return true; @@ -242,7 +258,7 @@ public class ImportToImportFromIntention implements IntentionAction { } public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException { - IntentionState state = new IntentionState(editor, file); + final IntentionState state = new IntentionState(editor, file); state.invoke(); } diff --git a/python/src/com/jetbrains/python/codeInsight/intentions/PyGenerateDocstringIntention.java b/python/src/com/jetbrains/python/codeInsight/intentions/PyGenerateDocstringIntention.java index 7acfc9716fea..ca7ec65f9908 100644 --- a/python/src/com/jetbrains/python/codeInsight/intentions/PyGenerateDocstringIntention.java +++ b/python/src/com/jetbrains/python/codeInsight/intentions/PyGenerateDocstringIntention.java @@ -69,6 +69,7 @@ public class PyGenerateDocstringIntention extends BaseIntentionAction { if (function == null || statementList != null) { return false; } + if (!elementAt.equals(function.getNameNode())) return false; return isAvailableForFunction(project, function); } diff --git a/python/src/com/jetbrains/python/codeInsight/override/PyOverrideImplementUtil.java b/python/src/com/jetbrains/python/codeInsight/override/PyOverrideImplementUtil.java index 48a42753ebe5..e11f3e01e916 100644 --- a/python/src/com/jetbrains/python/codeInsight/override/PyOverrideImplementUtil.java +++ b/python/src/com/jetbrains/python/codeInsight/override/PyOverrideImplementUtil.java @@ -143,7 +143,7 @@ public class PyOverrideImplementUtil { return; } new WriteCommandAction(pyClass.getProject(), pyClass.getContainingFile()) { - protected void run(final Result result) throws Throwable { + protected void run(@NotNull final Result result) throws Throwable { write(pyClass, membersToOverride, editor, implement); } }.execute(); @@ -173,9 +173,7 @@ public class PyOverrideImplementUtil { PyPsiUtils.removeRedundantPass(statementList); if (element != null) { final PyStatementList targetStatementList = element.getStatementList(); - final int start = targetStatementList != null - ? targetStatementList.getTextRange().getStartOffset() - : element.getTextRange().getStartOffset(); + final int start = targetStatementList.getTextRange().getStartOffset(); editor.getCaretModel().moveToOffset(start); editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE); editor.getSelectionModel().setSelection(start, element.getTextRange().getEndOffset()); @@ -238,7 +236,7 @@ public class PyOverrideImplementUtil { PsiElement outerClass = PsiTreeUtil.getParentOfType(pyClass, PyClass.class, true, PyFunction.class); String className = pyClass.getName(); final List<String> nameResult = Lists.newArrayList(className); - while(outerClass instanceof PyClass) { + while(outerClass != null) { nameResult.add(0, ((PyClass)outerClass).getName()); outerClass = PsiTreeUtil.getParentOfType(outerClass, PyClass.class, true, PyFunction.class); } |