private void checkExpression(PyQualifiedExpression node) {
   final PyExpression qualifier = node.getQualifier();
   if (qualifier != null) {
     final PyType type = myTypeEvalContext.getType(qualifier);
     if (type instanceof PyClassType) {
       final PyClass cls = ((PyClassType) type).getPyClass();
       final String name = node.getName();
       if (name != null) {
         final Pair<PyClass, String> key = new Pair<PyClass, String>(cls, name);
         final Property property;
         if (myPropertyCache.containsKey(key)) {
           property = myPropertyCache.get(key);
         } else {
           property = cls.findProperty(name, true);
         }
         myPropertyCache.put(
             key, property); // we store nulls, too, to know that a property does not exist
         if (property != null) {
           final AccessDirection dir = AccessDirection.of(node);
           checkAccessor(node, name, dir, property);
           if (dir == AccessDirection.READ) {
             final PsiElement parent = node.getParent();
             if (parent instanceof PyAugAssignmentStatement
                 && ((PyAugAssignmentStatement) parent).getTarget() == node) {
               checkAccessor(node, name, AccessDirection.WRITE, property);
             }
           }
         }
       }
     }
   }
 }
 @Nullable
 private Ref<PyType> getTypeOfProperty(
     @Nullable PyType qualifierType, @NotNull String name, @NotNull TypeEvalContext context) {
   if (qualifierType instanceof PyClassType) {
     final PyClassType classType = (PyClassType) qualifierType;
     PyClass pyClass = classType.getPyClass();
     Property property = pyClass.findProperty(name, true);
     if (property != null) {
       if (classType.isDefinition()) {
         return Ref.<PyType>create(
             PyBuiltinCache.getInstance(pyClass).getObjectType(PyNames.PROPERTY));
       }
       if (AccessDirection.of(this) == AccessDirection.READ) {
         final PyType type = property.getType(context);
         if (type != null) {
           return Ref.create(type);
         }
       }
       return Ref.create();
     }
   } else if (qualifierType instanceof PyUnionType) {
     final PyUnionType unionType = (PyUnionType) qualifierType;
     for (PyType type : unionType.getMembers()) {
       final Ref<PyType> result = getTypeOfProperty(type, name, context);
       if (result != null) {
         return result;
       }
     }
   }
   return null;
 }
