PY-9795 Use DocStringUpdater API to remove parameters from docstring in DocstringQuic...
authorMikhail Golubev <mikhail.golubev@jetbrains.com>
Wed, 26 Aug 2015 16:21:57 +0000 (19:21 +0300)
committerMikhail Golubev <mikhail.golubev@jetbrains.com>
Wed, 2 Sep 2015 11:35:23 +0000 (14:35 +0300)
14 files changed:
python/psi-api/src/com/jetbrains/python/toolbox/Substring.java
python/src/com/jetbrains/python/documentation/DocStringLineParser.java
python/src/com/jetbrains/python/documentation/DocStringUtil.java
python/src/com/jetbrains/python/documentation/GoogleCodeStyleDocString.java
python/src/com/jetbrains/python/documentation/NumpyDocString.java
python/src/com/jetbrains/python/documentation/PyDocstringGenerator.java
python/src/com/jetbrains/python/documentation/SectionBasedDocString.java
python/src/com/jetbrains/python/documentation/TagBasedDocString.java
python/src/com/jetbrains/python/documentation/docstrings/DocStringUpdater.java
python/src/com/jetbrains/python/documentation/docstrings/SectionBasedDocStringUpdater.java
python/src/com/jetbrains/python/documentation/docstrings/TagBasedDocStringUpdater.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 4b6c09fba01c2b51ec05468b17ba49107f681f45..a71681f911fe971da04f012e0120136dc8ef4ecd 100644 (file)
@@ -16,6 +16,7 @@
 package com.jetbrains.python.toolbox;
 
 import com.intellij.openapi.util.TextRange;
+import com.intellij.openapi.util.text.StringUtil;
 import org.jetbrains.annotations.NotNull;
 
 import java.util.ArrayList;
@@ -221,11 +222,31 @@ public class Substring implements CharSequence {
     return new Substring(myString, start, end);
   }
 
+  /**
+   * If both substrings share the same origin, returns new substring that includes both of them.
+   */
+  @NotNull
+  public Substring union(@NotNull Substring other) {
+    if (!myString.equals(other.myString)) {
+      throw new IllegalArgumentException(String.format("Substrings '%s' and '%s' must belong to the same origin", this, other));
+    }
+    final TextRange unionRange = getTextRange().union(other.getTextRange());
+    return new Substring(getSuperString(), unionRange.getStartOffset(), unionRange.getEndOffset());
+  }
+
   public int getStartOffset() {
     return myStartOffset;
   }
 
+  public int getStartLine() {
+    return StringUtil.offsetToLineNumber(myString, myStartOffset);
+  }
+
   public int getEndOffset() {
     return myEndOffset;
   }
+
+  public int getEndLine() {
+    return StringUtil.offsetToLineNumber(myString, myEndOffset);
+  }
 }
index cfdfcd728f5755e6237e6f7f50b4510fcd0a9a2b..3278ec3488bc97ae28406f0bc675dcaba69deb50 100644 (file)
@@ -58,10 +58,6 @@ public abstract class DocStringLineParser {
     return myLines.get(lineNum);
   }
 
