Merge branch 'east825/py-move-to-toplevel'
authorMikhail Golubev <mikhail.golubev@jetbrains.com>
Thu, 8 Oct 2015 09:02:11 +0000 (12:02 +0300)
committerMikhail Golubev <mikhail.golubev@jetbrains.com>
Thu, 8 Oct 2015 09:02:11 +0000 (12:02 +0300)
1  2 
python/src/META-INF/python-core.xml
python/src/com/jetbrains/python/PyBundle.properties
python/src/com/jetbrains/python/psi/PyUtil.java
python/src/com/jetbrains/python/psi/impl/PyElementGeneratorImpl.java

index dedf9b380cfa6b42bd2ec8cb18a69bf7619b7295,0068b2c3284a15dd9b9774e74355be45b9eb4a3b..3883fd9064b61527d8b494b3f50b1d5aaa7147b9
@@@ -93,8 -93,6 +93,8 @@@
  
      <applicationService serviceInterface="com.jetbrains.python.packaging.PyPackageService"
                          serviceImplementation="com.jetbrains.python.packaging.PyPackageService"/>
 +    <applicationService serviceInterface="com.jetbrains.python.packaging.PyCondaPackageService"
 +                        serviceImplementation="com.jetbrains.python.packaging.PyCondaPackageService"/>
      <applicationService serviceInterface="com.jetbrains.python.module.PyModuleService"
                          serviceImplementation="com.jetbrains.python.module.PyModuleServiceImpl"/>
  
        <className>com.jetbrains.python.codeInsight.intentions.PyConvertStaticMethodToFunctionIntention</className>
        <category>Python</category>
      </intentionAction>
+     
      <intentionAction>
        <className>com.jetbrains.python.codeInsight.intentions.SpecifyTypeInDocstringIntention</className>
        <category>Python</category>
      <additionalTextAttributes scheme="Darcula" file="colorSchemes/PythonDarcula.xml"/>
  
      <postStartupActivity implementation="com.jetbrains.python.sdk.PythonSdkUpdater"/>
 -    <postStartupActivity implementation="com.jetbrains.python.packaging.PyPIPackagesUpdater"/>
 +    <postStartupActivity implementation="com.jetbrains.python.packaging.PyPackagesUpdater"/>
      <directoryProjectConfigurator implementation="com.jetbrains.python.testing.PyIntegratedToolsProjectConfigurator" id="integratedTools" order="after sdk"/>
  
  
      <extensionPoint qualifiedName="Pythonid.runConfigurationExtension" interface="com.jetbrains.python.run.PythonRunConfigurationExtension"/>
      <extensionPoint qualifiedName="Pythonid.visitorFilter" beanClass="com.intellij.lang.LanguageExtensionPoint"/>
      <extensionPoint qualifiedName="Pythonid.remoteInterpreterManager" interface="com.jetbrains.python.remote.PythonRemoteInterpreterManager"/>
 +    <extensionPoint qualifiedName="Pythonid.remoteProcessStarterManager" interface="com.jetbrains.python.run.PyRemoteProcessStarterManager"/>
      <extensionPoint qualifiedName="Pythonid.keywordArgumentProvider" interface="com.jetbrains.python.psi.impl.PyKeywordArgumentProvider"/>
      <extensionPoint qualifiedName="Pythonid.canonicalPathProvider" interface="com.jetbrains.python.psi.resolve.PyCanonicalPathProvider"/>
      <extensionPoint qualifiedName="Pythonid.templateContextProvider" interface="com.jetbrains.python.templateLanguages.TemplateContextProvider"/>
        <add-to-group group-id="XDebugger.ValueGroup" anchor="after" relative-to-action="Debugger.Tree.AddToWatches"/>
      </action>
  
-     <action id="PyConvertModuleToPackage" class="com.jetbrains.python.refactoring.convert.PyConvertModuleToPackageAction"
+     <action id="PyConvertModuleToPackage" class="com.jetbrains.python.refactoring.convertModulePackage.PyConvertModuleToPackageAction"
              text="Convert to Python Package"
              description="Create package with the same name and move content of the module to its __init__.py">
        <add-to-group group-id="RefactoringMenu" anchor="last" />
      </action>
  
