xref: /llvm-project/mlir/utils/clang-tidy/apply-clang-tidy.sh (revision 377af8684734ce1ca73bb81f3e559ff87a95f7fe)
1#!/bin/bash -u
2
3if [[ $# -lt 2 || $# -gt 4 ]]; then
4  echo "Usage: $0 <build dir> <file or dir path> [rejects dir] [checks]"
5  echo " - <build dir> has to be a LLVM build directory (you should use CCACHE!)."
6  echo " - <file or dir path> is the path that contains the .cpp files to update."
7  echo " - [rejects dir] is a directory where rejected patch (build failure) will be stored."
8  echo " - [checks] is an optional space-separated list of check to use instead of auto-detecting"
9  echo " Also define the env var CLANG_TIDY the path to use for the clang-tidy binary (default to 'clang-tidy' in the PATH)"
10  echo " Also define the env var TIMING_TIDY to 'time' to prefix clang-tidy execution with it"
11  echo ""
12  echo "This tool will execute clang-tidy on every .cpp file in the provided path and"
13  echo "rerun the tests. On success, a commit is added to the repo for each individual"
14  echo "pair <clang-tidy check, file>."
15  exit 1
16fi
17BUILD_DIR=$1
18SRCS=$2
19REJECT_DIR=${3:-}
20PRESET_CHECKS=${4:-}
21SRC_DIR=$PWD
22if [[ -v CLANG_TIDY ]] && [[ ! -z "$CLANG_TIDY" ]] ; then
23  CLANG_TIDY=$(realpath $CLANG_TIDY)
24  if [[ ! -f "$CLANG_TIDY" ]]; then
25    echo "Invalid path '$CLANG_TIDY'"
26    exit 1
27  fi
28else
29  CLANG_TIDY=clang-tidy
30fi
31TIMING_TIDY=${TIMING_TIDY:-}
32echo "Using: '$CLANG_TIDY"
33
34if [[ ! -z "$REJECT_DIR" ]] && [[ ! -d "$REJECT_DIR" ]]; then
35  echo "Expects 'rejects dir' to be a directory, got '$REJECT_DIR'"
36  exit 1
37fi
38
39ensure_clean_build() {
40  git reset --hard HEAD
41  time ninja -C $BUILD_DIR check-mlir-build-only > ${REJECT_DIR}/ninja.clean.log 2>&1
42  if [[ $? != 0 ]] ; then
43    echo "-- Build failed on clean state, cleaning TableGen files and retry"
44    # Reinitialize the TableGen generated file to have a clean state
45    find $BUILD_DIR/tools/mlir/ | grep '\.inc' | while read file ; do rm $file ; done
46    time ninja -C $BUILD_DIR check-mlir-build-only > ${REJECT_DIR}/ninja.clean.log 2>&1
47    if [[ $? != 0 ]] ; then
48      echo "check-mlir-build-only failed on clean state! (see ninja.clean.log)"
49      git status
50      exit 1
51    fi
52  fi
53}
54
55tmpfile=$(mktemp /tmp/mhlo-temp-checks.XXXXXX)
56find $SRCS | grep ".cpp$" | sort | while read file ; do
57  echo "================================"
58  echo "======= Processing $file ======="
59  date
60  echo "================================"
61  CHECKS=
62  if [[ ! -z "$PRESET_CHECKS" ]]; then
63    CHECKS="$PRESET_CHECKS"
64  else
65    CHECKS=$($CLANG_TIDY $file -p $BUILD_DIR --list-checks \
66              | grep -v "Enabled checks:"  | grep -v "^$" \
67              | while read check ; do echo -n "${check} " ; done;)
68  fi
69  echo "-----------------------------------"
70  echo "-- Reset state before applying all checks on file $file"
71  ensure_clean_build
72
73  echo "-----------------------------------"
74  echo "-- Apply all checks on file $file"
75  echo "$TIMING_TIDY $CLANG_TIDY -p $BUILD_DIR $file -fix -fix-errors"
76  $TIMING_TIDY $CLANG_TIDY -p $BUILD_DIR $file -fix -fix-errors \
77    | grep "warning:.*\]$" | sed -r 's#.*\[(.*)]$#\1#' | sort -u > $tmpfile
78  git clang-format -f
79  if [[ $(git diff --stat) == '' ]]; then
80    echo 'Nothing was applied, skip'
81    continue
82  fi
83  echo "-----------------------------------"
84  echo "-- Got some diff, run one check at a time now"
85  cat $tmpfile | while read check ; do
86    echo "-----------------------------------"
87    echo "-- Reset state before applying check $check on file $file"
88    ensure_clean_build
89
90    echo "-----------------------------------"
91    echo "-- Apply check $check on file $file"
92    echo "$TIMING_TIDY $CLANG_TIDY -p $BUILD_DIR $file --checks="-*,$check" -fix -fix-errors"
93    { $TIMING_TIDY $CLANG_TIDY -p $BUILD_DIR $file --checks="-*,$check" -fix -fix-errors ; } 2>&1
94    git clang-format -f
95    if [[ $(git diff --stat) == '' ]]; then
96      echo 'Nothing was applied, skip'
97      continue
98    fi
99    echo "-----------------------------------"
100    echo "-- Test check $check on file $file"
101    # Clang-tidy sometimes update files in the build directory, erase the .inc file generate by tablegen
102    # to force them to be regenerated now.
103    find $BUILD_DIR/tools/mlir/ | grep '\.inc' | while read file ; do rm $file ; done
104    ninja -C $BUILD_DIR check-mlir > ${REJECT_DIR}/ninja.${check}.$(basename $file).log 2>&1
105    if [[ $? != 0 ]] ; then
106      echo "check-mlir failed! (see ninja.${check}.${file}.log)"
107      [[ ! -z "$REJECT_DIR" ]] && git diff > "${REJECT_DIR}/${check}_$(basename ${file}).reject.diff"
108      continue
109    fi
110    echo "-----------------------------------"
111    echo "-- Success, commit changes for check $check on file $file"
112    git clang-format -f
113
114    git commit -a -m "Apply clang-tidy fixes for $check in $(basename $file) (NFC)"
115  done
116done
117