All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.jetbrains.python.refactoring.classes.membersManager.PropertiesManager Maven / Gradle / Ivy

Go to download

A packaging of the IntelliJ Community Edition python-community library. This is release number 1 of trunk branch 142.

The newest version!
/*
 * 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.refactoring.classes.membersManager;

import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiReference;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.containers.MultiMap;
import com.jetbrains.python.psi.*;
import org.jetbrains.annotations.NotNull;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

/**
 * Plugin that moves class properties.
 * It represents property (whatever old or new) as one of its methods.
 *
 * @author Ilya.Kazakevich
 */
class PropertiesManager extends MembersManager {

  PropertiesManager() {
    super(PyElement.class);
  }


  @NotNull
  @Override
  protected List getMembersCouldBeMoved(@NotNull final PyClass pyClass) {
    final List elements = new ArrayList(pyClass.getProperties().size());
    for (final Property property : pyClass.getProperties().values()) {
      elements.add(getElement(property));
    }
    return elements;
  }

  @NotNull
  private static PyElement getElement(@NotNull final Property property) {
    final PyCallable getter = property.getGetter().valueOrNull();
    final PyCallable setter = property.getSetter().valueOrNull();
    final PyCallable deleter = property.getDeleter().valueOrNull();

    if (getter != null) {
      return getter;
    }
    else if (setter != null) {
      return setter;
    }
    else if (deleter != null) {
      return deleter;
    }
    else {
      final PyTargetExpression site = property.getDefinitionSite();
      assert site != null : "Property has no methods nor declaration. That is not property";
      return site;
    }
  }

  @NotNull
  private static Property getProperty(@NotNull final PyClass pyClass, @NotNull final PyElement element) {
    final Collection properties = pyClass.getProperties().values();
    if (element instanceof PyTargetExpression) {
      return getPropertyByTargetExpression(properties, (PyTargetExpression)element);
    }
    if (element instanceof PyFunction) {
      return getPropertyByFunction(properties, (PyFunction)element);
    }
    throw new IllegalArgumentException("Not function nor target");
  }

  @NotNull
  private static Property getPropertyByFunction(@NotNull final Collection properties,
                                                @NotNull final PyFunction functionToSearch) {
    for (final Property property : properties) {
      for (final PyFunction function : getAllFunctions(property)) {
        if (function.equals(functionToSearch)) {
          return property;
        }
      }
    }
    throw new IllegalArgumentException("No property found");
  }

  @NotNull
  private static Property getPropertyByTargetExpression(@NotNull final Iterable properties,
                                                        @NotNull final PyTargetExpression element) {
    for (final Property property : properties) {
      if (element.equals(property.getDefinitionSite())) {
        return property;
      }
    }
    throw new IllegalArgumentException("No property found");
  }

  @NotNull
  private static Collection getAllFunctions(@NotNull final Property property) {
    final Collection result = new ArrayList(3);
    final PyCallable getter = property.getGetter().valueOrNull();
    final PyCallable setter = property.getSetter().valueOrNull();
    final PyCallable deleter = property.getDeleter().valueOrNull();

    if (getter instanceof PyFunction) {
      result.add((PyFunction)getter);
    }
    if (setter instanceof PyFunction) {
      result.add((PyFunction)setter);
    }
    if (deleter instanceof PyFunction) {
      result.add((PyFunction)deleter);
    }
    return result;
  }

  @Override
  protected Collection moveMembers(@NotNull final PyClass from,
                                              @NotNull final Collection> members,
                                              @NotNull final PyClass... to) {
    final Collection result = new ArrayList();

    final Collection elements = fetchElements(members);
    for (final PyElement element : elements) {
      final Property property = getProperty(from, element);
      final Collection functions = getAllFunctions(property);
      MethodsManager.moveMethods(from, functions, false, to);
      final PyTargetExpression definitionSite = property.getDefinitionSite();
      if (definitionSite != null) {
        final PyAssignmentStatement assignmentStatement = PsiTreeUtil.getParentOfType(definitionSite, PyAssignmentStatement.class);
        ClassFieldsManager.moveAssignmentsImpl(from, Collections.singleton(assignmentStatement), to);
      }
    }
    return result;
  }

  @NotNull
  @Override
  public PyMemberInfo apply(@NotNull final PyElement input) {
    return new PyMemberInfo(input, false, getName(input), false, this, false);
  }

  private static String getName(@NotNull final PyElement input) {
    final PyClass clazz = PsiTreeUtil.getParentOfType(input, PyClass.class);
    assert clazz != null : "Element not declared in class";
    final Property property = getProperty(clazz, input);
    return property.getName();
  }

  @Override
  public boolean hasConflict(@NotNull final PyElement member, @NotNull final PyClass aClass) {
    return false;
  }

  @NotNull
  @Override
  protected MultiMap getDependencies(@NotNull final PyElement member) {
    final PyRecursiveElementVisitorWithResult visitor = new PyReferenceVisitor();
    member.accept(visitor);

    return visitor.myResult;
  }

  @NotNull
  @Override
  protected Collection getDependencies(@NotNull final MultiMap usedElements) {
    return Collections.emptyList();
  }

  private static class PyReferenceVisitor extends PyRecursiveElementVisitorWithResult {


    @Override
    public void visitPyExpression(final PyExpression node) {
      final PsiReference reference = node.getReference();
      if (reference == null) {
        return;
      }

      final PsiElement declaration = reference.resolve();
      if (!(declaration instanceof PyFunction)) {
        return;
      }

      final PyFunction function = (PyFunction)declaration;
      final Property property = function.getProperty();
      if (property == null) {
        return;
      }

      final PyClass aClass = function.getContainingClass();
      if (aClass == null) {
        return;
      }
      final Collection functions = getAllFunctions(property);
      for (final PyFunction pyFunction : functions) {
        final PyClass functionClass = pyFunction.getContainingClass();
        if (functionClass != null) {
          myResult.putValue(functionClass, pyFunction);
        }
      }

      final PyTargetExpression definitionSite = property.getDefinitionSite();
      if (definitionSite != null) {
        final PyClass pyClass = PsiTreeUtil.getParentOfType(definitionSite, PyClass.class);
        if (pyClass != null) {
          myResult.putValue(pyClass, definitionSite);
        }
      }
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy