def calculate_scores(result_directory):
    # Init
    scores = {
        'compiler_and_sanitizer': {},
        'assertions': {},
        'cppcheck': {},
        'clang_tidy': {},
        'cyclomatic_complexity': {},
        'lizard_warnings': {},
        'unique': {},
        'kwstyle': {},
        'overall': {}
    }

    for score in scores:
        for folder in FOLDERS:
            scores[score][folder] = None

    # Get all the scores
    for folder in FOLDERS:
        # Get rates
        compiler_and_sanitizer_rate, assertion_rate, cppcheck_rate, clang_tidy_rate, ccn, lizard_rate, unique_rate, \
            kwstyle_rate = get_result_rates(result_directory, folder)

        # Get scores
        scores['compiler_and_sanitizer'][
            folder] = scoring.calculate_compiler_and_sanitizer_score(
                compiler_and_sanitizer_rate)
        scores['assertions'][folder] = scoring.calculate_assertion_score(
            assertion_rate)
        scores['cppcheck'][folder] = scoring.calculate_cppcheck_score(
            cppcheck_rate)
        scores['clang_tidy'][folder] = scoring.calculate_clang_tidy_score(
            clang_tidy_rate)
        scores['cyclomatic_complexity'][
            folder] = scoring.calculate_cyclomatic_complexity_score(ccn)
        scores['lizard_warnings'][
            folder] = scoring.calculate_lizard_warning_score(lizard_rate)
        scores['unique'][folder] = scoring.calculate_unique_score(unique_rate)
        scores['kwstyle'][folder] = scoring.calculate_kwstyle_score(
            kwstyle_rate)

        # Calculate the overall score
        list_of_scores = [
            scores[score][folder] for score in scores.keys()
            if score != 'overall'
        ]
        scores['overall'][folder] = scoring.average_score(list_of_scores)

    return scores
Exemple #2
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')
def calculate_scores(result_directory, absolute):
    # Init
    if absolute:
        scores = {
            'loc': {},
            'functions': {},
            'compiler': {},
            'sanitizer': {},
            'assertions': {},
            'cppcheck': {},
            'clang_tidy': {},
            'cyclomatic_complexity': {},
            'lizard_warnings': {},
            'unique': {},
            'kwstyle': {},
            'infer': {},
            TESTCOUNT_KEY: {}
        }
    else:
        scores = {
            'overall': {},
            'compiler_and_sanitizer': {},
            'assertions': {},
            'cppcheck': {},
            'clang_tidy': {},
            'cyclomatic_complexity': {},
            'lizard_warnings': {},
            'unique': {},
            'kwstyle': {},
            'infer': {},
            TESTCOUNT_KEY: {}
        }

    failed_tools_dict = {}

    for score in scores:
        for folder in FOLDERS:
            scores[score][folder] = None

    # Get all the scores
    for folder in FOLDERS:

        if absolute:
            # Get values
            loc, functions, compiler_warnings, sanitizer_warnings, assertions, cppcheck_warnings, clang_tidy_warnings, \
            ccn, lizard_warnings, unique, kwstyle_warnings, infer_warnings, test_count_loc, failed_tools = get_result_values(
                result_directory, folder)

            scores['loc'][folder] = loc
            scores['functions'][folder] = functions
            scores['compiler'][folder] = compiler_warnings
            scores['sanitizer'][folder] = sanitizer_warnings
            scores['assertions'][folder] = assertions
            scores['cppcheck'][folder] = cppcheck_warnings
            scores['clang_tidy'][folder] = clang_tidy_warnings
            scores['cyclomatic_complexity'][folder] = ccn
            scores['lizard_warnings'][folder] = lizard_warnings
            scores['unique'][folder] = unique
            scores['kwstyle'][folder] = kwstyle_warnings
            scores['infer'][folder] = infer_warnings
            scores[TESTCOUNT_KEY][folder] = test_count_loc

        else:
            # Get rates
            compiler_and_sanitizer_rate, assertion_rate, cppcheck_rate, clang_tidy_rate, ccn, lizard_rate, \
            unique_rate, kwstyle_rate, infer_rate, test_count_rate, failed_tools = get_result_rates(result_directory,
                                                                                                    folder)

            # Get scores
            if COMPILER_KEY not in failed_tools:
                scores['compiler_and_sanitizer'][folder] = \
                    scoring.calculate_compiler_and_sanitizer_score_absolute(compiler_and_sanitizer_rate)
            if ASSERTIONS_KEY not in failed_tools:
                scores['assertions'][
                    folder] = scoring.calculate_assertion_score_absolute(
                        assertion_rate)
            if CPPCHECK_KEY not in failed_tools:
                scores['cppcheck'][
                    folder] = scoring.calculate_cppcheck_score_absolute(
                        cppcheck_rate)
            if CLANG_TIDY_KEY not in failed_tools:
                scores['clang_tidy'][
                    folder] = scoring.calculate_clang_tidy_score_absolute(
                        clang_tidy_rate)
            if CYCLOMATIC_COMPLEXITY_KEY not in failed_tools:
                scores['cyclomatic_complexity'][
                    folder] = scoring.calculate_cyclomatic_complexity_score_absolute(
                        ccn)
            if LIZARD_WARNINGS_KEY not in failed_tools:
                scores['lizard_warnings'][
                    folder] = scoring.calculate_lizard_warning_score_absolute(
                        lizard_rate)
            if UNIQUE_KEY not in failed_tools:
                scores['unique'][
                    folder] = scoring.calculate_unique_score_absolute(
                        unique_rate)
            if KWSTYLE_KEY not in failed_tools:
                scores['kwstyle'][
                    folder] = scoring.calculate_kwstyle_score_absolute(
                        kwstyle_rate)
            if INFER_KEY not in failed_tools:
                scores['infer'][
                    folder] = scoring.calculate_infer_score_absolute(
                        infer_rate)
            if TESTCOUNT_KEY not in failed_tools:
                scores[TESTCOUNT_KEY][
                    folder] = scoring.calculate_testcount_score_absolute(
                        test_count_rate)

            # Calculate the overall score
            list_of_scores = [
                scores[score][folder] for score in scores.keys()
                if score != 'overall' and score not in failed_tools
            ]
            if None in list_of_scores: list_of_scores = []

            if list_of_scores:
                scores['overall'][folder] = scoring.average_score(
                    list_of_scores)
            else:
                scores['overall'][folder] = -1

        failed_tools_dict[folder] = failed_tools

    return scores, failed_tools_dict
