Пример #1
0
    def test_contains(self):
        range_a = TextRange.from_values(1, 1, 1, 19)
        range_b = TextRange.from_values(1, 1, 1, 20)

        self.assertIn(range_a, range_b)

        range_a = TextRange.from_values(1, 1, 1, 21)
        range_b = TextRange.from_values(1, 1, 1, 20)

        self.assertNotIn(range_a, range_b)

        range_a = TextRange.from_values(1, 5, 1, 5)
        range_b = TextRange.from_values(1, 1, 1, 20)

        self.assertIn(range_a, range_b)

        range_a = TextRange.from_values(1, 1, 1, 18)
        range_b = TextRange.from_values(1, 14, 1, 20)

        self.assertNotIn(range_a, range_b)

        range_a = TextRange.from_values(1, 1, 1, 20)
        range_b = TextRange.from_values(1, 1, 1, 20)

        self.assertIn(range_a, range_b)
    def test_contains(self):
        range_a = TextRange.from_values(1, 1, 1, 19)
        range_b = TextRange.from_values(1, 1, 1, 20)

        self.assertIn(range_a, range_b)

        range_a = TextRange.from_values(1, 1, 1, 21)
        range_b = TextRange.from_values(1, 1, 1, 20)

        self.assertNotIn(range_a, range_b)

        range_a = TextRange.from_values(1, 5, 1, 5)
        range_b = TextRange.from_values(1, 1, 1, 20)

        self.assertIn(range_a, range_b)

        range_a = TextRange.from_values(1, 1, 1, 18)
        range_b = TextRange.from_values(1, 14, 1, 20)

        self.assertNotIn(range_a, range_b)

        range_a = TextRange.from_values(1, 1, 1, 20)
        range_b = TextRange.from_values(1, 1, 1, 20)

        self.assertIn(range_a, range_b)
    def test_extract_documentation_CPP(self):
        data = DocumentationExtractionTest.load_testdata("data.cpp")

        # No built-in documentation for C++.
        with self.assertRaises(KeyError):
            tuple(extract_documentation(data, "CPP", "default"))

        docstyle_CPP_doxygen = DocstyleDefinition.load("CPP", "doxygen")

        self.assertEqual(
            tuple(extract_documentation(data, "CPP", "doxygen")),
            (DocumentationComment(("\n"
                                   " This is the main function.\n"
                                   " @returns Exit code.\n"
                                   "          Or any other number.\n"),
                                  docstyle_CPP_doxygen.markers[0],
                                  TextRange.from_values(4, 1, 8, 4)),
             DocumentationComment(
                 (" foobar\n"
                  " @param xyz\n"), docstyle_CPP_doxygen.markers[0],
                 TextRange.from_values(15, 1, 17, 4)),
             DocumentationComment(" Some alternate style of documentation\n",
                                  docstyle_CPP_doxygen.markers[4],
                                  TextRange.from_values(22, 1, 23, 1)),
             DocumentationComment(" ends instantly",
                                  docstyle_CPP_doxygen.markers[0],
                                  TextRange.from_values(26, 5, 26, 26)),
             DocumentationComment((" Should work\n"
                                   "\n"
                                   " even without a function standing below.\n"
                                   "\n"
                                   " @param foo WHAT PARAM PLEASE!?\n"),
                                  docstyle_CPP_doxygen.markers[4],
                                  TextRange.from_values(32, 1, 37, 1))))
Пример #4
0
    def test_no_overlap(self):
        uut1 = TextRange.from_values(2, None, 3)
        uut2 = TextRange.from_values(4, None, 5)
        self.assertFalse(uut1.overlaps(uut2))
        self.assertFalse(uut2.overlaps(uut1))

        uut1 = TextRange.from_values(2, None, 3, 6)
        uut2 = TextRange.from_values(3, 7, 5)
        self.assertFalse(uut1.overlaps(uut2))
        self.assertFalse(uut2.overlaps(uut1))
Пример #5
0
    def test_no_overlap(self):
        uut1 = TextRange.from_values(2, None, 3)
        uut2 = TextRange.from_values(4, None, 5)
        self.assertFalse(uut1.overlaps(uut2))
        self.assertFalse(uut2.overlaps(uut1))

        uut1 = TextRange.from_values(2, None, 3, 6)
        uut2 = TextRange.from_values(3, 7, 5)
        self.assertFalse(uut1.overlaps(uut2))
        self.assertFalse(uut2.overlaps(uut1))
Пример #6
0
    def generate_diff(file, doc_comment, new_comment):
        """
        Generates diff between the original doc_comment and its fix
        new_comment which are instances of DocumentationComment.

        :param doc_comment:
            Original instance of DocumentationComment.
        :param new_comment:
            Fixed instance of DocumentationComment.
        :return:
            Diff instance.
        """
        diff = Diff(file)

        # We need to update old comment positions, as `assemble()`
        # prepends indentation for first line.
        old_range = TextRange.from_values(doc_comment.range.start.line, 1,
                                          doc_comment.range.end.line,
                                          doc_comment.range.end.column)

        # Clearing cached assemble() so a fresh one is fetched.
        new_comment.assemble.cache_clear()

        diff.replace(old_range, new_comment.assemble())
        return diff
Пример #7
0
    def __init__(self, documentation, docstyle_definition,
                 indent, marker, position):
        """
        Instantiates a new DocumentationComment.

        :param documentation:
            The documentation text.
        :param docstyle_definition:
            The ``DocstyleDefinition`` instance that defines what docstyle is
            being used in the documentation.
        :param indent:
            The string of indentation used in front of the first marker of the
            documentation.
        :param marker:
            The three-element tuple with marker strings, that identified this
            documentation comment.
        :param position:
            The starting ``TextPosition`` of the documentation.
        """
        self.documentation = documentation
        self.docstyle_definition = docstyle_definition
        self.indent = '' if indent is None else indent
        self.marker = ('', '', '') if marker is None else marker
        self.position = position
        self.range = None if position is None else TextRange.from_values(
            position.line,
            position.column,
            position.line + self.assemble().count('\n'),
            len(self.assemble()) - self.assemble().rfind('\n'))
