From 4cd7b6be1b38bf9d3e08704cf38356d68c5a0caf Mon Sep 17 00:00:00 2001 From: Mikhail Golubev Date: Wed, 16 Nov 2016 15:39:08 +0300 Subject: [PATCH] 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. --- .../docstrings/DocStringUtil.java | 37 ++++++++++++++----- .../docstrings/PyDocstringGenerator.java | 5 +-- .../python/psi/impl/PyFunctionBuilder.java | 2 +- 3 files changed, 31 insertions(+), 13 deletions(-) diff --git a/python/src/com/jetbrains/python/documentation/docstrings/DocStringUtil.java b/python/src/com/jetbrains/python/documentation/docstrings/DocStringUtil.java index 7ffcd24ac742..e29e68898b10 100644 --- a/python/src/com/jetbrains/python/documentation/docstrings/DocStringUtil.java +++ b/python/src/com/jetbrains/python/documentation/docstrings/DocStringUtil.java @@ -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) { diff --git a/python/src/com/jetbrains/python/documentation/docstrings/PyDocstringGenerator.java b/python/src/com/jetbrains/python/documentation/docstrings/PyDocstringGenerator.java index 7fc0694fba06..11f24d7320d2 100644 --- a/python/src/com/jetbrains/python/documentation/docstrings/PyDocstringGenerator.java +++ b/python/src/com/jetbrains/python/documentation/docstrings/PyDocstringGenerator.java @@ -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); } diff --git a/python/src/com/jetbrains/python/psi/impl/PyFunctionBuilder.java b/python/src/com/jetbrains/python/psi/impl/PyFunctionBuilder.java index e2456210d268..e4469a12ade4 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyFunctionBuilder.java +++ b/python/src/com/jetbrains/python/psi/impl/PyFunctionBuilder.java @@ -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); }