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); } } }
@Override public void doApply( @NotNull Editor editor, @NotNull PySmartEnterProcessor processor, @NotNull PyWithStatement withStatement) throws IncorrectOperationException { final PsiElement colonToken = PyUtil.getFirstChildOfType(withStatement, PyTokenTypes.COLON); final PsiElement withToken = PyUtil.getFirstChildOfType(withStatement, PyTokenTypes.WITH_KEYWORD); final Document document = editor.getDocument(); if (colonToken == null && withToken != null) { int insertAt = withToken.getTextRange().getEndOffset(); String textToInsert = ":"; final PyWithItem lastItem = ArrayUtil.getLastElement(withStatement.getWithItems()); if (lastItem == null || lastItem.getExpression() == null) { textToInsert = " :"; processor.registerUnresolvedError(insertAt + 1); } else { final PyExpression expression = lastItem.getExpression(); insertAt = expression.getTextRange().getEndOffset(); final PsiElement asToken = PyUtil.getFirstChildOfType(lastItem, PyTokenTypes.AS_KEYWORD); if (asToken != null) { insertAt = asToken.getTextRange().getEndOffset(); final PyExpression target = lastItem.getTarget(); if (target != null) { insertAt = target.getTextRange().getEndOffset(); } else { textToInsert = " :"; processor.registerUnresolvedError(insertAt + 1); } } } document.insertString(insertAt, textToInsert); } }
public PyType getType(@NotNull TypeEvalContext context, @NotNull TypeEvalContext.Key key) { if (!TypeEvalStack.mayEvaluate(this)) { return null; } try { final boolean qualified = isQualified(); if (!qualified) { String name = getReferencedName(); if (PyNames.NONE.equals(name)) { return PyNoneType.INSTANCE; } } PyType type = getTypeFromProviders(context); if (type != null) { return type; } if (qualified) { PyType maybe_type = PyUtil.getSpecialAttributeType(this, context); if (maybe_type != null) return maybe_type; Ref<PyType> typeOfProperty = getTypeOfProperty(context); if (typeOfProperty != null) { return typeOfProperty.get(); } } final PsiPolyVariantReference reference = getReference(PyResolveContext.noImplicits().withTypeEvalContext(context)); final List<PsiElement> targets = PyUtil.multiResolveTopPriority(reference); if (targets.isEmpty()) { return getQualifiedReferenceTypeByControlFlow(context); } final List<PyType> members = new ArrayList<PyType>(); for (PsiElement target : targets) { if (target == this || target == null) { continue; } if (!target.isValid()) { LOG.error( "Reference " + this + " resolved to invalid element " + target + " (text=" + target.getText() + ")"); continue; } members.add(getTypeFromTarget(target, context, this)); } return PyUnionType.union(members); } finally { TypeEvalStack.evaluated(this); } }
private static void highlightStarArgumentTypeMismatch( PyArgumentList node, ProblemsHolder holder, TypeEvalContext context) { for (PyExpression arg : node.getArguments()) { if (arg instanceof PyStarArgument) { PyExpression content = PyUtil.peelArgument(PsiTreeUtil.findChildOfType(arg, PyExpression.class)); if (content != null) { PyType inside_type = context.getType(content); if (inside_type != null && !PyTypeChecker.isUnknown(inside_type)) { if (((PyStarArgument) arg).isKeyword()) { if (!PyABCUtil.isSubtype(inside_type, PyNames.MAPPING)) { holder.registerProblem( arg, PyBundle.message("INSP.expected.dict.got.$0", inside_type.getName())); } } else { // * arg if (!PyABCUtil.isSubtype(inside_type, PyNames.ITERABLE)) { holder.registerProblem( arg, PyBundle.message("INSP.expected.iter.got.$0", inside_type.getName())); } } } } } } }
@Override public void visitPyAssignmentStatement(PyAssignmentStatement node) { final PyExpression value = node.getAssignedValue(); if (value instanceof PyCallExpression) { final PyType type = myTypeEvalContext.getType(value); final PyExpression callee = ((PyCallExpression) value).getCallee(); if (type instanceof PyNoneType && callee != null) { final PyTypeChecker.AnalyzeCallResults analyzeCallResults = PyTypeChecker.analyzeCall(((PyCallExpression) value), myTypeEvalContext); if (analyzeCallResults != null) { final PyCallable callable = analyzeCallResults.getCallable(); if (PySdkUtil.isElementInSkeletons(callable)) { return; } if (callable instanceof PyFunction) { final PyFunction function = (PyFunction) callable; // Currently we don't infer types returned by decorators if (hasInheritors(function) || PyUtil.hasCustomDecorators(function)) { return; } } registerProblem( node, PyBundle.message("INSP.none.function.assignment", callee.getName()), new PyRemoveAssignmentQuickFix()); } } } }
@NotNull private static List<RatedResolveResult> resolveInDirectory( @NotNull final String referencedName, @Nullable final PsiFile containingFile, final PsiDirectory dir, boolean isFileOnly, boolean checkForPackage) { final PsiDirectory subdir = dir.findSubdirectory(referencedName); if (subdir != null && (!checkForPackage || PyUtil.isPackage(subdir, containingFile))) { return ResolveResultList.to(subdir); } final PsiFile module = findPyFileInDir(dir, referencedName); if (module != null) { return ResolveResultList.to(module); } if (!isFileOnly) { // not a subdir, not a file; could be a name in parent/__init__.py final PsiFile initPy = dir.findFile(PyNames.INIT_DOT_PY); if (initPy == containingFile) { return Collections.emptyList(); // don't dive into the file we're in } if (initPy instanceof PyFile) { return ((PyFile) initPy).multiResolveName(referencedName); } } return Collections.emptyList(); }
@NotNull private static List<RatedResolveResult> resolveInPackageDirectory( @Nullable PsiElement parent, @NotNull String referencedName, @Nullable PsiFile containingFile, boolean fileOnly, boolean checkForPackage) { final PsiElement parentDir = PyUtil.turnInitIntoDir(parent); if (parentDir instanceof PsiDirectory) { final List<RatedResolveResult> resolved = resolveInDirectory( referencedName, containingFile, (PsiDirectory) parentDir, fileOnly, checkForPackage); if (!resolved.isEmpty()) { for (RatedResolveResult result : resolved) { if (result.getRate() > RatedResolveResult.RATE_LOW) { return resolved; } } } if (parent instanceof PsiFile) { final PsiElement foreign = resolveForeignImports((PsiFile) parent, referencedName); if (foreign != null) { final ResolveResultList results = new ResolveResultList(); results.addAll(resolved); results.poke(foreign, RatedResolveResult.RATE_NORMAL); return results; } } return resolved; } return Collections.emptyList(); }
@NotNull private static List<RatedResolveResult> resolveInPackageModule( @NotNull PyFile parent, @NotNull String referencedName, @Nullable PsiFile containingFile, boolean fileOnly, boolean checkForPackage) { final List<RatedResolveResult> moduleMembers = resolveModuleMember(parent, referencedName); final List<RatedResolveResult> resolvedInModule = Lists.newArrayList(); final List<RatedResolveResult> results = Lists.newArrayList(); for (RatedResolveResult member : moduleMembers) { final PsiElement moduleMember = member.getElement(); if (!fileOnly || PyUtil.instanceOf(moduleMember, PsiFile.class, PsiDirectory.class)) { results.add(member); if (moduleMember != null && !preferResolveInDirectoryOverModule(moduleMember)) { resolvedInModule.add(member); } } } if (!resolvedInModule.isEmpty()) { return resolvedInModule; } final List<RatedResolveResult> resolvedInDirectory = resolveInPackageDirectory( parent, referencedName, containingFile, fileOnly, checkForPackage); if (!resolvedInDirectory.isEmpty()) { return resolvedInDirectory; } return results; }
@Override protected void moveOffsetAfter(boolean success) { if (success && (myPanel != null && myPanel.getInitPlace() != InitPlace.SAME_METHOD) || myOperation.getInplaceInitPlace() != InitPlace.SAME_METHOD) { final AccessToken accessToken = ApplicationManager.getApplication().acquireWriteActionLock(getClass()); try { final PyAssignmentStatement initializer = PsiTreeUtil.getParentOfType(myTarget, PyAssignmentStatement.class); assert initializer != null; final Function<String, PyStatement> callback = FunctionUtil.<String, PyStatement>constant(initializer); final PyClass pyClass = PyUtil.getContainingClassOrSelf(initializer); InitPlace initPlace = myPanel != null ? myPanel.getInitPlace() : myOperation.getInplaceInitPlace(); if (initPlace == InitPlace.CONSTRUCTOR) { AddFieldQuickFix.addFieldToInit(myProject, pyClass, "", callback); } else if (initPlace == InitPlace.SET_UP) { addFieldToSetUp(pyClass, callback); } if (myOperation.getOccurrences().size() > 0) { initializer.delete(); } else { final PyExpression copy = PyElementGenerator.getInstance(myProject) .createExpressionFromText( LanguageLevel.forElement(myTarget), myTarget.getText()); initializer.replace(copy); } initializer.delete(); } finally { accessToken.finish(); } } }
@Nullable private PyType getImplicitlyResolvedType( @NotNull List<Token<PyElementType>> tokens, @NotNull TypeEvalContext context, @NotNull Map<TextRange, PyType> types, @NotNull Map<PyType, TextRange> fullRanges, TextRange firstRange) { PyType type = null; QualifiedName qName = null; while (!tokens.isEmpty()) { final Token<PyElementType> token = tokens.get(0); final String name = token.getText().toString(); qName = qName != null ? qName.append(name) : QualifiedName.fromComponents(name); PsiElement module = new QualifiedNameResolverImpl(qName).fromElement(myAnchor).firstResult(); if (module == null) { break; } if (module instanceof PsiDirectory) { module = PyUtil.getPackageElement((PsiDirectory) module, myAnchor); } if (module instanceof PyTypedElement) { final PyType moduleType = context.getType((PyTypedElement) module); if (moduleType != null) { type = moduleType; types.put(token.getRange(), type); fullRanges.put( type, TextRange.create(firstRange.getStartOffset(), token.getRange().getEndOffset())); } } tokens.remove(0); } return type; }
public PsiElement setName(@NotNull String name) throws IncorrectOperationException { final ASTNode nameElement = PyUtil.createNewName(this, name); final ASTNode nameNode = getNameNode(); if (nameNode != null) { getNode().replaceChild(nameNode, nameElement); } return this; }
@Override protected PyAssignmentStatement createDeclaration( Project project, String assignmentText, PsiElement anchor) { final PyFunction container = PsiTreeUtil.getParentOfType(anchor, PyFunction.class); String selfName = PyUtil.getFirstParameterName(container); final LanguageLevel langLevel = LanguageLevel.forElement(anchor); return PyElementGenerator.getInstance(project) .createFromText(langLevel, PyAssignmentStatement.class, selfName + "." + assignmentText); }
@Override public PyType getType(@NotNull TypeEvalContext context, @NotNull TypeEvalContext.Key key) { for (PyTypeProvider provider : Extensions.getExtensions(PyTypeProvider.EP_NAME)) { final PyType type = provider.getCallableType(this, context); if (type != null) { return type; } } final boolean hasCustomDecorators = PyUtil.hasCustomDecorators(this) && !PyUtil.isDecoratedAsAbstract(this) && getProperty() == null; final PyFunctionType type = new PyFunctionType(this); if (hasCustomDecorators) { return PyUnionType.createWeakType(type); } return type; }
@Override public Icon getIcon(@NotNull PsiElement element, int flags) { if (element instanceof PsiDirectory) { final PsiDirectory directory = (PsiDirectory) element; if (PyUtil.isPackage(directory, null) && !isSpecialDirectory(directory)) { return PlatformIcons.PACKAGE_ICON; } } return null; }
private static void highlightIncorrectArguments( ProblemsHolder holder, CallArgumentsMapping result, @NotNull TypeEvalContext context) { for (Map.Entry<PyExpression, EnumSet<CallArgumentsMapping.ArgFlag>> argEntry : result.getArgumentFlags().entrySet()) { EnumSet<CallArgumentsMapping.ArgFlag> flags = argEntry.getValue(); if (!flags.isEmpty()) { // something's wrong PyExpression arg = argEntry.getKey(); if (flags.contains(CallArgumentsMapping.ArgFlag.IS_DUP)) { holder.registerProblem(arg, PyBundle.message("INSP.duplicate.argument")); } if (flags.contains(CallArgumentsMapping.ArgFlag.IS_DUP_KWD)) { holder.registerProblem(arg, PyBundle.message("INSP.duplicate.doublestar.arg")); } if (flags.contains(CallArgumentsMapping.ArgFlag.IS_DUP_TUPLE)) { holder.registerProblem(arg, PyBundle.message("INSP.duplicate.star.arg")); } if (flags.contains(CallArgumentsMapping.ArgFlag.IS_POS_PAST_KWD)) { holder.registerProblem( arg, PyBundle.message("INSP.cannot.appear.past.keyword.arg"), ProblemHighlightType.ERROR); } if (flags.contains(CallArgumentsMapping.ArgFlag.IS_UNMAPPED)) { holder.registerProblem(arg, PyBundle.message("INSP.unexpected.arg")); } if (flags.contains(CallArgumentsMapping.ArgFlag.IS_TOO_LONG)) { final PyCallExpression.PyMarkedCallee markedCallee = result.getMarkedCallee(); String parameterName = null; if (markedCallee != null) { final List<PyParameter> parameters = PyUtil.getParameters(markedCallee.getCallable(), context); for (int i = parameters.size() - 1; i >= 0; --i) { final PyParameter param = parameters.get(i); if (param instanceof PyNamedParameter) { final List<PyNamedParameter> unmappedParams = result.getUnmappedParams(); if (!((PyNamedParameter) param).isPositionalContainer() && !((PyNamedParameter) param).isKeywordContainer() && param.getDefaultValue() == null && !unmappedParams.contains(param)) { parameterName = param.getName(); break; } } } holder.registerProblem( arg, parameterName != null ? PyBundle.message( "INSP.multiple.values.resolve.to.positional.$0", parameterName) : PyBundle.message("INSP.more.args.that.pos.params")); } } } } }
@Nullable @Override public List<? extends RatedResolveResult> resolveMember( @NotNull String name, @Nullable PyExpression location, @NotNull AccessDirection direction, @NotNull PyResolveContext resolveContext) { final PsiElement resolved = myImportedModule.resolve(); if (resolved != null) { final PsiFile containingFile = location != null ? location.getContainingFile() : null; List<PsiElement> elements = Collections.singletonList( ResolveImportUtil.resolveChild(resolved, name, containingFile, false, true)); final PyImportElement importElement = myImportedModule.getImportElement(); final PyFile resolvedFile = PyUtil.as(resolved, PyFile.class); if (location != null && importElement != null && PyUtil.inSameFile(location, importElement) && ResolveImportUtil.getPointInImport(location) == PointInImport.NONE && resolved instanceof PsiFileSystemItem && (resolvedFile == null || !PyUtil.isPackage(resolvedFile) || resolvedFile.getElementNamed(name) == null)) { final List<PsiElement> importedSubmodules = PyModuleType.collectImportedSubmodules((PsiFileSystemItem) resolved, location); if (importedSubmodules != null) { final Set<PsiElement> imported = Sets.newHashSet(importedSubmodules); elements = ContainerUtil.filter( elements, new Condition<PsiElement>() { @Override public boolean value(PsiElement element) { return imported.contains(element); } }); } } return ResolveImportUtil.rateResults(elements); } return null; }
private static boolean isAbstractMethodForClass( @NotNull PyFunction method, @NotNull PyClass cls) { final String methodName = method.getName(); if (methodName == null || cls.findMethodByName(methodName, false) != null || cls.findClassAttribute(methodName, false) != null) { return false; } return PyUtil.isDecoratedAsAbstract(method) || PyOverrideImplementUtil.raisesNotImplementedError(method); }
@NotNull @Override public ProtectionLevel getProtectionLevel() { final int underscoreLevels = PyUtil.getInitialUnderscores(getName()); for (final ProtectionLevel level : ProtectionLevel.values()) { if (level.getUnderscoreLevel() == underscoreLevels) { return level; } } return ProtectionLevel.PRIVATE; }
@Override public LanguageLevel getLanguageLevel() { VirtualFile virtualFile = getVirtualFile(); if (virtualFile == null) { virtualFile = getUserData(IndexingDataKeys.VIRTUAL_FILE); } if (virtualFile == null) { virtualFile = getViewProvider().getVirtualFile(); } return PyUtil.getLanguageLevelForVirtualFile(getProject(), virtualFile); }
/** * @return if method could be made abstract? (that means "create abstract version if method in * parent class") */ private static boolean couldBeAbstract(@NotNull final PyFunction function) { if (PyUtil.isInit(function)) { return false; // Who wants to make __init__ abstract?! } final PyUtil.MethodFlags flags = PyUtil.MethodFlags.of(function); assert flags != null : "Function should be called on method!"; final boolean py3K = LanguageLevel.forElement(function).isPy3K(); // TODO: use strategy because we already has the same check in #addMetaAbcIfNeeded return flags.isInstanceMethod() || py3K; // Any method could be made abstract in py3 }
@Nullable private static Boolean isOverrides(final PyFunction pyFunction) { final PyClass clazz = PyUtil.getContainingClassOrSelf(pyFunction); assert clazz != null : "Refactoring called on function, not method: " + pyFunction; for (final PyClass parentClass : clazz.getSuperClasses()) { final PyFunction parentMethod = parentClass.findMethodByName(pyFunction.getName(), true); if (parentMethod != null) { return true; } } return null; }
private static boolean inConstructor(@NotNull PsiElement expression) { final PsiElement expr = expression instanceof PyClass ? expression : expression.getParent(); PyClass clazz = PyUtil.getContainingClassOrSelf(expr); final ScopeOwner current = ScopeUtil.getScopeOwner(expression); if (clazz != null && current != null && current instanceof PyFunction) { PyFunction init = clazz.findMethodByName(PyNames.INIT, false, null); if (current == init) { return true; } } return false; }
@Override public void launch() { final String defaultFilePath = FileUtil.toSystemDependentName( myClassUnderRefactoring.getContainingFile().getVirtualFile().getPath()); final VirtualFile[] roots = ProjectRootManager.getInstance(myClassUnderRefactoring.getProject()).getContentRoots(); final Collection<PyMemberInfo<PyElement>> pyMemberInfos = PyUtil.filterOutObject(myStorage.getClassMemberInfos(myClassUnderRefactoring)); myView.configure( new PyExtractSuperclassInitializationInfo(myModel, pyMemberInfos, defaultFilePath, roots)); myView.initAndShow(); }
/** * Resolves a module reference in a general case. * * @param qualifiedName qualified name of the module reference to resolve * @param sourceFile where that reference resides; serves as PSI foothold to determine module, * project, etc. * @param importIsAbsolute if false, try old python 2.x's "relative first, absolute next" * approach. * @param relativeLevel if > 0, step back from sourceFile and resolve from there (even if * importIsAbsolute is false!). * @return list of possible candidates */ @NotNull public static List<PsiElement> resolveModule( @Nullable QualifiedName qualifiedName, @Nullable PsiFile sourceFile, boolean importIsAbsolute, int relativeLevel) { if (qualifiedName == null || sourceFile == null) { return Collections.emptyList(); } final ResolveModuleParams params = new ResolveModuleParams(qualifiedName, sourceFile, importIsAbsolute, relativeLevel); return PyUtil.getParameterizedCachedValue( sourceFile, params, ResolveImportUtil::calculateResolveModule); }
@NotNull private static List<PsiElement> tryResolving( @NotNull PyExpression expression, @NotNull TypeEvalContext context) { final List<PsiElement> elements = Lists.newArrayList(); if (expression instanceof PyReferenceExpression) { final PyReferenceExpression referenceExpr = (PyReferenceExpression) expression; final PyResolveContext resolveContext = PyResolveContext.noImplicits().withTypeEvalContext(context); final PsiPolyVariantReference reference = referenceExpr.getReference(resolveContext); final List<PsiElement> resolved = PyUtil.multiResolveTopPriority(reference); for (PsiElement element : resolved) { if (element instanceof PyFunction) { final PyFunction function = (PyFunction) element; if (PyUtil.isInit(function)) { final PyClass cls = function.getContainingClass(); if (cls != null) { elements.add(cls); continue; } } } else if (element instanceof PyTargetExpression) { final PyTargetExpression targetExpr = (PyTargetExpression) element; // XXX: Requires switching from stub to AST final PyExpression assignedValue = targetExpr.findAssignedValue(); if (assignedValue != null) { elements.add(assignedValue); continue; } } if (element != null) { elements.add(element); } } } return !elements.isEmpty() ? elements : Collections.singletonList(expression); }
@Nullable private static PyType getGenericConstructorType( @NotNull PyFunction function, @NotNull Context context) { if (PyUtil.isInit(function)) { final PyClass cls = function.getContainingClass(); if (cls != null) { final List<PyGenericType> genericTypes = collectGenericTypes(cls, context); final List<PyType> elementTypes = new ArrayList<>(genericTypes); if (!elementTypes.isEmpty()) { return new PyCollectionTypeImpl(cls, false, elementTypes); } } } return null; }
@Override protected boolean checkEnabled(IntroduceOperation operation) { if (PyUtil.getContainingClassOrSelf(operation.getElement()) == null) { CommonRefactoringUtil.showErrorHint( operation.getProject(), operation.getEditor(), "Cannot introduce field: not in class", myDialogTitle, getHelpId()); return false; } if (dependsOnLocalScopeValues(operation.getElement())) { operation.removeAvailableInitPlace(InitPlace.CONSTRUCTOR); operation.removeAvailableInitPlace(InitPlace.SET_UP); } return true; }
public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { if (!(file instanceof PyFile)) { return false; } final PsiElement element = PyUtil.findNonWhitespaceAtOffset(file, editor.getCaretModel().getOffset()); final PyFunction function = PsiTreeUtil.getParentOfType(element, PyFunction.class); if (function == null) return false; final PyClass containingClass = function.getContainingClass(); if (containingClass == null) return false; final PyDecoratorList decoratorList = function.getDecoratorList(); if (decoratorList != null) { final PyDecorator staticMethod = decoratorList.findDecorator(PyNames.STATICMETHOD); if (staticMethod != null) return true; } return false; }
@Nullable @Override public PsiComment getTypeComment() { final PsiComment inlineComment = PyUtil.getCommentOnHeaderLine(this); if (inlineComment != null && PyTypingTypeProvider.getTypeCommentValue(inlineComment.getText()) != null) { return inlineComment; } final PyStatementList statements = getStatementList(); if (statements.getStatements().length != 0) { final PsiComment comment = as(statements.getFirstChild(), PsiComment.class); if (comment != null && PyTypingTypeProvider.getTypeCommentValue(comment.getText()) != null) { return comment; } } return null; }
@NotNull @Override public Collection<PsiReference> findReferencesToHighlight( @NotNull PsiElement target, @NotNull SearchScope searchScope) { if (target instanceof PyImportedModule) { target = ((PyImportedModule) target).resolve(); } if (target instanceof PyFile && PyNames.INIT_DOT_PY.equals(((PyFile) target).getName())) { List<PsiReference> result = new ArrayList<PsiReference>(); result.addAll(super.findReferencesToHighlight(target, searchScope)); PsiElement targetDir = PyUtil.turnInitIntoDir(target); if (targetDir != null) { result.addAll(ReferencesSearch.search(targetDir, searchScope, false).findAll()); } return result; } return super.findReferencesToHighlight(target, searchScope); }