Пример #8
0
    def test_extract_documentation_C(self):
        data = load_testdata("data.c")

        # No built-in documentation for C.
        with self.assertRaises(KeyError):
            tuple(extract_documentation(data, "C", "default"))

        docstyle_C_doxygen = DocstyleDefinition.load("C", "doxygen")

        expected_results = (DocumentationComment(
                                ("\n"
                                 " This is the main function.\n"
                                 "\n"
                                 " @returns Your favorite number.\n"),
                                docstyle_C_doxygen, "",
                                docstyle_C_doxygen.markers[0],
                                TextRange.from_values(3, 1, 7, 4)),
                            DocumentationComment(
                                ("\n"
                                 " Preserves alignment\n"
                                 " - Main item\n"
                                 "   - sub item\n"
                                 "     - sub sub item\n"),
                                docstyle_C_doxygen, "",
                                docstyle_C_doxygen.markers[2],
                                TextRange.from_values(15, 1, 20, 4)),
                            DocumentationComment(
                                (" ABC\n"
                                 "    Another type of comment\n"
                                 "\n"
                                 "    ..."),
                                docstyle_C_doxygen, "",
                                docstyle_C_doxygen.markers[1],
                                TextRange.from_values(23, 1, 26, 11)),
                            DocumentationComment(
                                (" foobar = barfoo.\n"
                                 " @param x whatever...\n"),
                                docstyle_C_doxygen, "",
                                docstyle_C_doxygen.markers[0],
                                TextRange.from_values(28, 1, 30, 4)))

        self.assertEqual(tuple(
            extract_documentation(data, "C", "doxygen")),
            expected_results)
Пример #9
0
    def test_extract_documentation_C(self):
        data = load_testdata('data.c')

        # No built-in documentation for C.
        with self.assertRaises(KeyError):
            tuple(extract_documentation(data, 'C', 'default'))

        docstyle_C_doxygen = DocstyleDefinition.load('C', 'doxygen')

        expected_results = (DocumentationComment(
                                ('\n'
                                 ' This is the main function.\n'
                                 '\n'
                                 ' @returns Your favorite number.\n'),
                                docstyle_C_doxygen, '',
                                docstyle_C_doxygen.markers[0],
                                TextRange.from_values(3, 1, 7, 4)),
                            DocumentationComment(
                                ('\n'
                                 ' Preserves alignment\n'
                                 ' - Main item\n'
                                 '   - sub item\n'
                                 '     - sub sub item\n'),
                                docstyle_C_doxygen, '',
                                docstyle_C_doxygen.markers[2],
                                TextRange.from_values(15, 1, 20, 4)),
                            DocumentationComment(
                                (' ABC\n'
                                 '    Another type of comment\n'
                                 '\n'
                                 '    ...'),
                                docstyle_C_doxygen, '',
                                docstyle_C_doxygen.markers[1],
                                TextRange.from_values(23, 1, 26, 11)),
                            DocumentationComment(
                                (' foobar = barfoo.\n'
                                 ' @param x whatever...\n'),
                                docstyle_C_doxygen, '',
                                docstyle_C_doxygen.markers[0],
                                TextRange.from_values(28, 1, 30, 4)))

        self.assertEqual(tuple(
            extract_documentation(data, 'C', 'doxygen')),
            expected_results)
Пример #10
0
    def test_extract_documentation_CPP(self):
        data = load_testdata("data.cpp")

        # No built-in documentation for C++.
        with self.assertRaises(KeyError):
            tuple(extract_documentation(data, "CPP", "default"))

        docstyle_CPP_doxygen = DocstyleDefinition.load("CPP", "doxygen")

        self.assertEqual(tuple(extract_documentation(data, "CPP", "doxygen")),
                         (DocumentationComment(
                              ("\n"
                               " This is the main function.\n"
                               " @returns Exit code.\n"
                               "          Or any other number.\n"),
                              docstyle_CPP_doxygen, "",
                              docstyle_CPP_doxygen.markers[0],
                              TextRange.from_values(4, 1, 8, 4)),
                          DocumentationComment(
                              (" foobar\n"
                               " @param xyz\n"),
                              docstyle_CPP_doxygen, "",
                              docstyle_CPP_doxygen.markers[0],
                              TextRange.from_values(15, 1, 17, 4)),
                          DocumentationComment(
                              " Some alternate style of documentation\n",
                              docstyle_CPP_doxygen, "",
                              docstyle_CPP_doxygen.markers[4],
                              TextRange.from_values(22, 1, 23, 1)),
                          DocumentationComment(
                              " ends instantly",
                              docstyle_CPP_doxygen, "\t",
                              docstyle_CPP_doxygen.markers[0],
                              TextRange.from_values(26, 2, 26, 23)),
                          DocumentationComment(
                              (" Should work\n"
                               "\n"
                               " even without a function standing below.\n"
                               "\n"
                               " @param foo WHAT PARAM PLEASE!?\n"),
                              docstyle_CPP_doxygen, "",
                              docstyle_CPP_doxygen.markers[4],
                              TextRange.from_values(32, 1, 37, 1))))
    def test_extract_documentation_CPP_2(self):
        data = DocumentationExtractionTest.load_testdata("data2.cpp")

        docstyle_CPP_doxygen = DocstyleDefinition.load("CPP", "doxygen")

        self.assertEqual(tuple(extract_documentation(
            data, "CPP", "doxygen")), (DocumentationComment(
                ("module comment\n"
                 " hello world\n"), docstyle_CPP_doxygen.markers[0],
                TextRange.from_values(1, 1, 3, 4)), ))
Пример #12
0
    def test_extract_documentation_C_2(self):
        data = ['/** my main description\n', ' * continues here */']

        docstyle_C_doxygen = DocstyleDefinition.load("C", "doxygen")

        self.assertEqual(
            list(extract_documentation(data, "C", "doxygen")),
            [DocumentationComment(" my main description\n continues here",
                                  docstyle_C_doxygen.markers[0],
                                  TextRange.from_values(1, 1, 2, 21))])