-     <action id="PyConvertPackageToModuleAction" class="com.jetbrains.python.refactoring.convert.PyConvertPackageToModuleAction"
+     <action id="PyConvertPackageToModuleAction" class="com.jetbrains.python.refactoring.convertModulePackage.PyConvertPackageToModuleAction"
              text="Convert to Python Module"
              description="Create module with the same name and move content of __init__.py to that module">
        <add-to-group group-id="RefactoringMenu" anchor="last" />
        <add-to-group group-id="XDebugger.ToolWindow.TopToolbar" relative-to-action="StepInto" anchor="after"/>
      </action>
  
+     <action id="PyConvertLocalFunctionToTopLevelFunctionAction" class="com.jetbrains.python.refactoring.makeFunctionTopLevel.PyMakeFunctionTopLevelRefactoring"
+             text="Make top-level function"
+             description="Convert local function or method to top-level function, transforming names from enclosing scope and instance attributes into parameters">
+       <add-to-group group-id="RefactoringMenu"/>
+     </action>
    </actions>
  
    <extensions defaultExtensionNs="com.intellij.spellchecker">
index bca9672a2650647cca54e5c2523c86985f0f2a9f,398f7396b5ce35e82289ffca24d2f36920958b68..efd29f0996bf5a1acf18da28ae2d718b976c7940
@@@ -1,4 -1,4 +1,4 @@@
- f### Generic words ###
+ f###=Generic words ###
  GNAME.function=function
  GNAME.class=class
  GNAME.var=variable
@@@ -632,6 -632,20 +632,20 @@@ refactoring.move.module.members.error.d
  refactoring.move.module.members.error.cannot.use.module.name.$0=Cannot use module name ''{0}'' in imports
  refactoring.move.module.members.error.selection=Cannot perform refactoring using selected element(s)
  
+ # Make function top-level
+ refactoring.make.function.top.level.function=Convert to top-level function
+ refactoring.make.method.top.level=Make method top-level
+ refactoring.make.local.function.top.level=Make local function top-level
+ refactoring.make.function.top.level.error.nonlocal.writes=Cannot move function with nonlocal writes
+ refactoring.make.function.top.level.error.self.reads=Cannot move function that contains usages of "self" parameter from outer scope
+ refactoring.make.function.top.level.error.outer.scope.reads=Cannon move method that references names from the outer scope
+ refactoring.make.function.top.level.error.private.attributes=Cannot move method that references private instance attributes
+ refactoring.make.function.top.level.error.attribute.writes=Cannot move method that writes to instance attributes
+ refactoring.make.function.top.level.error.method.calls=Cannot move method that calls other methods of the same class
+ refactoring.make.function.top.level.error.special.usage.of.self=Cannot move method that contains special usages of "self" parameter
  #change signature
  refactoring.change.signature.usage.view.declarations.header=Functions to be refactored
  refactoring.change.signature.dialog.validation.name.defined=Name is already defined in scope
@@@ -867,7 -881,6 +881,7 @@@ active.sdk.dialog.project.interpreter=P
  sdk.details.step.add.local=Add Local
  sdk.details.step.add.remote=Add Remote
  sdk.details.step.create.virtual.env=Create VirtualEnv
 +sdk.details.step.create.conda.env=Create Conda Env
  sdk.details.step.show.more=More...
  
  sdk.details.dialog.title=Project Interpreters
@@@ -891,7 -904,6 +905,7 @@@ remote.interpreter.configure.title=Conf
  remote.interpreter.configure.path.title=Select Python Interpreter
  remote.interpreter.configure.temp.files.path.title=Select Folder for PyCharm Helpers
  remote.interpreter.default.interpreter.path=/usr/bin/python
 +remote.interpreter.docker.default.interpreter.path=python
  remote.interpreter.unspecified.interpreter.path=Specify Python interpreter path
  remote.interpreter.unspecified.temp.files.path=Specify path for PyCharm helpers
  remote.interpreter.configure.path.label=Python interpreter path:
index 87d9be86fe81638433e6aa4df0c9b40951d71aea,1fbc96d6dd0fe9ed38bf985ee94c0a880ed64bc0..883e63fac11b550e85911e3e7f7666e2de9e356a
@@@ -23,7 -23,7 +23,7 @@@ import com.intellij.codeInsight.lookup.
  import com.intellij.codeInsight.lookup.LookupElementBuilder;
  import com.intellij.ide.fileTemplates.FileTemplate;
  import com.intellij.ide.fileTemplates.FileTemplateManager;
 -import com.intellij.ide.scratch.ScratchRootType;
 +import com.intellij.ide.scratch.ScratchFileService;
  import com.intellij.injected.editor.VirtualFileWindow;
  import com.intellij.lang.ASTFactory;
  import com.intellij.lang.ASTNode;
@@@ -55,7 -55,6 +55,7 @@@ import com.intellij.psi.*
  import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
  import com.intellij.psi.stubs.StubElement;
  import com.intellij.psi.util.PsiTreeUtil;
 +import com.intellij.psi.util.PsiUtilCore;
  import com.intellij.psi.util.QualifiedName;
  import com.intellij.ui.awt.RelativePoint;
  import com.intellij.util.*;
@@@ -295,64 -294,6 +295,6 @@@ public class PyUtil 
      if (addWhitespace) node.addChild(ASTFactory.whitespace(" "), beforeThis);
    }
  
-   /**
-    * Removes an element from a a comma-separated list in a PSI tree. E.g. can turn "foo, bar, baz" into "foo, baz",
-    * removing commas as needed. It removes a trailing comma if it results from deletion.
-    *
-    * @param item what to remove. Its parent is considered the list, and commas must be its peers.
-    */
-   public static void removeListNode(PsiElement item) {
-     PsiElement parent = item.getParent();
-     if (!FileModificationService.getInstance().preparePsiElementForWrite(parent)) {
-       return;
-     }
-     // remove comma after the item
-     ASTNode binder = parent.getNode();
-     assert binder != null : "parent node is null, ensureWritable() lied";
-     boolean got_comma_after = eraseWhitespaceAndComma(binder, item, false);
-     if (!got_comma_after) {
-       // there was not a comma after the item; remove a comma before the item
-       eraseWhitespaceAndComma(binder, item, true);
-     }
-     // finally
-     item.delete();
-   }
-   /**
-    * Removes whitespace and comma(s) that are siblings of the item, up to the first non-whitespace and non-comma.
-    *
-    * @param parent_node node of the parent of item.
-    * @param item        starting point; we erase left or right of it, but not it.
-    * @param backwards   true to erase prev siblings, false to erase next siblings.
-    * @return true       if a comma was found and removed.
-    */
-   public static boolean eraseWhitespaceAndComma(ASTNode parent_node, PsiElement item, boolean backwards) {
-     // we operate on AST, PSI won't let us delete whitespace easily.
-     boolean is_comma;
-     boolean got_comma = false;
-     ASTNode current = item.getNode();
-     ASTNode candidate;
-     boolean have_skipped_the_item = false;
-     while (current != null) {
-       candidate = current;
-       current = backwards ? current.getTreePrev() : current.getTreeNext();
-       if (have_skipped_the_item) {
-         is_comma = ",".equals(candidate.getText());
-         got_comma |= is_comma;
-         if (is_comma || candidate.getElementType() == TokenType.WHITE_SPACE) {
-           parent_node.removeChild(candidate);
-         }
-         else {
-           break;
-         }
-       }
-       else {
-         have_skipped_the_item = true;
-       }
-     }
-     return got_comma;
-   }
    /**
     * Collects superclasses of a class all the way up the inheritance chain. The order is <i>not</i> necessarily the MRO.
     */
      return AccessDirection.READ;
    }
  
