Skip to content

Commit

Permalink
AnnotationBear: Return precise string/comment info
Browse files Browse the repository at this point in the history
Earlier the return used to be either a tuple
of source ranges of strings/comments now it
is a tuple of dicts with keys
'start_delimiter_range', 'end_delimiter_range'
'content_range', 'full_range' of singleline
strings/multiline strings/singleline
comments/multiline comments.
  • Loading branch information
aptrishu committed Aug 24, 2017
1 parent 89b5913 commit 4207d9b
Show file tree
Hide file tree
Showing 7 changed files with 568 additions and 183 deletions.
260 changes: 175 additions & 85 deletions bears/general/AnnotationBear.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import sys

from coalib.bearlib.languages.LanguageDefinition import LanguageDefinition
from coalib.bears.LocalBear import LocalBear
from coalib.results.HiddenResult import HiddenResult
Expand All @@ -23,10 +25,12 @@ def run(self, filename, file, language: str, coalang_dir: str = None):
:param coalang_dir:
External directory for coalang file.
:return:
One HiddenResult containing a dictionary with keys being 'strings'
or 'comments' and values being a tuple of SourceRanges pointing to
the strings and a tuple of SourceRanges pointing to all comments
respectively. The ranges do include string quotes or the comment
One HiddenResult containing a dictionary with keys being
'singleline strings', 'multiline strings', 'singleline comments'
and 'multiline comments' and values being a dictionary with
keys ```'start_delimiter_range', 'end_delimiter_range'
'content_range', 'full_range'```.
The ranges do include string quotes or the comment
starting separator but not anything before (e.g. when using
``u"string"``, the ``u`` will not be in the source range).
"""
Expand All @@ -44,9 +48,9 @@ def run(self, filename, file, language: str, coalang_dir: str = None):
multiline_comment_delimiters = dict(
lang_dict['multiline_comment_delimiters'])
comment_delimiter = dict(lang_dict['comment_delimiter'])
string_ranges = comment_ranges = ()
ranges = ((), (), (), ())
try:
string_ranges, comment_ranges = self.find_annotation_ranges(
ranges = self.find_annotation_ranges(
file,
filename,
string_delimiters,
Expand All @@ -58,7 +62,10 @@ def run(self, filename, file, language: str, coalang_dir: str = None):
yield Result(self, str(e), severity=RESULT_SEVERITY.MAJOR,
affected_code=(e.code,))

content = {'strings': string_ranges, 'comments': comment_ranges}
content = {'singleline strings': ranges[0],
'multiline strings': ranges[1],
'singleline comments': ranges[2],
'multiline comments': ranges[3]}
yield HiddenResult(self, content)

def find_annotation_ranges(self,
Expand Down Expand Up @@ -88,66 +95,130 @@ def find_annotation_ranges(self,
A dictionary containing the various ways to define multi-line
comments in a language.
:return:
Two tuples first containing a tuple of strings, the second a tuple
of comments.
Four tuples containing dictionary for singleline strings,
multiline strings, singleline comments and multiline comments
respectively.
"""
text = ''.join(file)
strings_range = []
comments_range = []
singleline_string_range = []
multiline_string_range = []
singleline_comment_range = []
multiline_comment_range = []
position = 0

while position <= len(text):

def get_new_position():
_range, end_position = self.get_range_end_position(
file,
filename,
text,
multiline_string_delimiters,
position,
self.get_multiline)
if end_position and _range:
strings_range.append(_range)
end_position, start_delim, end_delim = (
self.get_range_end_position(
file,
filename,
text,
multiline_string_delimiters,
position,
self.get_multiline))
if end_position:
seperate_ranges = get_seperate_ranges(file,
filename,
start_delim,
end_delim,
position,
end_position)
multiline_string = {}
multiline_string[
'start_delimiter_range'] = seperate_ranges[0]
multiline_string[
'end_delimiter_range'] = seperate_ranges[1]
multiline_string['content_range'] = seperate_ranges[2]
multiline_string['full_range'] = seperate_ranges[3]
multiline_string_range.append(multiline_string)

return end_position + 1

_range, end_position = self.get_range_end_position(
file,
filename,
text,
string_delimiters,
position,
self.get_singleline_strings)
if end_position and _range:
strings_range.append(_range)
end_position, start_delim, end_delim = (
self.get_range_end_position(
file,
filename,
text,
string_delimiters,
position,
self.get_singleline_strings))
if end_position:
seperate_ranges = get_seperate_ranges(file,
filename,
start_delim,
end_delim,
position,
end_position)
singleline_string = {}
singleline_string[
'start_delimiter_range'] = seperate_ranges[0]
singleline_string[
'end_delimiter_range'] = seperate_ranges[1]
singleline_string['content_range'] = seperate_ranges[2]
singleline_string['full_range'] = seperate_ranges[3]
singleline_string_range.append(singleline_string)
return end_position + 1

_range, end_position = self.get_range_end_position(
file,
filename,
text,
multiline_comment_delimiters,
position,
self.get_multiline)
if end_position and _range:
comments_range.append(_range)
end_position, start_delim, end_delim = (
self.get_range_end_position(
file,
filename,
text,
multiline_comment_delimiters,
position,
self.get_multiline))
if end_position:
seperate_ranges = get_seperate_ranges(file,
filename,
start_delim,
end_delim,
position,
end_position)
multiline_comment = {}
multiline_comment[
'start_delimiter_range'] = seperate_ranges[0]
multiline_comment[
'end_delimiter_range'] = seperate_ranges[1]
multiline_comment['content_range'] = seperate_ranges[2]
multiline_comment['full_range'] = seperate_ranges[3]
multiline_comment_range.append(multiline_comment)
return end_position + 1