Ejemplo n.º 3
0
 public Property getProperty() {
   final PyClass containingClass = getContainingClass();
   if (containingClass != null) {
     return containingClass.findPropertyByCallable(this);
   }
   return null;
 }
 @NotNull
 private static List<PyGenericType> collectGenericTypes(
     @NotNull PyClass cls, @NotNull Context context) {
   boolean isGeneric = false;
   for (PyClass ancestor : cls.getAncestorClasses(context.getTypeContext())) {
     if (GENERIC_CLASSES.contains(ancestor.getQualifiedName())) {
       isGeneric = true;
       break;
     }
   }
   if (isGeneric) {
     final ArrayList<PyGenericType> results = new ArrayList<>();
     // 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) {
           for (PsiElement resolved : tryResolving(indexExpr, context.getTypeContext())) {
             final PyGenericType genericType = getGenericType(resolved, context);
             if (genericType != null) {
               results.add(genericType);
             }
           }
         }
       }
     }
     return results;
   }
   return Collections.emptyList();
 }
  /**
   * Creates abstract version of each method in each class (does not touch method itself as opposite
   * to {@link #moveMethods(com.jetbrains.python.psi.PyClass, java.util.Collection,
   * com.jetbrains.python.psi.PyClass...)})
   *
   * @param currentFunctions functions to make them abstract
   * @param to classes where abstract method should be created
   */
  private static void makeMethodsAbstract(
      final Collection<PyFunction> currentFunctions, final PyClass... to) {
    final Set<PsiFile> filesToCheckImport = new HashSet<PsiFile>();
    final Set<PyClass> classesToAddMetaAbc = new HashSet<PyClass>();

    for (final PyFunction function : currentFunctions) {
      for (final PyClass destClass : to) {
        final PyFunctionBuilder functionBuilder =
            PyFunctionBuilder.copySignature(function, DECORATORS_MAY_BE_COPIED_TO_ABSTRACT);
        functionBuilder.decorate(PyNames.ABSTRACTMETHOD);
        final LanguageLevel level = LanguageLevel.forElement(destClass);
        PyClassRefactoringUtil.addMethods(
            destClass, false, functionBuilder.buildFunction(destClass.getProject(), level));
        classesToAddMetaAbc.add(destClass);
      }
    }

    // Add ABCMeta to new classes if needed
    for (final PyClass aClass : classesToAddMetaAbc) {
      if (addMetaAbcIfNeeded(aClass)) {
        filesToCheckImport.add(aClass.getContainingFile());
      }
    }

    // Add imports for ABC if needed
    for (final PsiFile file : filesToCheckImport) {
      addImportFromAbc(file, PyNames.ABSTRACTMETHOD);
      addImportFromAbc(file, ABC_META_CLASS);
      PyClassRefactoringUtil.optimizeImports(file); // To remove redundant imports
    }
  }
 @Nullable
 private static PyType getParameterizedType(
     @NotNull PsiElement element, @NotNull Context context) {
   if (element instanceof PySubscriptionExpression) {
     final PySubscriptionExpression subscriptionExpr = (PySubscriptionExpression) element;
     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();
       final List<PyType> indexTypes = getIndexTypes(subscriptionExpr, context);
       if (PyNames.TUPLE.equals(cls.getQualifiedName())) {
         if (indexExpr instanceof PyTupleExpression) {
           final PyExpression[] elements = ((PyTupleExpression) indexExpr).getElements();
           if (elements.length == 2 && isEllipsis(elements[1])) {
             return PyTupleType.createHomogeneous(element, indexTypes.get(0));
           }
         }
         return PyTupleType.create(element, indexTypes);
       } else if (indexExpr != null) {
         return new PyCollectionTypeImpl(cls, false, indexTypes);
       }
     }
   }
   return null;
 }
  /**
   * Looks for two standard decorators to a function, or a wrapping assignment that closely follows
   * it.
   *
   * @return a flag describing what was detected.
   */
  @Nullable
  public Modifier getModifier() {
    final String deconame = getClassOrStaticMethodDecorator();
    if (PyNames.CLASSMETHOD.equals(deconame)) {
      return CLASSMETHOD;
    } else if (PyNames.STATICMETHOD.equals(deconame)) {
      return STATICMETHOD;
    }
    // implicit staticmethod __new__
    final PyClass cls = getContainingClass();
    if (cls != null && PyNames.NEW.equals(getName()) && cls.isNewStyleClass(null)) {
      return STATICMETHOD;
    }
    //
    if (getStub() != null) {
      return getWrappersFromStub();
    }
    final String funcName = getName();
    if (funcName != null) {
      PyAssignmentStatement currentAssignment =
          PsiTreeUtil.getNextSiblingOfType(this, PyAssignmentStatement.class);
      while (currentAssignment != null) {
        final String modifier =
            currentAssignment
                .getTargetsToValuesMapping()
                .stream()
                .filter(
                    pair ->
                        pair.getFirst() instanceof PyTargetExpression
                            && funcName.equals(pair.getFirst().getName()))
                .filter(pair -> pair.getSecond() instanceof PyCallExpression)
                .map(
                    pair ->
                        interpretAsModifierWrappingCall((PyCallExpression) pair.getSecond(), this))
                .filter(interpreted -> interpreted != null && interpreted.getSecond() == this)
                .map(interpreted -> interpreted.getFirst())
                .filter(
                    wrapperName ->
                        PyNames.CLASSMETHOD.equals(wrapperName)
                            || PyNames.STATICMETHOD.equals(wrapperName))
                .findAny()
                .orElse(null);

        if (PyNames.CLASSMETHOD.equals(modifier)) {
          return CLASSMETHOD;
        } else if (PyNames.STATICMETHOD.equals(modifier)) {
          return STATICMETHOD;
        }

        currentAssignment =
            PsiTreeUtil.getNextSiblingOfType(currentAssignment, PyAssignmentStatement.class);
      }
    }
    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);
 }
Ejemplo n.º 9
0
 protected String getElementLocation() {
   final PyClass containingClass = getContainingClass();
   if (containingClass != null) {
     return "("
         + containingClass.getName()
         + " in "
         + getPackageForFile(getContainingFile())
         + ")";
   }
   return super.getElementLocation();
 }
 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;
 }
Ejemplo n.º 11
0
 @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;
 }
