Steven Moreland | 0d14f5b | 2020-12-23 22:48:23 +0000 | [diff] [blame] | 1 | #!/usr/bin/env bash |
| 2 | |
| 3 | # Copyright (C) 2020 The Android Open Source Project |
| 4 | # |
| 5 | # Licensed under the Apache License, Version 2.0 (the "License"); |
| 6 | # you may not use this file except in compliance with the License. |
| 7 | # You may obtain a copy of the License at |
| 8 | # |
| 9 | # http://www.apache.org/licenses/LICENSE-2.0 |
| 10 | # |
| 11 | # Unless required by applicable law or agreed to in writing, software |
| 12 | # distributed under the License is distributed on an "AS IS" BASIS, |
| 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 14 | # See the License for the specific language governing permissions and |
| 15 | # limitations under the License. |
| 16 | |
| 17 | set -e |
| 18 | |
| 19 | # future considerations: |
| 20 | # - could we make this work with git-clang-format instead? |
| 21 | # - should we have our own formatter? |
| 22 | |
| 23 | function _aidl-format() ( |
Steven Moreland | 0d14f5b | 2020-12-23 22:48:23 +0000 | [diff] [blame] | 24 | # Do a "reversible" conversion of the input file so that it is more friendly |
| 25 | # to clang-format. For example 'oneway interface Foo{}' is not recognized as |
| 26 | # an interface. Convert it to 'interface __aidl_oneway__ Foo{}'. |
| 27 | function prepare() { |
| 28 | # oneway interface Foo {} is not correctly recognized as an interface by |
| 29 | # clang-format. Change it to interface __aidl_oneway__ Foo {}. |
| 30 | sed -i -E 's/oneway[[:space:]]+interface/interface\ __aidl_oneway__/g' "$1" |
| 31 | |
| 32 | # When a declaration becomes too long, clang-format splits the declaration |
| 33 | # into multiple lines. In doing so, annotations that are at the front of |
| 34 | # the declaration are always split. i.e. |
| 35 | # |
| 36 | # @utf8InCpp @nullable void foo(int looooooo....ong, int looo....ong); |
| 37 | # |
| 38 | # becomes |
| 39 | # |
| 40 | # @utf8InCpp |
| 41 | # @nullable |
| 42 | # void foo(int loooooo...ong, |
| 43 | # int looo.....ong); |
| 44 | # |
| 45 | # This isn't desirable for utf8InCpp and nullable annotations which are |
| 46 | # semantically tagged to the type, not the member (field/method). We want |
| 47 | # to have the annotations in the same line as the type that they actually |
| 48 | # annotate. i.e. |
| 49 | # |
| 50 | # @utf8InCpp @nullable void foo(int looo....ong, |
| 51 | # int looo.....ong); |
| 52 | # |
| 53 | # To do so, the annotations are temporarily replaced with tokens that are |
| 54 | # not annotations. |
| 55 | sed -i -E 's/@utf8InCpp/__aidl_utf8inCpp__/g' "$1" |
| 56 | sed -i -E 's/@nullable/__aidl_nullable__/g' "$1" |
| 57 | } |
| 58 | |
| 59 | function apply-clang-format() { |
| 60 | local input="$1" |
| 61 | local temp="$(mktemp)" |
| 62 | cat "$input" | clang-format \ |
Jiyong Park | ce74598 | 2021-01-22 17:05:17 +0900 | [diff] [blame^] | 63 | --style='{BasedOnStyle: Google, |
| 64 | ColumnLimit: 100, |
| 65 | IndentWidth: 4, |
| 66 | ContinuationIndentWidth: 8}' \ |
Steven Moreland | 0d14f5b | 2020-12-23 22:48:23 +0000 | [diff] [blame] | 67 | --assume-filename=${input%.*}.java \ |
| 68 | > "$temp" |
| 69 | mv "$temp" "$input" |
| 70 | } |
| 71 | |
| 72 | # clang-format is good, but doesn't perfectly fit to our needs. Fix the |
| 73 | # minor mismatches manually. |
| 74 | function fixup() { |
| 75 | # Revert the changes done during the prepare call. Notice that the |
| 76 | # original tokens (@utf8InCpp, etc.) are shorter than the temporary tokens |
| 77 | # (__aidl_utf8InCpp, etc.). This can make the output text length shorter |
| 78 | # than the specified column limit. We can try to reduce the undesirable |
| 79 | # effect by keeping the tokens to have similar lengths, but that seems to |
| 80 | # be an overkill at this moment. We can revisit this when this becomes a |
| 81 | # real problem. |
| 82 | sed -i -E 's/interface\ __aidl_oneway__/oneway\ interface/g' "$1" |
| 83 | sed -i -E 's/__aidl_utf8inCpp__/@utf8InCpp/g' "$1" |
| 84 | sed -i -E 's/__aidl_nullable__/@nullable/g' "$1" |
| 85 | |
| 86 | # clang-format adds space around "=" in annotation parameters. e.g. |
| 87 | # @Anno(a = 100). The following awk script removes the spaces back. |
| 88 | # @Anno(a = 1, b = 2) @Anno(c = 3, d = 4) int foo = 3; becomes |
| 89 | # @Anno(a=1, b=2) @Anno(c=3, d=4) int foo = 3; |
| 90 | # [^@,=] ensures that the match doesn't cross the characters, otherwise |
| 91 | # "a = 1, b = 2" would match only once and will become "a = 1, b=2". |
| 92 | gawk -i inplace \ |
| 93 | '/@[^@]+\(.*=.*\)/ { # matches a line having @anno(param = val) \ |
| 94 | print(gensub(/([^@,=]+) = ([^@,=]+)/, "\\1=\\2", "g", $0)); \ |
| 95 | done=1;\ |
| 96 | } \ |
| 97 | {if (!done) {print($0);} done=0;}' "$1" |
| 98 | } |
| 99 | |
| 100 | function format-one() { |
Jiyong Park | 0b8c0b1 | 2021-01-20 17:26:08 +0900 | [diff] [blame] | 101 | local mode="$1" |
| 102 | local input="$2" |
| 103 | local output="$(mktemp)" |
Steven Moreland | 0d14f5b | 2020-12-23 22:48:23 +0000 | [diff] [blame] | 104 | |
Jiyong Park | 0b8c0b1 | 2021-01-20 17:26:08 +0900 | [diff] [blame] | 105 | cp "$input" "$output" |
| 106 | prepare "$output" |
| 107 | apply-clang-format "$output" |
| 108 | fixup "$output" |
Steven Moreland | 0d14f5b | 2020-12-23 22:48:23 +0000 | [diff] [blame] | 109 | |
Jiyong Park | 0b8c0b1 | 2021-01-20 17:26:08 +0900 | [diff] [blame] | 110 | if [ $mode = "diff" ]; then |
| 111 | diff "$input" "$output" |
| 112 | rm "$output" |
| 113 | elif [ $mode = "write" ]; then |
Steven Moreland | 0d14f5b | 2020-12-23 22:48:23 +0000 | [diff] [blame] | 114 | if diff -q "$output" "$input" >/dev/null; then |
| 115 | rm "$output" |
| 116 | else |
| 117 | mv "$output" "$input" |
| 118 | fi |
Jiyong Park | 0b8c0b1 | 2021-01-20 17:26:08 +0900 | [diff] [blame] | 119 | elif [ $mode = "print" ]; then |
| 120 | cat "$output" |
| 121 | rm "$output" |
| 122 | fi |
Steven Moreland | 0d14f5b | 2020-12-23 22:48:23 +0000 | [diff] [blame] | 123 | } |
| 124 | |
Jiyong Park | 0b8c0b1 | 2021-01-20 17:26:08 +0900 | [diff] [blame] | 125 | function show-help-and-exit() { |
| 126 | echo "Usage: $0 [options] [path...]" |
| 127 | echo " -d: display diff instead of the formatted result" |
| 128 | echo " -w: rewrite the result back to the source file, instead of stdout" |
| 129 | echo " -h: show this help message" |
| 130 | echo " [path...]: source files. if none, input is read from stdin" |
| 131 | exit 1 |
| 132 | } |
| 133 | |
| 134 | local mode=print |
| 135 | if [ $# -gt 0 ]; then |
| 136 | case "$1" in |
| 137 | -d) mode=diff; shift;; |
| 138 | -w) mode=write; shift;; |
| 139 | -h) show-help-and-exit;; |
| 140 | -*) echo "$1" is wrong option; show-help-and-exit;; |
| 141 | esac |
| 142 | fi |
| 143 | |
| 144 | if [ $# -lt 1 ]; then |
| 145 | if [ $mode = "write" ]; then |
| 146 | echo "-w not supported when input is stdin" |
| 147 | exit 1 |
| 148 | fi |
| 149 | local input="$(mktemp)" |
| 150 | cat /dev/stdin > "$input" |
| 151 | format-one $mode "$input" |
| 152 | rm "$input" |
| 153 | else |
| 154 | for file in "$@" |
| 155 | do |
| 156 | if [ ! -f "$file" ]; then |
| 157 | echo "$file": no such file |
| 158 | exit 1 |
| 159 | fi |
| 160 | format-one $mode "$file" |
| 161 | done |
| 162 | fi |
Steven Moreland | 0d14f5b | 2020-12-23 22:48:23 +0000 | [diff] [blame] | 163 | ) |
| 164 | |
| 165 | _aidl-format "$@" |