File: infer-and-annotate.sh

package info (click to toggle)
checker-framework-java 3.0.1%2Bds2-3
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 22,736 kB
  • sloc: java: 145,286; xml: 785; sh: 456; makefile: 401; perl: 26
file content (183 lines) | stat: -rwxr-xr-x 6,445 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
#!/bin/sh

# This script runs the Checker Framework's whole-program inference
# iteratively on a program, adding type annotations to the program, until the
# .jaif files from one iteration are the same as the .jaif files from the
# previous iteration (which means there is nothing new to infer anymore).

# To use this script, the $CHECKERFRAMEWORK variable must be set to the
# Checker Framework's directory. Also, the AFU's insert-annotations-to-source
# program must be on the search path (that is, in the PATH environment variable).

# This script receives as arguments:
# 0. Any number of cmd-line arguments to insert-annotations-to-source (optional).
# 1. Processor's name (in any form recognized by CF's javac -processor argument).
# 2. Classpath (target project's classpath).
# 3. Any number of extra processor arguments to be passed to the checker.
# 4. Any number of paths to .jaif files -- used as input (optional).
# 5. Any number of paths to .java files in a program.

# Example of usage:
# ./infer-and-annotate.sh "LockChecker,NullnessChecker" \
#     plume-util/build/libs/plume-util-all.jar \
#     `find plume-util/src/main/java/ -name "*.java"`

# In case of using this script for Android projects, the classpath must include
# paths to: android.jar, gen folder, all libs used, source code folder.
# The Android project must be built with "ant debug" before running this script.

# TODO: This script deletes all .unannotated files, including ones that could
# have been generated previously by another means other than using this script.
# We must decide if we want to make a backup of previously generated
# .unannotated files, or if we want to keep the first set of generated
# .unannotated files.

# Halts the script when a nonzero value is returned from a command.
set -e

# Path to directory that will contain .jaif files after running the CF
# with -Ainfer
WHOLE_PROGRAM_INFERENCE_DIR=build/whole-program-inference

# Path that will contain .class files after running CF's javac. This dir will
# be deleted after executing this script.
TEMP_DIR=build/temp-whole-program-inference-output

# Path to directory that will contain .jaif files from the previous iteration.
PREV_ITERATION_DIR=build/prev-whole-program-inference

debug=
interactive=
# For debugging
# debug=1
# Require user confirmation before running each command
# interactive=1

CHECKERBIN=$(dirname "$0")

# This function separates extra arguments passed to the checker from Java files
# received as arguments.
# TODO: Handle the following limitation: This function makes the assumption
# that every argument starts with a hyphen. It means one cannot pass arguments
# such as -processorpath and -source, which are followed by a value.
read_input() {

    # Collect command-line arguments that come before the preprocessor.
    # Assumes that every command line argument starts with a hyphen.
    insert_to_source_args=""
    for i in "$@"
    do
        case "$1" in
            -*)
                insert_to_source_args="$insert_to_source_args $1"
                shift
            ;;
            *)
                break
            ;;
        esac
    done

    # First two arguments are processor and cp.
    processor=$1
    cp=$2
    shift
    shift

    extra_args=""
    java_files=""
    jaif_files=""
    for i in "$@"
    do
        # This function makes the assumption that every extra argument
        # starts with a hyphen. The rest are .java/.jaif files.
        case "$1" in
            -*)
                extra_args="$extra_args $1"
            ;;
            *.jaif)
                jaif_files="$jaif_files $1"
            ;;
            *.java)
                java_files="$java_files $1"
            ;;
        esac
        shift
    done
}

# Iteratively runs the Checker
infer_and_annotate() {
    mkdir -p $TEMP_DIR
    DIFF_JAIF=firstdiff
    # Create/clean whole-program-inference directory.
    rm -rf $WHOLE_PROGRAM_INFERENCE_DIR
    mkdir -p $WHOLE_PROGRAM_INFERENCE_DIR
    # If there are .jaif files as input, copy them.
    for file in $jaif_files;
    do
        cp $file $WHOLE_PROGRAM_INFERENCE_DIR/
    done

    # Perform inference and add annotations from .jaif to .java files until
    # $PREV_ITERATION_DIR has the same contents as $WHOLE_PROGRAM_INFERENCE_DIR.
    while [ "$DIFF_JAIF" != "" ]
    do
        # Updates $PREV_ITERATION_DIR folder
        rm -rf $PREV_ITERATION_DIR
        mv $WHOLE_PROGRAM_INFERENCE_DIR $PREV_ITERATION_DIR
        mkdir -p $WHOLE_PROGRAM_INFERENCE_DIR

        # Runs CF's javac
        command="$CHECKERBIN/javac -d $TEMP_DIR/ -cp $cp -processor $processor -Ainfer -Awarns -Xmaxwarns 10000 $extra_args $java_files"
        echo "About to run: ${command}"
        if [ $interactive ]; then
            echo "Press any key to run command... "
            read _
        fi
        ${command} || true
        # Deletes .unannotated backup files. This is necessary otherwise the
        # insert-annotations-to-source tool will use this file instead of the
        # updated .java one.
        # See TODO about .unannotated file at the top of this file.
        for file in $java_files;
        do
            rm -f "${file}.unannotated"
        done
        if [ ! `find $WHOLE_PROGRAM_INFERENCE_DIR -prune -empty` ]
        then
            # Only insert annotations if there is at least one .jaif file.
            insert-annotations-to-source $insert_to_source_args -i `find $WHOLE_PROGRAM_INFERENCE_DIR -name "*.jaif"` $java_files
        fi
        # Updates DIFF_JAIF variable.
        # diff returns exit-value 1 when there are differences between files.
        # When this happens, this script halts due to the "set -e"
        # in its header. To avoid this problem, we add the "|| true" below.
        DIFF_JAIF="$(diff -qr $PREV_ITERATION_DIR $WHOLE_PROGRAM_INFERENCE_DIR || true)"
    done
    if [ ! $debug ]; then
        clean
    fi
}

clean() {
    # It might be good to keep the final .jaif files.
    # rm -rf $WHOLE_PROGRAM_INFERENCE_DIR
    rm -rf $PREV_ITERATION_DIR
    rm -rf $TEMP_DIR
    # See TODO about .unannotated file at the top of this file.
    for file in $java_files;
        do
            rm -f "${file}.unannotated"
    done
}

# Main
if [ "$#" -lt 3 ]; then
    echo "Aborting infer-and-annotate.sh: Expected at least 3 arguments, received $#."
    echo "Received the following arguments: $@"
    exit 1
fi

read_input "$@"
infer_and_annotate