Пример #13
0
    def test_extract_documentation_CPP(self):
        data = load_testdata('data.cpp')

        # No built-in documentation for C++.
        with self.assertRaises(KeyError):
            tuple(extract_documentation(data, 'CPP', 'default'))

        docstyle_CPP_doxygen = DocstyleDefinition.load('CPP', 'doxygen')

        self.assertEqual(tuple(extract_documentation(data, 'CPP', 'doxygen')),
                         (DocumentationComment(
                              ('\n'
                               ' This is the main function.\n'
                               ' @returns Exit code.\n'
                               '          Or any other number.\n'),
                              docstyle_CPP_doxygen, '',
                              docstyle_CPP_doxygen.markers[0],
                              TextRange.from_values(4, 1, 8, 4)),
                          DocumentationComment(
                              (' foobar\n'
                               ' @param xyz\n'),
                              docstyle_CPP_doxygen, '',
                              docstyle_CPP_doxygen.markers[0],
                              TextRange.from_values(15, 1, 17, 4)),
                          DocumentationComment(
                              ' Some alternate style of documentation\n',
                              docstyle_CPP_doxygen, '',
                              docstyle_CPP_doxygen.markers[4],
                              TextRange.from_values(22, 1, 23, 1)),
                          DocumentationComment(
                              ' ends instantly',
                              docstyle_CPP_doxygen, '\t',
                              docstyle_CPP_doxygen.markers[0],
                              TextRange.from_values(26, 2, 26, 23)),
                          DocumentationComment(
                              (' Should work\n'
                               '\n'
                               ' even without a function standing below.\n'
                               '\n'
                               ' @param foo WHAT PARAM PLEASE!?\n'),
                              docstyle_CPP_doxygen, '',
                              docstyle_CPP_doxygen.markers[4],
                              TextRange.from_values(32, 1, 37, 1))))
Пример #14
0
    def test_extract_documentation_C_2(self):
        data = ['/** my main description\n', ' * continues here */']

        docstyle_C_doxygen = DocstyleDefinition.load("C", "doxygen")

        self.assertEqual(list(extract_documentation(data, "C", "doxygen")), [
            DocumentationComment(" my main description\n continues here", "C",
                                 "doxygen", "", docstyle_C_doxygen.markers[0],
                                 TextRange.from_values(1, 1, 2, 21))
        ])
Пример #15
0
    def test_extract_documentation_CPP_2(self):
        data = DocumentationExtractionTest.load_testdata("data2.cpp")

        docstyle_CPP_doxygen = DocstyleDefinition.load("CPP", "doxygen")

        self.assertEqual(tuple(extract_documentation(data, "CPP", "doxygen")),
                         (DocumentationComment(
                              ("module comment\n"
                               " hello world\n"),
                              docstyle_CPP_doxygen.markers[0],
                              TextRange.from_values(1, 1, 3, 4)),))
Пример #16
0
    def test_extract_documentation_CPP_2(self):
        data = load_testdata('data2.cpp')

        docstyle_CPP_doxygen = DocstyleDefinition.load('CPP', 'doxygen')

        self.assertEqual(tuple(extract_documentation(data, 'CPP', 'doxygen')),
                         (DocumentationComment(
                             ('module comment\n'
                              ' hello world\n'), docstyle_CPP_doxygen, '',
                             docstyle_CPP_doxygen.markers[0],
                             TextRange.from_values(1, 1, 3, 4)), ))
Пример #17
0
    def test_extract_documentation_PYTHON3_2(self):
        data = ['\n', '""" documentation in single line  """\n', 'print(1)\n']

        docstyle_PYTHON3_default = DocstyleDefinition.load("PYTHON3",
                                                           "default")

        self.assertEqual(
            list(extract_documentation(data, "PYTHON3", "default")),
            [DocumentationComment(" documentation in single line  ",
                                  docstyle_PYTHON3_default.markers[0],
                                  TextRange.from_values(2, 1, 2, 38))])
Пример #18
0
    def test_extract_documentation_PYTHON3_2(self):
        data = ['\n', '""" documentation in single line  """\n', 'print(1)\n']

        docstyle_PYTHON3_default = DocstyleDefinition.load("PYTHON3",
                                                           "default")

        self.assertEqual(
            list(extract_documentation(data, "PYTHON3", "default")),
            [DocumentationComment(" documentation in single line  ",
                                  docstyle_PYTHON3_default.markers[0],
                                  TextRange.from_values(2, 1, 2, 38))])
Пример #19
0
    def test_extract_documentation_CPP_2(self):
        data = load_testdata('data2.cpp')

        docstyle_CPP_doxygen = DocstyleDefinition.load('CPP', 'doxygen')

        self.assertEqual(tuple(extract_documentation(data, 'CPP', 'doxygen')),
                         (DocumentationComment(
                          ('module comment\n'
                           ' hello world\n'),
                          docstyle_CPP_doxygen, '',
                          docstyle_CPP_doxygen.markers[0],
                          TextRange.from_values(1, 1, 3, 4)),))
Пример #20
0
    def test_extract_documentation_PYTHON3_3(self):
        data = ['## documentation in single line without return at end.']

        docstyle_PYTHON3_doxygen = DocstyleDefinition.load("PYTHON3",
                                                           "doxygen")

        self.assertEqual(
            list(extract_documentation(data, "PYTHON3", "doxygen")),
            [DocumentationComment(" documentation in single line without "
                                      "return at end.",
                                  docstyle_PYTHON3_doxygen.markers[1],
                                  TextRange.from_values(1, 1, 1, 55))])
Пример #21
0
    def test_extract_documentation_PYTHON3_3(self):
        data = ['## documentation in single line without return at end.']

        docstyle_PYTHON3_doxygen = DocstyleDefinition.load("PYTHON3",
                                                           "doxygen")

        self.assertEqual(
            list(extract_documentation(data, "PYTHON3", "doxygen")),
            [DocumentationComment(" documentation in single line without "
                                  "return at end.",
                                  docstyle_PYTHON3_doxygen.markers[1],
                                  TextRange.from_values(1, 1, 1, 55))])
    def test_extract_documentation_PYTHON3(self):
        data = DocumentationExtractionTest.load_testdata("data.py")

        docstyle_PYTHON3_default = DocstyleDefinition.load(
            "PYTHON3", "default")
        docstyle_PYTHON3_doxygen = DocstyleDefinition.load(
            "PYTHON3", "doxygen")

        expected = (DocumentationComment(("\n"
                                          "Module description.\n"
                                          "\n"
                                          "Some more foobar-like text.\n"),
                                         docstyle_PYTHON3_default.markers[0],
                                         TextRange.from_values(1, 1, 5, 4)),
                    DocumentationComment(
                        ("\n"
                         "A nice and neat way of documenting code.\n"
                         ":param radius: The explosion radius.\n"),
                        docstyle_PYTHON3_default.markers[0],
                        TextRange.from_values(8, 5, 11, 8)),
                    DocumentationComment(
                        ("\n"
                         "Docstring with layouted text.\n"
                         "\n"
                         "    layouts inside docs are preserved for these "
                         "documentation styles.\n"
                         "this is intended.\n"),
                        docstyle_PYTHON3_default.markers[0],
                        TextRange.from_values(14, 1, 19, 4)),
                    DocumentationComment(
                        (" Docstring directly besides triple quotes.\n"
                         "    Continues here. "),
                        docstyle_PYTHON3_default.markers[0],
                        TextRange.from_values(21, 1, 22, 24)),
                    DocumentationComment(("super\n"
                                          " nicely\n"
                                          "short"),
                                         docstyle_PYTHON3_default.markers[0],
                                         TextRange.from_values(35, 1, 37, 9)))

        self.assertEqual(
            tuple(extract_documentation(data, "PYTHON3", "default")), expected)

        # Change only the docstyle in expected results.
        expected = list(
            DocumentationComment(r.documentation, r.marker, r.range)
            for r in expected)

        expected.insert(
            4,
            DocumentationComment(
                (" Alternate documentation style in doxygen.\n"
                 "  Subtext\n"
                 " More subtext (not correctly aligned)\n"
                 "      sub-sub-text\n"
                 "\n"), docstyle_PYTHON3_doxygen.markers[1],
                TextRange.from_values(25, 1, 30, 1)))

        self.assertEqual(
            list(extract_documentation(data, "PYTHON3", "doxygen")), expected)
