Docstring parameters are removed via PyDocstringGenerator as well
authorMikhail Golubev <mikhail.golubev@jetbrains.com>
Fri, 28 Aug 2015 10:55:05 +0000 (13:55 +0300)
committerMikhail Golubev <mikhail.golubev@jetbrains.com>
Wed, 2 Sep 2015 11:35:33 +0000 (14:35 +0300)
python/src/com/jetbrains/python/documentation/DocStringUtil.java
python/src/com/jetbrains/python/documentation/PyDocstringGenerator.java
python/src/com/jetbrains/python/inspections/quickfix/DocstringQuickFix.java
python/src/com/jetbrains/python/inspections/quickfix/PyRemoveParameterQuickFix.java
python/src/com/jetbrains/python/refactoring/changeSignature/PyChangeSignatureUsageProcessor.java

index e340160f5bbc35bed3b971b19642e3fc6f9597ad..3203928603334d19deda6451032c53eafda0d971 100644 (file)
@@ -29,10 +29,6 @@ import com.intellij.psi.PsiWhiteSpace;
 import com.intellij.psi.util.PsiTreeUtil;
 import com.intellij.util.ArrayUtil;
 import com.jetbrains.python.codeInsight.controlflow.ScopeOwner;
-import com.jetbrains.python.documentation.docstrings.DocStringUpdater;
-import com.jetbrains.python.documentation.docstrings.GoogleCodeStyleDocStringUpdater;
-import com.jetbrains.python.documentation.docstrings.NumpyDocStringUpdater;
-import com.jetbrains.python.documentation.docstrings.TagBasedDocStringUpdater;
 import com.jetbrains.python.psi.*;
 import com.jetbrains.python.psi.impl.PyPsiUtils;
 import com.jetbrains.python.psi.impl.PyStringLiteralExpressionImpl;
@@ -41,8 +37,6 @@ import org.jetbrains.annotations.NonNls;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
-import java.util.Arrays;
-import java.util.Collection;
 import java.util.List;
 import java.util.regex.Matcher;
 
@@ -268,44 +262,4 @@ public class DocStringUtil {
     final PyDocumentationSettings settings = PyDocumentationSettings.getInstance(getModuleForElement(anchor));
     return settings.getFormatForFile(anchor.getContainingFile());
   }
-  
-  public static PyStringLiteralExpression removeParamsFromDocString(@NotNull PyStringLiteralExpression docString, 
-                                                                    @NotNull Collection<String> paramNames) {
-    final Module module = getModuleForElement(docString);
-    final DocStringFormat format = PyDocumentationSettings.getInstance(module).getFormatForFile(docString.getContainingFile());
-    DocStringUpdater updater;
-    switch (format) {
-      case EPYTEXT:
-        final EpydocString epyParsed = (EpydocString)parseDocString(format, docString);
-        updater = new TagBasedDocStringUpdater(epyParsed, "@", PyIndentUtil.getElementIndent(docString));
-        break;
-      case REST:
-        final SphinxDocString restParsed = (SphinxDocString)parseDocString(format, docString);
-        updater = new TagBasedDocStringUpdater(restParsed, ":", PyIndentUtil.getElementIndent(docString));
-        break;
-      case GOOGLE:
-        final GoogleCodeStyleDocString googleParsed = (GoogleCodeStyleDocString)parseDocString(format, docString);
-        updater = new GoogleCodeStyleDocStringUpdater(googleParsed, PyIndentUtil.getElementIndent(docString));
-        break;
-      case NUMPY:
-        final NumpyDocString numpyParsed = (NumpyDocString)parseDocString(format, docString);
-        updater = new NumpyDocStringUpdater(numpyParsed, PyIndentUtil.getElementIndent(docString));
-        break;
-      default:
-        return docString;
-    }
-    for (String name : paramNames) {
-      updater.removeParameter(name);
-    }
-    final String newText = updater.getDocStringText();
-    final PyExpressionStatement replacement = PyElementGenerator.getInstance(docString.getProject()).createDocstring(newText);
-    return (PyStringLiteralExpression)docString.replace(replacement.getExpression());
-    
-  }
-
-  @NotNull
-  public static PyStringLiteralExpression removeParamsFromDocString(@NotNull PyStringLiteralExpression docString, 
-                                                                    @NotNull String... paramNames) {
-    return removeParamsFromDocString(docString, Arrays.asList(paramNames));
-  }
 }