-  public int getLineByOffset(int offset) {
-    return StringUtil.countNewLines(myDocStringContent.getSuperString().subSequence(0, offset));
-  }
-
   @Nullable
   public Substring getLineOrNull(int lineNum) {
     return lineNum >= 0 && lineNum < myLines.size() ? myLines.get(lineNum) : null;
@@ -80,4 +76,29 @@ public abstract class DocStringLineParser {
   public Substring getDocStringContent() {
     return myDocStringContent;
   }
+
+  /**
+   * Finds line number of the <em>line next after the end of indented block</em>, i.e. if returned value equals startLine,
+   * it means that no block with requested indentation exist. Block can contain intermediate empty lines or lines that consists 
+   * solely of spaces: their indentation is ignored, but it always ends with non-empty line. Non-empty lines in a block must
+   * have indentation greater than indentThreshold and for them {@link #isBlockEnd(int)} must return false.
+   */
+  public int parseIndentedBlock(int startLine, int indentThreshold) {
+    int blockEnd = startLine - 1;
+    int lineNum = startLine;
+    while (!(lineNum >= getLineCount() || isBlockEnd(lineNum))) {
+      if (!isEmpty(lineNum)) {
+        if (getLineIndentSize(lineNum) > indentThreshold) {
+          blockEnd = lineNum;
+        }
+        else {
+          break;
+        }
+      }
+      lineNum++;
+    }
+    return blockEnd + 1;
+  }
+
+  protected abstract boolean isBlockEnd(int lineNum);
 }
index 3203928603334d19deda6451032c53eafda0d971..692f124038fa86209de01a6d024688663051d558 100644 (file)
@@ -29,6 +29,10 @@ 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;
@@ -262,4 +266,34 @@ public class DocStringUtil {
     final PyDocumentationSettings settings = PyDocumentationSettings.getInstance(getModuleForElement(anchor));
     return settings.getFormatForFile(anchor.getContainingFile());
   }
+
+  public static void removeParamFromDocString(@NotNull PyStringLiteralExpression docString, @NotNull String paramName) {
+    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;
+    }
+    updater.removeParameter(paramName);
+    final String newText = updater.getDocStringText();
+    final PyExpressionStatement replacement = PyElementGenerator.getInstance(docString.getProject()).createDocstring(newText);
+    docString.replace(replacement.getExpression());
+  }
 }
