def test_cstyle_multi_comment_multi_line(self): """ Multi line C style comment with multiple review status comment. /* codechecker_false_positive [ my.checker_2, my.checker_1 ] comment codechecker_intentional [ my.checker_1 ] intentional comment */ """ bug_line = 49 sc_handler = SourceCodeCommentHandler(self.__tmp_srcfile_3) res = sc_handler.has_source_line_comments(bug_line) self.assertTrue(res) source_line_comments = sc_handler.get_source_line_comments( bug_line) for l in source_line_comments: print(l) self.assertEqual(len(source_line_comments), 2) expected = [{ 'checkers': {'my.checker_1'}, 'message': 'intentional comment', 'status': 'intentional'}, { 'checkers': {'my.checker_1', 'my.checker_2'}, 'message': 'some comment', 'status': 'false_positive' }] self.assertDictEqual(expected[0], source_line_comments[0]) self.assertDictEqual(expected[1], source_line_comments[1]) current_line_comments = \ sc_handler.filter_source_line_comments(bug_line, 'my.checker_1') self.assertEqual(len(current_line_comments), 2) self.assertEqual(current_line_comments[0]['message'], expected[0]['message']) self.assertEqual(current_line_comments[0]['status'], expected[0]['status']) self.assertEqual(current_line_comments[1]['message'], expected[1]['message']) self.assertEqual(current_line_comments[1]['status'], expected[1]['status']) current_line_comments = \ sc_handler.filter_source_line_comments(bug_line, 'my.checker_2') self.assertEqual(len(current_line_comments), 1) self.assertEqual(current_line_comments[0]['message'], expected[1]['message']) self.assertEqual(current_line_comments[0]['status'], expected[1]['status']) current_line_comments = \ sc_handler.filter_source_line_comments(bug_line, 'my.dummy') self.assertEqual(len(current_line_comments), 0)
def test_cstyle_multi_comment_multi_line(self): """ Multi line C style comment with multiple review status comment. /* codechecker_false_positive [ my.checker_2, my.checker_1 ] comment codechecker_intentional [ my.checker_1 ] intentional comment */ """ bug_line = 49 sc_handler = SourceCodeCommentHandler(self.__tmp_srcfile_3) res = sc_handler.has_source_line_comments(bug_line) self.assertTrue(res) source_line_comments = sc_handler.get_source_line_comments(bug_line) for l in source_line_comments: print(l) self.assertEqual(len(source_line_comments), 2) expected = [{ 'checkers': {'my.checker_1'}, 'message': 'intentional comment', 'status': 'intentional' }, { 'checkers': {'my.checker_1', 'my.checker_2'}, 'message': 'some comment', 'status': 'false_positive' }] self.assertDictEqual(expected[0], source_line_comments[0]) self.assertDictEqual(expected[1], source_line_comments[1]) current_line_comments = \ sc_handler.filter_source_line_comments(bug_line, 'my.checker_1') self.assertEqual(len(current_line_comments), 2) self.assertEqual(current_line_comments[0]['message'], expected[0]['message']) self.assertEqual(current_line_comments[0]['status'], expected[0]['status']) self.assertEqual(current_line_comments[1]['message'], expected[1]['message']) self.assertEqual(current_line_comments[1]['status'], expected[1]['status']) current_line_comments = \ sc_handler.filter_source_line_comments(bug_line, 'my.checker_2') self.assertEqual(len(current_line_comments), 1) self.assertEqual(current_line_comments[0]['message'], expected[1]['message']) self.assertEqual(current_line_comments[0]['status'], expected[1]['status']) current_line_comments = \ sc_handler.filter_source_line_comments(bug_line, 'my.dummy') self.assertEqual(len(current_line_comments), 0)
def test_multiple_all_comments(self): """Check multiple comment.""" bug_line = 37 sc_handler = SourceCodeCommentHandler() res = sc_handler.has_source_line_comments(self.__tmp_srcfile_3, bug_line) self.assertTrue(res) source_line_comments = \ sc_handler.get_source_line_comments(self.__tmp_srcfile_3, bug_line) self.assertEqual(len(source_line_comments), 2) expected = [{ 'checkers': {'my.checker_1'}, 'message': 'intentional comment', 'status': 'intentional' }, { 'checkers': {'all'}, 'message': 'some comment', 'status': 'false_positive' }] self.assertDictEqual(expected[0], source_line_comments[0]) self.assertDictEqual(expected[1], source_line_comments[1]) current_line_comments = \ sc_handler.filter_source_line_comments(self.__tmp_srcfile_3, bug_line, 'my.checker_1') self.assertEqual(len(current_line_comments), 1) self.assertEqual(current_line_comments[0]['message'], expected[0]['message']) self.assertEqual(current_line_comments[0]['status'], expected[0]['status']) current_line_comments = \ sc_handler.filter_source_line_comments(self.__tmp_srcfile_3, bug_line, '') self.assertEqual(len(current_line_comments), 1) self.assertEqual(current_line_comments[0]['message'], expected[1]['message']) self.assertEqual(current_line_comments[0]['status'], expected[1]['status']) current_line_comments = \ sc_handler.filter_source_line_comments(self.__tmp_srcfile_3, bug_line, 'my.dummy') self.assertEqual(len(current_line_comments), 1) self.assertEqual(len(current_line_comments), 1) self.assertEqual(current_line_comments[0]['message'], expected[1]['message']) self.assertEqual(current_line_comments[0]['status'], expected[1]['status'])
def test_multiple_comments(self): """Check multiple comment.""" bug_line = 23 sc_handler = SourceCodeCommentHandler() res = sc_handler.has_source_line_comments(self.__tmp_srcfile_3, bug_line) self.assertTrue(res) source_line_comments = \ sc_handler.get_source_line_comments(self.__tmp_srcfile_3, bug_line) self.assertEqual(len(source_line_comments), 2) expected = [{ 'checkers': {'my.checker_1'}, 'message': 'intentional comment', 'status': 'intentional', 'line': '// codechecker_intentional [ my.checker_1 ] ' 'intentional comment\n'}, { 'checkers': {'my.checker_2'}, 'message': 'confirmed bug', 'status': 'confirmed', 'line': '// codechecker_confirmed [ my.checker_2 ] ' 'confirmed bug\n' }] self.assertDictEqual(expected[0], source_line_comments[0]) self.assertDictEqual(expected[1], source_line_comments[1]) current_line_comments = \ sc_handler.filter_source_line_comments(self.__tmp_srcfile_3, bug_line, 'my.checker_1') self.assertEqual(len(current_line_comments), 1) self.assertEqual(current_line_comments[0]['message'], expected[0]['message']) self.assertEqual(current_line_comments[0]['status'], expected[0]['status']) current_line_comments = \ sc_handler.filter_source_line_comments(self.__tmp_srcfile_3, bug_line, 'my.checker_2') self.assertEqual(len(current_line_comments), 1) self.assertEqual(current_line_comments[0]['message'], expected[1]['message']) self.assertEqual(current_line_comments[0]['status'], expected[1]['status']) current_line_comments = \ sc_handler.filter_source_line_comments(self.__tmp_srcfile_3, bug_line, 'my.dummy') self.assertEqual(len(current_line_comments), 0)
def test_multiple_all_comments(self): """Check multiple comment.""" bug_line = 37 sc_handler = SourceCodeCommentHandler(self.__tmp_srcfile_3) res = sc_handler.has_source_line_comments(bug_line) self.assertTrue(res) source_line_comments = sc_handler.get_source_line_comments(bug_line) self.assertEqual(len(source_line_comments), 2) expected = [{ 'checkers': {'my.checker_1'}, 'message': 'intentional comment', 'status': 'intentional'}, { 'checkers': {'all'}, 'message': 'some comment', 'status': 'false_positive' }] self.assertDictEqual(expected[0], source_line_comments[0]) self.assertDictEqual(expected[1], source_line_comments[1]) current_line_comments = \ sc_handler.filter_source_line_comments(bug_line, 'my.checker_1') self.assertEqual(len(current_line_comments), 1) self.assertEqual(current_line_comments[0]['message'], expected[0]['message']) self.assertEqual(current_line_comments[0]['status'], expected[0]['status']) current_line_comments = \ sc_handler.filter_source_line_comments(bug_line, '') self.assertEqual(len(current_line_comments), 1) self.assertEqual(current_line_comments[0]['message'], expected[1]['message']) self.assertEqual(current_line_comments[0]['status'], expected[1]['status']) current_line_comments = \ sc_handler.filter_source_line_comments(bug_line, 'my.dummy') self.assertEqual(len(current_line_comments), 1) self.assertEqual(len(current_line_comments), 1) self.assertEqual(current_line_comments[0]['message'], expected[1]['message']) self.assertEqual(current_line_comments[0]['status'], expected[1]['status'])
def test_multiple_checker_name_comments(self): """ Check multiple comment where same checker name are given for multiple source code comment. """ bug_line = 43 sc_handler = SourceCodeCommentHandler() res = sc_handler.has_source_line_comments(self.__tmp_srcfile_3, bug_line) self.assertTrue(res) source_line_comments = sc_handler.get_source_line_comments( self.__tmp_srcfile_3, bug_line) self.assertEqual(len(source_line_comments), 2) expected = [{ 'checkers': {'my.checker_1'}, 'message': 'intentional comment', 'status': 'intentional' }, { 'checkers': {'my.checker_2', 'my.checker_1'}, 'message': 'some comment', 'status': 'false_positive' }] self.assertDictEqual(expected[0], source_line_comments[0]) self.assertDictEqual(expected[1], source_line_comments[1]) current_line_comments = \ sc_handler.filter_source_line_comments(self.__tmp_srcfile_3, bug_line, 'my.checker_1') self.assertEqual(len(current_line_comments), 2)
def get_suppressed_reports(reports): """ Returns suppressed reports. """ suppressed_in_code = [] for rep in reports: bughash = rep.report_hash source_file = rep.main['location']['file_name'] bug_line = rep.main['location']['line'] checker_name = rep.main['check_name'] sc_handler = SourceCodeCommentHandler(source_file) src_comment_data = sc_handler.filter_source_line_comments( bug_line, checker_name) if len(src_comment_data) == 1: suppressed_in_code.append(bughash) LOG.debug("Bug %s is suppressed in code. file: %s Line %s", bughash, source_file, bug_line) elif len(src_comment_data) > 1: LOG.warning( "Multiple source code comment can be found " "for '%s' checker in '%s' at line %s. " "This bug will not be suppressed!", checker_name, source_file, bug_line) return suppressed_in_code
def get_suppressed_reports(reports): """ Returns suppressed reports. """ suppressed_in_code = [] for rep in reports: bughash = rep.report_hash source_file = rep.main['location']['file_name'] bug_line = rep.main['location']['line'] checker_name = rep.main['check_name'] sc_handler = SourceCodeCommentHandler(source_file) src_comment_data = sc_handler.filter_source_line_comments( bug_line, checker_name) if len(src_comment_data) == 1: suppressed_in_code.append(bughash) LOG.debug("Bug %s is suppressed in code. file: %s Line %s", bughash, source_file, bug_line) elif len(src_comment_data) > 1: LOG.warning( "Multiple source code comment can be found " "for '%s' checker in '%s' at line %s. " "This bug will not be suppressed!", checker_name, source_file, bug_line) return suppressed_in_code
def test_multiple_checker_name_comments(self): """ Check multiple comment where same checker name are given for multiple source code comment. """ bug_line = 43 sc_handler = SourceCodeCommentHandler(self.__tmp_srcfile_3) res = sc_handler.has_source_line_comments(bug_line) self.assertTrue(res) source_line_comments = sc_handler.get_source_line_comments( bug_line) self.assertEqual(len(source_line_comments), 2) expected = [{ 'checkers': {'my.checker_1'}, 'message': 'intentional comment', 'status': 'intentional' }, { 'checkers': {'my.checker_2', 'my.checker_1'}, 'message': 'some comment', 'status': 'false_positive' }] self.assertDictEqual(expected[0], source_line_comments[0]) self.assertDictEqual(expected[1], source_line_comments[1]) current_line_comments = \ sc_handler.filter_source_line_comments(bug_line, 'my.checker_1') self.assertEqual(len(current_line_comments), 2)
def skip_report(report_hash, source_file, report_line, checker_name, src_comment_handler=None, src_comment_status_filter=None): """ Returns a tuple where the first value will be True if the report was suppressed in the source code, otherwise False. The second value will be the list of available source code comments. """ bug = {'hash_value': report_hash, 'file_path': source_file} if src_comment_handler and src_comment_handler.get_suppressed(bug): LOG.debug("Suppressed by suppress file: %s:%s [%s] %s", source_file, report_line, checker_name, report_hash) return True, [] sc_handler = SourceCodeCommentHandler() src_comment_data = [] # Check for source code comment. with open(source_file, encoding='utf-8', errors='ignore') as sf: try: src_comment_data = sc_handler.filter_source_line_comments( sf, report_line, checker_name) except SpellException as ex: LOG.warning("%s contains %s", os.path.basename(source_file), str(ex)) if not src_comment_data: skip = True if src_comment_status_filter and \ 'unreviewed' not in src_comment_status_filter else False return skip, src_comment_data elif len(src_comment_data) == 1: status = src_comment_data[0]['status'] LOG.debug("Suppressed by source code comment.") if src_comment_handler: file_name = os.path.basename(source_file) message = src_comment_data[0]['message'] src_comment_handler.store_suppress_bug_id( report_hash, file_name, message, status) if src_comment_status_filter and \ status not in src_comment_status_filter: return True, src_comment_data elif len(src_comment_data) > 1: LOG.warning("Multiple source code comment can be found " "for '%s' checker in '%s' at line %d. " "This bug will not be suppressed!", checker_name, source_file, report_line) return False, src_comment_data
def parse_codechecker_review_comment(source_file_name: str, report_line: int, checker_name: str) -> SourceLineComments: """Parse the CodeChecker review comments from a source file at a given position. Returns an empty list if there are no comments. """ src_comment_data = [] with open(source_file_name, encoding='utf-8', errors='ignore') as f: if contains_codechecker_comment(f): sc_handler = SourceCodeCommentHandler() try: src_comment_data = sc_handler.filter_source_line_comments( f, report_line, checker_name) except SpellException as ex: LOG.warning("File %s contains %s", source_file_name, ex) return src_comment_data
def skip_report(report_hash, source_file, report_line, checker_name, src_comment_handler=None): """ Returns True if the report was suppressed in the source code, otherwise False. """ bug = {'hash_value': report_hash, 'file_path': source_file} if src_comment_handler and src_comment_handler.get_suppressed(bug): LOG.debug("Suppressed by suppress file: %s:%s [%s] %s", source_file, report_line, checker_name, report_hash) return True sc_handler = SourceCodeCommentHandler() # Check for source code comment. src_comment_data = sc_handler.filter_source_line_comments( source_file, report_line, checker_name) if len(src_comment_data) == 1: status = src_comment_data[0]['status'] LOG.debug("Suppressed by source code comment.") if src_comment_handler: file_name = os.path.basename(source_file) message = src_comment_data[0]['message'] src_comment_handler.store_suppress_bug_id( report_hash, file_name, message, status) if skip_suppress_status(status): return True elif len(src_comment_data) > 1: LOG.warning("Multiple source code comment can be found " "for '%s' checker in '%s' at line %d. " "This bug will not be suppressed!", checker_name, source_file, report_line) return False
def skip_report(report_hash, source_file, report_line, checker_name, src_comment_handler=None): """ Returns True if the report was suppressed in the source code, otherwise False. """ bug = {'hash_value': report_hash, 'file_path': source_file} if src_comment_handler and src_comment_handler.get_suppressed(bug): LOG.debug("Suppressed by suppress file: %s:%s [%s] %s", source_file, report_line, checker_name, report_hash) return True sc_handler = SourceCodeCommentHandler(source_file) # Check for source code comment. src_comment_data = sc_handler.filter_source_line_comments( report_line, checker_name) if len(src_comment_data) == 1: status = src_comment_data[0]['status'] LOG.debug("Suppressed by source code comment.") if src_comment_handler: file_name = os.path.basename(source_file) message = src_comment_data[0]['message'] src_comment_handler.store_suppress_bug_id( report_hash, file_name, message, status) if skip_suppress_status(status): return True elif len(src_comment_data) > 1: LOG.warning("Multiple source code comment can be found " "for '%s' checker in '%s' at line %d. " "This bug will not be suppressed!", checker_name, source_file, report_line) return False
class Report: """Represents an analyzer report. The main section is where the analyzer reported the issue. The bugpath contains additional locations (and messages) which lead to the main section. """ def __init__(self, main: Dict, bugpath: Dict, files: Dict[int, str], metadata: Dict[str, str]): # Dictionary containing checker name, report hash, # main report position, report message ... self.__main = main # Dictionary containing bug path related data # with control, event ... sections. self.__bug_path = bugpath # Dictionary fileid to filepath that bugpath events refer to self.__files = files # Can contain the source line where the main section was reported. self.__source_line = "" # Dictionary containing metadata information (analyzer name, version). self.__metadata = metadata self.__source_code_comments = None self.__sc_handler = SourceCodeCommentHandler() @property def line(self) -> int: return self.__main['location']['line'] @property def col(self) -> int: return self.__main['location']['col'] @property def description(self) -> str: return self.__main['description'] @property def main(self) -> Dict: return self.__main @property def report_hash(self) -> str: return self.__main['issue_hash_content_of_line_in_context'] @property def check_name(self) -> str: return self.__main['check_name'] @property def bug_path(self) -> Dict: return self.__bug_path @property def notes(self) -> List[str]: return self.__main.get('notes', []) @property def macro_expansions(self) -> List[str]: return self.__main.get('macro_expansions', []) @property def files(self) -> Dict[int, str]: return self.__files @property def file_path(self) -> str: """ Get the filepath for the main report location. """ return self.files[self.__main['location']['file']] @property def source_line(self) -> str: """Get the source line for the main location. If the source line is already set returns that if not tries to read it from the disk. """ if not self.__source_line: self.__source_line = util.get_line(self.file_path, self.line) return self.__source_line @source_line.setter def source_line(self, sl): self.__source_line = sl @property def metadata(self) -> Dict: return self.__metadata @property def source_code_comments(self): """ Get source code comments for the report. It will read the source file only once. """ if self.__source_code_comments is not None: return self.__source_code_comments self.__source_code_comments = [] if not os.path.exists(self.file_path): return self.__source_code_comments with open(self.file_path, encoding='utf-8', errors='ignore') as sf: try: self.__source_code_comments = \ self.__sc_handler.filter_source_line_comments( sf, self.line, self.check_name) except SpellException as ex: LOG.warning("%s contains %s", os.path.basename(self.file_path), str(ex)) if len(self.__source_code_comments) == 1: LOG.debug("Report %s is suppressed in code. file: %s Line %s", self.report_hash, self.file_path, self.line) elif len(self.__source_code_comments) > 1: LOG.warning( "Multiple source code comment can be found " "for '%s' checker in '%s' at line %s. " "This bug will not be suppressed!", self.check_name, self.file_path, self.line) return self.__source_code_comments def check_source_code_comments(self, comment_types: List[str]): """ True if it doesn't have a source code comment or if every comments have specified comment types. """ if not self.source_code_comments: return True return all(c['status'] in comment_types for c in self.source_code_comments) def __str__(self): msg = json.dumps(self.__main, sort_keys=True, indent=2) msg += str(self.__files) return msg def trim_path_prefixes(self, path_prefixes=None): """ Removes the longest matching leading path from the file paths. """ self.__files = {i: util.trim_path_prefixes(file_path, path_prefixes) for i, file_path in self.__files.items()} def to_json(self): """Converts to a special json format. This format is used by the parse command when the reports are printed to the stdout in json format.""" ret = self.__main ret["path"] = self.bug_path ret["files"] = self.files.values() return ret
def test_cstyle_multi_comment_multi_line_long(self): """ Multi line C style comment with multiple review status comment. /* codechecker_false_positive [ my.checker_2, my.checker_1 ] comment which is long codechecker_intentional [ my.checker_1 ] intentional comment long again */ """ bug_line = 60 sc_handler = SourceCodeCommentHandler() res = sc_handler.has_source_line_comments(self.__tmp_srcfile_3, bug_line) self.assertTrue(res) source_line_comments = sc_handler.get_source_line_comments( self.__tmp_srcfile_3, bug_line) for line in source_line_comments: print(line) self.assertEqual(len(source_line_comments), 2) expected = [{ 'checkers': {'my.checker_1'}, 'message': 'intentional comment long again', 'status': 'intentional', 'line': 'codechecker_intentional [ my.checker_1 ] ' 'intentional comment\n long\n again */\n' }, { 'checkers': {'my.checker_1', 'my.checker_2'}, 'message': 'comment which is long', 'status': 'false_positive', 'line': '/* codechecker_false_positive [ ' 'my.checker_2, my.checker_1 ] comment\n ' 'which\n is\n long\n' }] self.assertDictEqual(expected[0], source_line_comments[0]) self.assertDictEqual(expected[1], source_line_comments[1]) current_line_comments = \ sc_handler.filter_source_line_comments(self.__tmp_srcfile_3, bug_line, 'my.checker_1') self.assertEqual(len(current_line_comments), 2) self.assertEqual(current_line_comments[0]['message'], expected[0]['message']) self.assertEqual(current_line_comments[0]['status'], expected[0]['status']) self.assertEqual(current_line_comments[1]['message'], expected[1]['message']) self.assertEqual(current_line_comments[1]['status'], expected[1]['status']) current_line_comments = \ sc_handler.filter_source_line_comments(self.__tmp_srcfile_3, bug_line, 'my.checker_2') self.assertEqual(len(current_line_comments), 1) self.assertEqual(current_line_comments[0]['message'], expected[1]['message']) self.assertEqual(current_line_comments[0]['status'], expected[1]['status']) current_line_comments = \ sc_handler.filter_source_line_comments(self.__tmp_srcfile_3, bug_line, 'my.dummy') self.assertEqual(len(current_line_comments), 0)