Exemple #4
0
def main():
    file_path = sys.argv[1]
    space_pattern = [
        22, 9, 16, 24, 12, 10, 12, 23, 17, 8, 9, 7,
        len("test_count") + 2
    ]
    space_pattern_constant = [
        17, 8, 11, 10, 11, 12, 10, 12, 23, 17, 20, 9, 7,
        len("test_count") + 2
    ]

    scores = defaultdict()
    scores["compiler_and_sanitizer"] = {}
    scores["assertions"] = {}
    scores["cppcheck"] = {}
    scores["clang_tidy"] = {}
    scores["cyclomatic_complexity"] = {}
    scores["lizard_warnings"] = {}
    scores["unique"] = {}
    scores["kwstyle"] = {}
    scores["infer"] = {}
    scores["test_count"] = {}
    scores["overall"] = {}

    scores_absolute = defaultdict()
    scores_absolute["relative_score"] = {}
    scores_absolute["compiler_and_sanitizer"] = {}
    scores_absolute["assertions"] = {}
    scores_absolute["cppcheck"] = {}
    scores_absolute["clang_tidy"] = {}
    scores_absolute["cyclomatic_complexity"] = {}
    scores_absolute["lizard_warnings"] = {}
    scores_absolute["unique"] = {}
    scores_absolute["kwstyle"] = {}
    scores_absolute["infer"] = {}
    scores_absolute["test_count"] = {}
    scores_absolute["overall"] = {}

    rates = {
        'compiler_and_sanitizer': [],
        'assertions': [],
        'cppcheck': [],
        'clang_tidy': [],
        'cyclomatic_complexity': [],
        'lizard_warnings': [],
        'unique': [],
        'kwstyle': [],
        'infer': [],
        "test_count": []
    }

    d = defaultdict()
    d_absolute = defaultdict()
    constants = defaultdict()

    available_categories = {}

    # | program | overall | relative score | compiler_and_sanitizer | assertions | cppcheck | clang_tidy | cyclomatic_complexity | lizard_warnings | unique | kwstyle | infer |
    # | program | loc | functions | compiler | sanitizer | assertions | cppcheck | clang_tidy | cyclomatic_complexity | lizard_warnings | unique | kwstyle | infer |

    folder_included = []

    with open(file_path) as file:
        for line in file:
            line = line.rstrip().replace(" ", "").split("|")
            if len(line) < 15: continue

            skip_round = False
            for i in range(
                    1, 4
            ):  # if we can't even get the loc or function numbers, we just skip the tool
                if NA_SEQUENCE in line[i]: skip_round = True
            if skip_round: continue

            folder = line[1]
            loc = int(line[2])
            functions = int(line[3])
            compiler = int(line[4])
            sanitizer = int(line[5])

            if len(
                    line
            ) == 15:  # TODO: fix this, this was used to add a new category to the table
                line.append("")
                if not line[14]: line[14] = NA_SEQUENCE
            else:
                if folder in folder_included:
                    folder_included.remove(folder)  # update old value

            if folder in folder_included: continue
            folder_included.append(folder)

            available_categories[folder] = []

            # TODO: turn this pile of shame into elegant code someday
            if NA_SEQUENCE not in line[6]:
                assertions = int(line[6])
                assertion_rate = assertions / loc
                scores['assertions'][
                    folder] = scoring.calculate_assertion_score(assertion_rate)
                scores_absolute['assertions'][
                    folder] = scoring.calculate_assertion_score_absolute(
                        assertion_rate)
                available_categories[folder].append('assertions')
                rates['assertions'].append((folder, assertion_rate))

            if NA_SEQUENCE not in line[7]:
                cppcheck = int(line[7])
                cppcheck_rate = cppcheck / loc
                scores['cppcheck'][folder] = scoring.calculate_cppcheck_score(
                    cppcheck_rate)
                scores_absolute['cppcheck'][
                    folder] = scoring.calculate_cppcheck_score_absolute(
                        cppcheck_rate)
                available_categories[folder].append('cppcheck')
                rates['cppcheck'].append((folder, cppcheck_rate))

            if NA_SEQUENCE not in line[8]:
                clang_tidy = int(line[8])
                clang_tidy_rate = clang_tidy / loc
                scores['clang_tidy'][
                    folder] = scoring.calculate_clang_tidy_score(
                        clang_tidy_rate)
                scores_absolute['clang_tidy'][
                    folder] = scoring.calculate_clang_tidy_score_absolute(
                        clang_tidy_rate)
                available_categories[folder].append('clang_tidy')
                rates['clang_tidy'].append((folder, clang_tidy_rate))

            if NA_SEQUENCE not in line[9]:
                cyclomatic_complexity = float(line[9])
                ccn = cyclomatic_complexity
                scores['cyclomatic_complexity'][
                    folder] = scoring.calculate_cyclomatic_complexity_score(
                        ccn)
                scores_absolute['cyclomatic_complexity'][
                    folder] = scoring.calculate_cyclomatic_complexity_score_absolute(
                        ccn)
                available_categories[folder].append('cyclomatic_complexity')
                rates['cyclomatic_complexity'].append((folder, ccn))

            if NA_SEQUENCE not in line[10]:
                lizard_warnings = int(line[10])
                lizard_rate = lizard_warnings / functions
                scores['lizard_warnings'][
                    folder] = scoring.calculate_lizard_warning_score(
                        lizard_rate)
                scores_absolute['lizard_warnings'][
                    folder] = scoring.calculate_lizard_warning_score_absolute(
                        lizard_rate)
                available_categories[folder].append('lizard_warnings')
                rates['lizard_warnings'].append((folder, lizard_rate))

            if NA_SEQUENCE not in line[11]:
                unique = float(line[11])
                unique_rate = unique
                scores['unique'][folder] = scoring.calculate_unique_score(
                    unique_rate)
                scores_absolute['unique'][
                    folder] = scoring.calculate_unique_score_absolute(
                        unique_rate)
                available_categories[folder].append('unique')
                rates['unique'].append((folder, unique_rate))

            if NA_SEQUENCE not in line[12]:
                kwstyle = int(line[12])
                kwstyle_rate = kwstyle / loc
                scores['kwstyle'][folder] = scoring.calculate_kwstyle_score(
                    kwstyle_rate)
                scores_absolute['kwstyle'][
                    folder] = scoring.calculate_kwstyle_score_absolute(
                        kwstyle_rate)
                available_categories[folder].append('kwstyle')
                rates['kwstyle'].append((folder, kwstyle_rate))

            if NA_SEQUENCE not in line[13]:
                infer = int(line[13])
                infer_rate = infer / loc
                scores['infer'][folder] = scoring.calculate_infer_score(
                    infer_rate)
                scores_absolute['infer'][
                    folder] = scoring.calculate_infer_score_absolute(
                        infer_rate)
                available_categories[folder].append('infer')
                rates['infer'].append((folder, infer_rate))

            if NA_SEQUENCE not in line[14]:
                test_count = int(line[14])
                test_count_rate = test_count / loc
                scores['test_count'][
                    folder] = scoring.calculate_testcount_score(
                        test_count_rate)
                scores_absolute['test_count'][
                    folder] = scoring.calculate_testcount_score_absolute(
                        test_count_rate)
                available_categories[folder].append('test_count')
                rates['test_count'].append((folder, test_count_rate))

            compiler_and_sanitizer_rate = (compiler + sanitizer) / loc
            scores['compiler_and_sanitizer'][
                folder] = scoring.calculate_compiler_and_sanitizer_score(
                    compiler_and_sanitizer_rate)
            scores_absolute['compiler_and_sanitizer'][
                folder] = scoring.calculate_compiler_and_sanitizer_score_absolute(
                    compiler_and_sanitizer_rate)
            available_categories[folder].append('compiler_and_sanitizer')
            rates['compiler_and_sanitizer'].append(
                (folder, compiler_and_sanitizer_rate))

            list_of_scores = [
                scores[score][folder] for score in scores.keys()
                if score != 'overall' and score in available_categories[folder]
            ]
            scores['overall'][folder] = scoring.average_score(list_of_scores)

            scores_absolute['relative_score'][folder] = scores['overall'][
                folder]
            available_categories[folder].append('relative_score')

            list_of_scores = [
                scores_absolute[score][folder]
                for score in scores_absolute.keys()
                if score != 'overall' and score != 'relative_score'
                and score in available_categories[folder]
            ]
            scores_absolute['overall'][folder] = scoring.average_score(
                list_of_scores)

            d[folder] = scores['overall'][folder]
            d_absolute[folder] = scores_absolute['overall'][folder]

            constants[folder] = line[1:-1]

    sorted_list = sorted(d.items(), key=lambda x: x[1], reverse=True)
    sorted_list_absolute = sorted(d_absolute.items(),
                                  key=lambda x: x[1],
                                  reverse=True)

    sorted_list_constants = sorted(constants.items(),
                                   key=lambda x: int(x[1][1]),
                                   reverse=True)

    for (name, score) in sorted_list_constants:
        print("|", end="")
        counter = 0
        for index in constants[name]:
            print(" {}".format(index).ljust(space_pattern_constant[counter]),
                  end="|")
            counter += 1
        print()
    print()

    for (name, score) in sorted_list_absolute:
        score_absolute = scores_absolute['overall'][name]
        print("| {}".format(name).ljust(space_pattern[0]), end="|")
        print(" {}".format(round(score_absolute, 1)).ljust(space_pattern[1]),
              end="|")
        counter = 2

        for key in scores_absolute.keys():
            if key == 'overall': continue

            if key not in available_categories[name]:
                print((" " + NA_SEQUENCE).ljust(space_pattern[counter]),
                      end="|")
            else:
                print(" {0:0.1f}".format(round(scores_absolute[key][name],
                                               1)).ljust(
                                                   space_pattern[counter]),
                      end="|")
            counter += 1
        print()

    counter = 0
    rc_d_squared_sum = 0
    for (name, _) in sorted_list:
        counter2 = 0
        for (name2, _) in sorted_list_absolute:
            if name == name2:
                rc_d_squared_sum += (counter - counter2) * (counter - counter2)
            counter2 += 1
        counter += 1
    n = counter
    rc = 1 - (6 * rc_d_squared_sum / (n * (n * n - 1)))
    print("Rank correlation: {}".format(rc))

    sorted_rates = compare_results.sort_rates(rates)
    print()
    compare_results.print_best_rates(sorted_rates)
    compare_results.print_softwipe_scoring_values(sorted_rates)

    return 0
Exemple #5
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]))