Ejemplo n.º 12
0
 /**
  * Looks for two standard decorators to a function, or a wrapping assignment that closely follows
  * it.
  *
  * @return a flag describing what was detected.
  */
 @Nullable
 public Modifier getModifier() {
   String deconame = getClassOrStaticMethodDecorator();
   if (PyNames.CLASSMETHOD.equals(deconame)) {
     return CLASSMETHOD;
   } else if (PyNames.STATICMETHOD.equals(deconame)) {
     return STATICMETHOD;
   }
   // implicit staticmethod __new__
   PyClass cls = getContainingClass();
   if (cls != null && PyNames.NEW.equals(getName()) && cls.isNewStyleClass()) {
     return STATICMETHOD;
   }
   //
   if (getStub() != null) {
     return getWrappersFromStub();
   }
   String func_name = getName();
   if (func_name != null) {
     PyAssignmentStatement assignment =
         PsiTreeUtil.getNextSiblingOfType(this, PyAssignmentStatement.class);
     if (assignment != null) {
       for (Pair<PyExpression, PyExpression> pair : assignment.getTargetsToValuesMapping()) {
         PyExpression value = pair.getSecond();
         if (value instanceof PyCallExpression) {
           PyExpression target = pair.getFirst();
           if (target instanceof PyTargetExpression && func_name.equals(target.getName())) {
             Pair<String, PyFunction> interpreted =
                 interpretAsModifierWrappingCall((PyCallExpression) value, this);
             if (interpreted != null) {
               PyFunction original = interpreted.getSecond();
               if (original == this) {
                 String wrapper_name = interpreted.getFirst();
                 if (PyNames.CLASSMETHOD.equals(wrapper_name)) {
                   return CLASSMETHOD;
                 } else if (PyNames.STATICMETHOD.equals(wrapper_name)) {
                   return STATICMETHOD;
                 }
               }
             }
           }
         }
       }
     }
   }
   return null;
 }
 @Nullable
 private static PsiElement addFieldToSetUp(
     PyClass clazz, final Function<String, PyStatement> callback) {
   final PyFunction init =
       clazz.findMethodByName(PythonUnitTestUtil.TESTCASE_SETUP_NAME, false, null);
   if (init != null) {
     return AddFieldQuickFix.appendToMethod(init, callback);
   }
   final PyFunctionBuilder builder =
       new PyFunctionBuilder(PythonUnitTestUtil.TESTCASE_SETUP_NAME, clazz);
   builder.parameter(PyNames.CANONICAL_SELF);
   PyFunction setUp = builder.buildFunction(clazz.getProject(), LanguageLevel.getDefault());
   final PyStatementList statements = clazz.getStatementList();
   final PsiElement anchor = statements.getFirstChild();
   setUp = (PyFunction) statements.addBefore(setUp, anchor);
   return AddFieldQuickFix.appendToMethod(setUp, callback);
 }
 private void addPredefinedMethodDoc(PyFunction fun, String mothodName) {
   PyClassType objectType =
       PyBuiltinCache.getInstance(fun)
           .getObjectType(); // old- and new-style classes share the __xxx__ stuff
   if (objectType != null) {
     PyClass objectClass = objectType.getPyClass();
     PyFunction predefinedMethod = objectClass.findMethodByName(mothodName, false);
     if (predefinedMethod != null) {
       PyStringLiteralExpression predefinedDocstring = predefinedMethod.getDocStringExpression();
       String predefinedDoc =
           predefinedDocstring != null ? predefinedDocstring.getStringValue() : null;
       if (predefinedDoc != null
           && predefinedDoc.length() > 1) { // only a real-looking doc string counts
         addFormattedDocString(fun, predefinedDoc, myBody, myBody);
         myEpilog.addItem(BR).addItem(BR).addItem(PyBundle.message("QDOC.copied.from.builtin"));
       }
     }
   }
 }
  private void buildFromAttributeDoc() {
    PyClass cls = PsiTreeUtil.getParentOfType(myElement, PyClass.class);
    assert cls != null;
    String type =
        PyUtil.isInstanceAttribute((PyExpression) myElement)
            ? "Instance attribute "
            : "Class attribute ";
    myProlog
        .addItem(type)
        .addWith(TagBold, $().addWith(TagCode, $(((PyTargetExpression) myElement).getName())))
        .addItem(" of class ")
        .addWith(PythonDocumentationProvider.LinkMyClass, $().addWith(TagCode, $(cls.getName())))
        .addItem(BR);

    final String docString = ((PyTargetExpression) myElement).getDocStringValue();
    if (docString != null) {
      addFormattedDocString(myElement, docString, myBody, myEpilog);
    }
  }
