class PerlCriticBear: """ Check the code with perlcritic. This will run perlcritic over each of the files seperately. """ LANGUAGES = {'Perl'} REQUIREMENTS = { DistributionRequirement(apt_get='perl'), DistributionRequirement(apt_get='libperl-critic-perl') } AUTHORS = {'The coala developers'} AUTHORS_EMAILS = {'*****@*****.**'} LICENSE = 'AGPL-3.0' CAN_DETECT = {'Syntax', 'Formatting', 'Code Simplification'} @staticmethod def create_arguments(filename, file, config_file, perlcritic_profile: str = ''): """ :param perlcritic_profile: Location of the perlcriticrc config file. """ args = ('--no-color', ) if perlcritic_profile: args += ('--profile', perlcritic_profile) return args + (filename, )
class VerilogLintBear: """ Analyze Verilog code using ``verilator`` and checks for all lint related and code style related warning messages. It supports the synthesis subset of Verilog, plus initial statements, proper blocking/non-blocking assignments, functions, tasks. It also warns about unused code when a specified signal is never sinked, and unoptimized code due to some construct, with which the optimization of the specified signal or block is disabled. This is done using the ``--lint-only`` command. For more information visit <http://www.veripool.org/projects/verilator/wiki/Manual-verilator>. """ LANGUAGES = {'Verilog'} REQUIREMENTS = {DistributionRequirement(apt_get='verilator')} AUTHORS = {'The coala developers'} AUTHORS_EMAILS = {'*****@*****.**'} LICENSE = 'AGPL-3.0' ASCIINEMA_URL = 'https://asciinema.org/a/45275' CAN_DETECT = {'Formatting', 'Code Simplification', 'Syntax', 'Unused Code'} @staticmethod def create_arguments(filename, file, config_file): return '--lint-only', filename
class CSecurityBear: """ Report possible security weaknesses for C/C++. For more information, consult <http://www.dwheeler.com/flawfinder/>. """ LANGUAGES = {'C', 'C++'} REQUIREMENTS = {DistributionRequirement(apt='flawfinder')} AUTHORS = {'The coala developers'} AUTHORS_EMAILS = {'*****@*****.**'} LICENSE = 'AGPL-3.0' ASCIINEMA_URL = 'https://asciinema.org/a/7z8ol9mpsgtuo1096c6jk8hi6' CAN_DETECT = {'Security', 'Memory Leak', 'Code Simplification'} @staticmethod def create_arguments(filename, file, config_file, neverignore: bool = False): """ :param neverignore: Never ignore security issues, even if they have an ``ignore`` directive in a comment. """ args = "--columns", "--dataonly", "--quiet", "--singleline" args += ("--neverignore", filename) if neverignore else (filename, ) return args
class CPPCheckBear: """ Report possible security weaknesses for C/C++. For more information, consult <https://github.com/danmar/cppcheck>. """ LANGUAGES = {"C", "C++"} REQUIREMENTS = {DistributionRequirement(apt='cppcheck')} AUTHORS = {'The coala developers'} AUTHORS_EMAILS = {'*****@*****.**'} LICENSE = 'AGPL-3.0' CAN_DETECT = {'Security', 'Unused Code', 'Unreachable Code', 'Smell'} @staticmethod def create_arguments(filename, file, config_file, enable: typed_list(str) = []): """ :param enable: Choose specific issues to report. Issues that can be reported are: all, warning, style, performance, portability, information, unusedFunction, missingInclude """ args = ("--template={line}:{severity}:{id}:{message}", ) if enable: args += ('--enable=' + ",".join(enable), ) return args + (filename, )
class XMLBear: """ Checks the code with ``xmllint``. See http://xmlsoft.org/xmllint.html """ LANGUAGES = {'XML'} REQUIREMENTS = {DistributionRequirement(apt_get='libxml2')} AUTHORS = {'The coala developers'} AUTHORS_EMAILS = {'*****@*****.**'} LICENSE = 'AGPL-3.0' CAN_DETECT = {'Formatting', 'Syntax'} _output_regex = re.compile( r'.*:(?P<line>\d+):.*(?P<severity>error|warning)\s?: ' r'(?P<message>.*)\n.*\n.*') @staticmethod def create_arguments(filename, file, config_file, xml_schema: path = '', xml_dtd: path_or_url = ''): """ :param xml_schema: ``W3C XML Schema`` file used for validation. :param xml_dtd: ``Document type Definition (DTD)`` file or url used for validation. """ args = (filename, ) if xml_schema: args += ('-schema', xml_schema) if xml_dtd: args += ('-dtdvalid', xml_dtd) return args def process_output(self, output, filename, file): stdout, stderr = output if stdout: # Return issues from stderr and stdout if stdout is not empty return itertools.chain( self.process_output_regex(stderr, filename, file, output_regex=self._output_regex), self.process_output_corrected( stdout, filename, file, diff_severity=RESULT_SEVERITY.INFO, result_message='XML can be formatted better.')) else: # Return issues from stderr if stdout is empty return self.process_output_regex(stderr, filename, file, output_regex=self._output_regex)
class LatexLintBear: """ Checks the code with ``chktex``. """ LANGUAGES = {"Tex"} REQUIREMENTS = {DistributionRequirement(apt_get='chktex')} AUTHORS = {'The coala developers'} AUTHORS_EMAILS = {'*****@*****.**'} LICENSE = 'AGPL-3.0' CAN_DETECT = {'Syntax', 'Formatting'} @staticmethod def create_arguments(filename, file, config_file): return filename,
class CSharpLintBear: """ Checks C# code for syntactical correctness using the ``mcs`` compiler. """ LANGUAGES = {"C#"} REQUIREMENTS = {DistributionRequirement(apt_get='mono-mcs')} AUTHORS = {'The coala developers'} AUTHORS_EMAILS = {'*****@*****.**'} LICENSE = 'AGPL-3.0' CAN_DETECT = {'Syntax'} @staticmethod def create_arguments(filename, file, config_file): return filename,
class LuaLintBear: """ Check Lua code for possible semantic problems, like unused code. Read more at <https://github.com/mpeterv/luacheck>. """ LANGUAGES = {'Lua'} REQUIREMENTS = {DistributionRequirement(apt_get='luarocks')} AUTHORS = {'The coala developers'} AUTHORS_EMAILS = {'*****@*****.**'} LICENSE = 'AGPL-3.0' CAN_DETECT = {'Unreachable Code', 'Unused Code', 'Variable Misuse'} @staticmethod def create_arguments(filename, file, config_file): return '-', '--formatter=plain', '--ranges', '--codes'
class CSecurityBear: """ Report possible security weaknesses for C/C++. For more information, consult <http://www.dwheeler.com/flawfinder/>. """ LANGUAGES = {'C', 'C++'} REQUIREMENTS = {DistributionRequirement(apt_get='flawfinder')} AUTHORS = {'The coala developers'} AUTHORS_EMAILS = {'*****@*****.**'} LICENSE = 'AGPL-3.0' ASCIINEMA_URL = 'https://asciinema.org/a/7z8ol9mpsgtuo1096c6jk8hi6' CAN_DETECT = {'Security', 'Memory Leak', 'Code Simplification'} @staticmethod def create_arguments(filename, file, config_file): return "--columns", "--dataonly", "--quiet", "--singleline", filename
class HaskellLintBear: """ Check Haskell code for possible problems. This bear can propose patches for using alternative functions, simplifying code and removing redundancies. See <http://community.haskell.org/~ndm/darcs/hlint/hlint.htm> for more information. """ LANGUAGES = {"Haskell"} REQUIREMENTS = {DistributionRequirement(apt_get='hlint')} AUTHORS = {'The coala developers'} AUTHORS_EMAILS = {'*****@*****.**'} LICENSE = 'AGPL-3.0' CAN_DETECT = {'Duplication'} CAN_FIX = {'Unused Code', 'Code Simplification'} severity_map = {"Error": RESULT_SEVERITY.MAJOR, "Warning": RESULT_SEVERITY.NORMAL, "Suggestion": RESULT_SEVERITY.INFO} @staticmethod def create_arguments(filename, file, config_file): return '--json', filename def process_output(self, output, filename, file): output = json.loads(output) for issue in output: assert issue["startLine"] == issue["endLine"] diff = Diff(file) line_nr = issue["startLine"] line_to_change = file[line_nr-1] newline = line_to_change.replace(issue["from"], issue["to"]) diff.change_line(line_nr, line_to_change, newline) yield Result.from_values( origin=self, message=issue["hint"], file=filename, severity=self.severity_map[issue["severity"]], line=issue["startLine"], diffs={filename: diff})
class XMLBear(LocalBear, Lint): executable = 'xmllint' diff_message = "XML can be formatted better." output_regex = r'(.*\.xml):(?P<line>\d+): (?P<message>.*)\n.*\n.*' gives_corrected = True use_stderr = True LANGUAGES = {"XML"} REQUIREMENTS = {DistributionRequirement(apt='libxml2')} AUTHORS = {'The coala developers'} AUTHORS_EMAILS = {'*****@*****.**'} LICENSE = 'AGPL-3.0' CAN_DETECT = {'Formatting', 'Syntax'} def process_output(self, output, filename, file): if self.stdout_output: # Return issues from stderr and stdout if stdout is not empty return itertools.chain( self._process_issues(self.stderr_output, filename), self._process_corrected(self.stdout_output, filename, file)) else: # Return issues from stderr if stdout is empty return self._process_issues(self.stderr_output, filename) def run(self, filename, file, xml_schema: path = "", xml_dtd: path_or_url = ""): ''' Checks the code with ``xmllint``. :param xml_schema: ``W3C XML Schema`` file used for validation. :param xml_dtd: ``Document type Definition (DTD)`` file or url used for validation. ''' self.arguments = "{filename} " if xml_schema: self.arguments += " -schema " + escape_path_argument(xml_schema) if xml_dtd: self.arguments += " -dtdvalid " + xml_dtd return self.lint(filename, file)
class JuliaLintBear: """ Provide analysis related to common bugs and potential issues in Julia like dead code, undefined variable usage, duplicate keys in dicts, incorrect ADT usage, wrongfully using ellipsis, and much more. See <https://lintjl.readthedocs.org/en/stable/> for more information on the analysis provided. """ LANGUAGES = {"Julia"} REQUIREMENTS = {DistributionRequirement(apt='julia')} AUTHORS = {'The coala developers'} AUTHORS_EMAILS = {'*****@*****.**'} LICENSE = 'AGPL-3.0' CAN_DETECT = { 'Unused Code', 'Syntax', 'Redundancy', 'Duplication', 'Unreachable Code', 'Security', 'Formatting' } @staticmethod def create_arguments(filename, file, config_file): lintcode = ('import Lint.lintfile; display(lintfile("' + escape(filename, '"\\') + '"))') return '-e', lintcode
class PHPCodeSnifferBear: """ Ensures that your PHP, JavaScript or CSS code remains clean and consistent. See <https://github.com/squizlabs/PHP_CodeSniffer> for more information. """ LANGUAGES = {"PHP", "JavaScript", "CSS"} REQUIREMENTS = {DistributionRequirement(apt_get='php-codesniffer')} AUTHORS = {'The coala developers'} AUTHORS_EMAILS = {'*****@*****.**'} LICENSE = 'AGPL-3.0' CAN_DETECT = { 'Formatting', 'Syntax', 'Documentation', 'Code Simplification' } ASCIINEMA_URL = 'https://asciinema.org/a/efawv96vdalck73tc3hwcabov' @staticmethod def create_arguments(filename, file, config_file): return '--report=emacs', '--standard=' + config_file, filename @staticmethod def generate_config(filename, file, max_line_length: int = 79, line_ending_character: str = "\\n", indent_size: int = SpacingHelper.DEFAULT_TAB_WIDTH, use_spaces: bool = True, allow_multiple_statements_per_line: bool = False, force_lower_case_keywords: bool = True, force_lower_case_constants: bool = True, blank_line_after_namespace_declaration: bool = True, check_use_blocks: bool = True, check_class_declaration: bool = True, check_property_declaration: bool = True, force_scope_modifier_on_method: bool = True, function_declaration_argument_spacing: int = 1, allow_multiline_function_declaration: bool = True): """ :param max_line_length: Maximum number of characters for a line. :param line_ending_character: Checks that end of line characters correspond to the one provided. :param indent_size: Number of spaces per indentation level. :param use_spaces: True if spaces are to be used instead of tabs. :param allow_multiple_statements_per_line: Allows having multiple statements on one line. :param force_lower_case_keyword: Checks that ``PHP`` keywords are lowercase. :param force_lower_case_constant: Checks that all uses of ``true``, ``false`` and ``null`` are lowercase. :param blank_line_after_namespace_declaration: Ensures that there is a blank line after a namespace declaration. :param check_use_blocks: Ensures that there is one blank line after a ``use`` block, that there is only one use block per line, and that all ``use`` declaration are done after namespaces declaration. :param check_class_declaration: Ensures that ``extends`` and ``implements`` keywords are declared on the same line as the class name, that the opening brace for a class is on the next line, and that the closing brace for a class is on the next line after the body. Allows splitting implements list accross multiple lines. :param check_property_declaration: Ensures that visibility is declared on all properties, that the ``var`` keyword is not used to declare a property, that there is not more that one property declared on a line, that properties are not prefixed with an underscore. :param force_scope_modifier_on_method: Verifies that class methods have scope modifiers. :param function_declaration_argument_spacing: Number of spaces between arguments in function declaration. :param allow_multiline_function_declaration: Allows argument lists to be split accross multiple lines correctly indented. """ rules_map = { "Generic.WhiteSpace.DisallowTabIndent": use_spaces, "Generic.Formatting.DisallowMultipleStatements": not allow_multiple_statements_per_line, "Generic.PHP.LowerCaseKeyword": force_lower_case_keywords, "Generic.PHP.LowerCaseConstant": force_lower_case_constants, "PSR2.Namespaces.UseDeclaration": check_use_blocks, "PSR2.Namespaces.NamespaceDeclaration": blank_line_after_namespace_declaration, "PSR2.Classes.ClassDeclaration": check_class_declaration, "PSR2.Classes.PropertyDeclaration": check_property_declaration, "Squiz.Scope.MethodScope": force_scope_modifier_on_method, "Squiz.Functions.MultiLineFunctionDeclaration": allow_multiline_function_declaration } rules = '' for k, v in rules_map.items(): rules += '<rule ref="{}"/>\n'.format(k) if v else '' configs = '''<?xml version="1.0"?> <ruleset name="Custom Standard"> <description>A custom coding standard</description> <rule ref="Generic.Files.LineLength"> <properties> <property name="lineLimit" value="{max_line_length}"/> </properties> </rule> <rule ref="Generic.Files.LineEndings"> <properties> <property name="eolChar" value="{line_ending_character}"/> </properties> </rule> <rule ref="Generic.WhiteSpace.ScopeIndent"> <properties> <property name="ignoreIndentationTokens" type="array" value="T_COMMENT,T_DOC_COMMENT_OPEN_TAG"/> </properties> <properties> <property name="indent" value="{indent_size}"/> </properties> <properties> <property name="exact" value="true"/> </properties> </rule> {some_rules} <rule ref="Squiz.WhiteSpace.ScopeKeywordSpacing"/> <rule ref="Squiz.Functions.FunctionDeclarationArgumentSpacing"> <properties> <property name="equalsSpacing" value="{function_declaration_argument_spacing}"/> </properties> </rule> <rule ref="Squiz.Functions.FunctionDeclarationArgumentSpacing.SpacingAfterHint"> <severity>0</severity> </rule> </ruleset> '''.format(max_line_length=max_line_length, line_ending_character=line_ending_character, indent_size=indent_size, some_rules=rules, function_declaration_argument_spacing=( function_declaration_argument_spacing)) return configs
def test_install_command_mock_incompatible_os(self, call_mock): self.assertEqual(platform.linux_distribution()[0], 'bad_os') with self.assertRaises(OSError): DistributionRequirement(dnf='libclang', apt_get='libclangs').install_command()
def test_install_command_mock_fedora(self, call_mock): self.assertEqual(platform.linux_distribution()[0], 'Fedora') self.assertEqual( DistributionRequirement(dnf='libclang', apt_get='libclangs').install_command(), ['dnf', 'install', 'libclang'])
class GNUIndentBear: """ This bear checks and corrects spacing and indentation via the well known Indent utility. C++ support is considered experimental. """ LANGUAGES = {'C', 'C++'} REQUIREMENTS = {DistributionRequirement(apt_get='indent')} AUTHORS = {'The coala developers'} AUTHORS_EMAILS = {'*****@*****.**'} LICENSE = 'AGPL-3.0' CAN_FIX = {'Formatting'} @staticmethod @deprecate_settings(indent_size='tab_width') def create_arguments(filename, file, config_file, max_line_length: int = 79, use_spaces: bool = True, blank_lines_after_declarations: bool = False, blank_lines_after_procedures: bool = False, blank_lines_after_commas: bool = False, braces_on_if_line: bool = False, braces_on_func_def_line: bool = False, cuddle_else: bool = False, while_and_brace_on_same_line: bool = False, case_indentation: int = 0, space_before_semicolon_after_empty_loop: bool = True, delete_optional_blank_lines: bool = True, declaration_indent: int = 0, brace_indent: int = 2, gnu_style: bool = False, k_and_r_style: bool = False, linux_style: bool = False, indent_size: int = SpacingHelper.DEFAULT_TAB_WIDTH, indent_cli_options: str = ''): """ :param max_line_length: Maximum number of characters for a line. :param use_spaces: True if spaces are to be used, else tabs. :param blank_lines_after_declarations: Forces blank lines after the declarations. Example: If ``blank_lines_after_declarations = True`` then ``` int a; return ...; ``` changes to ``` int a; return ...; ``` :param blank_lines_after_procedures: Force blank lines after procedure bodies. :param blank_lines_after_commas: Forces newline after comma in declaration. Example: If ``blank_lines_after_commas = True`` then ``` int a, b; ``` changes to ``` int a, b; ``` :param braces_on_if_line: Puts the brace ``{`` on same line with if. Example: If ``braces_on_if_line = True`` then ``` if (x > 0) { ``` changes to ``` if (x > 0) { ``` :param braces_on_func_def_line: Puts the brace `{` on same line with the function declaration. :param cuddle_else: Cuddle else and preceding ``}``. Example: If ``cuddle_else = True`` then ``` if (...) { .... } else { ``` changes to ``` if (...) { .... } else { ``` :param while_and_brace_on_same_line: Cuddles while of ``do {} while``; and preceding ``}``. :param case_indentation: Specifies the number of spaces by which ``case`` in the ``switch`` are indented. :param space_before_semicolon_after_empty_loop: Forces a blank before the semicolon ``;`` on one-line ``for`` and ``while`` statements. :param delete_optional_blank_lines: Deletes blank lines that are not needed. An example of needed blank line, is the blank line following a declaration when ``blank_line_after_declaration=True``. :param declaration_indent: Forces variables names to be aligned in column ``n`` with ``n = declaration_indent`` in declaration. Example: If ``declaration_indent = 8`` then, ``` int a; float b; ``` changes to ``` int a; float b; ``` :param brace_indent: Specifies the number of spaces by which braces are indented. Its default value is 2. :param gnu_style: Uses GNU coding style. :param k_and_r_style: Uses Kernighan & Ritchie coding style. :param linux_style: Uses Linux coding style. :param indent_size: Number of spaces per indentation level. :param indent_cli_options: Any command line options the indent binary understands. They will be simply passed through. """ indent_options = ( '--no-tabs' if use_spaces else '--use-tabs', '--line-length', str(max_line_length), '--indent-level', str(indent_size), '--tab-size', str(indent_size), ) indent_options += (('--cuddle-do-while', ) if while_and_brace_on_same_line else ('--dont-cuddle-do-while', )) indent_options += (('--swallow-optional-blank-lines', ) if delete_optional_blank_lines else ('-nsob', )) indent_options += (('--blank-lines-after-declarations', ) if blank_lines_after_declarations else ('-nbad', )) indent_options += (('--blank-lines-after-commas', ) if blank_lines_after_commas else ('-nbc', )) indent_options += (('--blank-lines-after-procedures', ) if blank_lines_after_procedures else ('-nbap', )) indent_options += (('-di' + str(declaration_indent), ) if declaration_indent != 0 else ()) indent_options += (('--case-indentation' + str(case_indentation), ) if case_indentation != 0 else ()) indent_options += (('--space-special-semicolon', ) if space_before_semicolon_after_empty_loop else ('-nss', )) indent_options += ('--brace-indent' + str(brace_indent), ) indent_options += (('--braces-on-func-def-line', ) if braces_on_func_def_line else ('-blf', )) indent_options += ((('-ce', ) if cuddle_else else ('-nce', )) + ('-br', )) if braces_on_if_line else ('-bl', ) indent_style_option = () indent_style_option += ('--gnu-style', ) if gnu_style else () indent_style_option += (('--k-and-r-style', ) if k_and_r_style and indent_style_option is () else ()) indent_style_option += (('--linux-style', ) if linux_style and indent_style_option is () else ()) # If a style is chosen the other configs aren't passed to `indent` return (indent_style_option if indent_style_option is not () else indent_options) + tuple(shlex.split(indent_cli_options))