Пример #23
0
    def test_extract_documentation_C(self):
        data = load_testdata('data.c')

        # No built-in documentation for C.
        with self.assertRaises(KeyError):
            tuple(extract_documentation(data, 'C', 'default'))

        docstyle_C_doxygen = DocstyleDefinition.load('C', 'doxygen')

        expected_results = (DocumentationComment(
            ('\n'
             ' This is the main function.\n'
             '\n'
             ' @returns Your favorite number.\n'), docstyle_C_doxygen, '',
            docstyle_C_doxygen.markers[0], TextRange.from_values(3, 1, 7, 4)),
                            DocumentationComment(
                                ('\n'
                                 ' Preserves alignment\n'
                                 ' - Main item\n'
                                 '   - sub item\n'
                                 '     - sub sub item\n'), docstyle_C_doxygen,
                                '', docstyle_C_doxygen.markers[2],
                                TextRange.from_values(15, 1, 20, 4)),
                            DocumentationComment(
                                (' ABC\n'
                                 '    Another type of comment\n'
                                 '\n'
                                 '    ...'), docstyle_C_doxygen, '',
                                docstyle_C_doxygen.markers[1],
                                TextRange.from_values(23, 1, 26, 11)),
                            DocumentationComment(
                                (' foobar = barfoo.\n'
                                 ' @param x whatever...\n'),
                                docstyle_C_doxygen, '',
                                docstyle_C_doxygen.markers[0],
                                TextRange.from_values(28, 1, 30, 4)))

        self.assertEqual(tuple(extract_documentation(data, 'C', 'doxygen')),
                         expected_results)
Пример #24
0
    def test_extract_documentation_CPP(self):
        data = load_testdata('data.cpp')

        # No built-in documentation for C++.
        with self.assertRaises(KeyError):
            tuple(extract_documentation(data, 'CPP', 'default'))

        docstyle_CPP_doxygen = DocstyleDefinition.load('CPP', 'doxygen')

        self.assertEqual(
            tuple(extract_documentation(data, 'CPP', 'doxygen')),
            (DocumentationComment(
                ('\n'
                 ' This is the main function.\n'
                 ' @returns Exit code.\n'
                 '          Or any other number.\n'), docstyle_CPP_doxygen, '',
                docstyle_CPP_doxygen.markers[0],
                TextRange.from_values(4, 1, 8, 4)),
             DocumentationComment((' foobar\n'
                                   ' @param xyz\n'), docstyle_CPP_doxygen, '',
                                  docstyle_CPP_doxygen.markers[0],
                                  TextRange.from_values(15, 1, 17, 4)),
             DocumentationComment(' Some alternate style of documentation\n',
                                  docstyle_CPP_doxygen, '',
                                  docstyle_CPP_doxygen.markers[4],
                                  TextRange.from_values(22, 1, 23, 1)),
             DocumentationComment(' ends instantly', docstyle_CPP_doxygen,
                                  '\t', docstyle_CPP_doxygen.markers[0],
                                  TextRange.from_values(26, 2, 26, 23)),
             DocumentationComment(
                 (' Should work\n'
                  '\n'
                  ' even without a function standing below.\n'
                  '\n'
                  ' @param foo WHAT PARAM PLEASE!?\n'), docstyle_CPP_doxygen,
                 '', docstyle_CPP_doxygen.markers[4],
                 TextRange.from_values(32, 1, 37, 1))))
Пример #25
0
def _extract_doc_comment_from_line(content, line, column, regex, marker_dict):
    begin_match = regex.search(content[line], column)
    if begin_match:
        column = begin_match.end()
        for marker in marker_dict[begin_match.group()]:
            doc_comment = _extract_doc_comment(content, line, column, marker)
            if doc_comment is not None:
                end_line, end_column, documentation = doc_comment

                rng = TextRange.from_values(line + 1,
                                            begin_match.start() + 1,
                                            end_line + 1, end_column + 1)
                doc = DocumentationComment(documentation, marker, rng)

                return end_line, end_column, doc

    return line + 1, 0, None
def _extract_doc_comment_from_line(content, line, column, regex, marker_dict):
    begin_match = regex.search(content[line], column)
    if begin_match:
        column = begin_match.end()
        for marker in marker_dict[begin_match.group()]:
            doc_comment = _extract_doc_comment(content, line, column, marker)
            if doc_comment is not None:
                end_line, end_column, documentation = doc_comment

                rng = TextRange.from_values(line + 1,
                                            begin_match.start() + 1,
                                            end_line + 1,
                                            end_column + 1)
                doc = DocumentationComment(documentation, marker, rng)

                return end_line, end_column, doc

    return line + 1, 0, None
Пример #27
0
    def test_overlap(self):
        uut1 = TextRange.from_values(2, None, 3)
        uut2 = TextRange.from_values(3, None, 5)
        self.assertTrue(uut1.overlaps(uut2))
        self.assertTrue(uut2.overlaps(uut1))

        uut1 = TextRange.from_values(2, None, 3, 6)
        uut2 = TextRange.from_values(3, 6, 5)
        self.assertTrue(uut1.overlaps(uut2))
        self.assertTrue(uut2.overlaps(uut1))

        uut1 = TextRange.from_values(2, None, 7)
        uut2 = TextRange.from_values(3, None, 5)
        self.assertTrue(uut1.overlaps(uut2))
        self.assertTrue(uut2.overlaps(uut1))

        uut1 = TextRange.from_values(5, None, 7)
        uut2 = TextRange.from_values(3, None, 6)
        self.assertTrue(uut1.overlaps(uut2))
        self.assertTrue(uut2.overlaps(uut1))