Ejemplo n.º 16
0
 @Nullable
 @Override
 public String getQualifiedName() {
   String name = getName();
   if (name == null) {
     return null;
   }
   PyClass containingClass = getContainingClass();
   if (containingClass != null) {
     return containingClass.getQualifiedName() + "." + name;
   }
   if (PsiTreeUtil.getStubOrPsiParent(this) instanceof PyFile) {
     VirtualFile virtualFile = getContainingFile().getVirtualFile();
     if (virtualFile != null) {
       final String packageName =
           QualifiedNameFinder.findShortestImportableName(this, virtualFile);
       return packageName + "." + name;
     }
   }
   return null;
 }
 @Override
 public void visitPyClass(PyClass pyClass) {
   if (isAbstract(pyClass)) {
     return;
   }
   final Set<PyFunction> toBeImplemented = new HashSet<PyFunction>();
   final Collection<PyFunction> functions =
       PyOverrideImplementUtil.getAllSuperFunctions(pyClass);
   for (PyFunction method : functions) {
     if (isAbstractMethodForClass(method, pyClass)) {
       toBeImplemented.add(method);
     }
   }
   final ASTNode nameNode = pyClass.getNameNode();
   if (!toBeImplemented.isEmpty() && nameNode != null) {
     registerProblem(
         nameNode.getPsi(),
         PyBundle.message("INSP.NAME.abstract.class.$0.must.implement", pyClass.getName()),
         new PyImplementMethodsQuickFix(pyClass, toBeImplemented));
   }
 }
 private static boolean isAbstract(@NotNull PyClass pyClass) {
   final PyType metaClass =
       pyClass.getMetaClassType(
           TypeEvalContext.userInitiated(pyClass.getProject(), pyClass.getContainingFile()));
   if (metaClass instanceof PyClassLikeType
       && PyNames.ABC_META_CLASS.equals(metaClass.getName())) {
     return true;
   }
   if (metaClass == null) {
     final PyExpression metaClassExpr =
         as(pyClass.getMetaClassExpression(), PyReferenceExpression.class);
     if (metaClassExpr != null && PyNames.ABC_META_CLASS.equals(metaClassExpr.getName())) {
       return true;
     }
   }
   for (PyFunction method : pyClass.getMethods(false)) {
     if (PyUtil.isDecoratedAsAbstract(method)) {
       return true;
     }
   }
   return false;
 }
