示例#1
0
def check_assert_usage(source_files, lines_of_code):
    """
    Check how many assertions are used in the code.
    :param source_files: The list of files to count assertions in.
    :param lines_of_code: The total lines of code.
    :return: The assertion score.
    """
    print(strings.RUN_ASSERTION_CHECK_HEADER)
    assert_count = 0

    for file in source_files:
        f = open(file, 'r', encoding='latin-1')

        file_lines = f.readlines()
        for line in file_lines:
            if assertion_used_in_code_line(line):
                assert_count += 1

        f.close()

    assertion_rate = assert_count / lines_of_code

    detailled_result_string = strings.RESULT_ASSERTION_RATE_DETAILED.format(count=assert_count, loc=lines_of_code,
                                                                            rate=assertion_rate,
                                                                            percentage=100*assertion_rate)
    print(strings.RESULT_ASSERTION_RATE.format(assertion_rate, assert_count, lines_of_code))
    util.write_into_file_string(strings.RESULTS_FILENAME_ASSERTION_CHECK, detailled_result_string)

    score = scoring.calculate_assertion_score(assertion_rate)
    scoring.print_score(score, 'Assertion')
    return score
示例#2
0
def run_kwstyle(source_files, lines_of_code):
    """
    Runs KWStyle.
    :param source_files: The list of source files to analyze.
    :param lines_of_code: The lines of pure code count.
    :return: The KWStyle score.
    """
    print(strings.RUN_KWSTYLE_HEADER)

    softwipe_directory = os.path.dirname(os.path.realpath(__file__))
    kwstyle_xml = os.path.join(softwipe_directory, 'KWStyle.xml')
    kwstyle_call = [TOOLS.KWSTYLE.exe_name, '-v', '-xml', kwstyle_xml]

    output = ''
    # KWStyle only works properly when specifying just one single input file. Thus, iterate and call KWStyle again
    # for each source file, each time appending to the result output.
    for source_file in source_files:
        cur_kwstyle_call = kwstyle_call[::]
        cur_kwstyle_call.append(source_file)
        try:
            output += subprocess.check_output(cur_kwstyle_call, universal_newlines=True, stderr=subprocess.STDOUT)
        except subprocess.CalledProcessError as e:  # Same as with the lizard call. KWStyle exits with status 1 by
            output += e.output  # default. So catch that, ignore the exception, and keep the output of the command
        
    warning_count = get_kwstyle_warning_count_from_kwstyle_output(output)
    warning_rate = warning_count / lines_of_code

    print(strings.RESULT_KWSTYLE_WARNING_RATE.format(warning_rate, warning_count, lines_of_code))
    util.write_into_file_string(strings.RESULTS_FILENAME_KWSTYLE, output)

    score = scoring.calculate_kwstyle_score(warning_rate)
    scoring.print_score(score, 'KWStyle')
    return score
示例#3
0
def run_clang_tidy(source_files, lines_of_code, cpp):
    """
    Runs clang-tidy.
    :param source_files: The list of source files to analyze.
    :param lines_of_code: The lines of pure code count.
    :param cpp: Whether C++ is used or not. True if C++, false if C.
    :return: The clang-tidy score.
    """
    print(strings.RUN_CLANG_TIDY_HEADER)
    clang_tidy_call = [TOOLS.CLANG_TIDY.exe_name]
    clang_tidy_call.extend(source_files)

    # Create checks list
    clang_tidy_checks = strings.CLANG_TIDY_CHECKS_CPP if cpp else strings.CLANG_TIDY_CHECKS_C
    clang_tidy_call.append('-checks=' + clang_tidy_checks)

    try:
        output = subprocess.check_output(clang_tidy_call, universal_newlines=True, stderr=subprocess.STDOUT)
    except subprocess.CalledProcessError as e:
        output = e.output
        # clang-tidy can exit with exit code 1 if there is no compilation database, which might be the case when
        # compiling with just clang. Thus, ignore the exception here.
    warning_lines = get_clang_tidy_warning_lines_from_clang_tidy_output(output)
    weighted_warning_count = get_weighted_clang_tidy_warning_count_from_clang_tidy_warning_lines(warning_lines)
    warning_rate = weighted_warning_count / lines_of_code

    print(strings.RESULT_WEIGHTED_CLANG_TIDY_WARNING_RATE.format(warning_rate, weighted_warning_count, lines_of_code))
    beautified_warning_lines = beautify_clang_tidy_warning_lines(warning_lines)
    util.write_into_file_list(strings.RESULTS_FILENAME_CLANG_TIDY, beautified_warning_lines)

    score = scoring.calculate_clang_tidy_score(warning_rate)
    scoring.print_score(score, 'Clang-tidy')
    return score