Пример #28
0
    def test_overlap(self):
        uut1 = TextRange.from_values(2, None, 3)
        uut2 = TextRange.from_values(3, None, 5)
        self.assertTrue(uut1.overlaps(uut2))
        self.assertTrue(uut2.overlaps(uut1))

        uut1 = TextRange.from_values(2, None, 3, 6)
        uut2 = TextRange.from_values(3, 6, 5)
        self.assertTrue(uut1.overlaps(uut2))
        self.assertTrue(uut2.overlaps(uut1))

        uut1 = TextRange.from_values(2, None, 7)
        uut2 = TextRange.from_values(3, None, 5)
        self.assertTrue(uut1.overlaps(uut2))
        self.assertTrue(uut2.overlaps(uut1))

        uut1 = TextRange.from_values(5, None, 7)
        uut2 = TextRange.from_values(3, None, 6)
        self.assertTrue(uut1.overlaps(uut2))
        self.assertTrue(uut2.overlaps(uut1))
Пример #29
0
    def test_generate_diff(self):
        data_old = ['\n', '""" documentation in single line  """\n']
        for doc_comment in DocBaseClass.extract(data_old, 'PYTHON3',
                                                'default'):
            old_doc_comment = doc_comment

        old_range = TextRange.from_values(old_doc_comment.range.start.line, 1,
                                          old_doc_comment.range.end.line,
                                          old_doc_comment.range.end.column)

        data_new = ['\n', '"""\n documentation in single line\n"""\n']
        for doc_comment in DocBaseClass.extract(data_new, 'PYTHON3',
                                                'default'):
            new_doc_comment = doc_comment

        diff = DocBaseClass.generate_diff(data_old, old_doc_comment,
                                          new_doc_comment)

        diff_expected = Diff(data_old)
        diff_expected.replace(old_range, new_doc_comment.assemble())

        self.assertEqual(diff, diff_expected)
Пример #30
0
    def test_generate_diff(self):
        data_old = ['\n', '""" documentation in single line  """\n']
        for doc_comment in DocBaseClass.extract(
                                data_old, 'PYTHON3', 'default'):
            old_doc_comment = doc_comment

        old_range = TextRange.from_values(
            old_doc_comment.range.start.line,
            1,
            old_doc_comment.range.end.line,
            old_doc_comment.range.end.column)

        data_new = ['\n', '"""\n documentation in single line\n"""\n']
        for doc_comment in DocBaseClass.extract(
                                data_new, 'PYTHON3', 'default'):
            new_doc_comment = doc_comment

        diff = DocBaseClass.generate_diff(
                        data_old, old_doc_comment, new_doc_comment)

        diff_expected = Diff(data_old)
        diff_expected.replace(old_range, new_doc_comment.assemble())

        self.assertEqual(diff, diff_expected)
Пример #31
0
    def test_from_values(self):
        # Check if invalid ranges still fail.
        with self.assertRaises(ValueError):
            TextRange.from_values(0, 10, 0, 7)

        uut = TextRange.from_values(1, 0, 7, 3)
        self.assertEqual(uut.start, TextPosition(1, 0))
        self.assertEqual(uut.end, TextPosition(7, 3))

        uut = TextRange.from_values(1, 0, None, 88)
        self.assertEqual(uut.start, TextPosition(1, 0))
        self.assertEqual(uut.end, TextPosition(1, 0))

        uut = TextRange.from_values(1, 0, 7, None)
        self.assertEqual(uut.start, TextPosition(1, 0))
        self.assertEqual(uut.end, TextPosition(7, None))

        # Test defaults.
        uut = TextRange.from_values()
        self.assertEqual(uut.start, TextPosition(None, None))
        self.assertEqual(uut.end, TextPosition(None, None))
Пример #32
0
    def test_from_values(self):
        # Check if invalid ranges still fail.
        with self.assertRaises(ValueError):
            TextRange.from_values(0, 10, 0, 7)

        uut = TextRange.from_values(1, 0, 7, 3)
        self.assertEqual(uut.start, TextPosition(1, 0))
        self.assertEqual(uut.end, TextPosition(7, 3))

        uut = TextRange.from_values(1, 0, None, 88)
        self.assertEqual(uut.start, TextPosition(1, 0))
        self.assertEqual(uut.end, TextPosition(1, 0))

        uut = TextRange.from_values(1, 0, 7, None)
        self.assertEqual(uut.start, TextPosition(1, 0))
        self.assertEqual(uut.end, TextPosition(7, None))

        # Test defaults.
        uut = TextRange.from_values()
        self.assertEqual(uut.start, TextPosition(None, None))
        self.assertEqual(uut.end, TextPosition(None, None))
Пример #33
0
 def test_expand_semi(self):
     file = ["abc\n", "defg\n", "hijkl\n", "mnopqr\n"]
     semi_range = TextRange.from_values(2, None, 3, None)
     full_range = TextRange.from_values(2, 1, 3, 6)
     self.assertEqual(semi_range.expand(file), full_range)
