Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add PVN metrics #258

Merged
merged 3 commits into from Mar 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
72 changes: 55 additions & 17 deletions metrics/ast.py
Expand Up @@ -319,7 +319,28 @@ def annts(tlist: list[tuple[Any, javalang.tree.ClassDeclaration]]) -> int:
return len(tlist[0][1].annotations or [])


def varcomp(tlist: list[tuple[Any, javalang.tree.ClassDeclaration]]) -> float:
def _components_number(name: str) -> int:
"""Return number of parts in variable name.
Variables are split considering "$" and "_" symbols, snake_case and camelCase naming conventions.
r:type: int
"""
parts = 0
components = [comp for comp in re.split(r'[\$_]+', name) if comp != '']
for component in components:
parts += 1
prev_char = component[:1]
for char in component[1:]:
if prev_char.isdigit() != char.isdigit():
parts += 1
elif prev_char.islower() and char.isupper():
parts += 1
prev_char = char
if len(components) == 0:
parts += 1
return parts


def pvn(tlist: list[tuple[Any, javalang.tree.ClassDeclaration]]) -> float:
"""Return average number of parts in variable names in class.
r:type: float
"""
Expand All @@ -329,24 +350,37 @@ def varcomp(tlist: list[tuple[Any, javalang.tree.ClassDeclaration]]) -> float:
if (name := node.name) == '':
continue
variables += 1
# Java only allows "$" and "_" as special symbols in variable names.
# Split variable name by them to only count words and numbers.
components = [comp for comp in re.split(r'[\$_]+', name) if comp != '']
if len(components) == 0:
parts += 1
continue
for component in components:
parts += 1
prev_char = component[:1]
for char in component[1:]:
if prev_char.isdigit() != char.isdigit():
parts += 1
elif prev_char.islower() and char.isupper():
parts += 1
prev_char = char
parts += _components_number(name)
return (parts / variables) if variables != 0 else 0


def mxpvn(tlist: list[tuple[Any, javalang.tree.ClassDeclaration]]) -> int:
"""Return maximum number of parts in variable names in class.
r:type: int
"""
max_parts = 0
for _, node in tlist[0][1].filter(javalang.tree.VariableDeclarator):
if (name := node.name) == '':
continue
name_parts = _components_number(name)
max_parts = max(name_parts, max_parts)
return max_parts


def mnpvn(tlist: list[tuple[Any, javalang.tree.ClassDeclaration]]) -> int:
"""Return minimun number of parts in variable names in class.
r:type: int
"""
min_parts = 0
for _, node in tlist[0][1].filter(javalang.tree.VariableDeclarator):
if (name := node.name) == '':
continue
name_parts = _components_number(name)
if min_parts == 0 or name_parts < min_parts:
min_parts = name_parts
return min_parts


def pcn(tlist: list[tuple[Any, javalang.tree.ClassDeclaration]]) -> int:
"""Return number of words in the name of a class.
r:type: int
Expand Down Expand Up @@ -428,8 +462,12 @@ class NotClassError(Exception):
f'Class is ``final\'\' (1) or not (0)\n')
metric.write(f'noca {annts(tree_class)} '
f'Number of Class Annotations\n')
metric.write(f'varcomp {varcomp(tree_class)} '
metric.write(f'pvn {pvn(tree_class)} '
f'Average number of parts in variable names\n')
metric.write(f'mxpvn {mxpvn(tree_class)} '
f'Maximum number of parts in variable names\n')
metric.write(f'mnpvn {mnpvn(tree_class)} '
f'Minimum number of parts in variable names\n')
metric.write(f'pcn {pcn(tree_class)} '
f'Number of words in the name of a class\n')
metric.write(f'mhf {mhf(tree_class)} '
Expand Down
4 changes: 3 additions & 1 deletion tests/metrics/test-ast.sh
Expand Up @@ -48,7 +48,9 @@ stdout=$2
grep "notp 1 " "${temp}/stdout"
grep "final 1 " "${temp}/stdout"
grep "noca 1 " "${temp}/stdout"
grep "varcomp 2.75 " "${temp}/stdout"
grep "pvn 2.75 " "${temp}/stdout"
grep "mxpvn 6 " "${temp}/stdout"
grep "mnpvn 1 " "${temp}/stdout"
grep "pcn 1" "${temp}/stdout"
grep "mhf 1.0 " "${temp}/stdout"
grep "smhf 0 " "${temp}/stdout"
Expand Down
2 changes: 1 addition & 1 deletion tests/steps/test-measure-file.sh
Expand Up @@ -45,7 +45,7 @@ EOT
set -x
test "$(echo "${msg}" | grep -c "sum=0")" = 0
all=$(find "${temp}" -name 'm1.*' -type f -exec basename {} \; | sort)
expected=50
expected=52
actual=$(echo "${all}" | wc -l | xargs)
if [ ! "${actual}" = "${expected}" ]; then
echo "Exactly ${expected} metrics were expected, but ${actual} were actually collected"
Expand Down