index e168c8c01801cdc937d91531dd7552e9498fce8f..67c98ef589437bc87236c027392e9d2776997da5 100644 (file)
@@ -104,7 +104,7 @@ public class GoogleCodeStyleDocString extends SectionBasedDocString {
     final List<Substring> nestedBlock = pair.getFirst();
     if (!nestedBlock.isEmpty()) {
       //noinspection ConstantConditions
-      description = mergeSubstrings(description, ContainerUtil.getLastItem(nestedBlock));
+      description = description.union(ContainerUtil.getLastItem(nestedBlock));
     }
     description = description.trim();
     return Pair.create(new SectionField(name, type, description), pair.getSecond());
index 590ff46f0548c229691f44184ad0a6a4ae66855f..2ce118237ea24d7268de41d012cb120de202bef9 100644 (file)
@@ -85,7 +85,7 @@ public class NumpyDocString extends SectionBasedDocString {
     final Pair<List<Substring>, Integer> parsedDescription = parseIndentedBlock(lineNum + 1, getLineIndentSize(lineNum), sectionIndent);
     final List<Substring> descriptionLines = parsedDescription.getFirst();
     if (!descriptionLines.isEmpty()) {
-      description = mergeSubstrings(descriptionLines.get(0), descriptionLines.get(descriptionLines.size() - 1));
+      description = descriptionLines.get(0).union(descriptionLines.get(descriptionLines.size() - 1));
     }
     return Pair.create(new SectionField(name, type, description != null ? description.trim() : null), parsedDescription.getSecond());
   }
@@ -96,7 +96,7 @@ public class NumpyDocString extends SectionBasedDocString {
   }
 
   @Override
-  protected boolean isSectionBreak(int lineNum, int curSectionIndent) {
-    return super.isSectionBreak(lineNum, curSectionIndent) || (isEmpty(lineNum) && isEmptyOrDoesNotExist(lineNum + 1));
+  protected boolean isBlockEnd(int lineNum) {
+    return super.isBlockEnd(lineNum) || (isEmpty(lineNum) && isEmptyOrDoesNotExist(lineNum + 1));
   }
 }
index faf90326ca7b24518711614bac968b5f0ded2a19..c363adcfe9cd72acf8899c755f4f93f4532a52f8 100644 (file)
@@ -371,7 +371,7 @@ public class PyDocstringGenerator {
     if (updater != null) {
       for (DocstringParam param : myParams) {
         if (param.isReturnValue()) {
-          updater.addReturnValue((param.getType()));
+          updater.addReturnValue(param.getType());
         }
         else {
           updater.addParameter(param.getName(), param.getType());
index 87bceb127f131c4d8ddd27536d94115d044febd9..0cf2f0c92362ec968cd07766592bb681f6838d1c 100644 (file)
@@ -120,7 +120,7 @@ public abstract class SectionBasedDocString extends DocStringLineParser implemen
       lineNum = skipEmptyLines(lineNum);
     }
     //noinspection ConstantConditions
-    mySummary = summary.isEmpty() ? null : mergeSubstrings(summary.get(0), summary.get(summary.size() - 1)).trim();
+    mySummary = summary.isEmpty() ? null : summary.get(0).union(summary.get(summary.size() - 1)).trim();
   }
 
   @NotNull
@@ -197,7 +197,7 @@ public abstract class SectionBasedDocString extends DocStringLineParser implemen
     final Substring firstLine = ContainerUtil.getFirstItem(pair.getFirst());
     final Substring lastLine = ContainerUtil.getLastItem(pair.getFirst());
     if (firstLine != null && lastLine != null) {
-      return Pair.create(new SectionField(null, null, mergeSubstrings(firstLine, lastLine).trim()), pair.getSecond());
+      return Pair.create(new SectionField(null, null, firstLine.union(lastLine).trim()), pair.getSecond());
     }
     return Pair.create(null, pair.getSecond());
   }
@@ -218,9 +218,9 @@ public abstract class SectionBasedDocString extends DocStringLineParser implemen
   }
 
   protected boolean isSectionBreak(int lineNum, int curSectionIndent) {
-    return lineNum >= getLineCount() ||
-           isSectionStart(lineNum) ||
-           (!isEmpty(lineNum) && getLineIndentSize(lineNum) <= curSectionIndent);
+    return lineNum >= getLineCount() || 
+           (!isEmpty(lineNum) && getLineIndentSize(lineNum) <= curSectionIndent) || 
+           isBlockEnd(lineNum);
   }
 
   /**
@@ -231,22 +231,13 @@ public abstract class SectionBasedDocString extends DocStringLineParser implemen
    */
   @NotNull
   protected Pair<List<Substring>, Integer> parseIndentedBlock(int lineNum, int blockIndent, int sectionIndent) {
-    final List<Substring> result = new ArrayList<Substring>();
-    int lastNonEmpty = lineNum - 1;
-    while (!isSectionBreak(lineNum, sectionIndent)) {
-      if (getLineIndentSize(lineNum) > blockIndent) {
-        // copy all lines after the last non empty including the current one
-        for (int i = lastNonEmpty + 1; i <= lineNum; i++) {
-          result.add(getLine(i));
-        }
-        lastNonEmpty = lineNum;
-      }
-      else if (!isEmpty(lineNum)) {
-        break;
-      }
-      lineNum++;
-    }
-    return Pair.create(result, lineNum);
+    final int blockEnd = parseIndentedBlock(lineNum, blockIndent);
+    return Pair.create(myLines.subList(lineNum, blockEnd), blockEnd);
+  }
+
+  @Override
+  protected boolean isBlockEnd(int lineNum) {
+    return isSectionStart(lineNum);
   }
 
   /**
@@ -274,22 +265,6 @@ public abstract class SectionBasedDocString extends DocStringLineParser implemen
     return line.split(":", 1);
   }
 
-  /**
-   * If both substrings share the same origin, returns new substring that includes both of them. Otherwise return {@code null}.
-   *
-   * @param s2 substring to concat with
-   * @return new substring as described
-   */
-  @NotNull
-  protected static Substring mergeSubstrings(@NotNull Substring s1, @NotNull Substring s2) {
-    if (!s1.getSuperString().equals(s2.getSuperString())) {
-      throw new IllegalArgumentException(String.format("Substrings '%s' and '%s' must belong to the same origin", s1, s2));
-    }
-    return new Substring(s1.getSuperString(),
-                       Math.min(s1.getStartOffset(), s2.getStartOffset()),
-                       Math.max(s1.getEndOffset(), s2.getEndOffset()));
-  }
-
   // like Python's textwrap.dedent()
   @NotNull
   protected static String stripCommonIndent(@NotNull Substring text, boolean ignoreFirstStringIfNonEmpty) {
index 432d1fc0c18b6399ea121754495c5bf7777454a4..663bb6bb5497b602d31b0d4667c9c7c9d173223c 100644 (file)
@@ -217,4 +217,9 @@ public abstract class TagBasedDocString extends DocStringLineParser implements S
     results.addAll(getTagArguments(PARAM_TYPE_TAGS));
     return results;
   }
+
+  @Override
+  protected boolean isBlockEnd(int lineNum) {
+    return getLine(lineNum).trimLeft().startsWith(myTagPrefix);
+  }
 }