Пример #34
0
    def test_extract_documentation_PYTHON3(self):
        data = load_testdata('data.py')
        docstyle_PYTHON3_default = DocstyleDefinition.load(
            'PYTHON3', 'default')
        docstyle_PYTHON3_doxygen = DocstyleDefinition.load(
            'PYTHON3', 'doxygen')

        expected = (DocumentationComment(('\n'
                                          'Module description.\n'
                                          '\n'
                                          'Some more foobar-like text.\n'),
                                         docstyle_PYTHON3_default, '',
                                         docstyle_PYTHON3_default.markers[0],
                                         TextRange.from_values(1, 1, 5, 4)),
                    DocumentationComment(
                        ('\n'
                         'A nice and neat way of documenting code.\n'
                         ':param radius: The explosion radius.\n'),
                        docstyle_PYTHON3_default, ' ' * 4,
                        docstyle_PYTHON3_default.markers[0],
                        TextRange.from_values(8, 5, 11, 8)),
                    DocumentationComment('\nA function that returns 55.\n',
                                         docstyle_PYTHON3_default, ' ' * 8,
                                         docstyle_PYTHON3_default.markers[0],
                                         TextRange.from_values(13, 9, 15, 12)),
                    DocumentationComment(
                        ('\n'
                         'Docstring with layouted text.\n'
                         '\n'
                         '    layouts inside docs are preserved for these '
                         'documentation styles.\n'
                         'this is intended.\n'), docstyle_PYTHON3_default, '',
                        docstyle_PYTHON3_default.markers[0],
                        TextRange.from_values(19, 1, 24, 4)),
                    DocumentationComment(
                        (' Docstring directly besides triple quotes.\n'
                         '    Continues here. '), docstyle_PYTHON3_default, '',
                        docstyle_PYTHON3_default.markers[0],
                        TextRange.from_values(26, 1, 27, 24)),
                    DocumentationComment(('super\n'
                                          ' nicely\n'
                                          'short'), docstyle_PYTHON3_default,
                                         '',
                                         docstyle_PYTHON3_default.markers[0],
                                         TextRange.from_values(40, 1, 42, 9)))

        self.assertEqual(
            tuple(extract_documentation(data, 'PYTHON3', 'default')), expected)

        # Change only the docstyle in expected results.
        expected = list(
            DocumentationComment(r.documentation, docstyle_PYTHON3_doxygen,
                                 r.indent, r.marker, r.range)
            for r in expected)

        expected.insert(
            5,
            DocumentationComment(
                (' Alternate documentation style in doxygen.\n'
                 '  Subtext\n'
                 ' More subtext (not correctly aligned)\n'
                 '      sub-sub-text\n'
                 '\n'), docstyle_PYTHON3_doxygen, '',
                docstyle_PYTHON3_doxygen.markers[1],
                TextRange.from_values(30, 1, 35, 1)))

        self.assertEqual(
            list(extract_documentation(data, 'PYTHON3', 'doxygen')), expected)
Пример #35
0
def extract_documentation_with_markers(content, docstyle_definition):
    """
    Extracts all documentation texts inside the given source-code-string.

    :param content:
        The source-code-string where to extract documentation from.
        Needs to be a list or tuple where each string item is a single
        line (including ending whitespaces like ``\\n``).
    :param docstyle_definition:
        The ``DocstyleDefinition`` instance that defines what docstyle is
        being used in the documentation.
    :return:
        An iterator returning each DocumentationComment found in the content.
    """
    # Prepare marker-tuple dict that maps a begin pattern to the corresponding
    # marker_set(s). This makes it faster to retrieve a marker-set from a
    # begin sequence we initially want to search for in source code. Then
    # the possible found documentation match is processed further with the
    # rest markers.
    markers = docstyle_definition.markers

    marker_dict = {}
    for marker_set in markers:
        if marker_set[0] not in marker_dict:
            marker_dict[marker_set[0]] = [marker_set]
        else:
            marker_dict[marker_set[0]].append(marker_set)

    # Using regexes to perform a variable match is faster than finding each
    # substring with ``str.find()`` choosing the lowest match.
    begin_regex = _compile_multi_match_regex(marker_set[0]
                                             for marker_set in markers)

    line = 0
    column = 0
    while line < len(content):
        line, column, doc = _extract_doc_comment_from_line(
            content, line, column, begin_regex, marker_dict,
            docstyle_definition)

        if doc and isinstance(doc, MalformedComment):
            yield doc
        elif doc:
            # Ignore string literals
            ignore_regex = re.compile('^\s*r?(?P<marker>' + ('|'.join(
                re.escape(s) for s in doc.marker[0])) + ')')
            # Starting line of doc_string where marker is present
            start_line = doc.range.start.line - 1
            ignore_string_match = ignore_regex.search(content[start_line])

            # Instantiate padding
            top_padding = 0
            bottom_padding = 0
            # minus 2 because we want to check the line before the marker.
            start_index = doc.range.start.line - 2
            end_index = doc.range.end.line
            while start_index >= 0 and not content[start_index].strip():
                top_padding += 1
                start_index -= 1
            # If the end_index is instantiated above the len(content) i.e.
            # In case where ending marker of docstring is at the last line.
            # Then the doc.bottom_padding will be default to 0. This will also
            # prevent IndexError raised by content[end_index].
            while end_index < len(content) and not content[end_index].strip():
                # This condition will take place if theres an inline docstring
                # following documentation.
                if ((doc.marker[2] + '\n') != content[end_index - 1][-4:]
                        and bottom_padding == 0):
                    break
                bottom_padding += 1
                end_index += 1

            class_regex = re.compile(
                doc.docstyle_definition.docstring_type_regex.class_sign)
            function_regex = re.compile(
                doc.docstyle_definition.docstring_type_regex.func_sign)

            # End line differs when mid marker and end marker is different
            if doc.marker[1] == doc.marker[2]:
                end_index = end_index - 1

            # Check for docstring_position and then check for class regex
            # and function regex to define the type of docstring.
            if doc.docstyle_definition.docstring_position == 'top':
                if class_regex.search(content[start_index]):
                    doc.docstring_type = 'class'
                elif function_regex.search(content[start_index]):
                    doc.docstring_type = 'function'
            elif doc.docstyle_definition.docstring_position == 'bottom':
                if (end_index < len(content)
                        and class_regex.search(content[end_index])):
                    doc.docstring_type = 'class'
                elif (end_index < len(content)
                      and function_regex.search(content[end_index])):
                    doc.docstring_type = 'function'

            # Disabled automatic padding for docstring_type='others' as this
            # will cause overlapping of range in consecutive docstrings. Which
            # diff.replace() is unable to handle.
            if doc.docstring_type != 'others':
                doc.top_padding = top_padding
                doc.bottom_padding = bottom_padding

                doc.range = TextRange.from_values(
                    start_index + 2,
                    1 if top_padding > 0 else doc.range.start.column,
                    end_index,
                    1 if bottom_padding > 0 else doc.range.end.column)

            if ignore_string_match:
                yield doc
