OSS-forge/CodeQualityEval
12
1import json2import os3import re4import pandas as pd5from collections import Counter, defaultdict6 7# === CONFIG ===8REPORTS_DIR = "./reports" # folder with files report_*.json9ODC_MAPPING_FILE = "../2_ODC_Mapping/Mapping_PMD_ODC.xlsx" # mapping PMD rule -> ODC10EXCLUDED_RULES = {11 "AvoidDuplicateLiterals",12 "UseLocaleWithCaseConversions",13 "AbstractClassWithoutAbstractMethod", 14 "AccessorClassGeneration",15 "AbstractClassWithoutAnyMethod",16 "ClassWithOnlyPrivateConstructorsShouldBeFinal", 17 "DataClass",18 "GodClass", 19 "CloneMethodReturnTypeMustMatchClassName",20 "MethodWithSameNameAsEnclosingClass", 21 "MissingStaticMethodInNonInstantiatableClass", 22 "UseUtilityClass", 23 "LawOfDemeter", 24 "UnusedPrivateMethod", 25 "AvoidLiteralsInIfCondition"26}27 28# === Load mapping PMD -> ODC ===29mapping_df = pd.read_excel(ODC_MAPPING_FILE, engine="openpyxl")30odc_map = dict(zip(mapping_df["PMD Rule"], mapping_df["ODC Defect Type"]))31 32#input("Did you change the total size of the dataset?")33 34total_size = 100 # total number of samples in the dataset 35 36total_defects = 037odc_counter = Counter()38rule_counter = Counter()39unique_defective_files = set()40defects_by_file = defaultdict(list)41rules_by_odc = defaultdict(Counter)42 43# === NUOVE VARIABILI PER ERRORI ===44processing_errors = defaultdict(int)45error_types_count = Counter()46parse_exception_filenames = set()47priority_counter = Counter()48exception_regex = re.compile(r"(\w+Exception)")49 50# === PARSING FILES REPORT ===51for fname in os.listdir(REPORTS_DIR):52 if fname.startswith("report_") and fname.endswith(".json"):53 with open(os.path.join(REPORTS_DIR, fname)) as f:54 data = json.load(f)55 56 # === ERRORI DI PARSING ===57 if "processingErrors" in data:58 for error in data["processingErrors"]:59 processing_errors["total"] += 160 61 message = error.get("message", "")62 match = exception_regex.search(message)63 if match:64 error_type = match.group(1)65 error_types_count[error_type] += 166 67 if error_type == "ParseException":68 filename = error.get("filename")69 if filename:70 parse_exception_filenames.add(filename)71 72 73 for file_entry in data.get("files", []):74 filename = file_entry.get("filename")75 has_valid_defect = False76 77 for violation in file_entry.get("violations", []):78 rule = violation.get("rule")79 odc = odc_map.get(rule, "--")80 priority = violation.get("priority")81 if priority:82 priority_counter[priority] += 183 84 if rule in EXCLUDED_RULES:85 continue # skip excluded rules86 87 if odc != "--":88 total_defects += 189 odc_counter[odc] += 190 rule_counter[rule] += 191 defects_by_file[filename].append(odc)92 rules_by_odc[odc][rule] += 193 has_valid_defect = True94 95 if has_valid_defect:96 unique_defective_files.add(filename)97 98unique_instance_count = len(unique_defective_files)99average_defects_per_instance = total_defects / unique_instance_count if unique_instance_count else 0100 101print("\nPMD + ODC stats")102print("────────────────────────────")103print(f"Total number of samples: {total_size}")104print(f"Total number of defects: {total_defects}")105print(f"Total number of defective samples: {unique_instance_count} ({(unique_instance_count/total_size)*100:.2f}%)")106print(f"Average number of defects per sample: {average_defects_per_instance:.2f}")107print(f"Total number of samples with ParseException: {len(parse_exception_filenames)} ({(len(parse_exception_filenames)/total_size)*100:.2f}%)")108 109print("\nTotal defects divided per ODC Defect Type:")110for category, count in odc_counter.most_common():111 print(f" - {category}: {count}")112 113print("\nTop 10 defect:")114for rule, count in rule_counter.most_common(10):115 print(f" - {rule}: {count}")116 117print("\nDistribution of ODC Defect Types per sample:")118distribution = Counter(len(set(v)) for v in defects_by_file.values())119for num_cats, count in sorted(distribution.items()):120 print(f" - {count} samples in {num_cats} different ODC defect types")121 122print("\nDistrbution of defects per ODC Defect Type:")123for odc, rule_counter in rules_by_odc.items():124 print(f"\n {odc} ({sum(rule_counter.values())})")125 for rule, count in rule_counter.most_common():126 print(f" • {rule}: {count}")127 128print("\nDistribution of defects per priority (severity):")129for p, count in sorted(priority_counter.items()):130 print(f" - Priority {p}: {count}")131 132 