Extracted StructuredDocString interface and moved to PSI API

This commit is contained in:
Andrey Vlasovskikh
2013-06-17 14:16:14 +04:00
parent 69911153e6
commit dc00f2d941
17 changed files with 130 additions and 75 deletions
@@ -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<Substring> getTagArguments(String... tagNames);
List<Substring> getParameterSubstrings();
@Nullable
Substring getParamByNameAndKind(@NotNull String name, String kind);
List<String> getParameters();
List<String> 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<String> getRaisedExceptions();
@Nullable
String getRaisedExceptionDescription(@Nullable String exceptionName);
@Nullable
String getAttributeDescription();
List<String> getAdditionalTags();
List<Substring> getKeywordArgumentSubstrings();
@Nullable
Substring getReturnTypeSubstring();
@Nullable
Substring getParamTypeSubstring(@Nullable String paramName);
}
@@ -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.
* <p>
* 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)");
@@ -12,7 +12,8 @@ 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.StructuredDocString;
import com.jetbrains.python.documentation.StructuredDocStringBase;
import com.jetbrains.python.psi.*;
import org.jetbrains.annotations.NotNull;
@@ -85,7 +86,7 @@ public class SpecifyTypeInDocstringIntention extends TypeIntention {
if (pyFunction != null && parameter != null) {
final String docstring = pyFunction.getDocStringValue();
if (docstring != null) {
StructuredDocString structuredDocString = StructuredDocString.parse(docstring);
StructuredDocString structuredDocString = StructuredDocStringBase.parse(docstring);
return structuredDocString != null && structuredDocString.getParamType(StringUtil.notNullize(parameter.getName())) != null;
}
return false;
@@ -97,7 +98,7 @@ public class SpecifyTypeInDocstringIntention extends TypeIntention {
protected boolean isReturnTypeDefined(@NotNull PyFunction function) {
final String docstring = function.getDocStringValue();
if (docstring != null) {
StructuredDocString structuredDocString = StructuredDocString.parse(docstring);
StructuredDocString structuredDocString = StructuredDocStringBase.parse(docstring);
return structuredDocString != null && structuredDocString.getReturnType( ) != null;
}
return false;
@@ -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.psi.StructuredDocString;
import com.jetbrains.python.documentation.StructuredDocStringBase;
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 StructuredDocStringBase.parse(docString);
}
@Nullable
@@ -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<PsiReference> result = new ArrayList<PsiReference>();
final int offset = ranges.get(0).getStartOffset();
// XXX: It does not work with multielement docstrings
StructuredDocString docString = StructuredDocString.parse(text);
StructuredDocString docString = StructuredDocStringBase.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));
@@ -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" };
@@ -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<String, Integer> addParamToDocstring() {
String text = getDocstringText();
StructuredDocString structuredDocString = StructuredDocString.parse(text);
StructuredDocString structuredDocString = StructuredDocStringBase.parse(text);
Collection<DocstringParam> paramsToAdd = getParamsToAdd(structuredDocString, myParams);
@@ -172,7 +173,7 @@ public class PyDocstringGenerator {
private Collection<DocstringParam> collectParametersToAdd() {
String text = getDocstringText();
StructuredDocString structuredDocString = StructuredDocString.parse(text); //TODO: do we need to cache it?
StructuredDocString structuredDocString = StructuredDocStringBase.parse(text); //TODO: do we need to cache it?
return getParamsToAdd(structuredDocString, myParams);
}
@@ -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)) {
StructuredDocStringBase.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)) {
StructuredDocStringBase.isSphinxDocstring(preparedDocstring)) {
String formatted = null;
Sdk pythonSdk = PythonSdkType.findPython2Sdk(module);
if (pythonSdk != null) {
@@ -451,7 +452,7 @@ class PyDocumentationBuilder {
}
private static Pair<String, String> getTypeAndDescr(String docString, @NotNull PyNamedParameter followed) {
StructuredDocString structuredDocString = StructuredDocString.parse(docString);
StructuredDocString structuredDocString = StructuredDocStringBase.parse(docString);
String type = null;
String desc = null;
if (structuredDocString != null) {
@@ -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 = StructuredDocStringBase.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 = StructuredDocStringBase.parse(docStringExpression.getStringValue());
if (docString != null) {
summary = docString.getSummary();
}
@@ -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",
@@ -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<String, Substring> mySimpleTagValues = Maps.newHashMap();
@@ -39,7 +41,7 @@ public abstract class StructuredDocString {
public static String VARIABLE = "variable";
@Nullable
public static StructuredDocString parse(String text) {
public static StructuredDocString parse(@Nullable String text) {
if (text == null) {
return null;
}
@@ -57,7 +59,7 @@ public abstract class StructuredDocString {
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<Substring> lines = docString.splitLines();
final int nlines = lines.size();
@@ -76,10 +78,12 @@ public abstract class StructuredDocString {
myDescription = builder.toString();
}
@Override
public String getDescription() {
return myDescription;
}
@Override
public String getSummary() {
final List<String> strings = StringUtil.split(StringUtil.trimLeading(myDescription), "\n", true, false);
if (strings.size() > 1) {
@@ -166,6 +170,7 @@ public abstract class StructuredDocString {
return result;
}
@Override
@Nullable
public Substring getTagValue(String... tagNames) {
for (String tagName : tagNames) {
@@ -177,12 +182,14 @@ public abstract class StructuredDocString {
return null;
}
@Override
@Nullable
public Substring getTagValue(String tagName, @NotNull String argName) {
final Map<Substring, Substring> 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 +201,7 @@ public abstract class StructuredDocString {
return null;
}
@Override
public List<Substring> getTagArguments(String... tagNames) {
for (String tagName : tagNames) {
final Map<Substring, Substring> map = myArgTagValues.get(tagName);
@@ -204,6 +212,7 @@ public abstract class StructuredDocString {
return Collections.emptyList();
}
@Override
public List<Substring> getParameterSubstrings() {
final List<Substring> results = new ArrayList<Substring>();
results.addAll(getTagArguments(PARAM_TAGS));
@@ -211,6 +220,7 @@ public abstract class StructuredDocString {
return results;
}
@Override
@Nullable
public Substring getParamByNameAndKind(@NotNull String name, String kind) {
for (Substring s: getTagArguments(kind)) {
@@ -220,39 +230,4 @@ public abstract class StructuredDocString {
}
return null;
}
public abstract List<String> getParameters();
public abstract List<String> 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<String> getRaisedExceptions();
@Nullable
public abstract String getRaisedExceptionDescription(@Nullable String exceptionName);
@Nullable
public abstract String getAttributeDescription();
public abstract List<String> getAdditionalTags();
public abstract List<Substring> getKeywordArgumentSubstrings();
@Nullable
public abstract Substring getReturnTypeSubstring();
@Nullable
public abstract Substring getParamTypeSubstring(@Nullable String paramName);
}
@@ -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 = StructuredDocStringBase.parse(text);
if (docString == null) {
return false;
@@ -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.psi.StructuredDocString;
import com.jetbrains.python.documentation.StructuredDocStringBase;
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 = StructuredDocStringBase.parse(text);
if (docString == null) {
return;
}
@@ -22,7 +22,8 @@ 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.psi.StructuredDocString;
import com.jetbrains.python.documentation.StructuredDocStringBase;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.resolve.QualifiedNameFinder;
import com.jetbrains.python.psi.stubs.PyClassStub;
@@ -396,7 +397,7 @@ public class PyFunctionImpl extends PyPresentableElementImpl<PyFunctionStub> imp
}
}
StructuredDocString epydocString = StructuredDocString.parse(docString);
StructuredDocString epydocString = StructuredDocStringBase.parse(docString);
return epydocString != null ? epydocString.getReturnType() : null;
}
@@ -17,7 +17,8 @@ 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.StructuredDocString;
import com.jetbrains.python.documentation.StructuredDocStringBase;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.resolve.PyResolveContext;
import com.jetbrains.python.psi.stubs.PyNamedParameterStub;
@@ -212,7 +213,7 @@ public class PyNamedParameterImpl extends PyPresentableElementImpl<PyNamedParame
if (pyClass != null)
docString = pyClass.getDocStringValue();
}
StructuredDocString epydocString = StructuredDocString.parse(docString);
StructuredDocString epydocString = StructuredDocStringBase.parse(docString);
if (epydocString != null) {
String typeName = epydocString.getParamType(getName());
if (typeName != null) {
@@ -24,7 +24,8 @@ import com.jetbrains.python.codeInsight.controlflow.ControlFlowCache;
import com.jetbrains.python.codeInsight.controlflow.ScopeOwner;
import com.jetbrains.python.codeInsight.dataflow.scope.Scope;
import com.jetbrains.python.codeInsight.dataflow.scope.ScopeUtil;
import com.jetbrains.python.documentation.StructuredDocString;
import com.jetbrains.python.psi.StructuredDocString;
import com.jetbrains.python.documentation.StructuredDocStringBase;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.impl.references.PyQualifiedReference;
import com.jetbrains.python.psi.impl.references.PyTargetReference;
@@ -249,7 +250,7 @@ public class PyTargetExpressionImpl extends PyPresentableElementImpl<PyTargetExp
public static PyType getTypeFromDocString(PyTargetExpressionImpl targetExpression) {
final String docString = PyPsiUtils.strValue(PyUtil.getAttributeDocString(targetExpression));
if (docString != null) {
StructuredDocString structuredDocString = StructuredDocString.parse(docString);
StructuredDocString structuredDocString = StructuredDocStringBase.parse(docString);
if (structuredDocString != null) {
String typeName = structuredDocString.getParamType(null);
if (typeName == null) {
@@ -267,7 +268,7 @@ public class PyTargetExpressionImpl extends PyPresentableElementImpl<PyTargetExp
public static PyType getTypeFromComment(PyTargetExpressionImpl targetExpression) {
String docComment = PyUtil.getAttributeDocComment(targetExpression);
if (docComment != null) {
StructuredDocString structuredDocString = StructuredDocString.parse(docComment);
StructuredDocString structuredDocString = StructuredDocStringBase.parse(docComment);
if (structuredDocString != null) {
String typeName = structuredDocString.getParamType(null);
if (typeName == null) {
@@ -2,7 +2,7 @@ package com.jetbrains.python;
import com.intellij.testFramework.UsefulTestCase;
import com.jetbrains.python.documentation.EpydocString;
import com.jetbrains.python.documentation.Substring;
import com.jetbrains.python.toolbox.Substring;
import java.util.List;