示例#4
0
def end_game():
    #print "\nDone! Analysing game performance..."
    print "\n"
    perc = scoring.get_result(lines, result_lines) * 100.0
    #print_result(perc)
    scoring.print_score(user_name, perc)
    km.print_funsies()
    
    time.sleep(25)

    cancel_game()

    return
示例#5
0
def compile_and_execute_program_with_sanitizers(args,
                                                lines_of_code,
                                                program_dir_abs,
                                                cpp,
                                                excluded_paths,
                                                no_exec=False):
    """
    Automatically compile and execute the program
    :param args: The "args" Namespace as returned from parse_arguments().
    :param lines_of_code: The lines of pure code count.
    :param program_dir_abs: The absolute path to the root directory of the target program.
    :param cpp: Whether C++ is used or not. True if C++, False if C.
    :param excluded_paths: A tupel containing the paths to be excluded.
    :param no_exec: If True, skip execution of the program.
    :return The compiler + sanitizer score.
    """
    compiler_flags = strings.COMPILER_WARNING_FLAGS if no_exec else strings.COMPILE_FLAGS
    if args.compileroptionsfile:
        options = open(args.compileroptionsfile[0], 'r').read().rstrip()
        compiler_flags += " " + options

    weighted_sum_of_compiler_warnings = compile_program(
        args, lines_of_code, cpp, compiler_flags, excluded_paths)

    if not no_exec:
        execute_file = args.executefile[0] if args.executefile else None
        weighted_sum_of_sanitizer_warnings = execute_program(
            program_dir_abs, execute_file, args.cmake, lines_of_code)
    else:
        weighted_sum_of_sanitizer_warnings = 0
        print(strings.WARNING_PROGRAM_EXECUTION_SKIPPED)

    weighted_warning_rate = (
        weighted_sum_of_compiler_warnings +
        weighted_sum_of_sanitizer_warnings) / lines_of_code
    score = scoring.calculate_compiler_and_sanitizer_score(
        weighted_warning_rate)
    scoring.print_score(score, 'Compiler + Sanitizer')

    return score
示例#6
0
def main():
    add_kwstyle_to_path_variable()

    # Allow the user to auto-install the dependencies by just running "./softwipe.py" without any arguments
    if len(sys.argv) == 1:
        automatic_tool_installation.check_if_all_required_tools_are_installed()

    args = parse_arguments()

    # Normal check for the dependencies
    if len(sys.argv) != 1:
        automatic_tool_installation.check_if_all_required_tools_are_installed()

    add_user_paths_to_path_variable(args)

    if not args.allow_running_as_root:
        warn_if_user_is_root()

    cpp = True if args.cpp else False
    program_dir_abs = os.path.abspath(args.programdir)
    exclude = args.exclude[0] if args.exclude else None
    excluded_paths = util.get_excluded_paths(program_dir_abs, exclude)

    source_files = util.find_all_source_files(program_dir_abs, excluded_paths)
    lines_of_code = util.count_lines_of_code(source_files)

    compiler_and_sanitizer_score = compile_and_execute_program_with_sanitizers(
        args, lines_of_code, program_dir_abs, cpp, excluded_paths,
        args.no_execution)
    assertion_score, cppcheck_score, clang_tidy_score, cyclomatic_complexity_score, warning_score, \
        unique_score, kwstyle_score = static_analysis(source_files, lines_of_code, cpp)

    all_scores = [
        compiler_and_sanitizer_score, assertion_score, cppcheck_score,
        clang_tidy_score, cyclomatic_complexity_score, warning_score,
        unique_score, kwstyle_score
    ]
    overall_score = scoring.average_score(all_scores)
    scoring.print_score(overall_score, 'Overall program')
示例#7
0
def run_cppcheck(source_files, lines_of_code, cpp):
    """
    Runs cppcheck.
    :param source_files: The list of source files to analyze.
    :param lines_of_code: The lines of pure code count.
    :param cpp: Whether we're using C++ or not. True if C++ is used, False if C is used.
    :return: The Cppcheck score.
    """
    print(strings.RUN_CPPCHECK_HEADER)
    language = 'c++' if cpp else 'c'
    cppcheck_call = [TOOLS.CPPCHECK.exe_name, '--enable=all', '--force', '--language=' + language]
    cppcheck_call.extend(source_files)

    output = subprocess.check_output(cppcheck_call, universal_newlines=True, stderr=subprocess.STDOUT)
    warning_lines = get_cppcheck_warning_lines_from_cppcheck_output(output)
    cppcheck_output = output_classes.CppcheckOutput(warning_lines)

    weighted_cppcheck_rate = cppcheck_output.print_information(lines_of_code)
    util.write_into_file_list(strings.RESULTS_FILENAME_CPPCHECK, warning_lines)

    score = scoring.calculate_cppcheck_score(weighted_cppcheck_rate)
    scoring.print_score(score, 'Cppcheck')
    return score
