Skip to content

Commit

Permalink
Merge branch 'master' into issue_528_2
Browse files Browse the repository at this point in the history
  • Loading branch information
aravij committed Jul 31, 2020
2 parents ad8e13d + 0382fdc commit 5ed91b5
Show file tree
Hide file tree
Showing 116 changed files with 3,877 additions and 1,923 deletions.
3 changes: 2 additions & 1 deletion .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
* text=auto eol=lf
*.java ident
*.xml ident
*.puml ident
*.png binary
*.rpm binary
*.jar binary
*.pkl binary
*.pkl binary
2 changes: 0 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,9 @@ build/
dist/
.coverage
venv/
aibolit/scripts/output
html
sphinx
.vscode/
models/
.ipynb_checkpoints/
.mypy_cache/
*.aux
Expand Down
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ unittest:

integrationtest:
python3 -m test.integration.all
python3 -m test.integration.test_model
./test/integration/test_recommend.sh

install:
Expand Down
33 changes: 30 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,20 @@
[![Maintainability](https://api.codeclimate.com/v1/badges/fd7e32d8472b4d5e8ecb/maintainability)](https://codeclimate.com/github/cqfn/aibolit/maintainability)
[![License](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/cqfn/aibolit/blob/master/LICENSE.txt)


## How it works?

Learn how Aibolit works in our [White Paper](https://github.com/cqfn/aibolit/releases/download/1.2.5-post.1/aibolit_wp.pdf).



## How to use ?

First, you install it (you must have [Python 3.7.7](https://www.python.org/downloads/)
and [Pip](https://pip.pypa.io/en/stable/installing/) installed):



```bash
$ pip3 install aibolit
```
Expand Down Expand Up @@ -242,10 +253,19 @@ $ aibolit recommend --help
2. Go to `cloned_aibolit_path`
3. Run `pip install .`
4. Set env variable `export HOME_AIBOLIT=cloned_aibolit_path` (example for Linux).
5. If you need to set up own directory where model will be saved, set up also `SAVE_MODEL_FOLDER` environment variable.
5. Set env variable `TARGET_FOLDER` if you need to save all dataset files to another directory.
6. You have to specify train and test dataset: set the `HOME_TRAIN_DATASET` environment variable
for train dataset and the `HOME_TEST_DATASET` environment variable for test dataset.
Usually, these files are in `scripts/target/08` directory after dataset collection (if you have not skipped it).
But you can use your own datasets.

Please notice, that if you set `TARGET_FOLDER`, your dataset files will be in `TARGET_FOLDER/target`.
That is why it is necessary to
set HOME_TRAIN_DATASET=`TARGET_FOLDER`\target\08\08-train.csv,
HOME_TEST_DATASET =`TARGET_FOLDER`\target\08\08-test.csv
7. If you need to set up own directory where model will be saved, set up also `SAVE_MODEL_FOLDER` environment variable.
Otherwise model will be saved into `cloned_aibolit_path/aibolit/binary_files/model.pkl`
6. If you need to set up own folder with Java files, use `--java_folder parameter`, the default value will be `scripts/target/01` of aibolit cloned repo
7. You need to install Java 13 and Maven
8. If you need to set up own folder with Java files, use `--java_folder parameter`, the default value will be `scripts/target/01` of aibolit cloned repo

Or you can use our docker image (link will be soon here)

Expand All @@ -261,6 +281,13 @@ If you need to save the dataset with all calculated metrics to a different direc
$ aibolit train --java_folder=src/java --dataset_file /mnt/d/new_dir/dataset.csv
```

You can skip dataset collection with `skip_collect_dataset` parameter. In this case
the model will be trained with predefined dataset (see 5 point):

```bash
$ aibolit train --java_folder=src/java --skip_collect_dataset
```

## How to contribute?

First, you need to install:
Expand Down
145 changes: 86 additions & 59 deletions aibolit/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
from aibolit.config import Config
from aibolit.ml_pipeline.ml_pipeline import train_process, collect_dataset
from aibolit.utils.ast_builder import build_ast
from javalang.parser import JavaSyntaxError

dir_path = os.path.dirname(os.path.realpath(__file__))

Expand All @@ -72,7 +73,7 @@ def predict(input_params, model, args):
# deepcode ignore ExpectsIntDislikesStr: false-positive recommendation of deepcode
input = [input_params[i] for i in features_order] + [input_params['M2']]
th = float(args.threshold) or 1.0
preds, importances = model.informative(input, th=th)
preds, importances = model.rank(input, th=th)

return {features_order[int(x)]: int(x) for x in preds}, list(importances)

Expand Down Expand Up @@ -259,7 +260,7 @@ def traverse(node):

def calculate_patterns_and_metrics(file, args):
code_lines_dict = input_params = {} # type: ignore
error_string = None
error_exc = None
patterns_to_suppress = args.suppress
try:
config = Config.get_patterns_config()
Expand All @@ -276,10 +277,10 @@ def calculate_patterns_and_metrics(file, args):
continue
__count_value(metric, input_params, code_lines_dict, file, is_metric=True)
except Exception as ex:
error_string = str(ex)
error_exc = ex
input_params = [] # type: ignore

return input_params, code_lines_dict, error_string
return input_params, code_lines_dict, error_exc


def inference(
Expand Down Expand Up @@ -331,63 +332,82 @@ def inference(
return results


def run_recommend_for_file(file: str, args):
def create_results(
input_params: List[int],
code_lines_dict: Dict[Any, Any],
args: argparse.Namespace,
classes_with_patterns_ignored: List[Any],
patterns_ignored: Dict[Any, Any]):
results_list = inference(input_params, code_lines_dict, args)
new_results: List[Any] = []
for pattern_item in results_list:
# check if the whole class is suppressed
if pattern_item['pattern_code'] not in classes_with_patterns_ignored:
# then check if patterns are ignored in fields or functions
add_pattern_if_ignored(patterns_ignored, pattern_item, new_results)
# add_pattern_if_ignored(patterns_for_fields_ignored, pattern_item, new_results)
else:
continue

return new_results


def run_recommend_for_file(file: str, args): # flake8: noqa
"""
Calculate patterns and metrics, pass values to model and suggest pattern to change
:param file: file to analyze
:param args: different command line arguments
:return: dict with code lines, filename and pattern name
"""
java_file = str(Path(os.getcwd(), file))
tree = build_ast(file)
classes_with_annonations = find_annotation_by_node_type(tree, javalang.tree.ClassDeclaration)
functions_with_annotations = find_annotation_by_node_type(tree, javalang.tree.MethodDeclaration)
fields_with_annotations = find_annotation_by_node_type(tree, javalang.tree.FieldDeclaration)
classes_with_patterns_ignored = flatten(
[pattern_code for node, pattern_code in classes_with_annonations.items()])
patterns_ignored = defaultdict(list)

for node, patterns_list in functions_with_annotations.items():
start_pos, end_pos = find_start_and_end_lines(node)
for p in patterns_list:
patterns_ignored[p].append([start_pos, end_pos])

for node, patterns_list in fields_with_annotations.items():
for p in patterns_list:
patterns_ignored[p].append([node.position.line, node.position.line])

input_params, code_lines_dict, error_string = calculate_patterns_and_metrics(java_file, args)

if not input_params:
results_list = [] # type: ignore
error_string = 'Empty java file; ncss = 0'
# deepcode ignore ExpectsIntDislikesStr: False positive
elif input_params['M2'] == 0:
results_list = [] # type: ignore
error_string = 'Empty java file; ncss = 0'
else:
results_list = inference(input_params, code_lines_dict, args)
new_results: List[Any] = []
for pattern_item in results_list:
# check if the whole class is suppressed
if pattern_item['pattern_code'] not in classes_with_patterns_ignored:
# then check if patterns are ignored in fields or functions
add_pattern_if_ignored(patterns_ignored, pattern_item, new_results)
# add_pattern_if_ignored(patterns_for_fields_ignored, pattern_item, new_results)
else:
continue

results_list = new_results

if error_string:
try:
tree = build_ast(file)
classes_with_annonations = find_annotation_by_node_type(tree, javalang.tree.ClassDeclaration)
functions_with_annotations = find_annotation_by_node_type(tree, javalang.tree.MethodDeclaration)
fields_with_annotations = find_annotation_by_node_type(tree, javalang.tree.FieldDeclaration)
classes_with_patterns_ignored = flatten(
[pattern_code for node, pattern_code in classes_with_annonations.items()])
patterns_ignored = defaultdict(list)

for node, patterns_list in functions_with_annotations.items():
start_pos, end_pos = find_start_and_end_lines(node)
for p in patterns_list:
patterns_ignored[p].append([start_pos, end_pos])

for node, patterns_list in fields_with_annotations.items():
for p in patterns_list:
patterns_ignored[p].append([node.position.line, node.position.line])

input_params, code_lines_dict, error_exception = calculate_patterns_and_metrics(java_file, args)

if not input_params:
results_list = [] # type: ignore
error_exception = 'Empty java file; ncss = 0'
# deepcode ignore ExpectsIntDislikesStr: False positive
elif input_params['M2'] == 0:
results_list = [] # type: ignore
error_exception = 'Empty java file; ncss = 0'
else:
results_list = create_results(
input_params,
code_lines_dict,
args,
classes_with_patterns_ignored,
patterns_ignored)

except Exception as e:
error_exception = e
results_list = []

if error_exception:
ncss = 0
else:
ncss = input_params.get('M4', 0)

return {
'filename': file,
'results': results_list,
'error_string': error_string,
'exception': error_exception,
'ncss': ncss,
}

Expand All @@ -411,7 +431,7 @@ def create_xml_tree(results, full_report, cmd, exit_code):
files_number_tag.addprevious(etree.Comment('Files with found patterns'))
files_number_tag.text = str(len(
[x for x in results
if (not x.get('error_string') and x.get('results'))]
if (not x.get('exception') and x.get('results'))]
))
patterns_number_tag = etree.SubElement(header_tag, 'patterns')
ncss_tag = etree.SubElement(header_tag, 'ncss')
Expand All @@ -433,7 +453,8 @@ def create_xml_tree(results, full_report, cmd, exit_code):
output_string_tag = etree.SubElement(file, 'summary')
name.text = filename
results_item = result_for_file.get('results')
errors_string = result_for_file.get('error_string')
ex = result_for_file.get('exception')
errors_string = str(result_for_file.get('exception')) or type(ex).__name__
if not results_item and not errors_string:
output_string = 'Your code is perfect in aibolit\'s opinion'
output_string_tag.text = output_string
Expand Down Expand Up @@ -486,15 +507,21 @@ def get_exit_code(results):
files_analyzed = len(results)
errors_number = 0
perfect_code_number = 0
errors_strings = []
for result_for_file in results:
results = result_for_file.get('results')
errors_string = result_for_file.get('error_string')
if not results and not errors_string:
ex = result_for_file.get('exception')
if not results and not ex:
perfect_code_number += 1
elif not results and errors_string:
errors_number += 1
elif not results and ex:
if not isinstance(ex, JavaSyntaxError):
errors_strings.append(ex)
errors_number += 1
else:
# ignore JavaSyntaxError, it is expected error
perfect_code_number += 1

if errors_number == files_analyzed:
if len(errors_strings) == files_analyzed:
# we have errors everywhere
exit_code = 2
elif perfect_code_number == files_analyzed:
Expand All @@ -518,17 +545,17 @@ def create_text(results, full_report, is_long=False):
for result_for_file in results:
filename = result_for_file.get('filename')
results_item = result_for_file.get('results')
errors_string = result_for_file.get('error_string')
if not results_item and not errors_string:
ex = result_for_file.get('exception')
if not results_item and not ex:
# Do nothing, patterns were not found
pass
if not results_item and errors_string:
if not results_item and ex:
output_string = '{}: error when calculating patterns: {}'.format(
filename,
str(errors_string)
str(ex) or type(ex).__name__
)
buffer.append(output_string)
elif results_item and not errors_string:
elif results_item and not ex:
# get unique patterns score
patterns_scores = print_total_score_for_file(buffer, filename, importances_for_all_classes, result_for_file)
patterns_number = len(patterns_scores)
Expand Down
7 changes: 7 additions & 0 deletions aibolit/ast_framework/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
from aibolit.ast_framework.ast_node_type import ASTNodeType # noqa: F401
from aibolit.ast_framework.ast_node import ASTNode # noqa: F401
from aibolit.ast_framework.ast import AST # noqa: F401

# register all standard computed fields from 'computed_fields_catalog'
from aibolit.ast_framework.computed_fields_catalog.standard_fields import (
register_standard_computed_properties,
)

register_standard_computed_properties()

1 comment on commit 5ed91b5

@0pdd
Copy link
Collaborator

@0pdd 0pdd commented on 5ed91b5 Jul 31, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wasn't able to retrieve PDD puzzles from the code base and submit them to GitHub. If you think that it's a bug on our side, please submit it to yegor256/0pdd:

set -x && set -e && set -o pipefail && cd /tmp/0pdd20200730-13-157q04g/cqfn/aibolit && pdd -v -f /tmp/20200731-6219-199ptjk [1]: + set -e + set -o pipefail + cd /tmp/0pdd20200730-13-157q04g/cqfn/aibolit + pdd -v -f /tmp/20200731-6219-199ptjk Found 10 lines in...

Please, copy and paste this stack trace to GitHub:

UserError
set -x && set -e && set -o pipefail && cd /tmp/0pdd20200730-13-157q04g/cqfn/aibolit && pdd -v -f /tmp/20200731-6219-199ptjk [1]:
+ set -e
+ set -o pipefail
+ cd /tmp/0pdd20200730-13-157q04g/cqfn/aibolit
+ pdd -v -f /tmp/20200731-6219-199ptjk

Found 10 lines in /tmp/0pdd20200730-13-157q04g/cqfn/aibolit/.pdd
My version is 0.20.5
Ruby version is 2.6.0 at x86_64-linux
Reading .
Excluding test/**/*
Excluding test/**/*
Excluding stubs/**/*
Excluding aibolit/metrics/halsteadvolume/target/**/*
Excluding scripts/target/**/*
227 file(s) found, 4316 excluded
/tmp/0pdd20200730-13-157q04g/cqfn/aibolit/aibolit/binary_files/halstead.jar is a binary file (10595980 bytes)
/tmp/0pdd20200730-13-157q04g/cqfn/aibolit/aibolit/binary_files/model.pkl is a binary file (16409229 bytes)
/tmp/0pdd20200730-13-157q04g/cqfn/aibolit/aibolit/binary_files/__init__.py is a binary file (0 bytes)
/tmp/0pdd20200730-13-157q04g/cqfn/aibolit/aibolit/utils/__init__.py is a binary file (0 bytes)
/tmp/0pdd20200730-13-157q04g/cqfn/aibolit/aibolit/ast_framework/computed_fields_catalog/__init__.py is a binary file (0 bytes)
/tmp/0pdd20200730-13-157q04g/cqfn/aibolit/aibolit/patterns/non_final_class/__init__.py is a binary file (0 bytes)
/tmp/0pdd20200730-13-157q04g/cqfn/aibolit/aibolit/patterns/array_as_argument/__init__.py is a binary file (0 bytes)
/tmp/0pdd20200730-13-157q04g/cqfn/aibolit/aibolit/patterns/private_static_method/__init__.py is a binary file (0 bytes)
/tmp/0pdd20200730-13-157q04g/cqfn/aibolit/aibolit/patterns/nested_blocks/__init__.py is a binary file (0 bytes)
/tmp/0pdd20200730-13-157q04g/cqfn/aibolit/aibolit/patterns/supermethod/__init__.py is a binary file (0 bytes)
/tmp/0pdd20200730-13-157q04g/cqfn/aibolit/aibolit/patterns/many_primary_ctors/__init__.py is a binary file (0 bytes)
/tmp/0pdd20200730-13-157q04g/cqfn/aibolit/aibolit/patterns/send_null/__init__.py is a binary file (0 bytes)
/tmp/0pdd20200730-13-157q04g/cqfn/aibolit/aibolit/patterns/method_siblings/__init__.py is a binary file (0 bytes)
/tmp/0pdd20200730-13-157q04g/cqfn/aibolit/aibolit/patterns/er_class/__init__.py is a binary file (0 bytes)
/tmp/0pdd20200730-13-157q04g/cqfn/aibolit/aibolit/patterns/assert_in_code/__init__.py is a binary file (0 bytes)
/tmp/0pdd20200730-13-157q04g/cqfn/aibolit/aibolit/patterns/public_static_method/__init__.py is a binary file (0 bytes)
/tmp/0pdd20200730-13-157q04g/cqfn/aibolit/aibolit/patterns/nested_loop/__init__.py is a binary file (0 bytes)
/tmp/0pdd20200730-13-157q04g/cqfn/aibolit/aibolit/patterns/protected_method/__init__.py is a binary file (0 bytes)
/tmp/0pdd20200730-13-157q04g/cqfn/aibolit/aibolit/patterns/non_final_argument/__init__.py is a binary file (0 bytes)
/tmp/0pdd20200730-13-157q04g/cqfn/aibolit/aibolit/patterns/bidirect_index/__init__.py is a binary file (0 bytes)
/tmp/0pdd20200730-13-157q04g/cqfn/aibolit/aibolit/patterns/mutable_index/__init__.py is a binary file (0 bytes)
/tmp/0pdd20200730-13-157q04g/cqfn/aibolit/aibolit/patterns/classic_setter/__init__.py is a binary file (0 bytes)
/tmp/0pdd20200730-13-157q04g/cqfn/aibolit/aibolit/patterns/non_final_attribute/__init__.py is a binary file (0 bytes)
/tmp/0pdd20200730-13-157q04g/cqfn/aibolit/aibolit/patterns/redundant_catch/__init__.py is a binary file (0 bytes)
/tmp/0pdd20200730-13-157q04g/cqfn/aibolit/aibolit/patterns/string_concat/__init__.py is a binary file (0 bytes)
/tmp/0pdd20200730-13-157q04g/cqfn/aibolit/aibolit/patterns/implements_multi/__init__.py is a binary file (0 bytes)
/tmp/0pdd20200730-13-157q04g/cqfn/aibolit/aibolit/patterns/empty_rethrow/__init__.py is a binary file (0 bytes)
/tmp/0pdd20200730-13-157q04g/cqfn/aibolit/aibolit/patterns/multiple_while/__init__.py is a binary file (0 bytes)
/tmp/0pdd20200730-13-157q04g/cqfn/aibolit/aibolit/patterns/multiple_try/__init__.py is a binary file (0 bytes)
/tmp/0pdd20200730-13-157q04g/cqfn/aibolit/aibolit/patterns/var_siblings/__init__.py is a binary file (0 bytes)
/tmp/0pdd20200730-13-157q04g/cqfn/aibolit/aibolit/patterns/loop_outsider/__init__.py is a binary file (0 bytes)
/tmp/0pdd20200730-13-157q04g/cqfn/aibolit/aibolit/patterns/var_decl_diff/__init__.py is a binary file (0 bytes)
/tmp/0pdd20200730-13-157q04g/cqfn/aibolit/aibolit/patterns/return_null/__init__.py is a binary file (0 bytes)
/tmp/0pdd20200730-13-157q04g/cqfn/aibolit/aibolit/patterns/force_type_casting_finder/__init__.py is a binary file (0 bytes)
/tmp/0pdd20200730-13-157q04g/cqfn/aibolit/aibolit/patterns/var_middle/__init__.py is a binary file (0 bytes)
/tmp/0pdd20200730-13-157q04g/cqfn/aibolit/aibolit/patterns/if_return_if_detection/__init__.py is a binary file (0 bytes)
/tmp/0pdd20200730-13-157q04g/cqfn/aibolit/aibolit/patterns/assign_null_finder/__init__.py is a binary file (0 bytes)
/tmp/0pdd20200730-13-157q04g/cqfn/aibolit/aibolit/patterns/instanceof/__init__.py is a binary file (0 bytes)
/tmp/0pdd20200730-13-157q04g/cqfn/aibolit/aibolit/patterns/null_check/__init__.py is a binary file (0 bytes)
/tmp/0pdd20200730-13-157q04g/cqfn/aibolit/aibolit/patterns/hybrid_constructor/__init__.py is a binary file (0 bytes)
/tmp/0pdd20200730-13-157q04g/cqfn/aibolit/aibolit/patterns/method_chaining/__init__.py is a binary file (0 bytes)
/tmp/0pdd20200730-13-157q04g/cqfn/aibolit/aibolit/patterns/joined_validation/__init__.py is a binary file (0 bytes)
/tmp/0pdd20200730-13-157q04g/cqfn/aibolit/aibolit/patterns/partial_synchronized/__init__.py is a binary file (0 bytes)
/tmp/0pdd20200730-13-157q04g/cqfn/aibolit/aibolit/metrics/local_methods_calls/__init__.py is a binary file (0 bytes)
/tmp/0pdd20200730-13-157q04g/cqfn/aibolit/aibolit/metrics/cognitiveC/__init__.py is a binary file (0 bytes)
/tmp/0pdd20200730-13-157q04g/cqfn/aibolit/aibolit/metrics/number_variables/__init__.py is a binary file (0 bytes)
/tmp/0pdd20200730-13-157q04g/cqfn/aibolit/aibolit/metrics/entropy/__init__.py is a binary file (0 bytes)
/tmp/0pdd20200730-13-157q04g/cqfn/aibolit/aibolit/metrics/maxDiameter/__init__.py is a binary file (0 bytes)
/tmp/0pdd20200730-13-157q04g/cqfn/aibolit/aibolit/metrics/external_methods_called/__init__.py is a binary file (0 bytes)
/tmp/0pdd20200730-13-157q04g/cqfn/aibolit/aibolit/metrics/spaces/__init__.py is a binary file (0 bytes)
/tmp/0pdd20200730-13-157q04g/cqfn/aibolit/aibolit/metrics/lcom4/__init__.py is a binary file (0 bytes)
/tmp/0pdd20200730-13-157q04g/cqfn/aibolit/aibolit/metrics/RFC/__init__.py is a binary file (0 bytes)
/tmp/0pdd20200730-13-157q04g/cqfn/aibolit/aibolit/metrics/loc/__init__.py is a binary file (0 bytes)
/tmp/0pdd20200730-13-157q04g/cqfn/aibolit/aibolit/metrics/fanout/__init__.py is a binary file (0 bytes)
/tmp/0pdd20200730-13-157q04g/cqfn/aibolit/aibolit/metrics/mda/__init__.py is a binary file (0 bytes)
/tmp/0pdd20200730-13-157q04g/cqfn/aibolit/aibolit/metrics/countLeaves/__init__.py is a binary file (0 bytes)
/tmp/0pdd20200730-13-157q04g/cqfn/aibolit/aibolit/metrics/cc/__init__.py is a binary file (0 bytes)
/tmp/0pdd20200730-13-157q04g/cqfn/aibolit/aibolit/ml_pipeline/__init__.py is a binary file (0 bytes)
/tmp/0pdd20200730-13-157q04g/cqfn/aibolit/wp/sections/motivation.tex is a binary file (1 bytes)
/tmp/0pdd20200730-13-157q04g/cqfn/aibolit/wp/sections/.gitkeep is a binary file (0 bytes)
/tmp/0pdd20200730-13-157q04g/cqfn/aibolit/wp/how_it_works_diagram_5.jpg is a binary file (71972 bytes)
/tmp/0pdd20200730-13-157q04g/cqfn/aibolit/wp/logo.png is a binary file (208813 bytes)
/tmp/0pdd20200730-13-157q04g/cqfn/aibolit/logo.png is a binary file (208813 bytes)
/tmp/0pdd20200730-13-157q04g/cqfn/aibolit/uml/recommendation_pipeline.png is a binary file (223568 bytes)
/tmp/0pdd20200730-13-157q04g/cqfn/aibolit/uml/train_pipeline.png is a binary file (167130 bytes)
/tmp/0pdd20200730-13-157q04g/cqfn/aibolit/uml/classes_diagram.png is a binary file (190488 bytes)
Reading appveyor.yml...
Reading .gitignore...
Reading README.md...
Reading .gitattributes...
Reading MANIFEST.in...
Reading .rultor.yml...
Reading aibolit/types_decl.py...
Reading aibolit/__main__.py...
Reading aibolit/utils/lines.py...
Reading aibolit/utils/utils.py...
Reading aibolit/utils/ast_builder.py...
Reading aibolit/utils/encoding_detector.py...
Reading aibolit/utils/java_parser.py...
Reading aibolit/utils/scope_status.py...
Reading aibolit/utils/cfg_builder.py...
Reading aibolit/utils/filter.py...
Reading aibolit/utils/cohesiongraph.py...
Reading aibolit/config.py...
Reading aibolit/model/model.py...
Reading aibolit/model/stats.py...
Reading aibolit/ast_framework/ast.py...
Reading aibolit/ast_framework/computed_fields_catalog/nodes_filter.py...
Reading aibolit/ast_framework/computed_fields_catalog/standard_fields.py...
Reading aibolit/ast_framework/computed_fields_catalog/chained_fields.py...
Reading aibolit/ast_framework/ast_node.py...
Reading aibolit/ast_framework/_auxiliary_data.py...
Reading aibolit/ast_framework/java_class.py...
Reading aibolit/ast_framework/java_package.py...
Reading aibolit/ast_framework/java_class_method.py...
Reading aibolit/ast_framework/java_class_decomposition.py...
Reading aibolit/ast_framework/computed_fields_registry.py...
Reading aibolit/ast_framework/ast_node_type.py...
Reading aibolit/ast_framework/__init__.py...
Reading aibolit/ast_framework/java_class_field.py...
Reading aibolit/patterns/non_final_class/non_final_class.py...
Reading aibolit/patterns/array_as_argument/array_as_argument.py...
Reading aibolit/patterns/private_static_method/private_static_method.py...
Reading aibolit/patterns/nested_blocks/nested_blocks.py...
Reading aibolit/patterns/nested_blocks/README.md...
Reading aibolit/patterns/supermethod/supermethod.py...
Reading aibolit/patterns/many_primary_ctors/many_primary_ctors.py...
Reading aibolit/patterns/send_null/send_null.py...
Reading aibolit/patterns/send_null/readme.md...
Reading aibolit/patterns/method_siblings/method_siblings.py...
Reading aibolit/patterns/er_class/er_class.py...
Reading aibolit/patterns/assert_in_code/assert_in_code.py...
Reading aibolit/patterns/public_static_method/public_static_method.py...
Reading aibolit/patterns/nested_loop/nested_loop.py...
Reading aibolit/patterns/protected_method/protected_method.py...
Reading aibolit/patterns/non_final_argument/NonFinalArgumentCtor.java...
Reading aibolit/patterns/non_final_argument/non_final_argument.py...
Puzzle 146-4f2084fc 30/DEV at aibolit/patterns/non_final_argument/non_final_argument.py
Reading aibolit/patterns/non_final_argument/NonFinalArgumentMethod.java...
Reading aibolit/patterns/bidirect_index/bidirect_index.py...
Puzzle 139-732b1bcc 30/DEV at aibolit/patterns/bidirect_index/bidirect_index.py
Reading aibolit/patterns/mutable_index/mutable_index.py...
Puzzle 147-d9d6862a 30/DEV at aibolit/patterns/mutable_index/mutable_index.py
Reading aibolit/patterns/classic_setter/classic_setter.py...
Reading aibolit/patterns/non_final_attribute/non_final_attribute.py...
Reading aibolit/patterns/redundant_catch/redundant_catch.py...
Reading aibolit/patterns/string_concat/string_concat.py...
Reading aibolit/patterns/implements_multi/implements_multi.py...
Reading aibolit/patterns/empty_rethrow/empty_rethrow.py...
Reading aibolit/patterns/multiple_while/multiple_while.py...
Reading aibolit/patterns/multiple_try/multiple_try.py...
Reading aibolit/patterns/var_siblings/var_siblings.py...
Reading aibolit/patterns/loop_outsider/loop_outsider.py...
Reading aibolit/patterns/var_decl_diff/README.md...
Reading aibolit/patterns/var_decl_diff/var_decl_diff.py...
Reading aibolit/patterns/return_null/return_null.py...
Reading aibolit/patterns/force_type_casting_finder/force_type_casting_finder.py...
Reading aibolit/patterns/var_middle/README.md...
Reading aibolit/patterns/var_middle/var_middle.py...
Reading aibolit/patterns/if_return_if_detection/if_detection.py...
Reading aibolit/patterns/assign_null_finder/assign_null_finder.py...
Reading aibolit/patterns/instanceof/instance_of.py...
Reading aibolit/patterns/null_check/null_check.py...
Reading aibolit/patterns/hybrid_constructor/hybrid_constructor.py...
Reading aibolit/patterns/__init__.py...
Reading aibolit/patterns/method_chaining/method_chaining.py...
Reading aibolit/patterns/joined_validation/joined_validation.py...
Reading aibolit/patterns/partial_synchronized/partial_synchronized.py...
Reading aibolit/metrics/local_methods_calls/local_methods_calls.py...
Puzzle 183-069e5295 30/DEV at aibolit/metrics/local_methods_calls/local_methods_calls.py
Reading aibolit/metrics/halsteadvolume/README.md...
Reading aibolit/metrics/halsteadvolume/pom.xml...
Reading aibolit/metrics/halsteadvolume/src/main/java/com/metrics/halstead/ASTVisitorMod.java...
Reading aibolit/metrics/halsteadvolume/src/main/java/com/metrics/halstead/App.java...
Reading aibolit/metrics/halsteadvolume/src/main/java/com/metrics/halstead/HalsteadMetrics.java...
Reading aibolit/metrics/cognitiveC/README.md...
Reading aibolit/metrics/cognitiveC/cognitive_c.py...
Reading aibolit/metrics/number_variables/numVariables.py...
Reading aibolit/metrics/number_variables/README.md...
Reading aibolit/metrics/npath/README.md...
Reading aibolit/metrics/npath/pom.xml...
Reading aibolit/metrics/npath/npath.xml...
Reading aibolit/metrics/npath/main.py...
Reading aibolit/metrics/npath/__init__.py...
Reading aibolit/metrics/hv/README.md...
Reading aibolit/metrics/hv/main.py...
Reading aibolit/metrics/hv/__init__.py...
Reading aibolit/metrics/entropy/README.md...
Reading aibolit/metrics/entropy/entropy.py...
Reading aibolit/metrics/maxDiameter/README.md...
Reading aibolit/metrics/maxDiameter/max_diam_of_tree.py...
Reading aibolit/metrics/external_methods_called/external_methods_called.py...
Puzzle 183-9b03d7d9 30/DEV at aibolit/metrics/external_methods_called/external_methods_called.py
Reading aibolit/metrics/spaces/SpaceCounter.py...
Reading aibolit/metrics/lcom4/lcom4.py...
Reading aibolit/metrics/RFC/rfc.py...
Reading aibolit/metrics/ncss/README.md...
Reading aibolit/metrics/ncss/ncss.py...
Reading aibolit/metrics/ncss/__init__.py...
Reading aibolit/metrics/loc/README.md...
Reading aibolit/metrics/loc/loc.py...
Reading aibolit/metrics/fanout/FanOut.py...
Reading aibolit/metrics/mda/mda.py...
Reading aibolit/metrics/__init__.py...
Reading aibolit/metrics/countLeaves/README.md...
Reading aibolit/metrics/countLeaves/numberofleaves.py...
Reading aibolit/metrics/cc/README.md...
Reading aibolit/metrics/cc/cyclical.xml...
Reading aibolit/metrics/cc/pom.xml...
Reading aibolit/metrics/cc/requirements.txt...
Reading aibolit/metrics/cc/main.py...
Reading aibolit/ml_pipeline/ml_pipeline.py...
Reading aibolit/__init__.py...
Reading wp/.gitignore...
Reading wp/references.bib...
Reading wp/.latexmkrc...
Reading wp/sections/usage_scenarios.tex...
Reading wp/sections/related_work.tex...
Reading wp/sections/how_aibolit_works.tex...
Reading wp/sections/conclusion.tex...
Reading wp/sections/pattern_emp_analysis.tex...
Reading wp/sections/appendix.tex...
Reading wp/sections/introduction.tex...
Reading wp/sections/threats_to_validity.tex...
Reading wp/Makefile...
Reading wp/wp.tex...
ERROR: wp/wp.tex; puzzle at line #62; TODO must have a leading space to become a puzzle, as this page explains: https://github.com/yegor256/pdd#how-to-format
If you can't understand the cause of this issue or you don't know how to fix it, please submit a GitHub issue, we will try to help you: https://github.com/yegor256/pdd/issues. This tool is still in its beta version and we will appreciate your feedback. Here is where you can find more documentation: https://github.com/yegor256/pdd/blob/master/README.md.
Exit code is 1

/app/objects/git_repo.rb:66:in `rescue in block in xml'
/app/objects/git_repo.rb:63:in `block in xml'
/app/vendor/ruby-2.6.0/lib/ruby/2.6.0/tempfile.rb:295:in `open'
/app/objects/git_repo.rb:62:in `xml'
/app/objects/puzzles.rb:36:in `deploy'
/app/objects/job.rb:38:in `proceed'
/app/objects/job_starred.rb:33:in `proceed'
/app/objects/job_recorded.rb:32:in `proceed'
/app/objects/job_emailed.rb:35:in `proceed'
/app/objects/job_commiterrors.rb:36:in `proceed'
/app/objects/job_detached.rb:48:in `exclusive'
/app/objects/job_detached.rb:36:in `block in proceed'
/app/objects/job_detached.rb:36:in `fork'
/app/objects/job_detached.rb:36:in `proceed'
/app/0pdd.rb:358:in `block in <top (required)>'
/app/vendor/bundle/ruby/2.6.0/gems/sinatra-2.0.4/lib/sinatra/base.rb:1635:in `call'
/app/vendor/bundle/ruby/2.6.0/gems/sinatra-2.0.4/lib/sinatra/base.rb:1635:in `block in compile!'
/app/vendor/bundle/ruby/2.6.0/gems/sinatra-2.0.4/lib/sinatra/base.rb:992:in `block (3 levels) in route!'
/app/vendor/bundle/ruby/2.6.0/gems/sinatra-2.0.4/lib/sinatra/base.rb:1011:in `route_eval'
/app/vendor/bundle/ruby/2.6.0/gems/sinatra-2.0.4/lib/sinatra/base.rb:992:in `block (2 levels) in route!'
/app/vendor/bundle/ruby/2.6.0/gems/sinatra-2.0.4/lib/sinatra/base.rb:1040:in `block in process_route'
/app/vendor/bundle/ruby/2.6.0/gems/sinatra-2.0.4/lib/sinatra/base.rb:1038:in `catch'
/app/vendor/bundle/ruby/2.6.0/gems/sinatra-2.0.4/lib/sinatra/base.rb:1038:in `process_route'
/app/vendor/bundle/ruby/2.6.0/gems/sinatra-2.0.4/lib/sinatra/base.rb:990:in `block in route!'
/app/vendor/bundle/ruby/2.6.0/gems/sinatra-2.0.4/lib/sinatra/base.rb:989:in `each'
/app/vendor/bundle/ruby/2.6.0/gems/sinatra-2.0.4/lib/sinatra/base.rb:989:in `route!'
/app/vendor/bundle/ruby/2.6.0/gems/sinatra-2.0.4/lib/sinatra/base.rb:1097:in `block in dispatch!'
/app/vendor/bundle/ruby/2.6.0/gems/sinatra-2.0.4/lib/sinatra/base.rb:1076:in `block in invoke'
/app/vendor/bundle/ruby/2.6.0/gems/sinatra-2.0.4/lib/sinatra/base.rb:1076:in `catch'
/app/vendor/bundle/ruby/2.6.0/gems/sinatra-2.0.4/lib/sinatra/base.rb:1076:in `invoke'
/app/vendor/bundle/ruby/2.6.0/gems/sinatra-2.0.4/lib/sinatra/base.rb:1094:in `dispatch!'
/app/vendor/bundle/ruby/2.6.0/gems/sinatra-2.0.4/lib/sinatra/base.rb:924:in `block in call!'
/app/vendor/bundle/ruby/2.6.0/gems/sinatra-2.0.4/lib/sinatra/base.rb:1076:in `block in invoke'
/app/vendor/bundle/ruby/2.6.0/gems/sinatra-2.0.4/lib/sinatra/base.rb:1076:in `catch'
/app/vendor/bundle/ruby/2.6.0/gems/sinatra-2.0.4/lib/sinatra/base.rb:1076:in `invoke'
/app/vendor/bundle/ruby/2.6.0/gems/sinatra-2.0.4/lib/sinatra/base.rb:924:in `call!'
/app/vendor/bundle/ruby/2.6.0/gems/sinatra-2.0.4/lib/sinatra/base.rb:913:in `call'
/app/vendor/bundle/ruby/2.6.0/gems/rack-protection-2.0.4/lib/rack/protection/xss_header.rb:18:in `call'
/app/vendor/bundle/ruby/2.6.0/gems/rack-protection-2.0.4/lib/rack/protection/path_traversal.rb:16:in `call'
/app/vendor/bundle/ruby/2.6.0/gems/rack-protection-2.0.4/lib/rack/protection/json_csrf.rb:26:in `call'
/app/vendor/bundle/ruby/2.6.0/gems/rack-protection-2.0.4/lib/rack/protection/base.rb:50:in `call'
/app/vendor/bundle/ruby/2.6.0/gems/rack-protection-2.0.4/lib/rack/protection/base.rb:50:in `call'
/app/vendor/bundle/ruby/2.6.0/gems/rack-protection-2.0.4/lib/rack/protection/frame_options.rb:31:in `call'
/app/vendor/bundle/ruby/2.6.0/gems/rack-2.0.6/lib/rack/logger.rb:15:in `call'
/app/vendor/bundle/ruby/2.6.0/gems/rack-2.0.6/lib/rack/common_logger.rb:33:in `call'
/app/vendor/bundle/ruby/2.6.0/gems/sinatra-2.0.4/lib/sinatra/base.rb:231:in `call'
/app/vendor/bundle/ruby/2.6.0/gems/sinatra-2.0.4/lib/sinatra/base.rb:224:in `call'
/app/vendor/bundle/ruby/2.6.0/gems/rack-2.0.6/lib/rack/head.rb:12:in `call'
/app/vendor/bundle/ruby/2.6.0/gems/rack-2.0.6/lib/rack/method_override.rb:22:in `call'
/app/vendor/bundle/ruby/2.6.0/gems/sinatra-2.0.4/lib/sinatra/base.rb:194:in `call'
/app/vendor/bundle/ruby/2.6.0/gems/sinatra-2.0.4/lib/sinatra/base.rb:1957:in `call'
/app/vendor/bundle/ruby/2.6.0/gems/sinatra-2.0.4/lib/sinatra/base.rb:1502:in `block in call'
/app/vendor/bundle/ruby/2.6.0/gems/sinatra-2.0.4/lib/sinatra/base.rb:1729:in `synchronize'
/app/vendor/bundle/ruby/2.6.0/gems/sinatra-2.0.4/lib/sinatra/base.rb:1502:in `call'
/app/vendor/bundle/ruby/2.6.0/gems/rack-2.0.6/lib/rack/handler/webrick.rb:86:in `service'
/app/vendor/ruby-2.6.0/lib/ruby/2.6.0/webrick/httpserver.rb:140:in `service'
/app/vendor/ruby-2.6.0/lib/ruby/2.6.0/webrick/httpserver.rb:96:in `run'
/app/vendor/ruby-2.6.0/lib/ruby/2.6.0/webrick/server.rb:307:in `block in start_thread'

Please sign in to comment.