Skip to content

Commit

Permalink
wip(label-tool): Support applying and writing fixes back to the confi…
Browse files Browse the repository at this point in the history
…guration file
  • Loading branch information
whisperity committed Jul 9, 2024
1 parent f874563 commit 018f074
Show file tree
Hide file tree
Showing 5 changed files with 97 additions and 16 deletions.
71 changes: 71 additions & 0 deletions scripts/labels/checker_labels.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
from codechecker_common.checker_labels import split_label_kv

from .output import Settings as OutputSettings, error, trace
from . import fixit


# The raw label structure, as present verbatim in the configuration file.
Expand Down Expand Up @@ -222,6 +223,37 @@ def get_checker_labels_multiple(path: pathlib.Path) -> MultipleLabels:
}


def apply_label_fixes(labels: MultipleLabels,
fixes: fixit.FixMap) -> MultipleLabels:
"""
Applies the `FixAction`s in `fixes` to the `labels` structure, in place.
(Returns a reference to the input `labels` parameter.)
The `fixes` are applied in the order they appear in the input.
Consistency and order-independence of the resulting actions are **NOT**
verified by this function, please see `fixit.filter_conflicting_fixes`
for that.
"""
for checker, fix_actions in fixes.items():
checker_labels: KeySplitLabels = labels.get(checker, dict())

for fix in fix_actions:
if isinstance(fix, (fixit.ModifyLabelAction,
fixit.RemoveLabelAction)):
ok, ov = split_label_kv(cast(str, fix.old))
checker_labels[ok] = [
v_ for v_ in checker_labels.get(ok, list()) if v_ != ov]

if isinstance(fix, (fixit.AddLabelAction,
fixit.ModifyLabelAction)):
nk, nv = split_label_kv(cast(str, fix.new))
checker_labels[nk] = checker_labels.get(nk, list()) + [nv]

labels[checker] = checker_labels

return labels


def update_checker_labels(
analyser: str,
path: pathlib.Path,
Expand Down Expand Up @@ -285,3 +317,42 @@ def update_checker_labels(
label_cfg[checker] = sorted(checker_labels)

_save_json(path, config)


def update_checker_labels_multiple_overwrite(
analyser: str,
path: pathlib.Path,
labels: MultipleLabels
):
"""
Loads the checker config label file available at `path` and updates it to
reflect the **CONTENTS** of `labels`.
Entries in the file which do not have a corresponding key in `labels` are
left intact, but the labels for which **ANY** value exists in `labels` are
**OVERWRITTEN** as a single entity.
To mark a checker for **DELETION**, map it in `labels` to an explicit
`None`.
This method **DOES NOT** respect the ``label-tool-skip`` directives.
"""
try:
config = _load_json(path)
label_cfg = cast(_ConfigFileLabels, config[K_Labels])
except KeyError:
error("'%s's '%s' is not a label config file", analyser, path)
raise

for checker, kvs in labels.items():
if kvs is None:
try:
del label_cfg[checker]
except KeyError:
pass
continue

label_cfg[checker] = sorted({f"{k}:{v}"
for k, vs in kvs.items()
for v in vs
})

_save_json(path, config)
5 changes: 4 additions & 1 deletion scripts/labels/fixit.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
whether they can be applied cleanly.
"""
from itertools import groupby
from typing import List, Optional, Tuple
from typing import Dict, List, Optional, Tuple

from .util import remove_falsy_mapped

Expand Down Expand Up @@ -146,3 +146,6 @@ def filter_conflicting_fixes(fixes: List[FixAction]) \
safe_fixes))

return conflict_free, safe_fixes


FixMap = Dict[str, List[FixAction]]
27 changes: 17 additions & 10 deletions scripts/labels/invariant_check/tool/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,25 @@
# -------------------------------------------------------------------------
"""Implementation of the user-facing entry point to the script."""
import argparse
from copy import deepcopy
import fnmatch
import operator
import os
import pathlib
import sys
from typing import Dict, List, Optional, Set, Type
from typing import List, Optional, Type

from tabulate import tabulate

from codechecker_common.compatibility.multiprocessing import cpu_count
from codechecker_common.util import clamp

from ...checker_labels import SingleLabels, SkipDirectiveRespectStyle, \
get_checker_labels_multiple, update_checker_labels
from ...checker_labels import apply_label_fixes, \
get_checker_labels_multiple, update_checker_labels_multiple_overwrite
from ...codechecker import default_checker_label_dir
from ...exception import EngineError
from ...output import Settings as GlobalOutputSettings, \
error, log, trace, coloured, emoji
from ...util import merge_if_no_collision, plural
from ...util import plural
from ... import fixit
from ..output import Settings as OutputSettings
from ..rules import Base as RuleBase, rules_visible_to_user
Expand Down Expand Up @@ -303,11 +303,18 @@ def main(args: argparse.Namespace) -> Optional[int]:
analyser,
path)
try:
pass
# update_checker_labels(
# analyser, path, K_DocUrl, urls,
# SkipDirectiveRespectStyle.AsPassed,
# checkers_to_skip)
new_labels = apply_label_fixes(deepcopy(labels), fixes)
except Exception:
import traceback
traceback.print_exc()

error("Failed to fix-up checker labels for '%s'!",
analyser)
continue

try:
update_checker_labels_multiple_overwrite(
analyser, path, new_labels)
except Exception:
import traceback
traceback.print_exc()
Expand Down
4 changes: 2 additions & 2 deletions scripts/labels/invariant_check/tool/action.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,11 +99,11 @@ def run_check(pool: Pool,
rules: List[Type[RuleBase]],
labels: MultipleLabels) \
-> Tuple["Counter[str]", "Counter[str]", "Counter[str]",
Dict[str, List[fixit.FixAction]]]:
fixit.FixMap]:
count_oks: Counter[str] = Counter()
count_not_oks: Counter[str] = Counter()
count_fixes: Counter[str] = Counter()
fixes: Dict[str, List[fixit.FixAction]] = dict()
fixes: fixit.FixMap = dict()

def _consume_result(checker: str,
status: bool,
Expand Down
6 changes: 3 additions & 3 deletions scripts/labels/invariant_check/tool/tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from codechecker_common.compatibility.multiprocessing import Pool

from ...checker_labels import MultipleLabels
from ...fixit import FixAction, \
from ...fixit import FixAction, FixMap, \
AddLabelAction, RemoveLabelAction, ModifyLabelAction
from ...output import log, trace, emoji, coloured
from ...util import plural
Expand Down Expand Up @@ -86,7 +86,7 @@ def execute(analyser: str,
labels: MultipleLabels,
process_count: int) -> Tuple[ReturnFlags,
List[Statistics],
Dict[str, List[FixAction]]]:
FixMap]:
"""
Runs one instance of the verification pipeline, all selected invariants
for the checkers of an analyser.
Expand All @@ -96,7 +96,7 @@ def execute(analyser: str,
plural(process_count, "process", "processes"))
status = cast(ReturnFlags, 0)
stats: List[Statistics] = list()
fixes: Dict[str, List[FixAction]] = dict()
fixes: FixMap = dict()

with Pool(max_workers=process_count) as pool:
ok_rules, not_ok_rules, fixing_rules, fixes = \
Expand Down

0 comments on commit 018f074

Please sign in to comment.