Пример #36
0
    def test_extract_documentation_PYTHON3(self):
        data = DocumentationExtractionTest.load_testdata("data.py")

        docstyle_PYTHON3_default = DocstyleDefinition.load("PYTHON3",
                                                           "default")
        docstyle_PYTHON3_doxygen = DocstyleDefinition.load("PYTHON3",
                                                           "doxygen")

        expected = (DocumentationComment(
                        ("\n"
                         "Module description.\n"
                         "\n"
                         "Some more foobar-like text.\n"),
                        docstyle_PYTHON3_default.markers[0],
                        TextRange.from_values(1, 1, 5, 4)),
                    DocumentationComment(
                        ("\n"
                         "A nice and neat way of documenting code.\n"
                         ":param radius: The explosion radius.\n"),
                        docstyle_PYTHON3_default.markers[0],
                        TextRange.from_values(8, 5, 11, 8)),
                    DocumentationComment(
                        ("\n"
                         "Docstring with layouted text.\n"
                         "\n"
                         "    layouts inside docs are preserved for these "
                         "documentation styles.\n"
                         "this is intended.\n"),
                        docstyle_PYTHON3_default.markers[0],
                        TextRange.from_values(14, 1, 19, 4)),
                    DocumentationComment(
                        (" Docstring directly besides triple quotes.\n"
                         "    Continues here. "),
                        docstyle_PYTHON3_default.markers[0],
                        TextRange.from_values(21, 1, 22, 24)),
                    DocumentationComment(
                        ("super\n"
                         " nicely\n"
                         "short"),
                        docstyle_PYTHON3_default.markers[0],
                        TextRange.from_values(35, 1, 37, 9)))

        self.assertEqual(
            tuple(extract_documentation(data, "PYTHON3", "default")),
            expected)

        # Change only the docstyle in expected results.
        expected = list(DocumentationComment(r.documentation,
                                             r.marker,
                                             r.range)
                        for r in expected)

        expected.insert(4, DocumentationComment(
            (" Alternate documentation style in doxygen.\n"
             "  Subtext\n"
             " More subtext (not correctly aligned)\n"
             "      sub-sub-text\n"
             "\n"),
            docstyle_PYTHON3_doxygen.markers[1],
            TextRange.from_values(25, 1, 30, 1)))

        self.assertEqual(
            list(extract_documentation(data, "PYTHON3", "doxygen")),
            expected)
Пример #37
0
def extract_documentation_with_markers(content, docstyle_definition):
    """
    Extracts all documentation texts inside the given source-code-string.

    :param content:
        The source-code-string where to extract documentation from.
        Needs to be a list or tuple where each string item is a single
        line (including ending whitespaces like ``\\n``).
    :param docstyle_definition:
        The ``DocstyleDefinition`` instance that defines what docstyle is
        being used in the documentation.
    :return:
        An iterator returning each DocumentationComment found in the content.
    """
    # Prepare marker-tuple dict that maps a begin pattern to the corresponding
    # marker_set(s). This makes it faster to retrieve a marker-set from a
    # begin sequence we initially want to search for in source code. Then
    # the possible found documentation match is processed further with the
    # rest markers.
    markers = docstyle_definition.markers

    marker_dict = {}
    for marker_set in markers:
        if marker_set[0] not in marker_dict:
            marker_dict[marker_set[0]] = [marker_set]
        else:
            marker_dict[marker_set[0]].append(marker_set)

    # Using regexes to perform a variable match is faster than finding each
    # substring with ``str.find()`` choosing the lowest match.
    begin_regex = _compile_multi_match_regex(
        marker_set[0] for marker_set in markers)

    line = 0
    column = 0
    while line < len(content):
        line, column, doc = _extract_doc_comment_from_line(
            content,
            line,
            column,
            begin_regex,
            marker_dict,
            docstyle_definition)

        if doc and isinstance(doc, MalformedComment):
            yield doc
        elif doc:
            # Ignore string literals
            ignore_regex = re.compile(
                '^\s*r?(?P<marker>' +
                ('|'.join(re.escape(s) for s in doc.marker[0])) +
                ')')
            # Starting line of doc_string where marker is present
            start_line = doc.range.start.line - 1
            ignore_string_match = ignore_regex.search(content[start_line])

            # Instantiate padding
            top_padding = 0
            bottom_padding = 0
            # minus 2 because we want to check the line before the marker.
            start_index = doc.range.start.line - 2
            end_index = doc.range.end.line
            while start_index >= 0 and not content[start_index].strip():
                top_padding += 1
                start_index -= 1
            # If the end_index is instantiated above the len(content) i.e.
            # In case where ending marker of docstring is at the last line.
            # Then the doc.bottom_padding will be default to 0. This will also
            # prevent IndexError raised by content[end_index].
            while end_index < len(content) and not content[end_index].strip():
                # This condition will take place if theres an inline docstring
                # following documentation.
                if ((doc.marker[2]+'\n') != content[end_index-1][-4:]
                        and bottom_padding == 0):
                    break
                bottom_padding += 1
                end_index += 1

            class_regex = re.compile(
                doc.docstyle_definition.docstring_type_regex.class_sign)
            function_regex = re.compile(
                doc.docstyle_definition.docstring_type_regex.func_sign)

            # End line differs when mid marker and end marker is different
            if doc.marker[1] == doc.marker[2]:
                end_index = end_index - 1

            # Check for docstring_position and then check for class regex
            # and function regex to define the type of docstring.
            if doc.docstyle_definition.docstring_position == 'top':
                if class_regex.search(content[start_index]):
                    doc.docstring_type = 'class'
                elif function_regex.search(content[start_index]):
                    doc.docstring_type = 'function'
            elif doc.docstyle_definition.docstring_position == 'bottom':
                if (end_index < len(content) and
                        class_regex.search(content[end_index])):
                    doc.docstring_type = 'class'
                elif (end_index < len(content) and
                        function_regex.search(content[end_index])):
                    doc.docstring_type = 'function'

            # Disabled automatic padding for docstring_type='others' as this
            # will cause overlapping of range in consecutive docstrings. Which
            # diff.replace() is unable to handle.
            if doc.docstring_type != 'others':
                doc.top_padding = top_padding
                doc.bottom_padding = bottom_padding

                doc.range = TextRange.from_values(
                    start_index + 2,
                    1 if top_padding > 0 else doc.range.start.column,
                    end_index,
                    1 if bottom_padding > 0 else doc.range.end.column)

            if ignore_string_match:
                yield doc
Пример #38
0
 def test_expand_full(self):
     empty_position = TextPosition()
     file = ["abc\n", "def\n", "ghi\n"]
     empty_range = TextRange(empty_position, empty_position)
     full_range = TextRange.from_values(1, 1, 3, 4)
     self.assertEqual(empty_range.expand(file), full_range)
