blob: fcddd3f4cf591d87e4c0ae64c1f333470762bcd5 [file] [log] [blame]
Steven Moreland0d14f5b2020-12-23 22:48:23 +00001#!/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
17set -e
18
19# future considerations:
20# - could we make this work with git-clang-format instead?
21# - should we have our own formatter?
22
23function _aidl-format() (
24 if [ $# != 1 ]; then
25 echo "Usage: $0 <file/directory>"
26 exit 1
27 fi
28
29 local loc="$1"
30
31 local tmpfile="$tmpfile"
32
33 # Do a "reversible" conversion of the input file so that it is more friendly
34 # to clang-format. For example 'oneway interface Foo{}' is not recognized as
35 # an interface. Convert it to 'interface __aidl_oneway__ Foo{}'.
36 function prepare() {
37 # oneway interface Foo {} is not correctly recognized as an interface by
38 # clang-format. Change it to interface __aidl_oneway__ Foo {}.
39 sed -i -E 's/oneway[[:space:]]+interface/interface\ __aidl_oneway__/g' "$1"
40
41 # When a declaration becomes too long, clang-format splits the declaration
42 # into multiple lines. In doing so, annotations that are at the front of
43 # the declaration are always split. i.e.
44 #
45 # @utf8InCpp @nullable void foo(int looooooo....ong, int looo....ong);
46 #
47 # becomes
48 #
49 # @utf8InCpp
50 # @nullable
51 # void foo(int loooooo...ong,
52 # int looo.....ong);
53 #
54 # This isn't desirable for utf8InCpp and nullable annotations which are
55 # semantically tagged to the type, not the member (field/method). We want
56 # to have the annotations in the same line as the type that they actually
57 # annotate. i.e.
58 #
59 # @utf8InCpp @nullable void foo(int looo....ong,
60 # int looo.....ong);
61 #
62 # To do so, the annotations are temporarily replaced with tokens that are
63 # not annotations.
64 sed -i -E 's/@utf8InCpp/__aidl_utf8inCpp__/g' "$1"
65 sed -i -E 's/@nullable/__aidl_nullable__/g' "$1"
66 }
67
68 function apply-clang-format() {
69 local input="$1"
70 local temp="$(mktemp)"
71 cat "$input" | clang-format \
72 --style='{BasedOnStyle: Google, BreakAfterJavaFieldAnnotations: false, ColumnLimit: 100}' \
73 --assume-filename=${input%.*}.java \
74 > "$temp"
75 mv "$temp" "$input"
76 }
77
78 # clang-format is good, but doesn't perfectly fit to our needs. Fix the
79 # minor mismatches manually.
80 function fixup() {
81 # Revert the changes done during the prepare call. Notice that the
82 # original tokens (@utf8InCpp, etc.) are shorter than the temporary tokens
83 # (__aidl_utf8InCpp, etc.). This can make the output text length shorter
84 # than the specified column limit. We can try to reduce the undesirable
85 # effect by keeping the tokens to have similar lengths, but that seems to
86 # be an overkill at this moment. We can revisit this when this becomes a
87 # real problem.
88 sed -i -E 's/interface\ __aidl_oneway__/oneway\ interface/g' "$1"
89 sed -i -E 's/__aidl_utf8inCpp__/@utf8InCpp/g' "$1"
90 sed -i -E 's/__aidl_nullable__/@nullable/g' "$1"
91
92 # clang-format adds space around "=" in annotation parameters. e.g.
93 # @Anno(a = 100). The following awk script removes the spaces back.
94 # @Anno(a = 1, b = 2) @Anno(c = 3, d = 4) int foo = 3; becomes
95 # @Anno(a=1, b=2) @Anno(c=3, d=4) int foo = 3;
96 # [^@,=] ensures that the match doesn't cross the characters, otherwise
97 # "a = 1, b = 2" would match only once and will become "a = 1, b=2".
98 gawk -i inplace \
99 '/@[^@]+\(.*=.*\)/ { # matches a line having @anno(param = val) \
100 print(gensub(/([^@,=]+) = ([^@,=]+)/, "\\1=\\2", "g", $0)); \
101 done=1;\
102 } \
103 {if (!done) {print($0);} done=0;}' "$1"
104 }
105
106 function format-one() {
107 local input="$1"
108 local output="$(mktemp)"
109
110 cp "$input" "$output"
111 prepare "$output"
112 apply-clang-format "$output"
113 fixup "$output"
114
115 if diff -q "$output" "$input" >/dev/null; then
116 rm "$output"
117 else
118 mv "$output" "$input"
119 fi
120 }
121
122 while read -d '' aidl; do
123 format-one "$aidl"
124 done < <(find "$loc" -not -path "*/aidl_api/*" -type f -name '*.aidl' -print0)
125)
126
127_aidl-format "$@"