From dffddee65940bf71906f6a68178f5b0b150d8f33 Mon Sep 17 00:00:00 2001 From: Mikhail Golubev Date: Wed, 2 Sep 2015 15:04:13 +0300 Subject: [PATCH] PY-16766 Fix recognition of Google code style docstrings from docstring content We should try all possible section headers inside docstring and confirm Google code style once at least one of them turns out to be known. Also I replaced predefined "\s" character group in internal regular expressions intended for matching on single line with explicit [ \t], because otherwise they match section headers with surrounding empty lines. --- .../python/documentation/DocStringUtil.java | 11 +++++------ .../documentation/GoogleCodeStyleDocString.java | 8 ++++---- .../python/documentation/NumpyDocString.java | 4 ++-- .../python/PySectionBasedDocStringTest.java | 14 ++++++++++++++ 4 files changed, 25 insertions(+), 12 deletions(-) diff --git a/python/src/com/jetbrains/python/documentation/DocStringUtil.java b/python/src/com/jetbrains/python/documentation/DocStringUtil.java index 320392860333..c7879624b5d9 100644 --- a/python/src/com/jetbrains/python/documentation/DocStringUtil.java +++ b/python/src/com/jetbrains/python/documentation/DocStringUtil.java @@ -38,7 +38,6 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.List; -import java.util.regex.Matcher; /** * User: catherine @@ -124,12 +123,12 @@ public class DocStringUtil { } public static boolean isGoogleDocString(@NotNull String text) { - final Matcher matcher = GoogleCodeStyleDocString.SECTION_HEADER_RE.matcher(text); - if (!matcher.find()) { - return false; + for (@NonNls String title : StringUtil.findMatches(text, GoogleCodeStyleDocString.SECTION_HEADER, 1)) { + if (SectionBasedDocString.SECTION_NAMES.contains(title.toLowerCase())) { + return true; + } } - @NonNls final String foundName = matcher.group(1).trim(); - return SectionBasedDocString.SECTION_NAMES.contains(foundName.toLowerCase()); + return false; } public static boolean isNumpyDocstring(@NotNull String text) { diff --git a/python/src/com/jetbrains/python/documentation/GoogleCodeStyleDocString.java b/python/src/com/jetbrains/python/documentation/GoogleCodeStyleDocString.java index 830fccd6eaf6..61f3a1a0184a 100644 --- a/python/src/com/jetbrains/python/documentation/GoogleCodeStyleDocString.java +++ b/python/src/com/jetbrains/python/documentation/GoogleCodeStyleDocString.java @@ -31,8 +31,8 @@ import java.util.regex.Pattern; * @see Google Python Style: Docstrings */ public class GoogleCodeStyleDocString extends SectionBasedDocString { - public static final Pattern SECTION_HEADER_RE = Pattern.compile("\\s*([\\w\\s]+):\\s*", Pattern.MULTILINE); - private static final Pattern FIELD_NAME_AND_TYPE_RE = Pattern.compile("\\s*(.+?)\\s*\\(\\s*(.*?)\\s*\\)\\s*"); + public static final Pattern SECTION_HEADER = Pattern.compile("^[ \t]*([\\w \t]+):[ \t]*$", Pattern.MULTILINE); + private static final Pattern FIELD_NAME_AND_TYPE = Pattern.compile("^[ \t]*(.+?)[ \t]*\\([ \t]*(.*?)[ \t]*\\)[ \t]*$", Pattern.MULTILINE); public GoogleCodeStyleDocString(@NotNull Substring text) { super(text); @@ -87,7 +87,7 @@ public class GoogleCodeStyleDocString extends SectionBasedDocString { final Substring textBeforeColon = colonSeparatedParts.get(0); name = textBeforeColon.trim(); if (mayHaveType) { - final Matcher matcher = FIELD_NAME_AND_TYPE_RE.matcher(textBeforeColon); + final Matcher matcher = FIELD_NAME_AND_TYPE.matcher(textBeforeColon); if (matcher.matches()) { name = textBeforeColon.getMatcherGroup(matcher, 1).trim(); type = textBeforeColon.getMatcherGroup(matcher, 2).trim(); @@ -115,7 +115,7 @@ public class GoogleCodeStyleDocString extends SectionBasedDocString { @Override protected Pair parseSectionHeader(int lineNum) { final Substring line = getLine(lineNum); - final Matcher matcher = SECTION_HEADER_RE.matcher(line); + final Matcher matcher = SECTION_HEADER.matcher(line); if (matcher.matches()) { @NonNls final Substring title = line.getMatcherGroup(matcher, 1).trim(); if (SECTION_NAMES.contains(title.toString().toLowerCase())) { diff --git a/python/src/com/jetbrains/python/documentation/NumpyDocString.java b/python/src/com/jetbrains/python/documentation/NumpyDocString.java index 2ce118237ea2..31767b4f0d88 100644 --- a/python/src/com/jetbrains/python/documentation/NumpyDocString.java +++ b/python/src/com/jetbrains/python/documentation/NumpyDocString.java @@ -29,8 +29,8 @@ import java.util.regex.Pattern; * @see Napoleon: Example NumPy Style Python Docstrings */ public class NumpyDocString extends SectionBasedDocString { - private static final Pattern SIGNATURE = Pattern.compile("^\\s*([\\w., ]+=)?\\s*[\\w\\.]+\\(.*\\)\\s*$", Pattern.MULTILINE); - public static final Pattern SECTION_HEADER = Pattern.compile("^\\s*[-=]{2,}\\s*$", Pattern.MULTILINE); + private static final Pattern SIGNATURE = Pattern.compile("^[ \t]*([\\w., ]+=)?[ \t]*[\\w\\.]+\\(.*\\)[ \t]*$", Pattern.MULTILINE); + public static final Pattern SECTION_HEADER = Pattern.compile("^[ \t]*[-=]{2,}[ \t]*$", Pattern.MULTILINE); private Substring mySignature; public NumpyDocString(@NotNull Substring text) { diff --git a/python/testSrc/com/jetbrains/python/PySectionBasedDocStringTest.java b/python/testSrc/com/jetbrains/python/PySectionBasedDocStringTest.java index 5555ba69c7ed..0f1c61ada95b 100644 --- a/python/testSrc/com/jetbrains/python/PySectionBasedDocStringTest.java +++ b/python/testSrc/com/jetbrains/python/PySectionBasedDocStringTest.java @@ -18,6 +18,7 @@ package com.jetbrains.python; import com.intellij.psi.PsiElement; import com.intellij.psi.search.PsiElementProcessor; import com.intellij.psi.util.PsiTreeUtil; +import com.jetbrains.python.documentation.DocStringUtil; import com.jetbrains.python.documentation.GoogleCodeStyleDocString; import com.jetbrains.python.documentation.NumpyDocString; import com.jetbrains.python.documentation.SectionBasedDocString; @@ -290,6 +291,19 @@ public class PySectionBasedDocStringTest extends PyTestCase { assertEquals("keyword arguments", docString.getSections().get(0).getNormalizedTitle()); } + // PY-16766 + public void testGoogleDocStringContentDetection() { + assertTrue(DocStringUtil.isGoogleDocString( + "\n" + + " My Section:\n" + + " some user defined section\n" + + " \n" + + " Parameters:\n" + + " param1: \n" + + "\n" + + " Returns:\n")); + } + @Override protected String getTestDataPath() { return super.getTestDataPath() + "/docstrings";