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
|
#!/bin/bash
#
# Detects style errors in the C++ source code. Run this from the top directory
# (which has the subdirectories build, src and utils).
#
# The output may include colour codes if and only if standard output is a
# terminal.
#
# Several check commands are used:
# * grep with a set of regular expressions
# * whitespace_checker (with detect_spurious_indentation.py as an inferior
# fallback)
#
# Results are cached (there are separate caches for colour/nocolour). The
# check commands do not write directly to a file at the cahce file location
# because that could leave behind an incomplete cache file that is newer than
# the source file in case that the check commands are interrupted. Instead
# write the output from the check commands to a temporary file and when that
# file is complete, move it to the cache file location.
#
# Instead of storing empty cache files for source files that do not give any
# errors, a per-directory timestamp file is stored. This drastically reduces
# the number of cache files. The drawback is that if the script is interrupted
# whilst checking a sequence of files with equal mtime, it will have to start
# over with that sequence the next time it is executed. But reducing the
# number of cache files is worth that minor inconvenience.
CHECKER=utils/spurious_source_code/whitespace_checker
if [ ! -f $CHECKER ]; then
echo "WARNING: $CHECKER does not exist!"
echo "WARNING: Go to utils/spurious_source_code and build it with make!"
echo "WARNING: Else many checks will be done much slower or not at all!"
unset CHECKER
fi
# Make sure that several instances of this script running concurrently each
# have a separate temporary directory.
TMP_DIR=/tmp/spurious_source_code_detect.$PPID
rm -fr $TMP_DIR
mkdir $TMP_DIR || { echo "ERROR: could not create $TMP_DIR"; exit; }
REGEXPS_FILE=$TMP_DIR/regexps
for r in utils/spurious_source_code/regexps/*; do
[[ -d $r && ! -f $r/disabled && ( ! $CHECKER || ! -f $r/redundant_with_whitespace_checker ) ]] &&
cat $r/regexps >> $REGEXPS_FILE
done
[[ -t 1 ]] && COLOUR=.colourized || unset COLOUR
RESULT_FILE=$TMP_DIR/result
# Runs all checks on single source file. The result is written to
# $RESULT_FILE.
#
# Requirements on the result:
# * Error message lines must begin with <filename>:<linenumber> so that they
# can be parsed by tools like KDevelop.
# * Any colour codes produced by commands like "grep --colour" must be
# included if and only if $COLOUR is set.
#
# Parameters:
# $1
# The name of the source file to be checked.
function check {
egrep --with-filename --line-number $([ $COLOUR ] && echo --colour=always) -f $REGEXPS_FILE $1 > $RESULT_FILE
([[ $CHECKER ]] && $CHECKER $1 || utils/detect_spurious_indentation.py $1) >> $RESULT_FILE
}
CACHE_DIR="build/stylecheck"
# Detects errors recursively and stores the result in a cache. The cache
# content (if any) is echoed to standard output.
#
# If a cached entry exists and is not older than the source file, no checks
# are done on that source file.
#
# Calls itself recursively for each subdirectory. Then checks all the source
# files in the current directory that are newer than the timestamp file there.
# Files are checked in mtime order, oldest first. After checking group of
# files that have the same mtime, the timestamp is is set to that mtime.
#
# Parameters:
# $1
# The name of the directory to start the search and check in.
function detect {
mkdir -p $CACHE_DIR/$1
for d in $1/*; do
[[ -d $d ]] && detect $d
done
TIMESTAMP=$CACHE_DIR/$1/timestamp
PREVIOUS_FILE=$1
for f in $(ls -tr $1/*.h $1/*.cc 2>/dev/null); do
CACHE_BASE=$CACHE_DIR/$f.stylecheck
CACHE_COLOUR=$CACHE_BASE.colourized
CACHE=$CACHE_BASE$COLOUR
if [[ $f -nt $TIMESTAMP || -s $CACHE_BASE || -s $CACHE_COLOUR ]]; then
if [ $f -nt $CACHE ]; then
echo "Checking for errors in $f ..."
check $f
if [ -s $RESULT_FILE ]; then
mv $RESULT_FILE $CACHE
[[ $f -nt $PREVIOUS_FILE && $PREVIOUS_FILE -nt $TIMESTAMP ]] &&
touch --reference=$PREVIOUS_FILE $TIMESTAMP
cat $CACHE
else
rm -f $CACHE_BASE $CACHE_COLOUR
fi
else
echo "Showing cached errors in $f ..."
cat $CACHE
fi
fi
PREVIOUS_FILE=$f
done
[[ $PREVIOUS_FILE -nt $TIMESTAMP ]] &&
touch --reference=$PREVIOUS_FILE $TIMESTAMP
}
detect src
rm -fr $TMP_DIR
|