EA-75111 Handle projects with no modules and, hence, no configured docstring format

It can happen in IDEA projects that contains no modules or, presumably,
in PyCharm projects which settings have been corrupted for some reason.
DocStringFormat.PLAIN is used in some cases as a fallback format.
This commit is contained in:
Mikhail Golubev
2016-11-16 15:49:40 +03:00
parent c38ed868d0
commit 4cd7b6be1b
3 changed files with 31 additions and 13 deletions
@@ -27,6 +27,7 @@ import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.ArrayUtil;
import com.intellij.util.ObjectUtils;
import com.jetbrains.python.codeInsight.controlflow.ScopeOwner;
import com.jetbrains.python.documentation.PyDocumentationSettings;
import com.jetbrains.python.psi.*;
@@ -172,7 +173,7 @@ public class DocStringUtil {
@NotNull
public static DocStringFormat guessDocStringFormat(@NotNull String text, @Nullable PsiElement anchor) {
final DocStringFormat guessed = guessDocStringFormat(text);
return guessed == DocStringFormat.PLAIN && anchor != null ? getConfiguredDocStringFormat(anchor) : guessed;
return guessed == DocStringFormat.PLAIN && anchor != null ? getConfiguredDocStringFormatOrPlain(anchor) : guessed;
}
/**
@@ -180,12 +181,22 @@ public class DocStringUtil {
* @return docstring format configured for file or module containing given anchor PSI element
* @see PyDocumentationSettings#getFormatForFile(PsiFile)
*/
@NotNull
@Nullable
public static DocStringFormat getConfiguredDocStringFormat(@NotNull PsiElement anchor) {
final PyDocumentationSettings settings = PyDocumentationSettings.getInstance(getModuleForElement(anchor));
final Module module = getModuleForElement(anchor);
if (module == null) {
return null;
}
final PyDocumentationSettings settings = PyDocumentationSettings.getInstance(module);
return settings.getFormatForFile(anchor.getContainingFile());
}
@NotNull
public static DocStringFormat getConfiguredDocStringFormatOrPlain(@NotNull PsiElement anchor) {
return ObjectUtils.chooseNotNull(getConfiguredDocStringFormat(anchor), DocStringFormat.PLAIN);
}
public static boolean isLikeSphinxDocString(@NotNull String text) {
return text.contains(":param ") ||
text.contains(":return:") || text.contains(":returns:") ||
@@ -313,16 +324,24 @@ public class DocStringUtil {
* @return false if no structured docstring format was specified initially and user didn't select any, true otherwise
*/
public static boolean ensureNotPlainDocstringFormat(@NotNull PsiElement anchor) {
return ensureNotPlainDocstringFormatForFile(anchor.getContainingFile(), getModuleForElement(anchor));
final Module module = getModuleForElement(anchor);
if (module == null) {
return false;
}
return ensureNotPlainDocstringFormatForFile(anchor.getContainingFile(), module);
}
@NotNull
// Might return {@code null} in some rare cases when PSI element doesn't have an associated module.
// For instance, an empty IDEA project with a Python scratch file.
@Nullable
private static Module getModuleForElement(@NotNull PsiElement element) {
Module module = ModuleUtilCore.findModuleForPsiElement(element);
if (module == null) {
module = ModuleManager.getInstance(element.getProject()).getModules()[0];
final Module module = ModuleUtilCore.findModuleForPsiElement(element);
if (module != null) {
return module;
}
return module;
return ArrayUtil.getFirstElement(ModuleManager.getInstance(element.getProject()).getModules());
}
private static boolean ensureNotPlainDocstringFormatForFile(@NotNull PsiFile file, @NotNull Module module) {
@@ -26,7 +26,6 @@ import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.fileEditor.OpenFileDescriptor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.text.StringUtil;
@@ -92,7 +91,7 @@ public class PyDocstringGenerator {
indentation = PyIndentUtil.getElementIndent(((PyStatementListContainer)owner).getStatementList());
}
final String docStringText = owner.getDocStringExpression() == null ? null : owner.getDocStringExpression().getText();
return new PyDocstringGenerator(owner, docStringText, DocStringUtil.getConfiguredDocStringFormat(owner), indentation, owner);
return new PyDocstringGenerator(owner, docStringText, DocStringUtil.getConfiguredDocStringFormatOrPlain(owner), indentation, owner);
}
/**
@@ -109,7 +108,7 @@ public class PyDocstringGenerator {
public static PyDocstringGenerator update(@NotNull PyStringLiteralExpression docString) {
return new PyDocstringGenerator(PsiTreeUtil.getParentOfType(docString, PyDocStringOwner.class),
docString.getText(),
DocStringUtil.getConfiguredDocStringFormat(docString),
DocStringUtil.getConfiguredDocStringFormatOrPlain(docString),
PyIndentUtil.getElementIndent(docString),
docString);
}
@@ -87,7 +87,7 @@ public class PyFunctionBuilder {
*/
public PyFunctionBuilder(@NotNull String name, @NotNull PsiElement settingsAnchor) {
myName = name;
myDocStringGenerator = PyDocstringGenerator.create(DocStringUtil.getConfiguredDocStringFormat(settingsAnchor),
myDocStringGenerator = PyDocstringGenerator.create(DocStringUtil.getConfiguredDocStringFormatOrPlain(settingsAnchor),
PyIndentUtil.getIndentFromSettings(settingsAnchor.getProject()),
settingsAnchor);
}