示例#8
0
    def print_information_and_return_scores(self):
        print('Average cyclomatic complexity:',
              self.average_cyclomatic_complexity)
        cyclomatic_complexity_score = scoring.calculate_cyclomatic_complexity_score(
            self.average_cyclomatic_complexity)
        scoring.print_score(cyclomatic_complexity_score,
                            'Cyclomatic complexity')

        warning_rate = self.warning_count / self.function_count
        print(
            'Lizard warning rate (~= rate of functions that are too complex):',
            strings.RATE_COUNT_TOTAL.format(warning_rate, self.warning_count,
                                            self.function_count))
        warning_score = scoring.calculate_lizard_warning_score(warning_rate)
        scoring.print_score(warning_score, 'Lizard warning')

        print('Unique code rate:', self.unique_rate)
        unique_score = scoring.calculate_unique_score(self.unique_rate)
        scoring.print_score(unique_score, 'Unique (code duplication)')

        return cyclomatic_complexity_score, warning_score, unique_score
示例#9
0
def main():
    """
    Main function: Runs compilation, static analysis and prints results.
    """
    add_kwstyle_to_path_variable(
    )  # TODO: hopefully get a conda package for this sometime
    add_lizard_to_path_variable()

    # Allow the user to auto-install the dependencies by just running "./softwipe.py" without any arguments
    # Should not be needed if conda is used. TODO: maybe remove this
    if len(sys.argv) == 1:
        automatic_tool_installation.check_if_all_required_tools_are_installed()

    args = parse_arguments()

    for argument in sys.argv:
        print(argument, end=" ")
    print()

    # Normal check for the dependencies
    if len(sys.argv) != 1:
        automatic_tool_installation.check_if_all_required_tools_are_installed()

    # if args.use_infer:
    #    add_infer_to_path_variable()

    add_user_paths_to_path_variable(args)

    if not args.allow_running_as_root:
        warn_if_user_is_root()

    use_cpp = args.cpp
    use_cmake = args.cmake
    use_make = args.make
    program_dir_abs = os.path.abspath(args.programdir)
    exclude = args.exclude[0] if args.exclude else None
    exclude_file = args.X[0] if args.X else None
    excluded_paths = util.get_excluded_paths(program_dir_abs, exclude,
                                             exclude_file)
    custom_asserts = args.custom_assert[0].split(
        ',') if args.custom_assert else None

    source_files = util.find_all_source_files(program_dir_abs, excluded_paths)
    lines_of_code = util.count_lines_of_code(source_files)

    analysis_tools = [
    ]  # TODO: maybe add valgrind at some point if we get its error counts normalized somehow
    all_scores = []

    data = {
        "program_dir_abs": program_dir_abs,
        "args": args,
        "excluded_paths": excluded_paths,
        "use_cpp": use_cpp,
        "use_cmake": use_cmake,
        "use_make": use_make,
        "custom_asserts": custom_asserts,
        "source_files": source_files,
        "lines_of_code": lines_of_code,
        "executefile": args.executefile
    }

    if not args.exclude_compilation:
        compiler_and_sanitizer_score = compile_and_execute_program_with_sanitizers(
            args, lines_of_code, program_dir_abs, use_cpp, excluded_paths,
            args.no_execution)
        all_scores.append(compiler_and_sanitizer_score)
        if args.use_infer:  # TODO: maybe completely remove Infer since it requires a lot of disk space
            add_infer_to_path_variable()
            analysis_tools.append(InferTool)

    if not args.exclude_assertions:
        analysis_tools.append(AssertionTool)
    if not args.exclude_clang_tidy:
        analysis_tools.append(ClangTidyTool)
    if not args.exclude_cppcheck:
        analysis_tools.append(CppcheckTool)
    if not args.exclude_lizard:
        analysis_tools.append(LizardTool)
    if not args.exclude_kwstyle:
        analysis_tools.append(KWStyleTool)
    analysis_tools.append(TestCountTool)

    for tool in analysis_tools:
        scores, log, success = tool.run(data)
        if success:
            print(log)
            all_scores.extend(scores)
        else:
            print("excluded {} from analysis\n".format(tool.name()))

    overall_score = scoring.average_score(all_scores)

    scoring.print_score(overall_score, 'Overall program absolute')

    if args.add_badge:
        add_badge_to_file(args.add_badge[0], overall_score)
        print("Added badge to file {}".format(args.add_badge[0]))