Ejemplo n.º 19
0
 // TODO: Copy/Paste with PyClass.getMeta..
 private static boolean addMetaAbcIfNeeded(@NotNull final PyClass aClass) {
   final PsiFile file = aClass.getContainingFile();
   final PyType type = aClass.getMetaClassType(TypeEvalContext.userInitiated(file));
   if (type != null) {
     return false; // User already has metaclass. He probably knows about metaclasses, so we should
                   // not add ABCMeta
   }
   final LanguageLevel languageLevel = LanguageLevel.forElement(aClass);
   if (languageLevel
       .isPy3K()) { // TODO: Copy/paste, use strategy because we already has the same check in
                    // #couldBeAbstract
     // Add (metaclass= for Py3K
     PyClassRefactoringUtil.addSuperClassExpressions(
         aClass.getProject(),
         aClass,
         null,
         Collections.singletonList(Pair.create(PyNames.METACLASS, ABC_META_CLASS)));
   } else {
     // Add __metaclass__ for Py2
     PyClassRefactoringUtil.addClassAttributeIfNotExist(
         aClass, PyNames.DUNDER_METACLASS, ABC_META_CLASS);
   }
   return true;
 }
  private boolean buildFromProperty(
      PsiElement elementDefinition,
      @Nullable final PsiElement outerElement,
      @NotNull final TypeEvalContext context) {
    if (myOriginalElement == null) {
      return false;
    }
    final String elementName = myOriginalElement.getText();
    if (!PyNames.isIdentifier(elementName)) {
      return false;
    }
    if (!(outerElement instanceof PyQualifiedExpression)) {
      return false;
    }
    final PyExpression qualifier = ((PyQualifiedExpression) outerElement).getQualifier();
    if (qualifier == null) {
      return false;
    }
    final PyType type = context.getType(qualifier);
    if (!(type instanceof PyClassType)) {
      return false;
    }
    final PyClass cls = ((PyClassType) type).getPyClass();
    final Property property = cls.findProperty(elementName, true, null);
    if (property == null) {
      return false;
    }

    final AccessDirection direction = AccessDirection.of((PyElement) outerElement);
    final Maybe<PyCallable> accessor = property.getByDirection(direction);
    myProlog
        .addItem("property ")
        .addWith(TagBold, $().addWith(TagCode, $(elementName)))
        .addItem(" of ")
        .add(PythonDocumentationProvider.describeClass(cls, TagCode, true, true));
    if (accessor.isDefined() && property.getDoc() != null) {
      myBody.addItem(": ").addItem(property.getDoc()).addItem(BR);
    } else {
      final PyCallable getter = property.getGetter().valueOrNull();
      if (getter != null && getter != myElement && getter instanceof PyFunction) {
        // not in getter, getter's doc comment may be useful
        final PyStringLiteralExpression docstring = ((PyFunction) getter).getDocStringExpression();
        if (docstring != null) {
          myProlog
              .addItem(BR)
              .addWith(TagItalic, $("Copied from getter:"))
              .addItem(BR)
              .addItem(docstring.getStringValue());
        }
      }
      myBody.addItem(BR);
    }
    myBody.addItem(BR);
    if (accessor.isDefined() && accessor.value() == null) elementDefinition = null;
    final String accessorKind = getAccessorKind(direction);
    if (elementDefinition != null) {
      myEpilog.addWith(TagSmall, $(BR, BR, accessorKind, " of property")).addItem(BR);
    }

    if (!(elementDefinition instanceof PyDocStringOwner)) {
      myBody
          .addWith(
              TagItalic,
              elementDefinition != null ? $("Declaration: ") : $(accessorKind + " is not defined."))
          .addItem(BR);
      if (elementDefinition != null) {
        myBody.addItem(combUp(PyUtil.getReadableRepr(elementDefinition, false)));
      }
    }
    return true;
  }
  private void addInheritedDocString(
      @NotNull final PyFunction pyFunction, @Nullable final PyClass pyClass) {
    boolean notFound = true;
    final String methodName = pyFunction.getName();
    if (pyClass == null || methodName == null) {
      return;
    }
    final boolean isConstructor = PyNames.INIT.equals(methodName);
    Iterable<PyClass> classes = pyClass.getAncestorClasses(null);
    if (isConstructor) {
      // look at our own class again and maybe inherit class's doc
      classes = new ChainIterable<PyClass>(pyClass).add(classes);
    }
    for (PyClass ancestor : classes) {
      PyStringLiteralExpression docstringElement = null;
      PyFunction inherited = null;
      boolean isFromClass = false;
      if (isConstructor) docstringElement = pyClass.getDocStringExpression();
      if (docstringElement != null) {
        isFromClass = true;
      } else {
        inherited = ancestor.findMethodByName(methodName, false);
      }
      if (inherited != null) {
        docstringElement = inherited.getDocStringExpression();
      }
      if (docstringElement != null) {
        final String inheritedDoc = docstringElement.getStringValue();
        if (inheritedDoc.length() > 1) {
          myEpilog.addItem(BR).addItem(BR);
          String ancestor_name = ancestor.getName();
          String marker =
              (pyClass == ancestor)
                  ? PythonDocumentationProvider.LINK_TYPE_CLASS
                  : PythonDocumentationProvider.LINK_TYPE_PARENT;
          final String ancestor_link =
              $().addWith(new LinkWrapper(marker + ancestor_name), $(ancestor_name)).toString();
          if (isFromClass) {
            myEpilog.addItem(PyBundle.message("QDOC.copied.from.class.$0", ancestor_link));
          } else {
            myEpilog.addItem(PyBundle.message("QDOC.copied.from.$0.$1", ancestor_link, methodName));
          }
          myEpilog.addItem(BR).addItem(BR);
          ChainIterable<String> formatted = new ChainIterable<String>();
          ChainIterable<String> unformatted = new ChainIterable<String>();
          addFormattedDocString(pyFunction, inheritedDoc, formatted, unformatted);
          myEpilog.addWith(TagCode, formatted).add(unformatted);
          notFound = false;
          break;
        }
      }
    }

    if (notFound) {
      // above could have not worked because inheritance is not searched down to 'object'.
      // for well-known methods, copy built-in doc string.
      // TODO: also handle predefined __xxx__ that are not part of 'object'.
      if (PyNames.UnderscoredAttributes.contains(methodName)) {
        addPredefinedMethodDoc(pyFunction, methodName);
      }
    }
  }
Ejemplo n.º 22
0
 @Override
 public boolean hasConflict(@NotNull final PyFunction member, @NotNull final PyClass aClass) {
   return NamePredicate.hasElementWithSameName(member, Arrays.asList(aClass.getMethods()));
 }
Ejemplo n.º 23
0
 @NotNull
 @Override
 protected List<PyElement> getMembersCouldBeMoved(@NotNull final PyClass pyClass) {
   return Lists.<PyElement>newArrayList(filterNameless(Arrays.asList(pyClass.getMethods())));
 }