index 32caf5d50767e85e5ee00a9eb29da6af6b5d83ed..9b4dd65da8c430ffe44dad85ffe176fd1a92e374 100644 (file)
@@ -59,6 +59,21 @@ public abstract class DocStringUpdater<T extends DocStringLineParser> {
     insert(line.getEndOffset(), '\n' + text);
   }
 
+  protected final void remove(int startOffset, int endOffset) {
+    replace(startOffset, endOffset, "");
+  }
+
+  protected final void removeLines(int startLine, int endLine) {
+    final List<Substring> lines = myOriginalDocString.getLines();
+    final int startOffset = lines.get(startLine).getStartOffset();
+    final int endOffset = endLine < lines.size() - 1 ? lines.get(endLine + 1).getStartOffset() : lines.get(endLine).getEndOffset();
+    remove(startOffset, endOffset);
+  }
+
+  protected final void removeLine(int line) {
+    removeLines(line, line);
+  }
+
   protected final void insertBeforeLine(int lineNumber, @NotNull String text) {
     final Substring line = myOriginalDocString.getLines().get(lineNumber);
     insert(line.getStartOffset(), text + '\n');
@@ -100,6 +115,10 @@ public abstract class DocStringUpdater<T extends DocStringLineParser> {
     return lastLineIndent;
   }
 
+  protected int getLineIndentSize(int lineNum) {
+    return PyIndentUtil.getLineIndentSize(getLineIndent(lineNum));
+  }
+
   protected int findLastNonEmptyLine() {
     for (int i = myOriginalDocString.getLineCount() - 1; i >= 0; i--) {
       if (!StringUtil.isEmptyOrSpaces(myOriginalDocString.getLine(i))) {
@@ -113,6 +132,8 @@ public abstract class DocStringUpdater<T extends DocStringLineParser> {
 
   public abstract void addReturnValue(@Nullable String type);
 
+  public abstract void removeParameter(@NotNull String name);
+
   private static class Modification implements Comparable<Modification> {
     @NotNull final TextRange range;
     @NotNull final String text;
index e9707bdd44d3917180c90d6b9ca1c131584edfb1..bb530817eba0b6a43b90b2d59acd8756ba219dc6 100644 (file)
@@ -116,6 +116,15 @@ public abstract class SectionBasedDocStringUpdater extends DocStringUpdater<Sect
     }
   }
 
+  @Override
+  public void removeParameter(@NotNull String name) {
+    for (SectionField param : myOriginalDocString.getParameterFields()) {
+      if (param.getName().equals(name)) {
+        removeLines(getFieldStartLine(param), getFieldEndLine(param));
+      }
+    }
+  }
+
   abstract void updateParamDeclarationWithType(@NotNull Substring nameSubstring, @NotNull String type);
 
   protected int getSectionLastTitleLine(@NotNull Section paramSection) {
@@ -195,12 +204,25 @@ public abstract class SectionBasedDocStringUpdater extends DocStringUpdater<Sect
   }
 
   protected int getSectionStartLine(@NotNull Section section) {
-    return myOriginalDocString.getLineByOffset(section.getTitleAsSubstring().getStartOffset());
+    return section.getTitleAsSubstring().getStartLine();
   }
 
   protected int getFieldStartLine(@NotNull SectionField field) {
     final Substring anyFieldSub = ObjectUtils.chooseNotNull(field.getNameAsSubstring(), field.getTypeAsSubstring());
     //noinspection ConstantConditions
-    return myOriginalDocString.getLineByOffset(anyFieldSub.getStartOffset());
+    return anyFieldSub.getStartLine();
+  }
+
+  protected int getFieldEndLine(@NotNull SectionField field) {
+    if (field.getDescriptionAsSubstring() != null) {
+      return field.getDescriptionAsSubstring().getEndLine();
+    }
+    else if (field.getTypeAsSubstring() != null) {
+      return field.getTypeAsSubstring().getEndLine();
+    }
+    else {
+      //noinspection ConstantConditions
+      return field.getNameAsSubstring().getEndLine();
+    } 
   }
 }
index 67e8122bdabece2a602d19c88e86d1bc1606e1af..7b79cfb111d5f01bf2b6a10f3274064efa96f19b 100644 (file)
@@ -20,14 +20,16 @@ import com.jetbrains.python.toolbox.Substring;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
+import java.util.List;
+
 /**
  * @author Mikhail Golubev
  */
-public class TagBasedDocStringUpdater<T extends TagBasedDocString> extends DocStringUpdater<T>{
+public class TagBasedDocStringUpdater extends DocStringUpdater<TagBasedDocString>{
 
   private final String myTagPrefix;
 
-  public TagBasedDocStringUpdater(@NotNull T docString, @NotNull String tagPrefix, @NotNull String minContentIndent) {
+  public TagBasedDocStringUpdater(@NotNull TagBasedDocString docString, @NotNull String tagPrefix, @NotNull String minContentIndent) {
     super(docString, minContentIndent);
     myTagPrefix = tagPrefix;
   }
@@ -57,6 +59,23 @@ public class TagBasedDocStringUpdater<T extends TagBasedDocString> extends DocSt
     }
   }
 
+  @Override
+  public void removeParameter(@NotNull String name) {
+    final List<Substring> nameSubs = myOriginalDocString.getParameterSubstrings();
+    for (Substring sub : nameSubs) {
+      if (sub.toString().equals(name)) {
+        final int startLine = sub.getStartLine();
+        final int nextAfterBlock = myOriginalDocString.parseIndentedBlock(startLine + 1, getLineIndentSize(startLine));
+        if (nextAfterBlock != startLine + 1) {
+          removeLines(startLine, nextAfterBlock - 1);
+        }
+        else {
+          removeLine(startLine);
+        }
+      }
+    }
+  }
+
   private void insertTagLine(@NotNull DocStringBuilder lineBuilder) {
     final int firstLineWithTag = findFirstLineWithTag();
     if (firstLineWithTag >= 0) {
index 77c425472d70573d56fc76e21a58b5f86a226318..40ffa24033af6862f7f2abcbb8926d69356682b2 100644 (file)
@@ -20,19 +20,18 @@ import com.intellij.codeInspection.ProblemDescriptor;
 import com.intellij.openapi.editor.Document;
 import com.intellij.openapi.editor.Editor;
 import com.intellij.openapi.editor.EditorFactory;
-import com.intellij.openapi.module.Module;
-import com.intellij.openapi.module.ModuleUtilCore;
 import com.intellij.openapi.project.Project;
-import com.intellij.openapi.util.text.StringUtil;
 import com.intellij.psi.PsiDocumentManager;
 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.documentation.PyDocumentationSettings;
-import com.jetbrains.python.editor.PythonDocCommentUtil;
-import com.jetbrains.python.psi.*;
+import com.jetbrains.python.psi.PyClass;
+import com.jetbrains.python.psi.PyDocStringOwner;
+import com.jetbrains.python.psi.PyFunction;
+import com.jetbrains.python.psi.PyStringLiteralExpression;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
@@ -90,27 +89,11 @@ public class DocstringQuickFix implements LocalQuickFix {
       return;
     }
     if (docStringExpression != null) {
-      PyElementGenerator elementGenerator = PyElementGenerator.getInstance(project);
-      final Module module = ModuleUtilCore.findModuleForPsiElement(docStringExpression);
-      if (module == null) return;
-      PyDocumentationSettings documentationSettings = PyDocumentationSettings.getInstance(module);
-      if (documentationSettings.isEpydocFormat(docStringExpression.getContainingFile())) {
-        myPrefix = "@";
-      }
-      else {
-        myPrefix = ":";
-      }
-
-      String replacement = docStringExpression.getText();
       if (myMissingText != null) {
-        replacement = new PyDocstringGenerator(docStringOwner).withParam(myMissingText).buildDocString();
-      }
-      if (myUnexpected != null) {
-        replacement = PythonDocCommentUtil.removeParamFromDocstring(replacement, myPrefix, myUnexpected);
+        new PyDocstringGenerator(docStringOwner).withParam(myMissingText).buildAndInsert();
       }
-      if (!replacement.equals(docStringExpression.getText()) && !StringUtil.isEmptyOrSpaces(replacement)) {
-        PyExpression str = elementGenerator.createDocstring(replacement).getExpression();
-        docStringExpression.replace(str);
+      else if (myUnexpected != null) {
+        DocStringUtil.removeParamFromDocString(docStringExpression, myUnexpected);
       }
     }
   }
index ed2f985af15329b9db74ff044a38adfffad4f68b..663d6a457e8346e541856f7c58978af33c67601b 100644 (file)
@@ -17,15 +17,12 @@ package com.jetbrains.python.inspections.quickfix;
 
 import com.intellij.codeInspection.LocalQuickFix;
 import com.intellij.codeInspection.ProblemDescriptor;
-import com.intellij.openapi.module.Module;
-import com.intellij.openapi.module.ModuleUtilCore;
 import com.intellij.openapi.project.Project;
 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.PyDocumentationSettings;
-import com.jetbrains.python.editor.PythonDocCommentUtil;
+import com.jetbrains.python.documentation.DocStringUtil;
 import com.jetbrains.python.psi.*;
 import com.jetbrains.python.psi.resolve.PyResolveContext;
 import com.jetbrains.python.refactoring.PyRefactoringUtil;
@@ -76,14 +73,7 @@ public class PyRemoveParameterQuickFix implements LocalQuickFix {
       final PyStringLiteralExpression expression = pyFunction.getDocStringExpression();
       final String paramName = ((PyParameter)element).getName();
       if (expression != null && paramName != null) {
-        final Module module = ModuleUtilCore.findModuleForPsiElement(pyFunction);
-        assert module != null;
-        PyDocumentationSettings documentationSettings = PyDocumentationSettings.getInstance(module);
-        String prefix = documentationSettings.isEpydocFormat(pyFunction.getContainingFile()) ? "@" : ":";
-        final String replacement = PythonDocCommentUtil.removeParamFromDocstring(expression.getText(), prefix, paramName);
-        PyExpression str =
-          PyElementGenerator.getInstance(project).createDocstring(replacement).getExpression();
-        expression.replace(str);
+        DocStringUtil.removeParamFromDocString(expression, paramName);
       }
     }
 
index 66da653c29b44ca3936442e6c7ea3a24d2833cd9..d108f416801f9c12e7b102e4b4edbb36f58e5bf6 100644 (file)
@@ -33,9 +33,8 @@ 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.documentation.PyDocumentationSettings;
-import com.jetbrains.python.editor.PythonDocCommentUtil;
 import com.jetbrains.python.psi.*;
 import com.jetbrains.python.psi.search.PyOverridingMethodsSearch;
 import com.jetbrains.python.refactoring.PyRefactoringUtil;
@@ -340,13 +339,7 @@ public class PyChangeSignatureUsageProcessor implements ChangeSignatureUsageProc
     for (PyParameter p : function.getParameterList().getParameters()) {
       final String paramName = p.getName();
       if (!names.contains(paramName) && paramName != null) {
-        PyDocumentationSettings documentationSettings = PyDocumentationSettings.getInstance(module);
-        String prefix = documentationSettings.isEpydocFormat(docStringExpression.getContainingFile()) ? "@" : ":";
-        final String replacement = PythonDocCommentUtil.removeParamFromDocstring(docStringExpression.getText(), prefix,
-                                                                                 paramName);
-        PyExpression str =
-          PyElementGenerator.getInstance(function.getProject()).createDocstring(replacement).getExpression();
-        docStringExpression.replace(str);
+        DocStringUtil.removeParamFromDocString(docStringExpression, paramName);
       }
     }
   }