You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
189 lines
6.4 KiB
189 lines
6.4 KiB
#!/usr/bin/env bash
|
|
|
|
# Copyright (C) 2020 The Android Open Source Project
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
|
|
set -e
|
|
|
|
# future considerations:
|
|
# - could we make this work with git-clang-format instead?
|
|
# - should we have our own formatter?
|
|
|
|
function _aidl-format() (
|
|
# Find .aidl-format file to use. The file is located in one of the parent
|
|
# directories of the source file
|
|
function find-aidl-format-style() {
|
|
local path="$1"
|
|
while [[ "$path" != / ]];
|
|
do
|
|
if find "$path" -maxdepth 1 -mindepth 1 -name .aidl-format | grep "."; then
|
|
return
|
|
fi
|
|
path="$(readlink -f "$path"/..)"
|
|
done
|
|
}
|
|
|
|
# Do a "reversible" conversion of the input file so that it is more friendly
|
|
# to clang-format. For example 'oneway interface Foo{}' is not recognized as
|
|
# an interface. Convert it to 'interface __aidl_oneway__ Foo{}'.
|
|
function prepare() {
|
|
# oneway interface Foo {} is not correctly recognized as an interface by
|
|
# clang-format. Change it to interface __aidl_oneway__ Foo {}.
|
|
sed -i -E 's/oneway[[:space:]]+interface/interface\ __aidl_oneway__/g' "$1"
|
|
|
|
# When a declaration becomes too long, clang-format splits the declaration
|
|
# into multiple lines. In doing so, annotations that are at the front of
|
|
# the declaration are always split. i.e.
|
|
#
|
|
# @utf8InCpp @nullable void foo(int looooooo....ong, int looo....ong);
|
|
#
|
|
# becomes
|
|
#
|
|
# @utf8InCpp
|
|
# @nullable
|
|
# void foo(int loooooo...ong,
|
|
# int looo.....ong);
|
|
#
|
|
# This isn't desirable for utf8InCpp and nullable annotations which are
|
|
# semantically tagged to the type, not the member (field/method). We want
|
|
# to have the annotations in the same line as the type that they actually
|
|
# annotate. i.e.
|
|
#
|
|
# @utf8InCpp @nullable void foo(int looo....ong,
|
|
# int looo.....ong);
|
|
#
|
|
# To do so, the annotations are temporarily replaced with tokens that are
|
|
# not annotations.
|
|
sed -i -E 's/@utf8InCpp/__aidl_utf8inCpp__/g' "$1"
|
|
sed -i -E 's/@nullable/__aidl_nullable__/g' "$1"
|
|
}
|
|
|
|
function apply-clang-format() {
|
|
local input="$1"
|
|
local style="$2"
|
|
local temp="$(mktemp)"
|
|
local styletext="$([ -f "$style" ] && cat "$style" | tr '\n' ',' 2> /dev/null)"
|
|
cat "$input" | clang-format \
|
|
--style='{BasedOnStyle: Google,
|
|
ColumnLimit: 100,
|
|
IndentWidth: 4,
|
|
ContinuationIndentWidth: 8, '"${styletext}"'}' \
|
|
--assume-filename=${input%.*}.java \
|
|
> "$temp"
|
|
mv "$temp" "$input"
|
|
}
|
|
|
|
# clang-format is good, but doesn't perfectly fit to our needs. Fix the
|
|
# minor mismatches manually.
|
|
function fixup() {
|
|
# Revert the changes done during the prepare call. Notice that the
|
|
# original tokens (@utf8InCpp, etc.) are shorter than the temporary tokens
|
|
# (__aidl_utf8InCpp, etc.). This can make the output text length shorter
|
|
# than the specified column limit. We can try to reduce the undesirable
|
|
# effect by keeping the tokens to have similar lengths, but that seems to
|
|
# be an overkill at this moment. We can revisit this when this becomes a
|
|
# real problem.
|
|
sed -i -E 's/interface\ __aidl_oneway__/oneway\ interface/g' "$1"
|
|
sed -i -E 's/__aidl_utf8inCpp__/@utf8InCpp/g' "$1"
|
|
sed -i -E 's/__aidl_nullable__/@nullable/g' "$1"
|
|
|
|
# clang-format adds space around "=" in annotation parameters. e.g.
|
|
# @Anno(a = 100). The following awk script removes the spaces back.
|
|
# @Anno(a = 1, b = 2) @Anno(c = 3, d = 4) int foo = 3; becomes
|
|
# @Anno(a=1, b=2) @Anno(c=3, d=4) int foo = 3;
|
|
# [^@,=] ensures that the match doesn't cross the characters, otherwise
|
|
# "a = 1, b = 2" would match only once and will become "a = 1, b=2".
|
|
gawk -i inplace \
|
|
'/@[^@]+\(.*=.*\)/ { # matches a line having @anno(param = val) \
|
|
print(gensub(/([^@,=]+) = ([^@,=]+)/, "\\1=\\2", "g", $0)); \
|
|
done=1;\
|
|
} \
|
|
{if (!done) {print($0);} done=0;}' "$1"
|
|
}
|
|
|
|
function format-one() {
|
|
local mode="$1"
|
|
local input="$2"
|
|
local style="$3"
|
|
local output="$(mktemp)"
|
|
|
|
cp "$input" "$output"
|
|
prepare "$output"
|
|
apply-clang-format "$output" "$style"
|
|
fixup "$output"
|
|
|
|
if [ $mode = "diff" ]; then
|
|
diff "$input" "$output" || (
|
|
echo "You can try to fix this by running:"
|
|
echo "$0 -w <file>"
|
|
echo ""
|
|
)
|
|
rm "$output"
|
|
elif [ $mode = "write" ]; then
|
|
if diff -q "$output" "$input" >/dev/null; then
|
|
rm "$output"
|
|
else
|
|
mv "$output" "$input"
|
|
fi
|
|
elif [ $mode = "print" ]; then
|
|
cat "$output"
|
|
rm "$output"
|
|
fi
|
|
}
|
|
|
|
function show-help-and-exit() {
|
|
echo "Usage: $0 [options] [path...]"
|
|
echo " -d: display diff instead of the formatted result"
|
|
echo " -w: rewrite the result back to the source file, instead of stdout"
|
|
echo " -h: show this help message"
|
|
echo " [path...]: source files. if none, input is read from stdin"
|
|
exit 1
|
|
}
|
|
|
|
local mode=print
|
|
if [ $# -gt 0 ]; then
|
|
case "$1" in
|
|
-d) mode=diff; shift;;
|
|
-w) mode=write; shift;;
|
|
-h) show-help-and-exit;;
|
|
-*) echo "$1" is wrong option; show-help-and-exit;;
|
|
esac
|
|
fi
|
|
|
|
if [ $# -lt 1 ]; then
|
|
if [ $mode = "write" ]; then
|
|
echo "-w not supported when input is stdin"
|
|
exit 1
|
|
fi
|
|
local input="$(mktemp)"
|
|
cat /dev/stdin > "$input"
|
|
local style="$(pwd)/.aidl-format"
|
|
format-one $mode "$input" "$style"
|
|
rm "$input"
|
|
else
|
|
for file in "$@"
|
|
do
|
|
if [ ! -f "$file" ]; then
|
|
echo "$file": no such file
|
|
exit 1
|
|
fi
|
|
local style="$(find-aidl-format-style $(dirname "$filename"))"
|
|
format-one $mode "$file" "$style"
|
|
done
|
|
fi
|
|
)
|
|
|
|
|
|
_aidl-format "$@"
|