index e61c3ef58de0f77316945f0c5b1be1a9d2fad248..ffe0697e58594db12acaf8b5dfa51803b11ad0cb 100644 (file)
@@ -49,7 +49,8 @@ import java.util.List;
  */
 public class PyDocstringGenerator {
 
-  private final List<DocstringParam> myParams = Lists.newArrayList();
+  private final List<DocstringParam> myAddedParams = Lists.newArrayList();
+  private final List<DocstringParam> myRemovedParams = Lists.newArrayList();
   // Updated after buildAndInsert
   @NotNull
   private PyDocStringOwner myDocStringOwner;
@@ -72,15 +73,21 @@ public class PyDocstringGenerator {
     return withParamTypedByName(name, null);
   }
 
+  @NotNull
+  public PyDocstringGenerator withoutParam(@NotNull String name) {
+    myRemovedParams.add(new DocstringParam(name, null, false));
+    return this;
+  }
+
   @NotNull
   public PyDocstringGenerator withParamTypedByName(@NotNull String name, @Nullable String type) {
-    myParams.add(new DocstringParam(name, type, false));
+    myAddedParams.add(new DocstringParam(name, type, false));
     return this;
   }
 
   @NotNull
   public PyDocstringGenerator withReturnValue(@Nullable String type) {
-    myParams.add(new DocstringParam("", type, true));
+    myAddedParams.add(new DocstringParam("", type, true));
     return this;
   }
 
@@ -120,8 +127,8 @@ public class PyDocstringGenerator {
   }
 
   private void prepareParameters() {
-    // Populate parameter list, if no one was specified explicitly
-    if (!myParametersPrepared && myParams.isEmpty()) {
+    // Populate parameter list, if no one was specified explicitly to add or remove
+    if (!myParametersPrepared && myAddedParams.isEmpty() && myRemovedParams.isEmpty()) {
       if (myDocStringOwner instanceof PyFunction) {
         PySignature signature = null;
         if (myUseTypesFromDebuggerSignature) {
@@ -151,7 +158,7 @@ public class PyDocstringGenerator {
         statementList.accept(visitor);
         if (visitor.myHasReturn || myAlwaysGenerateReturn) {
           // will add :return: placeholder in Sphinx/Epydoc docstrings
-          myParams.add(new DocstringParam("", null, true));
+          myAddedParams.add(new DocstringParam("", null, true));
           if (PyCodeInsightSettings.getInstance().INSERT_TYPE_DOCSTUB) {
             withReturnValue("");
           }
@@ -162,17 +169,17 @@ public class PyDocstringGenerator {
     if (format == DocStringFormat.GOOGLE || format == DocStringFormat.NUMPY) {
       // Google and Numpy docstring formats combine type and description in single declaration, thus
       // if both declaration with type and without it are requested, we should filter out duplicates
-      final ArrayList<DocstringParam> copy = new ArrayList<DocstringParam>(myParams);
+      final ArrayList<DocstringParam> copy = new ArrayList<DocstringParam>(myAddedParams);
       for (final DocstringParam param : copy) {
         if (param.getType() == null) {
-          final DocstringParam sameParamWithType = ContainerUtil.find(myParams, new Condition<DocstringParam>() {
+          final DocstringParam sameParamWithType = ContainerUtil.find(myAddedParams, new Condition<DocstringParam>() {
             @Override
             public boolean value(DocstringParam other) {
               return other.isReturnValue() == param.isReturnValue() && other.getName().equals(param.getName()) && other.getType() != null;
             }
           });
           if (sameParamWithType != null) {
-            myParams.remove(param);
+            myAddedParams.remove(param);
           }
         }
       }
@@ -182,7 +189,7 @@ public class PyDocstringGenerator {
 
   public boolean hasParametersToAdd() {
     prepareParameters();
-    return !myParams.isEmpty();
+    return !myAddedParams.isEmpty();
   }
 
   @Nullable
@@ -211,7 +218,7 @@ public class PyDocstringGenerator {
 
     final TemplateBuilder builder = TemplateBuilderFactory.getInstance().createTemplateBuilder(docStringExpression);
 
-    if (myParams.size() > 1) {
+    if (myAddedParams.size() > 1) {
       throw new IllegalArgumentException("TemplateBuilder can be created only for one parameter");
     }
 
@@ -254,6 +261,15 @@ public class PyDocstringGenerator {
     }
   }
 
+  @NotNull
+  private String getDocStringIndentation() {
+    String indentation = "";
+    if (myDocStringOwner instanceof PyStatementListContainer) {
+      indentation = PyIndentUtil.getElementIndent(((PyStatementListContainer)myDocStringOwner).getStatementList());
+    }
+    return indentation;
+  }
+
   @NotNull
   public String buildDocString() {
     prepareParameters();
@@ -276,7 +292,7 @@ public class PyDocstringGenerator {
       if (myAddFirstEmptyLine) {
         tagBuilder.addEmptyLine();
       }
-      for (DocstringParam param : myParams) {
+      for (DocstringParam param : myAddedParams) {
         if (param.isReturnValue()) {
           if (param.getType() != null) {
             tagBuilder.addReturnValueType(param.getType());
@@ -301,7 +317,7 @@ public class PyDocstringGenerator {
       if (myAddFirstEmptyLine) {
         sectionBuilder.addEmptyLine();
       }
-      final List<DocstringParam> parameters = ContainerUtil.findAll(myParams, new Condition<DocstringParam>() {
+      final List<DocstringParam> parameters = ContainerUtil.findAll(myAddedParams, new Condition<DocstringParam>() {
         @Override
         public boolean value(DocstringParam param) {
           return !param.isReturnValue();
@@ -314,7 +330,7 @@ public class PyDocstringGenerator {
         }
       }
 
-      final List<DocstringParam> returnValues = ContainerUtil.findAll(myParams, new Condition<DocstringParam>() {
+      final List<DocstringParam> returnValues = ContainerUtil.findAll(myAddedParams, new Condition<DocstringParam>() {
         @Override
         public boolean value(DocstringParam param) {
           return param.isReturnValue();
@@ -341,15 +357,6 @@ public class PyDocstringGenerator {
     return myQuotes + '\n' + indentation + myQuotes;
   }
 
-  @NotNull
-  private String getDocStringIndentation() {
-    String indentation = "";
-    if (myDocStringOwner instanceof PyStatementListContainer) {
-      indentation = PyIndentUtil.getElementIndent(((PyStatementListContainer)myDocStringOwner).getStatementList());
-    }
-    return indentation;
-  }
-
   @NotNull
   private String updateDocString() {
     final DocStringFormat format = getDocStringFormat();
@@ -369,7 +376,7 @@ public class PyDocstringGenerator {
       updater = new NumpyDocStringUpdater((SectionBasedDocString)getStructuredDocString(), docStringIndent);
     }
     if (updater != null) {
-      for (DocstringParam param : myParams) {
+      for (DocstringParam param : myAddedParams) {
         if (param.isReturnValue()) {
           updater.addReturnValue(param.getType());
         }
@@ -377,16 +384,21 @@ public class PyDocstringGenerator {
           updater.addParameter(param.getName(), param.getType());
         }
       }
+      for (DocstringParam param : myRemovedParams) {
+        if (!param.isReturnValue()) {
+          updater.removeParameter(param.getName());
+        }
+      }
       return updater.getDocStringText();
     }
     return myQuotes + myQuotes;
   }
 
   private DocstringParam getParamToEdit() {
-    if (myParams.size() == 0) {
+    if (myAddedParams.size() == 0) {
       throw new IllegalStateException("We should have at least one param to edit");
     }
-    return myParams.get(0);
+    return myAddedParams.get(0);
   }
 
   @NotNull
index 0bdd733da3a24d98feaa82f18ac887ec24e77183..b46b0c2091c8eef34a7c5f692f1f0fba2cfceb7e 100644 (file)
@@ -26,7 +26,6 @@ import com.intellij.psi.PsiElement;
 import com.intellij.psi.util.PsiTreeUtil;
 import com.jetbrains.python.PyBundle;
 import com.jetbrains.python.codeInsight.intentions.PyGenerateDocstringIntention;
-import com.jetbrains.python.documentation.DocStringUtil;
 import com.jetbrains.python.documentation.PyDocstringGenerator;
 import com.jetbrains.python.psi.PyClass;
 import com.jetbrains.python.psi.PyDocStringOwner;
@@ -89,12 +88,14 @@ public class DocstringQuickFix implements LocalQuickFix {
       return;
     }
     if (docStringExpression != null) {
+      final PyDocstringGenerator generator = new PyDocstringGenerator(docStringOwner);
       if (myMissingText != null) {
-        new PyDocstringGenerator(docStringOwner).withParam(myMissingText).buildAndInsert();
+        generator.withParam(myMissingText);
       }
       else if (myUnexpected != null) {
-        DocStringUtil.removeParamsFromDocString(docStringExpression, myUnexpected);
+        generator.withoutParam(myUnexpected);
       }
+      generator.buildAndInsert();
     }
   }
 
index bc41e03378db4a1d1ac0e5c6d9104a41c615a665..6ef60e59d3750c4b8f60055fc4d9672b06be7b2f 100644 (file)
@@ -22,7 +22,7 @@ import com.intellij.psi.PsiElement;
 import com.intellij.psi.util.PsiTreeUtil;
 import com.intellij.usageView.UsageInfo;
 import com.jetbrains.python.PyBundle;
-import com.jetbrains.python.documentation.DocStringUtil;
+import com.jetbrains.python.documentation.PyDocstringGenerator;
 import com.jetbrains.python.psi.*;
 import com.jetbrains.python.psi.resolve.PyResolveContext;
 import com.jetbrains.python.refactoring.PyRefactoringUtil;
@@ -73,10 +73,9 @@ public class PyRemoveParameterQuickFix implements LocalQuickFix {
       final PyStringLiteralExpression expression = pyFunction.getDocStringExpression();
       final String paramName = ((PyParameter)element).getName();
       if (expression != null && paramName != null) {
-        DocStringUtil.removeParamsFromDocString(expression, paramName);
+        new PyDocstringGenerator(pyFunction).withoutParam(paramName).buildAndInsert();
       }
     }
-
     element.delete();
   }
 }
index 31b157373b15ed55c795b5366bc728941e59a1e2..3dc62b258a28a6aa7c545b0e680c9d5be658729b 100644 (file)
@@ -33,7 +33,6 @@ import com.intellij.util.containers.HashSet;
 import com.intellij.util.containers.MultiMap;
 import com.jetbrains.python.PyNames;
 import com.jetbrains.python.PythonLanguage;
-import com.jetbrains.python.documentation.DocStringUtil;
 import com.jetbrains.python.documentation.PyDocstringGenerator;
 import com.jetbrains.python.psi.*;
 import com.jetbrains.python.psi.search.PyOverridingMethodsSearch;
@@ -336,14 +335,14 @@ public class PyChangeSignatureUsageProcessor implements ChangeSignatureUsageProc
     }
     final Module module = ModuleUtilCore.findModuleForPsiElement(function);
     if (module == null) return;
-    final List<String> removedParamNames = new ArrayList<String>();
+    final PyDocstringGenerator generator = new PyDocstringGenerator(function);
     for (PyParameter p : function.getParameterList().getParameters()) {
       final String paramName = p.getName();
       if (!names.contains(paramName) && paramName != null) {
-        removedParamNames.add(paramName);
+        generator.withoutParam(paramName);
       }
     }
-    DocStringUtil.removeParamsFromDocString(docStringExpression, removedParamNames);
+    generator.buildAndInsert();
   }
 
   private static void updateParameterList(PyChangeInfo changeInfo, PyFunction baseMethod) {