Пример #39
0
    def test_extract_documentation_PYTHON3(self):
        data = load_testdata('data.py')
        docstyle_PYTHON3_default = DocstyleDefinition.load('PYTHON3',
                                                           'default')
        docstyle_PYTHON3_doxygen = DocstyleDefinition.load('PYTHON3',
                                                           'doxygen')

        expected = (DocumentationComment(
                        ('\n'
                         'Module description.\n'
                         '\n'
                         'Some more foobar-like text.\n'),
                        docstyle_PYTHON3_default, '',
                        docstyle_PYTHON3_default.markers[0],
                        TextRange.from_values(1, 1, 5, 4)),
                    DocumentationComment(
                        ('\n'
                         'A nice and neat way of documenting code.\n'
                         ':param radius: The explosion radius.\n'),
                        docstyle_PYTHON3_default, ' ' * 4,
                        docstyle_PYTHON3_default.markers[0],
                        TextRange.from_values(8, 5, 11, 8)),
                    DocumentationComment(
                        '\nA function that returns 55.\n',
                        docstyle_PYTHON3_default, ' ' * 8,
                        docstyle_PYTHON3_default.markers[0],
                        TextRange.from_values(13, 9, 15, 12)),
                    DocumentationComment(
                        ('\n'
                         'Docstring with layouted text.\n'
                         '\n'
                         '    layouts inside docs are preserved for these '
                         'documentation styles.\n'
                         'this is intended.\n'),
                        docstyle_PYTHON3_default, '',
                        docstyle_PYTHON3_default.markers[0],
                        TextRange.from_values(19, 1, 24, 4)),
                    DocumentationComment(
                        (' Docstring directly besides triple quotes.\n'
                         '    Continues here. '),
                        docstyle_PYTHON3_default, '',
                        docstyle_PYTHON3_default.markers[0],
                        TextRange.from_values(26, 1, 27, 24)),
                    DocumentationComment(
                        ('super\n'
                         ' nicely\n'
                         'short'),
                        docstyle_PYTHON3_default, '',
                        docstyle_PYTHON3_default.markers[0],
                        TextRange.from_values(40, 1, 42, 9)))

        self.assertEqual(
            tuple(extract_documentation(data, 'PYTHON3', 'default')),
            expected)

        # Change only the docstyle in expected results.
        expected = list(DocumentationComment(r.documentation,
                                             docstyle_PYTHON3_doxygen,
                                             r.indent,
                                             r.marker,
                                             r.range)
                        for r in expected)

        expected.insert(5, DocumentationComment(
            (' Alternate documentation style in doxygen.\n'
             '  Subtext\n'
             ' More subtext (not correctly aligned)\n'
             '      sub-sub-text\n'
             '\n'),
            docstyle_PYTHON3_doxygen, '',
            docstyle_PYTHON3_doxygen.markers[1],
            TextRange.from_values(30, 1, 35, 1)))

        self.assertEqual(
            list(extract_documentation(data, 'PYTHON3', 'doxygen')),
            expected)
Пример #40
0
 def test_expand_semi(self):
     file = ["abc\n", "defg\n", "hijkl\n", "mnopqr\n"]
     semi_range = TextRange.from_values(2, None, 3, None)
     full_range = TextRange.from_values(2, 1, 3, 6)
     self.assertEqual(semi_range.expand(file), full_range)
Пример #41
0
 def test_expand_full(self):
     empty_position = TextPosition()
     file = ["abc\n", "def\n", "ghi\n"]
     empty_range = TextRange(empty_position, empty_position)
     full_range = TextRange.from_values(1, 1, 3, 4)
     self.assertEqual(empty_range.expand(file), full_range)
Пример #42
0
    def run(self,
            filename,
            file,
            language: str,
            docstyle: str = 'default',
            allow_missing_func_desc: str = False,
            indent_size: int = 4):
        """
        Checks for certain in-code documentation styles.

        It currently checks for the following style: ::

            The first line needs to have no indentation.
                - Following lines can have indentation

            :param x:
                4 space indent
            :return:
                also 4 space indent
                following lines are also 4 space indented

        :param language: The programming language of the file(s).
        :param docstyle: The docstyle to use. For example ``default`` or
                         ``doxygen``. Docstyles are language dependent, meaning
                         not every language is supported by a certain docstyle.
        :param allow_missing_func_desc: When set ``True`` this will allow
                         functions with missing descriptions, allowing
                         functions to start with params.
        :param indent_size: Number of spaces per indentation level.
        """
        for doc_comment in extract_documentation(file, language, docstyle):
            parsed = doc_comment.parse()
            metadata = iter(parsed)

            # Assuming that the first element is always the only main
            # description.
            main_description = next(metadata)

            if main_description.desc == '\n' and not allow_missing_func_desc:
                warning_desc = """
Missing function description.
Please set allow_missing_func_desc = True to ignore this warning.
"""
            else:
                warning_desc = 'Documentation does not have correct style.'

            # one empty line shall follow main description (except it's empty
            # or no annotations follow).
            if main_description.desc.strip() != '':
                main_description = main_description._replace(
                    desc='\n' + main_description.desc.strip() + '\n' *
                    (1 if len(parsed) == 1 else 2))

            new_metadata = [main_description]
            for m in metadata:
                # Split newlines and remove leading and trailing whitespaces.
                stripped_desc = list(map(str.strip, m.desc.splitlines()))

                if len(stripped_desc) == 0:
                    # Annotations should be on their own line, though no
                    # further description follows.
                    stripped_desc.append('')
                else:
                    # Wrap parameter description onto next line if it follows
                    # annotation directly.
                    if stripped_desc[0] != '':
                        stripped_desc.insert(0, '')

                # Indent with 4 spaces.
                stripped_desc = ('' if line == '' else ' ' * indent_size + line
                                 for line in stripped_desc)

                new_desc = '\n'.join(stripped_desc)

                # Strip away trailing whitespaces and obsolete newlines (except
                # one newline which is mandatory).
                new_desc = new_desc.rstrip() + '\n'

                new_metadata.append(m._replace(desc=new_desc.lstrip(' ')))

            new_comment = DocumentationComment.from_metadata(
                new_metadata, doc_comment.docstyle_definition,
                doc_comment.marker, doc_comment.indent, doc_comment.position)

            if new_comment != doc_comment:
                # Something changed, let's apply a result.
                diff = Diff(file)

                # We need to update old comment positions, as `assemble()`
                # prepends indentation for first line.
                old_range = TextRange.from_values(doc_comment.range.start.line,
                                                  1,
                                                  doc_comment.range.end.line,
                                                  doc_comment.range.end.column)
                diff.replace(old_range, new_comment.assemble())

                yield Result(origin=self,
                             message=warning_desc,
                             affected_code=(diff.range(filename), ),
                             diffs={filename: diff})