public void doInvoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException { final PsiElement element = PyUtil.findNonWhitespaceAtOffset(file, editor.getCaretModel().getOffset()); PyFunction problemFunction = PsiTreeUtil.getParentOfType(element, PyFunction.class); if (problemFunction == null) return; final PyClass containingClass = problemFunction.getContainingClass(); if (containingClass == null) return; final List<UsageInfo> usages = PyRefactoringUtil.findUsages(problemFunction, false); final PyDecoratorList decoratorList = problemFunction.getDecoratorList(); if (decoratorList != null) { final PyDecorator decorator = decoratorList.findDecorator(PyNames.STATICMETHOD); if (decorator != null) decorator.delete(); } final PsiElement copy = problemFunction.copy(); problemFunction.delete(); file.addAfter(copy, containingClass); for (UsageInfo usage : usages) { final PsiElement usageElement = usage.getElement(); if (usageElement instanceof PyReferenceExpression) { PyUtil.removeQualifier((PyReferenceExpression) usageElement); } } }
protected boolean isValidIntroduceContext(PsiElement element) { PyDecorator decorator = PsiTreeUtil.getParentOfType(element, PyDecorator.class); if (decorator != null && PsiTreeUtil.isAncestor(decorator.getCallee(), element, false)) { return false; } return PsiTreeUtil.getParentOfType(element, PyParameterList.class) == null; }
@Override public void visitPyDecoratorList(final PyDecoratorList node) { PyDecorator[] decorators = node.getDecorators(); for (PyDecorator deco : decorators) { if (deco.hasArgumentList()) continue; final PyCallExpression.PyMarkedCallee markedCallee = deco.resolveCallee(resolveWithoutImplicits()); if (markedCallee != null && !markedCallee.isImplicitlyResolved()) { final Callable callable = markedCallee.getCallable(); int firstParamOffset = markedCallee.getImplicitOffset(); final List<PyParameter> params = PyUtil.getParameters(callable, myTypeEvalContext); final PyNamedParameter allegedFirstParam = params.size() < firstParamOffset ? null : params.get(firstParamOffset - 1).getAsNamed(); if (allegedFirstParam == null || allegedFirstParam.isKeywordContainer()) { // no parameters left to pass function implicitly, or wrong param type registerProblem( deco, PyBundle.message( "INSP.func.$0.lacks.first.arg", callable.getName())); // TODO: better names for anon lambdas } else { // possible unfilled params for (int i = firstParamOffset; i < params.size(); i += 1) { final PyParameter parameter = params.get(i); if (parameter instanceof PySingleStarParameter) continue; final PyNamedParameter par = parameter.getAsNamed(); // param tuples, non-starred or non-default won't do if (par == null || (!par.isKeywordContainer() && !par.isPositionalContainer() && !par.hasDefaultValue())) { String parameterName = par != null ? par.getName() : "(...)"; registerProblem( deco, PyBundle.message("INSP.parameter.$0.unfilled", parameterName)); } } } } // else: this case is handled by arglist visitor } }
/** * When a function is decorated many decorators, finds the deepest builtin decorator: * * <pre> * @foo * @classmethod <b># <-- that's it</b> * @bar * def moo(cls): * pass * </pre> * * @return name of the built-in decorator, or null (even if there are non-built-in decorators). */ @Nullable private String getClassOrStaticMethodDecorator() { PyDecoratorList decolist = getDecoratorList(); if (decolist != null) { PyDecorator[] decos = decolist.getDecorators(); if (decos.length > 0) { for (int i = decos.length - 1; i >= 0; i -= 1) { PyDecorator deco = decos[i]; String deconame = deco.getName(); if (PyNames.CLASSMETHOD.equals(deconame) || PyNames.STATICMETHOD.equals(deconame)) { return deconame; } for (PyKnownDecoratorProvider provider : PyUtil.KnownDecoratorProviderHolder.KNOWN_DECORATOR_PROVIDERS) { String name = provider.toKnownDecorator(deconame); if (name != null) { return name; } } } } } return null; }
@Nullable public static PyType getTypeFromTarget( @NotNull final PsiElement target, final TypeEvalContext context, PyReferenceExpression anchor) { if (!(target instanceof PyTargetExpression)) { // PyTargetExpression will ask about its type itself final PyType pyType = getReferenceTypeFromProviders(target, context, anchor); if (pyType != null) { return pyType; } } if (target instanceof PyTargetExpression) { final String name = ((PyTargetExpression) target).getName(); if (PyNames.NONE.equals(name)) { return PyNoneType.INSTANCE; } if (PyNames.TRUE.equals(name) || PyNames.FALSE.equals(name)) { return PyBuiltinCache.getInstance(target).getBoolType(); } } if (target instanceof PyFile) { return new PyModuleType((PyFile) target); } if (target instanceof PyImportedModule) { return new PyImportedModuleType((PyImportedModule) target); } if ((target instanceof PyTargetExpression || target instanceof PyNamedParameter) && anchor != null && context.allowDataFlow(anchor)) { final ScopeOwner scopeOwner = PsiTreeUtil.getStubOrPsiParentOfType(anchor, ScopeOwner.class); if (scopeOwner != null && scopeOwner == PsiTreeUtil.getStubOrPsiParentOfType(target, ScopeOwner.class)) { final String name = ((PyElement) target).getName(); if (name != null) { final PyType type = getTypeByControlFlow(name, context, anchor, scopeOwner); if (type != null) { return type; } } } } if (target instanceof PyFunction) { final PyDecoratorList decoratorList = ((PyFunction) target).getDecoratorList(); if (decoratorList != null) { final PyDecorator propertyDecorator = decoratorList.findDecorator(PyNames.PROPERTY); if (propertyDecorator != null) { return PyBuiltinCache.getInstance(target).getObjectType(PyNames.PROPERTY); } for (PyDecorator decorator : decoratorList.getDecorators()) { final QualifiedName qName = decorator.getQualifiedName(); if (qName != null && (qName.endsWith(PyNames.SETTER) || qName.endsWith(PyNames.DELETER) || qName.endsWith(PyNames.GETTER))) { return PyBuiltinCache.getInstance(target).getObjectType(PyNames.PROPERTY); } } } } if (target instanceof PyTypedElement) { return context.getType((PyTypedElement) target); } if (target instanceof PsiDirectory) { final PsiDirectory dir = (PsiDirectory) target; PsiFile file = dir.findFile(PyNames.INIT_DOT_PY); if (file != null) { return getTypeFromTarget(file, context, anchor); } if (PyUtil.isPackage(dir, anchor)) { final PsiFile containingFile = anchor.getContainingFile(); if (containingFile instanceof PyFile) { final QualifiedName qualifiedName = QualifiedNameFinder.findShortestImportableQName(dir); if (qualifiedName != null) { final PyImportedModule module = new PyImportedModule(null, (PyFile) containingFile, qualifiedName); return new PyImportedModuleType(module); } } } } return null; }