_range, end_position = self.get_range_end_position(
file,
filename,
text,
comment_delimiter,
position,
self.get_singleline_comment,
single_comment=True)
if end_position and _range:
comments_range.append(_range)
end_position, start_delim, end_delim = (
self.get_range_end_position(
file,
filename,
text,
comment_delimiter,
position,
self.get_singleline_comment,
single_comment=True))
if end_position:
seperate_ranges = get_seperate_ranges(file,
filename,
start_delim,
end_delim,
position,
end_position)
singleline_comment = {}
singleline_comment[
'start_delimiter_range'] = seperate_ranges[0]
singleline_comment[
'end_delimiter_range'] = seperate_ranges[1]
singleline_comment['content_range'] = seperate_ranges[2]
singleline_comment['full_range'] = seperate_ranges[3]
singleline_comment_range.append(singleline_comment)
return end_position + 1

return position + 1

position = get_new_position()

return tuple(strings_range), tuple(comments_range)
return (tuple(singleline_string_range),
tuple(multiline_string_range),
tuple(singleline_comment_range),
tuple(multiline_comment_range))

@staticmethod
def get_range_end_position(file,
Expand All @@ -157,26 +228,27 @@ def get_range_end_position(file,
position,
func,
single_comment=False):
_range = end_position = None
selected_annotation = end_position = selected_end_annotation = None
for annotation in annotations.keys():
if text[position:].startswith(annotation):
selected_annotation = annotation
if not single_comment:
ret_val = func(file,
filename,
text,
annotation,
annotations[annotation],
position)
selected_end_annotation = annotations[selected_annotation]
end_position = func(file,
filename,
text,
annotation,
annotations[annotation],
position)
else:
ret_val = func(file,
filename,
text,
annotation,
position)
if ret_val:
_range, end_position = ret_val[0], ret_val[1]
selected_end_annotation = '\n'
end_position = func(file,
filename,
text,
annotation,
position)

return _range, end_position
return end_position, selected_annotation, selected_end_annotation

@staticmethod
def get_multiline(file,
Expand All @@ -200,8 +272,7 @@ def get_multiline(file,
:param position:
An integer identifying the position where the annotation started.
:return:
A SourceRange object holding the range of the multi-line annotation
and the end_position of the annotation as an integer.
The end_position of the annotation as an integer.
"""
end_end = get_end_position(annotation_end,
text,
Expand All @@ -212,11 +283,7 @@ def get_multiline(file,
AbsolutePosition(file, position))
raise NoCloseError(annotation_start, _range)

return (SourceRange.from_absolute_position(
filename,
AbsolutePosition(file, position),
AbsolutePosition(file, end_end)),
end_end)
return end_end

@staticmethod
def get_singleline_strings(file,
Expand All @@ -239,8 +306,7 @@ def get_singleline_strings(file,
:position:
An integer identifying the position where the string started.
:return:
A SourceRange object identifying the range of the single-line
string and the end_position of the string as an integer.
The end_position of the string as an integer.
"""
end_position = get_end_position(string_end,
text,
Expand All @@ -254,11 +320,7 @@ def get_singleline_strings(file,
AbsolutePosition(file, position))
raise NoCloseError(string_start, _range)
if newline > end_position:
return (SourceRange.from_absolute_position(
filename,
AbsolutePosition(file, position),
AbsolutePosition(file, end_position)),
end_position)
return end_position

@staticmethod
def get_singleline_comment(file, filename, text, comment, position):
Expand All @@ -275,19 +337,14 @@ def get_singleline_comment(file, filename, text, comment, position):
:position:
An integer identifying the position where the string started.
:return:
A SourceRange object identifying the range of the single-line
comment and the end_position of the comment as an integer.
The end_position of the comment as an integer.
"""
end_position = get_end_position('\n',
text,
position + len(comment) - 1)
if end_position == -1:
end_position = len(text) - 1
return (SourceRange.from_absolute_position(
filename,
AbsolutePosition(file, position),
AbsolutePosition(file, end_position)),
end_position)
return end_position


def get_end_position(end_marker, text, position):
Expand All @@ -300,6 +357,39 @@ def get_end_position(end_marker, text, position):
return end_position


def get_seperate_ranges(file,
filename,
start_delim,
end_delim,
start_position,
end_position):
ranges = []
ranges.append(SourceRange.from_absolute_position(
filename,
AbsolutePosition(file, start_position),
AbsolutePosition(file, start_position + len(start_delim) - 1)))

ranges.append(SourceRange.from_absolute_position(
filename,
AbsolutePosition(file, end_position - len(end_delim) + 1),
AbsolutePosition(file, end_position)))

if start_position + 1 == end_position: # empty string so no content
ranges.append([])
else:
ranges.append(SourceRange.from_absolute_position(
filename,
AbsolutePosition(file, start_position + len(start_delim)),
AbsolutePosition(file, end_position - len(end_delim))))

ranges.append(SourceRange.from_absolute_position(
filename,
AbsolutePosition(file, start_position),
AbsolutePosition(file, end_position)))

return ranges


class NoCloseError(Exception):

def __init__(self, annotation, code):
Expand Down
Loading

0 comments on commit 4207d9b

Please sign in to comment.