diff --git a/python/psi-api/src/com/jetbrains/python/psi/PyDocStringOwner.java b/python/psi-api/src/com/jetbrains/python/psi/PyDocStringOwner.java index 019504035267..5c1f96040ef0 100644 --- a/python/psi-api/src/com/jetbrains/python/psi/PyDocStringOwner.java +++ b/python/psi-api/src/com/jetbrains/python/psi/PyDocStringOwner.java @@ -3,6 +3,12 @@ package com.jetbrains.python.psi; import org.jetbrains.annotations.Nullable; public interface PyDocStringOwner extends PyElement { + @Nullable + String getDocStringValue(); + + @Nullable + StructuredDocString getStructuredDocString(); + @Nullable PyStringLiteralExpression getDocStringExpression(); } diff --git a/python/psi-api/src/com/jetbrains/python/psi/PyFunction.java b/python/psi-api/src/com/jetbrains/python/psi/PyFunction.java index 5d125c7f5ff0..b5bed943c78d 100644 --- a/python/psi-api/src/com/jetbrains/python/psi/PyFunction.java +++ b/python/psi-api/src/com/jetbrains/python/psi/PyFunction.java @@ -48,9 +48,6 @@ extends @Nullable PyType getReturnTypeFromDocString(); - @Nullable - String getDocStringValue(); - /** * If the function raises a DeprecationWarning or a PendingDeprecationWarning, returns the explanation text provided for the warning.. * diff --git a/python/psi-api/src/com/jetbrains/python/psi/StructuredDocString.java b/python/psi-api/src/com/jetbrains/python/psi/StructuredDocString.java new file mode 100644 index 000000000000..927187cf0a1b --- /dev/null +++ b/python/psi-api/src/com/jetbrains/python/psi/StructuredDocString.java @@ -0,0 +1,69 @@ +package com.jetbrains.python.psi; + +import com.jetbrains.python.toolbox.Substring; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +/** + * @author vlan + */ +public interface StructuredDocString { + String getDescription(); + + String getSummary(); + + @Nullable + Substring getTagValue(String... tagNames); + + @Nullable + Substring getTagValue(String tagName, @NotNull String argName); + + @Nullable + Substring getTagValue(String[] tagNames, @NotNull String argName); + + List getTagArguments(String... tagNames); + + List getParameterSubstrings(); + + @Nullable + Substring getParamByNameAndKind(@NotNull String name, String kind); + + List getParameters(); + + List getKeywordArguments(); + + @Nullable + String getReturnType(); + + @Nullable + String getReturnDescription(); + + @Nullable + String getParamType(@Nullable String paramName); + + @Nullable + String getParamDescription(@Nullable String paramName); + + @Nullable + String getKeywordArgumentDescription(@Nullable String paramName); + + List getRaisedExceptions(); + + @Nullable + String getRaisedExceptionDescription(@Nullable String exceptionName); + + @Nullable + String getAttributeDescription(); + + List getAdditionalTags(); + + List getKeywordArgumentSubstrings(); + + @Nullable + Substring getReturnTypeSubstring(); + + @Nullable + Substring getParamTypeSubstring(@Nullable String paramName); +} diff --git a/python/src/com/jetbrains/python/documentation/Substring.java b/python/psi-api/src/com/jetbrains/python/toolbox/Substring.java similarity index 98% rename from python/src/com/jetbrains/python/documentation/Substring.java rename to python/psi-api/src/com/jetbrains/python/toolbox/Substring.java index 11e600b97f4c..cee966de2dbc 100644 --- a/python/src/com/jetbrains/python/documentation/Substring.java +++ b/python/psi-api/src/com/jetbrains/python/toolbox/Substring.java @@ -1,4 +1,4 @@ -package com.jetbrains.python.documentation; +package com.jetbrains.python.toolbox; import com.intellij.openapi.util.TextRange; import org.jetbrains.annotations.NotNull; @@ -8,15 +8,13 @@ import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; -/** - * @author vlan - */ - /** * Substring with explicit offsets within its parent string. *

* Regular java.lang.String objects share a single char buffer for results of substring(), trim(), etc., but the offset and count * fields of Strings are unfortunately private. + * + * @author vlan */ public class Substring implements CharSequence { private static final Pattern RE_NL = Pattern.compile("(\\r?\\n)"); diff --git a/python/src/com/jetbrains/python/PythonDocStringFinder.java b/python/src/com/jetbrains/python/PythonDocStringFinder.java deleted file mode 100644 index f9a25a7cadfb..000000000000 --- a/python/src/com/jetbrains/python/PythonDocStringFinder.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.jetbrains.python; - -import com.intellij.psi.PsiElement; -import com.jetbrains.python.psi.PyElement; -import com.jetbrains.python.psi.PyExpressionStatement; -import com.jetbrains.python.psi.PyStringLiteralExpression; -import com.jetbrains.python.psi.PyUtil; -import org.jetbrains.annotations.Nullable; - -// TODO: find a better place for this. -/** - * Utility class for finding an expression which would fit as a doc string. - * User: dcheryasov - * Date: Jun 7, 2009 5:06:12 AM - */ -public class PythonDocStringFinder { - private PythonDocStringFinder() {} - - /** - * Looks for a doc string under given parent. - * @param parent where to look. For classes and functions, this would be PyStatementList, for modules, PyFile. - * @return the defining expression, or null. - */ - @Nullable - public static PyStringLiteralExpression find(PyElement parent) { - if (parent != null) { - PsiElement seeker = PyUtil.getFirstNonCommentAfter(parent.getFirstChild()); - if (seeker instanceof PyExpressionStatement) seeker = PyUtil.getFirstNonCommentAfter(seeker.getFirstChild()); - if (seeker instanceof PyStringLiteralExpression) return (PyStringLiteralExpression)seeker; - } - return null; - } -} diff --git a/python/src/com/jetbrains/python/codeInsight/imports/AddImportHelper.java b/python/src/com/jetbrains/python/codeInsight/imports/AddImportHelper.java index 3469eb7cd56e..b30e1048a613 100644 --- a/python/src/com/jetbrains/python/codeInsight/imports/AddImportHelper.java +++ b/python/src/com/jetbrains/python/codeInsight/imports/AddImportHelper.java @@ -8,8 +8,8 @@ import com.intellij.openapi.roots.ProjectRootManager; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; import com.intellij.util.IncorrectOperationException; -import com.jetbrains.python.PythonDocStringFinder; import com.jetbrains.python.codeInsight.PyCodeInsightSettings; +import com.jetbrains.python.documentation.DocStringUtil; import com.jetbrains.python.psi.*; import com.jetbrains.python.psi.impl.PyQualifiedName; import com.jetbrains.python.psi.resolve.QualifiedNameFinder; @@ -63,7 +63,7 @@ public class AddImportHelper { // maybe we arrived at the doc comment stmt; skip over it, too else if (!skippedOverImports && !skippedOverDoc && file instanceof PyFile) { PsiElement doc_elt = - PythonDocStringFinder.find((PyElement)file); // this gives the literal; its parent is the expr seeker may have encountered + DocStringUtil.findDocStringExpression((PyElement)file); // this gives the literal; its parent is the expr seeker may have encountered if (doc_elt != null && doc_elt.getParent() == feeler) { feeler = feeler.getNextSibling(); seeker = feeler; // skip over doc even if there's nothing below it diff --git a/python/src/com/jetbrains/python/codeInsight/intentions/SpecifyTypeInDocstringIntention.java b/python/src/com/jetbrains/python/codeInsight/intentions/SpecifyTypeInDocstringIntention.java index f7b4909f79c6..36e144d4c919 100644 --- a/python/src/com/jetbrains/python/codeInsight/intentions/SpecifyTypeInDocstringIntention.java +++ b/python/src/com/jetbrains/python/codeInsight/intentions/SpecifyTypeInDocstringIntention.java @@ -12,7 +12,6 @@ import com.jetbrains.python.PyBundle; import com.jetbrains.python.debugger.PySignature; import com.jetbrains.python.debugger.PySignatureCacheManager; import com.jetbrains.python.documentation.PyDocstringGenerator; -import com.jetbrains.python.documentation.StructuredDocString; import com.jetbrains.python.psi.*; import org.jetbrains.annotations.NotNull; @@ -83,23 +82,15 @@ public class SpecifyTypeInDocstringIntention extends TypeIntention { protected boolean isParamTypeDefined(PyParameter parameter) { PyFunction pyFunction = PsiTreeUtil.getParentOfType(parameter, PyFunction.class); if (pyFunction != null && parameter != null) { - final String docstring = pyFunction.getDocStringValue(); - if (docstring != null) { - StructuredDocString structuredDocString = StructuredDocString.parse(docstring); - return structuredDocString != null && structuredDocString.getParamType(StringUtil.notNullize(parameter.getName())) != null; - } - return false; + final StructuredDocString structuredDocString = pyFunction.getStructuredDocString(); + return structuredDocString != null && structuredDocString.getParamType(StringUtil.notNullize(parameter.getName())) != null; } return false; } @Override protected boolean isReturnTypeDefined(@NotNull PyFunction function) { - final String docstring = function.getDocStringValue(); - if (docstring != null) { - StructuredDocString structuredDocString = StructuredDocString.parse(docstring); - return structuredDocString != null && structuredDocString.getReturnType( ) != null; - } - return false; + final StructuredDocString structuredDocString = function.getStructuredDocString(); + return structuredDocString != null && structuredDocString.getReturnType() != null; } } \ No newline at end of file diff --git a/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibTypeProvider.java b/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibTypeProvider.java index 6d3d232d4e1c..f08782be5dc6 100644 --- a/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibTypeProvider.java +++ b/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibTypeProvider.java @@ -7,7 +7,8 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiElement; import com.jetbrains.python.PyNames; import com.jetbrains.python.PythonHelpersLocator; -import com.jetbrains.python.documentation.StructuredDocString; +import com.jetbrains.python.documentation.DocStringUtil; +import com.jetbrains.python.psi.StructuredDocString; import com.jetbrains.python.psi.*; import com.jetbrains.python.psi.impl.PyBuiltinCache; import com.jetbrains.python.psi.impl.PyQualifiedName; @@ -280,7 +281,7 @@ public class PyStdlibTypeProvider extends PyTypeProviderBase { if (docString == null && level.isPy3K()) { //if we couldn't find for Py3K will search in Python2 db return getStructuredDocString(qualifiedName, LanguageLevel.PYTHON27); } - return StructuredDocString.parse(docString); + return DocStringUtil.parse(docString); } @Nullable diff --git a/python/src/com/jetbrains/python/documentation/DocStringReferenceProvider.java b/python/src/com/jetbrains/python/documentation/DocStringReferenceProvider.java index e92b3e799150..fbdb4ea0f448 100644 --- a/python/src/com/jetbrains/python/documentation/DocStringReferenceProvider.java +++ b/python/src/com/jetbrains/python/documentation/DocStringReferenceProvider.java @@ -10,9 +10,11 @@ import com.jetbrains.python.PyNames; import com.jetbrains.python.psi.PyDocStringOwner; import com.jetbrains.python.psi.PyImportElement; import com.jetbrains.python.psi.PyStringLiteralExpression; +import com.jetbrains.python.psi.StructuredDocString; import com.jetbrains.python.psi.impl.PyStringLiteralExpressionImpl; import com.jetbrains.python.psi.types.PyType; import com.jetbrains.python.psi.types.PyTypeParser; +import com.jetbrains.python.toolbox.Substring; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -40,17 +42,17 @@ public class DocStringReferenceProvider extends PsiReferenceProvider { final List result = new ArrayList(); final int offset = ranges.get(0).getStartOffset(); // XXX: It does not work with multielement docstrings - StructuredDocString docString = StructuredDocString.parse(text); + StructuredDocString docString = DocStringUtil.parse(text); if (docString != null) { result.addAll(referencesFromNames(element, offset, docString, - docString.getTagArguments(StructuredDocString.PARAM_TAGS), StructuredDocString.PARAMETER)); + docString.getTagArguments(StructuredDocStringBase.PARAM_TAGS), StructuredDocStringBase.PARAMETER)); result.addAll(referencesFromNames(element, offset, docString, - docString.getTagArguments(StructuredDocString.PARAM_TYPE_TAGS), StructuredDocString.PARAMETER_TYPE)); + docString.getTagArguments(StructuredDocStringBase.PARAM_TYPE_TAGS), StructuredDocStringBase.PARAMETER_TYPE)); result.addAll(referencesFromNames(element, offset, docString, - docString.getKeywordArgumentSubstrings(), StructuredDocString.KEYWORD)); + docString.getKeywordArgumentSubstrings(), StructuredDocStringBase.KEYWORD)); result.addAll(referencesFromNames(element, offset, docString, - docString.getTagArguments(StructuredDocString.VARIABLE_TAGS), StructuredDocString.VARIABLE)); + docString.getTagArguments(StructuredDocStringBase.VARIABLE_TAGS), StructuredDocStringBase.VARIABLE)); result.addAll(returnTypes(element, docString, offset)); } return result.toArray(new PsiReference[result.size()]); @@ -81,7 +83,7 @@ public class DocStringReferenceProvider extends PsiReferenceProvider { if (PyNames.isIdentifier(s)) { result.add(new DocStringParameterReference(element, name.getTextRange().shiftRight(offset), refType)); } - if (refType.equals(StructuredDocString.PARAMETER_TYPE)) { + if (refType.equals(StructuredDocStringBase.PARAMETER_TYPE)) { final Substring type = docString.getParamTypeSubstring(s); if (type != null) { result.addAll(parseTypeReferences(element, type, offset)); diff --git a/python/src/com/jetbrains/python/documentation/DocStringUtil.java b/python/src/com/jetbrains/python/documentation/DocStringUtil.java index d1699d809bf2..de14248281d3 100644 --- a/python/src/com/jetbrains/python/documentation/DocStringUtil.java +++ b/python/src/com/jetbrains/python/documentation/DocStringUtil.java @@ -1,5 +1,18 @@ package com.jetbrains.python.documentation; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.module.ModuleUtilCore; +import com.intellij.psi.PsiComment; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiWhiteSpace; +import com.intellij.psi.util.PsiTreeUtil; +import com.jetbrains.python.PyNames; +import com.jetbrains.python.codeInsight.controlflow.ScopeOwner; +import com.jetbrains.python.psi.*; +import com.jetbrains.python.psi.impl.PyPsiUtils; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + /** * User: catherine */ @@ -12,4 +25,128 @@ public class DocStringUtil { .replaceFirst("^((:py)?:class:`[~!]?|[A-Z]\\{)", "") .replaceFirst("(`|\\})?\\.?$", ""); } + + @Nullable + public static String getDocStringValue(@NotNull PyDocStringOwner owner) { + return PyPsiUtils.strValue(owner.getDocStringExpression()); + } + + @Nullable + public static StructuredDocString parse(@Nullable String text) { + if (text == null) { + return null; + } + if (isSphinxDocString(text)) { + return new SphinxDocString(text); + } + return new EpydocString(text); + } + + public static boolean isSphinxDocString(@NotNull String text) { + return text.contains(":param ") || text.contains(":rtype") || text.contains(":type"); + } + + public static boolean isEpydocDocString(@NotNull String text) { + return text.contains("@param ") || text.contains("@rtype") || text.contains("@type"); + } + + /** + * Looks for a doc string under given parent. + * @param parent where to look. For classes and functions, this would be PyStatementList, for modules, PyFile. + * @return the defining expression, or null. + */ + @Nullable + public static PyStringLiteralExpression findDocStringExpression(@Nullable PyElement parent) { + if (parent != null) { + PsiElement seeker = PyUtil.getFirstNonCommentAfter(parent.getFirstChild()); + if (seeker instanceof PyExpressionStatement) seeker = PyUtil.getFirstNonCommentAfter(seeker.getFirstChild()); + if (seeker instanceof PyStringLiteralExpression) return (PyStringLiteralExpression)seeker; + } + return null; + } + + public static StructuredDocString getStructuredDocString(PyDocStringOwner owner) { + return parse(owner.getDocStringValue()); + } + + public static boolean isDocStringExpression(@Nullable PyExpression expression) { + final PyDocStringOwner docStringOwner = PsiTreeUtil.getParentOfType(expression, PyDocStringOwner.class); + if (docStringOwner != null) { + if (docStringOwner.getDocStringExpression() == expression) { + return true; + } + } + if (expression instanceof PyStringLiteralExpression) { + return isVariableDocString((PyStringLiteralExpression)expression); + } + return false; + } + + @Nullable + public static PyStringLiteralExpression getAttributeDocString(@NotNull PyTargetExpression attr) { + if (attr.getParent() instanceof PyAssignmentStatement) { + final PyAssignmentStatement assignment = (PyAssignmentStatement)attr.getParent(); + PsiElement nextSibling = assignment.getNextSibling(); + while (nextSibling != null && (nextSibling instanceof PsiWhiteSpace || nextSibling instanceof PsiComment)) { + nextSibling = nextSibling.getNextSibling(); + } + if (nextSibling instanceof PyExpressionStatement) { + final PyExpression expression = ((PyExpressionStatement)nextSibling).getExpression(); + if (expression instanceof PyStringLiteralExpression) { + return (PyStringLiteralExpression)expression; + } + } + } + return null; + } + + @Nullable + public static String getAttributeDocComment(@NotNull PyTargetExpression attr) { + if (attr.getParent() instanceof PyAssignmentStatement) { + final PyAssignmentStatement assignment = (PyAssignmentStatement)attr.getParent(); + PsiElement prevSibling = assignment.getPrevSibling(); + while (prevSibling != null && (prevSibling instanceof PsiWhiteSpace)) { + prevSibling = prevSibling.getPrevSibling(); + } + if (prevSibling instanceof PsiComment && prevSibling.getText().startsWith("#:")) { + return prevSibling.getText().substring(2); + } + } + return null; + } + + public static boolean isVariableDocString(@NotNull PyStringLiteralExpression expr) { + final Module module = ModuleUtilCore.findModuleForPsiElement(expr); + if (module == null) return false; + final PyDocumentationSettings settings = PyDocumentationSettings.getInstance(module); + if (settings.isEpydocFormat(expr.getContainingFile()) || settings.isReSTFormat(expr.getContainingFile())) { + final PsiElement parent = expr.getParent(); + if (!(parent instanceof PyExpressionStatement)) { + return false; + } + PsiElement prevElement = parent.getPrevSibling(); + while (prevElement instanceof PsiWhiteSpace || prevElement instanceof PsiComment) { + prevElement = prevElement.getPrevSibling(); + } + if (prevElement instanceof PyAssignmentStatement) { + final PyAssignmentStatement assignmentStatement = (PyAssignmentStatement)prevElement; + final ScopeOwner scope = PsiTreeUtil.getParentOfType(prevElement, ScopeOwner.class); + if (scope instanceof PyClass || scope instanceof PyFile) { + return true; + } + if (scope instanceof PyFunction) { + PyFunction function = (PyFunction) scope; + if (!PyNames.INIT.equals(function.getName())) { + return false; + } + for (PyExpression target : assignmentStatement.getTargets()) { + if (PyUtil.isInstanceAttribute(target)) { + return true; + } + } + } + } + } + return false; + } } diff --git a/python/src/com/jetbrains/python/documentation/EpydocString.java b/python/src/com/jetbrains/python/documentation/EpydocString.java index 38f3b93c8807..867af6b336a0 100644 --- a/python/src/com/jetbrains/python/documentation/EpydocString.java +++ b/python/src/com/jetbrains/python/documentation/EpydocString.java @@ -2,6 +2,7 @@ package com.jetbrains.python.documentation; import com.intellij.openapi.util.text.StringUtil; import com.intellij.xml.util.XmlTagUtilBase; +import com.jetbrains.python.toolbox.Substring; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -10,7 +11,7 @@ import java.util.*; /** * @author yole */ -public class EpydocString extends StructuredDocString { +public class EpydocString extends StructuredDocStringBase { public static String[] RTYPE_TAGS = new String[] { "rtype", "returntype" }; public static String[] KEYWORD_ARGUMENT_TAGS = new String[] { "keyword", "kwarg", "kwparam" }; diff --git a/python/src/com/jetbrains/python/documentation/EpydocUtil.java b/python/src/com/jetbrains/python/documentation/EpydocUtil.java deleted file mode 100644 index a71a7775df31..000000000000 --- a/python/src/com/jetbrains/python/documentation/EpydocUtil.java +++ /dev/null @@ -1,54 +0,0 @@ -package com.jetbrains.python.documentation; - -import com.intellij.openapi.module.Module; -import com.intellij.openapi.module.ModuleUtilCore; -import com.intellij.psi.PsiComment; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiWhiteSpace; -import com.intellij.psi.util.PsiTreeUtil; -import com.jetbrains.python.PyNames; -import com.jetbrains.python.codeInsight.controlflow.ScopeOwner; -import com.jetbrains.python.psi.*; - -/** - * @author yole - */ -public class EpydocUtil { - private EpydocUtil() { - } - - public static boolean isVariableDocString(PyStringLiteralExpression expr) { - final Module module = ModuleUtilCore.findModuleForPsiElement(expr); - if (module == null) return false; - final PyDocumentationSettings settings = PyDocumentationSettings.getInstance(module); - if (settings.isEpydocFormat(expr.getContainingFile()) || settings.isReSTFormat(expr.getContainingFile())) { - final PsiElement parent = expr.getParent(); - if (!(parent instanceof PyExpressionStatement)) { - return false; - } - PsiElement prevElement = parent.getPrevSibling(); - while (prevElement instanceof PsiWhiteSpace || prevElement instanceof PsiComment) { - prevElement = prevElement.getPrevSibling(); - } - if (prevElement instanceof PyAssignmentStatement) { - final PyAssignmentStatement assignmentStatement = (PyAssignmentStatement)prevElement; - final ScopeOwner scope = PsiTreeUtil.getParentOfType(prevElement, ScopeOwner.class); - if (scope instanceof PyClass || scope instanceof PyFile) { - return true; - } - if (scope instanceof PyFunction) { - PyFunction function = (PyFunction) scope; - if (!PyNames.INIT.equals(function.getName())) { - return false; - } - for (PyExpression target : assignmentStatement.getTargets()) { - if (PyUtil.isInstanceAttribute(target)) { - return true; - } - } - } - } - } - return false; - } -} diff --git a/python/src/com/jetbrains/python/documentation/PyDocstringGenerator.java b/python/src/com/jetbrains/python/documentation/PyDocstringGenerator.java index 721d0cab4ed0..bd561134c976 100644 --- a/python/src/com/jetbrains/python/documentation/PyDocstringGenerator.java +++ b/python/src/com/jetbrains/python/documentation/PyDocstringGenerator.java @@ -31,6 +31,7 @@ import com.jetbrains.python.debugger.PySignature; import com.jetbrains.python.debugger.PySignatureCacheManager; import com.jetbrains.python.debugger.PySignatureUtil; import com.jetbrains.python.psi.*; +import com.jetbrains.python.toolbox.Substring; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -149,7 +150,7 @@ public class PyDocstringGenerator { public Pair addParamToDocstring() { String text = getDocstringText(); - StructuredDocString structuredDocString = StructuredDocString.parse(text); + StructuredDocString structuredDocString = DocStringUtil.parse(text); Collection paramsToAdd = getParamsToAdd(structuredDocString, myParams); @@ -172,7 +173,7 @@ public class PyDocstringGenerator { private Collection collectParametersToAdd() { String text = getDocstringText(); - StructuredDocString structuredDocString = StructuredDocString.parse(text); //TODO: do we need to cache it? + StructuredDocString structuredDocString = DocStringUtil.parse(text); //TODO: do we need to cache it? return getParamsToAdd(structuredDocString, myParams); } diff --git a/python/src/com/jetbrains/python/documentation/PyDocumentationBuilder.java b/python/src/com/jetbrains/python/documentation/PyDocumentationBuilder.java index 25c74ad034d3..16465a6ed69b 100644 --- a/python/src/com/jetbrains/python/documentation/PyDocumentationBuilder.java +++ b/python/src/com/jetbrains/python/documentation/PyDocumentationBuilder.java @@ -30,6 +30,7 @@ import com.jetbrains.python.psi.types.*; import com.jetbrains.python.sdk.PythonSdkType; import com.jetbrains.python.toolbox.ChainIterable; import com.jetbrains.python.toolbox.Maybe; +import com.jetbrains.python.toolbox.Substring; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -365,7 +366,7 @@ class PyDocumentationBuilder { String[] lines = removeCommonIndentation(docstring); String preparedDocstring = StringUtil.join(lines, "\n"); if (documentationSettings.isEpydocFormat(element.getContainingFile()) || - StructuredDocString.isEpydocDocstring(preparedDocstring)) { + DocStringUtil.isEpydocDocString(preparedDocstring)) { final EpydocString epydocString = new EpydocString(preparedDocstring); String formatted = epydocString.getDescription(); @@ -375,7 +376,7 @@ class PyDocumentationBuilder { return; } else if (documentationSettings.isReSTFormat(element.getContainingFile()) || - StructuredDocString.isSphinxDocstring(preparedDocstring)) { + DocStringUtil.isSphinxDocString(preparedDocstring)) { String formatted = null; Sdk pythonSdk = PythonSdkType.findPython2Sdk(module); if (pythonSdk != null) { @@ -451,7 +452,7 @@ class PyDocumentationBuilder { } private static Pair getTypeAndDescr(String docString, @NotNull PyNamedParameter followed) { - StructuredDocString structuredDocString = StructuredDocString.parse(docString); + StructuredDocString structuredDocString = DocStringUtil.parse(docString); String type = null; String desc = null; if (structuredDocString != null) { @@ -473,7 +474,7 @@ class PyDocumentationBuilder { .addItem(" of class ").addWith(PythonDocumentationProvider.LinkMyClass, $().addWith(TagCode, $(cls.getName()))).addItem(BR) ; - final String docString = PyPsiUtils.strValue(PyUtil.getAttributeDocString((PyTargetExpression)myElement)); + final String docString = PyPsiUtils.strValue(DocStringUtil.getAttributeDocString((PyTargetExpression)myElement)); if (docString != null) { addFormattedDocString(myElement, docString, myBody, myEpilog); } diff --git a/python/src/com/jetbrains/python/documentation/PythonDocumentationProvider.java b/python/src/com/jetbrains/python/documentation/PythonDocumentationProvider.java index 05a7a13f42c8..6720540ec34e 100644 --- a/python/src/com/jetbrains/python/documentation/PythonDocumentationProvider.java +++ b/python/src/com/jetbrains/python/documentation/PythonDocumentationProvider.java @@ -73,7 +73,7 @@ public class PythonDocumentationProvider extends AbstractDocumentationProvider i String summary = ""; final PyStringLiteralExpression docStringExpression = func.getDocStringExpression(); if (docStringExpression != null) { - final StructuredDocString docString = StructuredDocString.parse(docStringExpression.getStringValue()); + final StructuredDocString docString = DocStringUtil.parse(docStringExpression.getStringValue()); if (docString != null) { summary = docString.getSummary(); } @@ -92,7 +92,7 @@ public class PythonDocumentationProvider extends AbstractDocumentationProvider i } } if (docStringExpression != null) { - final StructuredDocString docString = StructuredDocString.parse(docStringExpression.getStringValue()); + final StructuredDocString docString = DocStringUtil.parse(docStringExpression.getStringValue()); if (docString != null) { summary = docString.getSummary(); } diff --git a/python/src/com/jetbrains/python/documentation/SphinxDocString.java b/python/src/com/jetbrains/python/documentation/SphinxDocString.java index c73c138ef1e4..8f5670516bbd 100644 --- a/python/src/com/jetbrains/python/documentation/SphinxDocString.java +++ b/python/src/com/jetbrains/python/documentation/SphinxDocString.java @@ -1,5 +1,6 @@ package com.jetbrains.python.documentation; +import com.jetbrains.python.toolbox.Substring; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -9,7 +10,7 @@ import java.util.List; /** * @author yole */ -public class SphinxDocString extends StructuredDocString { +public class SphinxDocString extends StructuredDocStringBase { public static String[] KEYWORD_ARGUMENT_TAGS = new String[] { "keyword", "key" }; public static String[] ALL_TAGS = new String[] { ":param", ":parameter", ":arg", ":argument", ":keyword", ":key", ":type", ":raise", ":raises", ":var", ":cvar", ":ivar", diff --git a/python/src/com/jetbrains/python/documentation/StructuredDocString.java b/python/src/com/jetbrains/python/documentation/StructuredDocStringBase.java similarity index 81% rename from python/src/com/jetbrains/python/documentation/StructuredDocString.java rename to python/src/com/jetbrains/python/documentation/StructuredDocStringBase.java index 5c9a8d23eb36..0ed1e94def2c 100644 --- a/python/src/com/jetbrains/python/documentation/StructuredDocString.java +++ b/python/src/com/jetbrains/python/documentation/StructuredDocStringBase.java @@ -3,6 +3,8 @@ package com.jetbrains.python.documentation; import com.google.common.collect.Maps; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.text.StringUtil; +import com.jetbrains.python.psi.StructuredDocString; +import com.jetbrains.python.toolbox.Substring; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -16,7 +18,7 @@ import java.util.regex.Pattern; /** * @author yole */ -public abstract class StructuredDocString { +public abstract class StructuredDocStringBase implements StructuredDocString { protected final String myDescription; protected final Map mySimpleTagValues = Maps.newHashMap(); @@ -38,26 +40,7 @@ public abstract class StructuredDocString { public static String KEYWORD = "keyword"; public static String VARIABLE = "variable"; - @Nullable - public static StructuredDocString parse(String text) { - if (text == null) { - return null; - } - if (isSphinxDocstring(text)) { - return new SphinxDocString(text); - } - return new EpydocString(text); - } - - public static boolean isSphinxDocstring(String text) { - return text.contains(":param ") || text.contains(":rtype") || text.contains(":type"); - } - - public static boolean isEpydocDocstring(String text) { - return text.contains("@param ") || text.contains("@rtype") || text.contains("@type"); - } - - protected StructuredDocString(@NotNull String docStringText, String tagPrefix) { + protected StructuredDocStringBase(@NotNull String docStringText, String tagPrefix) { final Substring docString = new Substring(docStringText); final List lines = docString.splitLines(); final int nlines = lines.size(); @@ -76,10 +59,12 @@ public abstract class StructuredDocString { myDescription = builder.toString(); } + @Override public String getDescription() { return myDescription; } + @Override public String getSummary() { final List strings = StringUtil.split(StringUtil.trimLeading(myDescription), "\n", true, false); if (strings.size() > 1) { @@ -166,6 +151,7 @@ public abstract class StructuredDocString { return result; } + @Override @Nullable public Substring getTagValue(String... tagNames) { for (String tagName : tagNames) { @@ -177,12 +163,14 @@ public abstract class StructuredDocString { return null; } + @Override @Nullable public Substring getTagValue(String tagName, @NotNull String argName) { final Map argValues = myArgTagValues.get(tagName); return argValues != null ? argValues.get(new Substring(argName)) : null; } + @Override @Nullable public Substring getTagValue(String[] tagNames, @NotNull String argName) { for (String tagName : tagNames) { @@ -194,6 +182,7 @@ public abstract class StructuredDocString { return null; } + @Override public List getTagArguments(String... tagNames) { for (String tagName : tagNames) { final Map map = myArgTagValues.get(tagName); @@ -204,6 +193,7 @@ public abstract class StructuredDocString { return Collections.emptyList(); } + @Override public List getParameterSubstrings() { final List results = new ArrayList(); results.addAll(getTagArguments(PARAM_TAGS)); @@ -211,6 +201,7 @@ public abstract class StructuredDocString { return results; } + @Override @Nullable public Substring getParamByNameAndKind(@NotNull String name, String kind) { for (Substring s: getTagArguments(kind)) { @@ -220,39 +211,4 @@ public abstract class StructuredDocString { } return null; } - - public abstract List getParameters(); - public abstract List getKeywordArguments(); - - @Nullable - public abstract String getReturnType(); - - @Nullable - public abstract String getReturnDescription(); - - @Nullable - public abstract String getParamType(@Nullable String paramName); - - @Nullable - public abstract String getParamDescription(@Nullable String paramName); - - @Nullable - public abstract String getKeywordArgumentDescription(@Nullable String paramName); - - public abstract List getRaisedExceptions(); - - @Nullable - public abstract String getRaisedExceptionDescription(@Nullable String exceptionName); - - @Nullable - public abstract String getAttributeDescription(); - public abstract List getAdditionalTags(); - - public abstract List getKeywordArgumentSubstrings(); - - @Nullable - public abstract Substring getReturnTypeSubstring(); - - @Nullable - public abstract Substring getParamTypeSubstring(@Nullable String paramName); } diff --git a/python/src/com/jetbrains/python/inspections/PyDocstringInspection.java b/python/src/com/jetbrains/python/inspections/PyDocstringInspection.java index 0914a4b0c2f4..6dc21025f546 100644 --- a/python/src/com/jetbrains/python/inspections/PyDocstringInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyDocstringInspection.java @@ -21,6 +21,7 @@ import com.jetbrains.python.documentation.*; import com.jetbrains.python.inspections.quickfix.DocstringQuickFix; import com.jetbrains.python.inspections.quickfix.PySuppressInspectionFix; import com.jetbrains.python.psi.*; +import com.jetbrains.python.toolbox.Substring; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -117,7 +118,7 @@ public class PyDocstringInspection extends PyInspection { return false; } - StructuredDocString docString = StructuredDocString.parse(text); + StructuredDocString docString = DocStringUtil.parse(text); if (docString == null) { return false; diff --git a/python/src/com/jetbrains/python/inspections/PyDocstringTypesInspection.java b/python/src/com/jetbrains/python/inspections/PyDocstringTypesInspection.java index 6116ad2f9e51..9f4c59fe12ae 100644 --- a/python/src/com/jetbrains/python/inspections/PyDocstringTypesInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyDocstringTypesInspection.java @@ -8,8 +8,9 @@ import com.jetbrains.python.PyBundle; import com.jetbrains.python.debugger.PySignature; import com.jetbrains.python.debugger.PySignatureCacheManager; import com.jetbrains.python.debugger.PySignatureUtil; -import com.jetbrains.python.documentation.StructuredDocString; -import com.jetbrains.python.documentation.Substring; +import com.jetbrains.python.documentation.DocStringUtil; +import com.jetbrains.python.psi.StructuredDocString; +import com.jetbrains.python.toolbox.Substring; import com.jetbrains.python.psi.PyElementGenerator; import com.jetbrains.python.psi.PyFunction; import com.jetbrains.python.psi.PyStringLiteralExpression; @@ -72,7 +73,7 @@ public class PyDocstringTypesInspection extends PyInspection { return; } - StructuredDocString docString = StructuredDocString.parse(text); + StructuredDocString docString = DocStringUtil.parse(text); if (docString == null) { return; } diff --git a/python/src/com/jetbrains/python/inspections/PyStatementEffectInspection.java b/python/src/com/jetbrains/python/inspections/PyStatementEffectInspection.java index 61a7663df3c3..618691b6b0a7 100644 --- a/python/src/com/jetbrains/python/inspections/PyStatementEffectInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyStatementEffectInspection.java @@ -8,6 +8,7 @@ import com.intellij.psi.PsiWhiteSpace; import com.intellij.psi.ResolveResult; import com.intellij.psi.util.PsiTreeUtil; import com.jetbrains.python.PyBundle; +import com.jetbrains.python.documentation.DocStringUtil; import com.jetbrains.python.inspections.quickfix.StatementEffectDocstringQuickFix; import com.jetbrains.python.inspections.quickfix.StatementEffectFunctionCallQuickFix; import com.jetbrains.python.inspections.quickfix.StatementEffectIntroduceVariableQuickFix; @@ -81,7 +82,7 @@ public class PyStatementEffectInspection extends PyInspection { prevSibling = prevSibling.getPrevSibling(); if (prevSibling instanceof PyAssignmentStatement) { for (PyExpression target : ((PyAssignmentStatement)prevSibling).getTargets()) { - if (PyUtil.getAttributeDocString((PyTargetExpression)target) == expression) { + if (DocStringUtil.getAttributeDocString((PyTargetExpression)target) == expression) { return true; } } @@ -107,7 +108,7 @@ public class PyStatementEffectInspection extends PyInspection { } if (expression instanceof PyStringLiteralExpression) { - if (PyUtil.isDocString(expression)) return true; + if (DocStringUtil.isDocStringExpression(expression)) return true; } else if (expression instanceof PyListCompExpression) { if (hasEffect(((PyListCompExpression)expression).getResultExpression())) { diff --git a/python/src/com/jetbrains/python/psi/PyUtil.java b/python/src/com/jetbrains/python/psi/PyUtil.java index 27c34b283e9b..5ade1e62cdca 100644 --- a/python/src/com/jetbrains/python/psi/PyUtil.java +++ b/python/src/com/jetbrains/python/psi/PyUtil.java @@ -42,7 +42,6 @@ import com.jetbrains.python.PyTokenTypes; import com.jetbrains.python.codeInsight.controlflow.ScopeOwner; import com.jetbrains.python.codeInsight.dataflow.scope.ScopeUtil; import com.jetbrains.python.codeInsight.stdlib.PyNamedTupleType; -import com.jetbrains.python.documentation.EpydocUtil; import com.jetbrains.python.psi.impl.PyBuiltinCache; import com.jetbrains.python.psi.impl.PyPsiUtils; import com.jetbrains.python.psi.resolve.PyResolveContext; @@ -459,50 +458,6 @@ public class PyUtil { return element instanceof PyTargetExpression && ScopeUtil.getScopeOwner(element) instanceof PyClass; } - public static boolean isDocString(PyExpression expression) { - final PyDocStringOwner docStringOwner = PsiTreeUtil.getParentOfType(expression, PyDocStringOwner.class); - if (docStringOwner != null) { - if (docStringOwner.getDocStringExpression() == expression) { - return true; - } - } - if (EpydocUtil.isVariableDocString((PyStringLiteralExpression)expression)) return true; - return false; - } - - @Nullable - public static PyStringLiteralExpression getAttributeDocString(PyTargetExpression attr) { - if (attr.getParent() instanceof PyAssignmentStatement) { - final PyAssignmentStatement assignment = (PyAssignmentStatement)attr.getParent(); - PsiElement nextSibling = assignment.getNextSibling(); - while (nextSibling != null && (nextSibling instanceof PsiWhiteSpace || nextSibling instanceof PsiComment)) { - nextSibling = nextSibling.getNextSibling(); - } - if (nextSibling instanceof PyExpressionStatement) { - final PyExpression expression = ((PyExpressionStatement)nextSibling).getExpression(); - if (expression instanceof PyStringLiteralExpression) { - return (PyStringLiteralExpression)expression; - } - } - } - return null; - } - - @Nullable - public static String getAttributeDocComment(PyTargetExpression attr) { - if (attr.getParent() instanceof PyAssignmentStatement) { - final PyAssignmentStatement assignment = (PyAssignmentStatement)attr.getParent(); - PsiElement prevSibling = assignment.getPrevSibling(); - while (prevSibling != null && (prevSibling instanceof PsiWhiteSpace)) { - prevSibling = prevSibling.getPrevSibling(); - } - if (prevSibling instanceof PsiComment && prevSibling.getText().startsWith("#:")) { - return prevSibling.getText().substring(2); - } - } - return null; - } - public static boolean isIfNameEqualsMain(PyIfStatement ifStatement) { final PyExpression condition = ifStatement.getIfPart().getCondition(); return isNameEqualsMain(condition); diff --git a/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java b/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java index 0faad3f49cbc..b9fa2e3be6c1 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java @@ -19,6 +19,7 @@ import com.jetbrains.python.*; import com.jetbrains.python.codeInsight.controlflow.ControlFlowCache; import com.jetbrains.python.codeInsight.controlflow.ScopeOwner; import com.jetbrains.python.codeInsight.dataflow.scope.ScopeUtil; +import com.jetbrains.python.documentation.DocStringUtil; import com.jetbrains.python.psi.*; import com.jetbrains.python.psi.resolve.PyResolveContext; import com.jetbrains.python.psi.resolve.PyResolveUtil; @@ -1003,7 +1004,7 @@ public class PyClassImpl extends PyPresentableElementImpl implement } public PyStringLiteralExpression getDocStringExpression() { - return PythonDocStringFinder.find(getStatementList()); + return DocStringUtil.findDocStringExpression(getStatementList()); } @Override @@ -1012,7 +1013,13 @@ public class PyClassImpl extends PyPresentableElementImpl implement if (stub != null) { return stub.getDocString(); } - return PyPsiUtils.strValue(getDocStringExpression()); + return DocStringUtil.getDocStringValue(this); + } + + @Nullable + @Override + public StructuredDocString getStructuredDocString() { + return DocStringUtil.getStructuredDocString(this); } public String toString() { diff --git a/python/src/com/jetbrains/python/psi/impl/PyFileImpl.java b/python/src/com/jetbrains/python/psi/impl/PyFileImpl.java index 135000abe605..05b65330fcb8 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyFileImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyFileImpl.java @@ -19,6 +19,7 @@ import com.intellij.util.containers.MultiMap; import com.intellij.util.indexing.IndexingDataKeys; import com.jetbrains.python.*; import com.jetbrains.python.codeInsight.controlflow.ControlFlowCache; +import com.jetbrains.python.documentation.DocStringUtil; import com.jetbrains.python.inspections.PythonVisitorFilter; import com.jetbrains.python.psi.*; import com.jetbrains.python.psi.resolve.RatedResolveResult; @@ -719,8 +720,22 @@ public class PyFileImpl extends PsiFileBase implements PyFile, PyExpression { return myType; } + @Nullable + @Override + public String getDocStringValue() { + return DocStringUtil.getDocStringValue(this); + } + + @Nullable + @Override + public StructuredDocString getStructuredDocString() { + return DocStringUtil.getStructuredDocString(this); + } + + @Nullable + @Override public PyStringLiteralExpression getDocStringExpression() { - return PythonDocStringFinder.find(this); + return DocStringUtil.findDocStringExpression(this); } public void subtreeChanged() { diff --git a/python/src/com/jetbrains/python/psi/impl/PyFunctionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyFunctionImpl.java index 7edaf41d16da..378ab8a676cc 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyFunctionImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyFunctionImpl.java @@ -12,17 +12,18 @@ import com.intellij.psi.search.LocalSearchScope; import com.intellij.psi.search.SearchScope; import com.intellij.psi.stubs.IStubElementType; import com.intellij.psi.stubs.StubElement; +import com.intellij.psi.util.CachedValueProvider; +import com.intellij.psi.util.CachedValuesManager; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.IncorrectOperationException; import com.intellij.util.PlatformIcons; import com.jetbrains.python.PyElementTypes; import com.jetbrains.python.PyNames; import com.jetbrains.python.PyTokenTypes; -import com.jetbrains.python.PythonDocStringFinder; import com.jetbrains.python.codeInsight.controlflow.ControlFlowCache; import com.jetbrains.python.codeInsight.controlflow.ScopeOwner; import com.jetbrains.python.codeInsight.dataflow.scope.ScopeUtil; -import com.jetbrains.python.documentation.StructuredDocString; +import com.jetbrains.python.documentation.DocStringUtil; import com.jetbrains.python.psi.*; import com.jetbrains.python.psi.resolve.QualifiedNameFinder; import com.jetbrains.python.psi.stubs.PyClassStub; @@ -58,6 +59,17 @@ public class PyFunctionImpl extends PyPresentableElementImpl imp super(stub, nodeType); } + private class CachedStructuredDocStringProvider implements CachedValueProvider { + @Nullable + @Override + public Result compute() { + final PyFunctionImpl f = PyFunctionImpl.this; + return Result.create(DocStringUtil.getStructuredDocString(f), f); + } + } + + private CachedStructuredDocStringProvider myCachedStructuredDocStringProvider = new CachedStructuredDocStringProvider(); + @Nullable @Override public String getName() { @@ -305,8 +317,7 @@ public class PyFunctionImpl extends PyPresentableElementImpl imp @Nullable @Override public PyType getReturnTypeFromDocString() { - final String value = getDocStringValue(); - final String typeName = value != null ? extractReturnType(value) : null; + final String typeName = extractReturnType(); return typeName != null ? PyTypeParser.getTypeByName(this, typeName) : null; } @@ -364,8 +375,13 @@ public class PyFunctionImpl extends PyPresentableElementImpl imp if (stub != null) { return stub.getDocString(); } - final PyStringLiteralExpression docStringExpression = getDocStringExpression(); - return PyPsiUtils.strValue(docStringExpression); + return DocStringUtil.getDocStringValue(this); + } + + @Nullable + @Override + public StructuredDocString getStructuredDocString() { + return CachedValuesManager.getManager(getProject()).getCachedValue(this, myCachedStructuredDocStringProvider); } private boolean isGeneratedStub() { @@ -383,7 +399,11 @@ public class PyFunctionImpl extends PyPresentableElementImpl imp } @Nullable - private static String extractReturnType(String docString) { + private String extractReturnType() { + final String docString = getDocStringValue(); + if (docString == null) { + return null; + } final List lines = StringUtil.split(docString, "\n"); while (lines.size() > 0 && lines.get(0).trim().length() == 0) { lines.remove(0); @@ -395,9 +415,8 @@ public class PyFunctionImpl extends PyPresentableElementImpl imp return firstLine.substring(pos + 2).trim(); } } - - StructuredDocString epydocString = StructuredDocString.parse(docString); - return epydocString != null ? epydocString.getReturnType() : null; + final StructuredDocString structuredDocString = getStructuredDocString(); + return structuredDocString != null ? structuredDocString.getReturnType() : null; } private static class ReturnVisitor extends PyRecursiveElementVisitor { @@ -456,7 +475,7 @@ public class PyFunctionImpl extends PyPresentableElementImpl imp public PyStringLiteralExpression getDocStringExpression() { final PyStatementList stmtList = getStatementList(); - return stmtList != null ? PythonDocStringFinder.find(stmtList) : null; + return stmtList != null ? DocStringUtil.findDocStringExpression(stmtList) : null; } protected String getElementLocation() { diff --git a/python/src/com/jetbrains/python/psi/impl/PyNamedParameterImpl.java b/python/src/com/jetbrains/python/psi/impl/PyNamedParameterImpl.java index d3284f7af980..eda919c69c18 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyNamedParameterImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyNamedParameterImpl.java @@ -17,7 +17,6 @@ import com.jetbrains.python.PyNames; import com.jetbrains.python.PyTokenTypes; import com.jetbrains.python.PythonDialectsTokenSetProvider; import com.jetbrains.python.codeInsight.stdlib.PyStdlibTypeProvider; -import com.jetbrains.python.documentation.StructuredDocString; import com.jetbrains.python.psi.*; import com.jetbrains.python.psi.resolve.PyResolveContext; import com.jetbrains.python.psi.stubs.PyNamedParameterStub; @@ -206,15 +205,15 @@ public class PyNamedParameterImpl extends PyPresentableElementImpl { +public class Pep8ExternalAnnotator extends ExternalAnnotator { private static final Logger LOG = Logger.getInstance(Pep8ExternalAnnotator.class); public static class Problem { @@ -76,7 +76,6 @@ public class Pep8ExternalAnnotator extends ExternalAnnotator ignoredErrors; private final int margin; - public final List problems = new ArrayList(); public State(String interpreterPath, String fileText, HighlightDisplayLevel level, List ignoredErrors, int margin) { @@ -88,6 +87,15 @@ public class Pep8ExternalAnnotator extends ExternalAnnotator problems = new ArrayList(); + private final HighlightDisplayLevel level; + + public Results(HighlightDisplayLevel level) { + this.level = level; + } + } + private boolean myReportedMissingInterpreter; @Nullable @@ -136,7 +144,7 @@ public class Pep8ExternalAnnotator extends ExternalAnnotator options = new ArrayList(); @@ -151,23 +159,29 @@ public class Pep8ExternalAnnotator extends ExternalAnnotator