-   public static boolean deleteParameter(@NotNull final PyFunction problemFunction, int index) {
-     final PyParameterList parameterList = problemFunction.getParameterList();
-     final PyParameter[] parameters = parameterList.getParameters();
-     if (parameters.length <= 0) return false;
-     PsiElement first = parameters[index];
-     PsiElement last = parameters.length > index + 1 ? parameters[index + 1] : parameterList.getLastChild();
-     PsiElement prevSibling = last.getPrevSibling() != null ? last.getPrevSibling() : parameters[index];
-     parameterList.deleteChildRange(first, prevSibling);
-     return true;
-   }
    public static void removeQualifier(@NotNull final PyReferenceExpression element) {
      final PyExpression qualifier = element.getQualifier();
      if (qualifier == null) return;
  
      if (qualifier instanceof PyCallExpression) {
-       final StringBuilder newElement = new StringBuilder(element.getLastChild().getText());
        final PyExpression callee = ((PyCallExpression)qualifier).getCallee();
        if (callee instanceof PyReferenceExpression) {
          final PyExpression calleeQualifier = ((PyReferenceExpression)callee).getQualifier();
          if (calleeQualifier != null) {
-           newElement.insert(0, calleeQualifier.getText() + ".");
+           qualifier.replace(calleeQualifier);
+           return;
          }
        }
-       final PyElementGenerator elementGenerator = PyElementGenerator.getInstance(element.getProject());
-       final PyExpression expression = elementGenerator.createExpressionFromText(LanguageLevel.forElement(element), newElement.toString());
-       element.replace(expression);
-     }
-     else {
-       final PsiElement dot = qualifier.getNextSibling();
-       if (dot != null) dot.delete();
-       qualifier.delete();
      }
+     final PsiElement dot = PyPsiUtils.getNextNonWhitespaceSibling(qualifier);
+     if (dot != null) dot.delete();
+     qualifier.delete();
    }
  
    /**
     * @param name
     * @return true iff the name looks like a class-private one, starting with two underscores but not ending with two underscores.
     */
-   public static boolean isClassPrivateName(String name) {
+   public static boolean isClassPrivateName(@NotNull String name) {
      return name.startsWith("__") && !name.endsWith("__");
    }
  
  
    public static class MethodFlags {
  
-     private boolean myIsStaticMethod;
-     private boolean myIsMetaclassMethod;
-     private boolean myIsSpecialMetaclassMethod;
-     private boolean myIsClassMethod;
+     private final boolean myIsStaticMethod;
+     private final boolean myIsMetaclassMethod;
+     private final boolean myIsSpecialMetaclassMethod;
+     private final boolean myIsClassMethod;
  
      /**
       * @return true iff the method belongs to a metaclass (an ancestor of 'type').
    }
  
    public static boolean isInScratchFile(@NotNull PsiElement element) {
 -    PsiFile file = element.getContainingFile();
 -    return file != null && ScratchRootType.getInstance().isScratchFile(file.getVirtualFile());
 +    return ScratchFileService.isInScratchRoot(PsiUtilCore.getVirtualFile(element));
    }
  
    /**
index 0b40a3dae4423b0f9a4bc65cb7973072f53bce0f,9991cac8b3a93cb169e730f0bf567832b2f803af..9ee7076ab4cca6789a6898a3b9fe542846864dd3
@@@ -85,11 -85,7 +85,11 @@@ public class PyElementGeneratorImpl ext
    public PyStringLiteralExpression createStringLiteralAlreadyEscaped(String str) {
      final PsiFile dummyFile = createDummyFile(LanguageLevel.getDefault(), "a=(" + str + ")");
      final PyAssignmentStatement expressionStatement = (PyAssignmentStatement)dummyFile.getFirstChild();
 -    return (PyStringLiteralExpression)((PyParenthesizedExpression)expressionStatement.getAssignedValue()).getContainedExpression();
 +    final PyExpression assignedValue = expressionStatement.getAssignedValue();
 +    if (assignedValue != null) {
 +      return (PyStringLiteralExpression)((PyParenthesizedExpression)assignedValue).getContainedExpression();
 +    }
 +    return createStringLiteralFromString(str);
    }
  
  
      return createParameter(name, null, null, LanguageLevel.getDefault());
    }
  
+   @NotNull
+   @Override
+   public PyParameterList createParameterList(@NotNull LanguageLevel languageLevel, @NotNull String text) {
+     return createFromText(languageLevel, PyParameterList.class, "def f" + text + ": pass", new int[]{0, 3});
+   }
+   @NotNull
+   @Override
+   public PyArgumentList createArgumentList(@NotNull LanguageLevel languageLevel, @NotNull String text) {
+     return createFromText(languageLevel, PyArgumentList.class, "f" + text, new int[]{0, 0, 1});
+   }
    public PyNamedParameter createParameter(@NotNull String name, @Nullable String defaultValue, @Nullable String annotation,
                                            @NotNull LanguageLevel languageLevel) {
      String parameterText = name;