package org.jetbrains.plugins.ipnb;
import com.intellij.psi.PsiFile;
-import com.jetbrains.python.inspections.PyDocstringInspection;
+import com.jetbrains.python.inspections.PyIncorrectDocstringInspection;
+import com.jetbrains.python.inspections.PyMissingOrEmptyDocstringInspection;
import com.jetbrains.python.inspections.PyStatementEffectInspection;
import com.jetbrains.python.inspections.PythonVisitorFilter;
import org.jetbrains.annotations.NotNull;
public class IpnbVisitorFilter implements PythonVisitorFilter {
@Override
public boolean isSupported(@NotNull final Class visitorClass, @NotNull final PsiFile file) {
- if (visitorClass == PyDocstringInspection.class || visitorClass == PyStatementEffectInspection.class) {
+ if (visitorClass == PyIncorrectDocstringInspection.class ||
+ visitorClass == PyMissingOrEmptyDocstringInspection.class ||
+ visitorClass == PyStatementEffectInspection.class) {
return false;
}
return true;
+++ /dev/null
-<html>
-<body>
-<span style="font-family: verdana,serif;">
- This inspection detects mismatched parameters in docstring, lack of docstring and an empty docstring.
-</span>
-</body>
-</html>
\ No newline at end of file
--- /dev/null
+<html>
+<body>
+<span style="font-family: verdana,serif;">
+ This inspection detects mismatched parameters in docstring.
+</span>
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+<html>
+<body>
+<span style="font-family: verdana,serif;">
+This inspection detects lack of docstring and an empty docstring.
+</span>
+</body>
+</html>
\ No newline at end of file
<localInspection language="Python" shortName="PyExceptionInheritInspection" suppressId="PyExceptionInherit" bundle="com.jetbrains.python.PyBundle" key="INSP.NAME.exception.not.inherit" groupKey="INSP.GROUP.python" enabledByDefault="true" level="WARNING" implementationClass="com.jetbrains.python.inspections.PyExceptionInheritInspection"/>
<localInspection language="Python" shortName="PyDefaultArgumentInspection" suppressId="PyDefaultArgument" bundle="com.jetbrains.python.PyBundle" key="INSP.NAME.default.argument" groupKey="INSP.GROUP.python" enabledByDefault="true" level="WARNING" implementationClass="com.jetbrains.python.inspections.PyDefaultArgumentInspection"/>
<localInspection language="Python" shortName="PyRaisingNewStyleClassInspection" suppressId="PyRaisingNewStyleClass" bundle="com.jetbrains.python.PyBundle" key="INSP.NAME.raising.new.style.class" groupKey="INSP.GROUP.python" enabledByDefault="true" level="WARNING" implementationClass="com.jetbrains.python.inspections.PyRaisingNewStyleClassInspection"/>
- <localInspection language="Python" shortName="PyDocstringInspection" suppressId="PyDocstring" bundle="com.jetbrains.python.PyBundle" key="INSP.NAME.docstring" groupKey="INSP.GROUP.python" enabledByDefault="false" level="WEAK WARNING" implementationClass="com.jetbrains.python.inspections.PyDocstringInspection"/>
+ <localInspection language="Python" shortName="PyIncorrectDocstringInspection" suppressId="PyIncorrectDocstring" bundle="com.jetbrains.python.PyBundle" key="INSP.NAME.incorrect.docstring" groupKey="INSP.GROUP.python" enabledByDefault="true" level="WEAK WARNING" implementationClass="com.jetbrains.python.inspections.PyIncorrectDocstringInspection"/>
+ <localInspection language="Python" shortName="PyMissingOrEmptyDocstringInspection" suppressId="PyMissingOrEmptyDocstring" bundle="com.jetbrains.python.PyBundle" key="INSP.NAME.missing.or.empty.docstring" groupKey="INSP.GROUP.python" enabledByDefault="false" level="WEAK WARNING" implementationClass="com.jetbrains.python.inspections.PyMissingOrEmptyDocstringInspection"/>
<localInspection language="Python" shortName="PyUnboundLocalVariableInspection" suppressId="PyUnboundLocalVariable" bundle="com.jetbrains.python.PyBundle" key="INSP.NAME.unbound" groupKey="INSP.GROUP.python" enabledByDefault="true" level="WARNING" implementationClass="com.jetbrains.python.inspections.PyUnboundLocalVariableInspection"/>
<localInspection language="Python" shortName="PyStatementEffectInspection" suppressId="PyStatementEffect" bundle="com.jetbrains.python.PyBundle" key="INSP.NAME.statement.effect" groupKey="INSP.GROUP.python" enabledByDefault="true" level="WARNING" implementationClass="com.jetbrains.python.inspections.PyStatementEffectInspection"/>
<localInspection language="Python" shortName="PySimplifyBooleanCheckInspection" suppressId="PySimplifyBooleanCheck" bundle="com.jetbrains.python.PyBundle" key="INSP.NAME.check.can.be.simplified" groupKey="INSP.GROUP.python" enabledByDefault="true" level="WEAK WARNING" implementationClass="com.jetbrains.python.inspections.PySimplifyBooleanCheckInspection"/>
# PyRaisingNewStyleClassInspection
INSP.NAME.raising.new.style.class=Raising a new style class
-# PyDocstringInspection
-INSP.NAME.docstring=Missing, empty or incorrect docstring
+# PyIncorrectDocstringInspection
+INSP.NAME.incorrect.docstring=Incorrect docstring
+INSP.missing.parameter.in.docstring=Missing parameter {0} in docstring
+INSP.unexpected.parameter.in.docstring=Unexpected parameter {0} in docstring
+
+# PyMissingOrEmptyDocstringInspection
+INSP.NAME.missing.or.empty.docstring=Missing or empty docstring
INSP.no.docstring=Missing docstring
INSP.empty.docstring=Empty docstring
//inspections
if (visitorClass == PyUnusedLocalInspection.class || visitorClass == PyUnboundLocalVariableInspection.class ||
visitorClass == PyStatementEffectInspection.class || visitorClass == PySingleQuotedDocstringInspection.class ||
- visitorClass == PyDocstringInspection.class || visitorClass == PyMandatoryEncodingInspection.class) {
+ visitorClass == PyIncorrectDocstringInspection.class || visitorClass == PyMissingOrEmptyDocstringInspection.class ||
+ visitorClass == PyMandatoryEncodingInspection.class) {
return false;
}
if (visitorClass == PyArgumentListInspection.class) {
return false;
}
- if (visitorClass == PyDocstringInspection.class || visitorClass == PyStatementEffectInspection.class ||
+ if (visitorClass == PyIncorrectDocstringInspection.class || visitorClass == PyMissingOrEmptyDocstringInspection.class ||
visitorClass == PyUnboundLocalVariableInspection.class || visitorClass == PyUnnecessaryBackslashInspection.class ||
visitorClass == PyByteLiteralInspection.class || visitorClass == PyNonAsciiCharInspection.class ||
visitorClass == PyPackageRequirementsInspection.class || visitorClass == PyMandatoryEncodingInspection.class ||
visitorClass == PyInterpreterInspection.class || visitorClass == PyDocstringTypesInspection.class ||
- visitorClass == PySingleQuotedDocstringInspection.class || visitorClass == PyClassHasNoInitInspection.class) {
+ visitorClass == PySingleQuotedDocstringInspection.class || visitorClass == PyClassHasNoInitInspection.class ||
+ visitorClass == PyStatementEffectInspection.class) {
return false;
}
//annotators
--- /dev/null
+/*
+ * Copyright 2000-2015 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.jetbrains.python.inspections;
+
+import com.intellij.codeInspection.LocalInspectionToolSession;
+import com.intellij.codeInspection.ProblemsHolder;
+import com.intellij.openapi.extensions.Extensions;
+import com.jetbrains.python.psi.*;
+import com.jetbrains.python.testing.PythonUnitTestUtil;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * @author Mikhail Golubev
+ */
+public abstract class PyBaseDocstringInspection extends PyInspection {
+ @NotNull
+ @Override
+ public abstract Visitor buildVisitor(@NotNull ProblemsHolder holder,
+ boolean isOnTheFly,
+ @NotNull LocalInspectionToolSession session);
+
+ protected static abstract class Visitor extends PyInspectionVisitor {
+ public Visitor(@Nullable ProblemsHolder holder, @NotNull LocalInspectionToolSession session) {
+ super(holder, session);
+ }
+
+ @Override
+ public void visitPyFile(@NotNull PyFile node) {
+ checkDocString(node);
+ }
+
+ @Override
+ public void visitPyFunction(@NotNull PyFunction node) {
+ if (PythonUnitTestUtil.isUnitTestCaseFunction(node)) return;
+ final PyClass containingClass = node.getContainingClass();
+ if (containingClass != null && PythonUnitTestUtil.isUnitTestCaseClass(containingClass)) return;
+ final Property property = node.getProperty();
+ if (property != null && (node == property.getSetter().valueOrNull() || node == property.getDeleter().valueOrNull())) {
+ return;
+ }
+ final String name = node.getName();
+ if (name != null && !name.startsWith("_")) checkDocString(node);
+ }
+
+ @Override
+ public void visitPyClass(@NotNull PyClass node) {
+ if (PythonUnitTestUtil.isUnitTestCaseClass(node)) return;
+ final String name = node.getName();
+ if (name == null || name.startsWith("_")) {
+ return;
+ }
+ checkDocString(node);
+ }
+
+ protected void checkDocString(@NotNull PyDocStringOwner node) {
+ for (PyInspectionExtension extension : Extensions.getExtensions(PyInspectionExtension.EP_NAME)) {
+ if (extension.ignoreMissingDocstring(node)) {
+ return;
+ }
+ }
+ }
+ }
+}
+++ /dev/null
-/*
- * Copyright 2000-2014 JetBrains s.r.o.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.jetbrains.python.inspections;
-
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import com.intellij.codeInspection.LocalInspectionToolSession;
-import com.intellij.codeInspection.ProblemsHolder;
-import com.intellij.lang.ASTNode;
-import com.intellij.openapi.extensions.Extensions;
-import com.intellij.openapi.util.TextRange;
-import com.intellij.openapi.util.text.StringUtil;
-import com.intellij.psi.PsiElement;
-import com.intellij.psi.PsiElementVisitor;
-import com.jetbrains.python.PyBundle;
-import com.jetbrains.python.documentation.docstrings.DocStringUtil;
-import com.jetbrains.python.documentation.docstrings.PlainDocString;
-import com.jetbrains.python.inspections.quickfix.DocstringQuickFix;
-import com.jetbrains.python.psi.*;
-import com.jetbrains.python.testing.PythonUnitTestUtil;
-import com.jetbrains.python.toolbox.Substring;
-import org.jetbrains.annotations.Nls;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-
-/**
- * @author Alexey.Ivanov
- */
-public class PyDocstringInspection extends PyInspection {
- @Nls
- @NotNull
- @Override
- public String getDisplayName() {
- return PyBundle.message("INSP.NAME.docstring");
- }
-
- @Override
- public boolean isEnabledByDefault() {
- return false;
- }
-
- @NotNull
- @Override
- public PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder,
- boolean isOnTheFly,
- @NotNull LocalInspectionToolSession session) {
- return new Visitor(holder, session);
- }
-
- public static class Visitor extends PyInspectionVisitor {
- public Visitor(@Nullable ProblemsHolder holder, @NotNull LocalInspectionToolSession session) {
- super(holder, session);
- }
-
- @Override
- public void visitPyFile(@NotNull PyFile node) {
- checkDocString(node);
- }
-
- @Override
- public void visitPyFunction(@NotNull PyFunction node) {
- if (PythonUnitTestUtil.isUnitTestCaseFunction(node)) return;
- final PyClass containingClass = node.getContainingClass();
- if (containingClass != null && PythonUnitTestUtil.isUnitTestCaseClass(containingClass)) return;
- final Property property = node.getProperty();
- if (property != null && (node == property.getSetter().valueOrNull() || node == property.getDeleter().valueOrNull())) {
- return;
- }
- final String name = node.getName();
- if (name != null && !name.startsWith("_")) checkDocString(node);
- }
-
- @Override
- public void visitPyClass(@NotNull PyClass node) {
- if (PythonUnitTestUtil.isUnitTestCaseClass(node)) return;
- final String name = node.getName();
- if (name == null || name.startsWith("_")) {
- return;
- }
- for (PyInspectionExtension extension : Extensions.getExtensions(PyInspectionExtension.EP_NAME)) {
- if (extension.ignoreMissingDocstring(node)) {
- return;
- }
- }
- checkDocString(node);
- }
-
- private void checkDocString(@NotNull PyDocStringOwner node) {
- final PyStringLiteralExpression docStringExpression = node.getDocStringExpression();
- if (docStringExpression == null) {
- PsiElement marker = null;
- if (node instanceof PyClass) {
- final ASTNode n = ((PyClass)node).getNameNode();
- if (n != null) marker = n.getPsi();
- }
- else if (node instanceof PyFunction) {
- final ASTNode n = ((PyFunction)node).getNameNode();
- if (n != null) marker = n.getPsi();
- }
- else if (node instanceof PyFile) {
- final TextRange tr = new TextRange(0, 0);
- final ProblemsHolder holder = getHolder();
- if (holder != null) {
- holder.registerProblem(node, tr, PyBundle.message("INSP.no.docstring"));
- }
- return;
- }
- if (marker == null) marker = node;
- if (node instanceof PyFunction || (node instanceof PyClass && ((PyClass)node).findInitOrNew(false, null) != null)) {
- registerProblem(marker, PyBundle.message("INSP.no.docstring"), new DocstringQuickFix(null, null));
- }
- else {
- registerProblem(marker, PyBundle.message("INSP.no.docstring"));
- }
- }
- else {
- final boolean registered = checkParameters(node, docStringExpression);
- if (!registered && StringUtil.isEmptyOrSpaces(docStringExpression.getStringValue())) {
- registerProblem(docStringExpression, PyBundle.message("INSP.empty.docstring"));
- }
- }
- }
-
- private boolean checkParameters(@NotNull PyDocStringOwner pyDocStringOwner, @NotNull PyStringLiteralExpression node) {
- final String text = node.getText();
- if (text == null) {
- return false;
- }
-
- final StructuredDocString docString = DocStringUtil.parse(text, node);
-
- if (docString instanceof PlainDocString) {
- return false;
- }
-
- if (pyDocStringOwner instanceof PyFunction) {
- final PyParameter[] realParams = ((PyFunction)pyDocStringOwner).getParameterList().getParameters();
-
- final List<PyNamedParameter> missingParams = getMissingParams(docString, realParams);
- boolean registered = false;
- if (!missingParams.isEmpty()) {
- for (PyNamedParameter param : missingParams) {
- registerProblem(param, "Missing parameter " + param.getName() + " in docstring", new DocstringQuickFix(param, null));
- }
- registered = true;
- }
- final List<Substring> unexpectedParams = getUnexpectedParams(docString, realParams);
- if (!unexpectedParams.isEmpty()) {
- for (Substring param : unexpectedParams) {
- final ProblemsHolder holder = getHolder();
-
- if (holder != null) {
- holder.registerProblem(node, param.getTextRange(),
- "Unexpected parameter " + param + " in docstring",
- new DocstringQuickFix(null, param.getValue()));
- }
- }
- registered = true;
- }
- return registered;
- }
- return false;
- }
-
- @NotNull
- private static List<Substring> getUnexpectedParams(@NotNull StructuredDocString docString, @NotNull PyParameter[] realParams) {
- final Map<String, Substring> unexpected = Maps.newHashMap();
-
- for (Substring s : docString.getParameterSubstrings()) {
- unexpected.put(s.toString(), s);
- }
-
- for (PyParameter p : realParams) {
- if (unexpected.containsKey(p.getName())) {
- unexpected.remove(p.getName());
- }
- }
- return Lists.newArrayList(unexpected.values());
- }
-
- @NotNull
- private static List<PyNamedParameter> getMissingParams(@NotNull StructuredDocString docString, @NotNull PyParameter[] realParams) {
- final List<PyNamedParameter> missing = new ArrayList<PyNamedParameter>();
- final List<String> docStringParameters = docString.getParameters();
- for (PyParameter p : realParams) {
- if (p.isSelf() || !(p instanceof PyNamedParameter)) {
- continue;
- }
- if (!docStringParameters.contains(p.getName())) {
- missing.add((PyNamedParameter)p);
- }
- }
- return missing;
- }
- }
-}
--- /dev/null
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.jetbrains.python.inspections;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.intellij.codeInspection.LocalInspectionToolSession;
+import com.intellij.codeInspection.ProblemsHolder;
+import com.jetbrains.python.PyBundle;
+import com.jetbrains.python.documentation.docstrings.DocStringUtil;
+import com.jetbrains.python.documentation.docstrings.PlainDocString;
+import com.jetbrains.python.inspections.quickfix.DocstringQuickFix;
+import com.jetbrains.python.psi.*;
+import com.jetbrains.python.toolbox.Substring;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author Mikhail Golubev
+ * @author Alexey.Ivanov
+ */
+public class PyIncorrectDocstringInspection extends PyBaseDocstringInspection {
+ @NotNull
+ @Override
+ public Visitor buildVisitor(@NotNull ProblemsHolder holder,
+ boolean isOnTheFly,
+ @NotNull LocalInspectionToolSession session) {
+ return new Visitor(holder, session) {
+
+ @Override
+ protected void checkDocString(@NotNull PyDocStringOwner node) {
+ super.checkDocString(node);
+ final PyStringLiteralExpression docStringExpression1 = node.getDocStringExpression();
+ if (docStringExpression1 != null) {
+ checkParameters(node, docStringExpression1);
+ }
+ }
+
+ private boolean checkParameters(@NotNull PyDocStringOwner pyDocStringOwner, @NotNull PyStringLiteralExpression node) {
+ final String text = node.getText();
+ if (text == null) {
+ return false;
+ }
+
+ final StructuredDocString docString = DocStringUtil.parse(text, node);
+
+ if (docString instanceof PlainDocString) {
+ return false;
+ }
+
+ if (pyDocStringOwner instanceof PyFunction) {
+ final PyParameter[] realParams = ((PyFunction)pyDocStringOwner).getParameterList().getParameters();
+
+ final List<PyNamedParameter> missingParams = getMissingParams(docString, realParams);
+ boolean registered = false;
+ if (!missingParams.isEmpty()) {
+ for (PyNamedParameter param : missingParams) {
+ registerProblem(param,
+ PyBundle.message("INSP.missing.parameter.in.docstring", param.getName()),
+ new DocstringQuickFix(param, null));
+ }
+ registered = true;
+ }
+ final List<Substring> unexpectedParams = getUnexpectedParams(docString, realParams);
+ if (!unexpectedParams.isEmpty()) {
+ for (Substring param : unexpectedParams) {
+ final ProblemsHolder holder = getHolder();
+
+ if (holder != null) {
+ holder.registerProblem(node, param.getTextRange(),
+ PyBundle.message("INSP.unexpected.parameter.in.docstring", param),
+ new DocstringQuickFix(null, param.getValue()));
+ }
+ }
+ registered = true;
+ }
+ return registered;
+ }
+ return false;
+ }
+ };
+ }
+
+ @NotNull
+ private static List<PyNamedParameter> getMissingParams(@NotNull StructuredDocString docString, @NotNull PyParameter[] realParams) {
+ final List<PyNamedParameter> missing = new ArrayList<PyNamedParameter>();
+ final List<String> docStringParameters = docString.getParameters();
+ for (PyParameter p : realParams) {
+ if (p.isSelf() || !(p instanceof PyNamedParameter)) {
+ continue;
+ }
+ if (!docStringParameters.contains(p.getName())) {
+ missing.add((PyNamedParameter)p);
+ }
+ }
+ return missing;
+ }
+
+ @NotNull
+ private static List<Substring> getUnexpectedParams(@NotNull StructuredDocString docString, @NotNull PyParameter[] realParams) {
+ final Map<String, Substring> unexpected = Maps.newHashMap();
+
+ for (Substring s : docString.getParameterSubstrings()) {
+ unexpected.put(s.toString(), s);
+ }
+
+ for (PyParameter p : realParams) {
+ if (unexpected.containsKey(p.getName())) {
+ unexpected.remove(p.getName());
+ }
+ }
+ return Lists.newArrayList(unexpected.values());
+ }
+}
public class PyInspectionsSuppressor implements InspectionSuppressor {
private static final Pattern SUPPRESS_PATTERN = Pattern.compile(SuppressionUtil.COMMON_SUPPRESS_REGEXP);
- private static final String PY_DOCSTRING_INSPECTION_ID = new PyDocstringInspection().getID();
+ private static final String PY_INCORRECT_DOCSTRING_INSPECTION_ID = new PyIncorrectDocstringInspection().getID();
+ private static final String PY_MISSING_OR_EMPTY_DOCSTRING_INSPECTION_ID = new PyMissingOrEmptyDocstringInspection().getID();
@NotNull
@Override
public SuppressQuickFix[] getSuppressActions(@Nullable PsiElement element, @NotNull String toolId) {
- if (PY_DOCSTRING_INSPECTION_ID.equals(toolId)) {
+ if (PY_INCORRECT_DOCSTRING_INSPECTION_ID.equals(toolId) || PY_MISSING_OR_EMPTY_DOCSTRING_INSPECTION_ID.equals(toolId)) {
return new SuppressQuickFix[]{
new PySuppressInspectionFix(toolId, "Suppress for function", PyFunction.class),
new PySuppressInspectionFix(toolId, "Suppress for class", PyClass.class)
--- /dev/null
+/*
+ * Copyright 2000-2015 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.jetbrains.python.inspections;
+
+import com.intellij.codeInspection.LocalInspectionToolSession;
+import com.intellij.codeInspection.ProblemsHolder;
+import com.intellij.lang.ASTNode;
+import com.intellij.openapi.util.TextRange;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.psi.PsiElement;
+import com.jetbrains.python.PyBundle;
+import com.jetbrains.python.inspections.quickfix.DocstringQuickFix;
+import com.jetbrains.python.psi.*;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author Mikhail Golubev
+ */
+public class PyMissingOrEmptyDocstringInspection extends PyBaseDocstringInspection {
+ @NotNull
+ @Override
+ public Visitor buildVisitor(@NotNull ProblemsHolder holder,
+ boolean isOnTheFly,
+ @NotNull LocalInspectionToolSession session) {
+ return new Visitor(holder, session) {
+ @Override
+ protected void checkDocString(@NotNull PyDocStringOwner node) {
+ super.checkDocString(node);
+ final PyStringLiteralExpression docStringExpression = node.getDocStringExpression();
+ if (docStringExpression == null) {
+ PsiElement marker = null;
+ if (node instanceof PyClass) {
+ final ASTNode n = ((PyClass)node).getNameNode();
+ if (n != null) marker = n.getPsi();
+ }
+ else if (node instanceof PyFunction) {
+ final ASTNode n = ((PyFunction)node).getNameNode();
+ if (n != null) marker = n.getPsi();
+ }
+ else if (node instanceof PyFile) {
+ final TextRange tr = new TextRange(0, 0);
+ final ProblemsHolder holder = getHolder();
+ if (holder != null) {
+ holder.registerProblem(node, tr, PyBundle.message("INSP.no.docstring"));
+ }
+ return;
+ }
+ if (marker == null) marker = node;
+ if (node instanceof PyFunction || (node instanceof PyClass && ((PyClass)node).findInitOrNew(false, null) != null)) {
+ registerProblem(marker, PyBundle.message("INSP.no.docstring"), new DocstringQuickFix(null, null));
+ }
+ else {
+ registerProblem(marker, PyBundle.message("INSP.no.docstring"));
+ }
+ }
+ else if (StringUtil.isEmptyOrSpaces(docStringExpression.getStringValue())) {
+ registerProblem(docStringExpression, PyBundle.message("INSP.empty.docstring"));
+ }
+ }
+ };
+ }
+}
<line>13</line>
<description>Empty docstring</description>
</problem>
+ <problem>
+ <file>test.py</file>
+ <line>17</line>
+ <description>Missing docstring</description>
+ </problem>
+ <problem>
+ <file>test.py</file>
+ <line>19</line>
+ <description>Missing docstring</description>
+ </problem>
</problems>
\ No newline at end of file
def bar():
""""""
- pass
\ No newline at end of file
+ pass
+
+
+class C:
+ @property
+ def x(self):
+ return 42
+
+ @x.setter
+ def x(self, value):
+ pass
+
+ @x.deleter
+ def x(self):
+ pass
\ No newline at end of file
@return:
"""
pass
-
-class <weak_warning descr="Missing docstring">C</weak_warning>:
- @property
- def <weak_warning descr="Missing docstring">x</weak_warning>(self):
- return 42
-
- @x.setter
- def x(self, value):
- pass
-
- @x.deleter
- def x(self):
- pass
\ No newline at end of file
getIndentOptions().INDENT_SIZE = 2;
runWithDocStringFormat(DocStringFormat.EPYTEXT, new Runnable() {
public void run() {
- doInspectionTest(PyDocstringInspection.class, PyBundle.message("QFIX.docstring.add.$0", "b"), true, true);
+ doInspectionTest(PyIncorrectDocstringInspection.class, PyBundle.message("QFIX.docstring.add.$0", "b"), true, true);
}
});
}
getIndentOptions().INDENT_SIZE = 2;
runWithDocStringFormat(DocStringFormat.EPYTEXT, new Runnable() {
public void run() {
- doInspectionTest(PyDocstringInspection.class, PyBundle.message("QFIX.docstring.remove.$0", "c"), true, true);
+ doInspectionTest(PyIncorrectDocstringInspection.class, PyBundle.message("QFIX.docstring.remove.$0", "c"), true, true);
}
});
}
public void testDocstringParams2() {
runWithDocStringFormat(DocStringFormat.EPYTEXT, new Runnable() {
public void run() {
- doInspectionTest(PyDocstringInspection.class, PyBundle.message("QFIX.docstring.add.$0", "ham"), true, true);
+ doInspectionTest(PyIncorrectDocstringInspection.class, PyBundle.message("QFIX.docstring.add.$0", "ham"), true, true);
}
});
}
runWithDocStringFormat(DocStringFormat.GOOGLE, new Runnable() {
@Override
public void run() {
- doInspectionTest(PyDocstringInspection.class, PyBundle.message("QFIX.docstring.add.$0", "b"), true, true);
+ doInspectionTest(PyIncorrectDocstringInspection.class, PyBundle.message("QFIX.docstring.add.$0", "b"), true, true);
}
});
}
runWithDocStringFormat(DocStringFormat.GOOGLE, new Runnable() {
@Override
public void run() {
- doInspectionTest(PyDocstringInspection.class, PyBundle.message("QFIX.docstring.remove.$0", "c"), true, true);
+ doInspectionTest(PyIncorrectDocstringInspection.class, PyBundle.message("QFIX.docstring.remove.$0", "c"), true, true);
}
});
}
runWithDocStringFormat(DocStringFormat.GOOGLE, new Runnable() {
@Override
public void run() {
- doInspectionTest(PyDocstringInspection.class, PyBundle.message("QFIX.docstring.remove.$0", "c"), true, true);
+ doInspectionTest(PyIncorrectDocstringInspection.class, PyBundle.message("QFIX.docstring.remove.$0", "c"), true, true);
}
});
}
runWithDocStringFormat(DocStringFormat.GOOGLE, new Runnable() {
@Override
public void run() {
- doInspectionTest(PyDocstringInspection.class, PyBundle.message("QFIX.docstring.remove.$0", "args"), true, true);
+ doInspectionTest(PyIncorrectDocstringInspection.class, PyBundle.message("QFIX.docstring.remove.$0", "args"), true, true);
}
});
}
runWithDocStringFormat(DocStringFormat.GOOGLE, new Runnable() {
@Override
public void run() {
- doInspectionTest(PyDocstringInspection.class, PyBundle.message("QFIX.docstring.remove.$0", "kwargs"), true, true);
+ doInspectionTest(PyIncorrectDocstringInspection.class, PyBundle.message("QFIX.docstring.remove.$0", "kwargs"), true, true);
}
});
}
runWithDocStringFormat(DocStringFormat.GOOGLE, new Runnable() {
@Override
public void run() {
- doInspectionTest(PyDocstringInspection.class, PyBundle.message("QFIX.docstring.add.$0", "args"), true, true);
+ doInspectionTest(PyIncorrectDocstringInspection.class, PyBundle.message("QFIX.docstring.add.$0", "args"), true, true);
}
});
}
runWithDocStringFormat(DocStringFormat.GOOGLE, new Runnable() {
@Override
public void run() {
- doInspectionTest(PyDocstringInspection.class, PyBundle.message("QFIX.docstring.add.$0", "kwargs"), true, true);
+ doInspectionTest(PyIncorrectDocstringInspection.class, PyBundle.message("QFIX.docstring.add.$0", "kwargs"), true, true);
}
});
}
runWithDocStringFormat(DocStringFormat.NUMPY, new Runnable() {
@Override
public void run() {
- doInspectionTest(PyDocstringInspection.class, PyBundle.message("QFIX.docstring.remove.$0", "x"), true, true);
+ doInspectionTest(PyIncorrectDocstringInspection.class, PyBundle.message("QFIX.docstring.remove.$0", "x"), true, true);
}
});
}
runWithDocStringFormat(DocStringFormat.NUMPY, new Runnable() {
@Override
public void run() {
- doInspectionTest(PyDocstringInspection.class, PyBundle.message("QFIX.docstring.remove.$0", "y"), true, true);
+ doInspectionTest(PyIncorrectDocstringInspection.class, PyBundle.message("QFIX.docstring.remove.$0", "y"), true, true);
}
});
}
runWithDocStringFormat(DocStringFormat.NUMPY, new Runnable() {
@Override
public void run() {
- doInspectionTest(PyDocstringInspection.class, PyBundle.message("QFIX.docstring.remove.$0", "z"), true, true);
+ doInspectionTest(PyIncorrectDocstringInspection.class, PyBundle.message("QFIX.docstring.remove.$0", "z"), true, true);
}
});
}
runWithDocStringFormat(DocStringFormat.NUMPY, new Runnable() {
@Override
public void run() {
- doInspectionTest(PyDocstringInspection.class, PyBundle.message("QFIX.docstring.remove.$0", "args"), true, true);
+ doInspectionTest(PyIncorrectDocstringInspection.class, PyBundle.message("QFIX.docstring.remove.$0", "args"), true, true);
}
});
}
}
public void testPyDocstringInspection() {
- LocalInspectionTool inspection = new PyDocstringInspection();
+ LocalInspectionTool inspection = new PyMissingOrEmptyDocstringInspection();
doTest(getTestName(false), inspection);
}
public void testPyDocstringParametersInspection() {
runWithDocStringFormat(DocStringFormat.EPYTEXT, new Runnable() {
public void run() {
- doHighlightingTest(PyDocstringInspection.class, LanguageLevel.PYTHON33);
+ doHighlightingTest(PyIncorrectDocstringInspection.class, LanguageLevel.PYTHON33);
}
});
}
public void testGoogleDocstringParametersInspection() {
runWithDocStringFormat(DocStringFormat.GOOGLE, new Runnable() {
public void run() {
- doHighlightingTest(PyDocstringInspection.class, LanguageLevel.PYTHON33);
+ doHighlightingTest(PyIncorrectDocstringInspection.class, LanguageLevel.PYTHON33);
}
});
}