|
|
|
@ -167,6 +167,15 @@ execute() {
|
|
|
|
|
echo "$(fixMissingUseStatements "$file")" > "$file"
|
|
|
|
|
fi
|
|
|
|
|
;;
|
|
|
|
|
ns | namespace)
|
|
|
|
|
checkCache
|
|
|
|
|
declare file="$1"
|
|
|
|
|
|
|
|
|
|
# Try the index, if that doesn't work, attempt to extract the namespace from the file itself.
|
|
|
|
|
if ! grep "(?<=$file:).*" "$NAMESPACE_FILE_PATHS"; then
|
|
|
|
|
grep -Po '(?<=^namespace[[:blank:]])[A-Za-z_\\]+' "$file"
|
|
|
|
|
fi
|
|
|
|
|
;;
|
|
|
|
|
cns | classes-in-namespace)
|
|
|
|
|
handleArguments classes-in-namespace "$@" || return $?
|
|
|
|
|
checkCache
|
|
|
|
@ -183,7 +192,7 @@ execute() {
|
|
|
|
|
grep -Po "^.*(?=:${CONFIG[$CLASS_PATH]//\\/\\\\}$)" "$FILE_PATHS"
|
|
|
|
|
;;
|
|
|
|
|
*)
|
|
|
|
|
printf 'Command "%s" is not a valid phpns command.\n' "$command" >&2
|
|
|
|
|
printf 'Command "%s" is not a valid subcommand.\n' "$command" >&2
|
|
|
|
|
exit 1
|
|
|
|
|
;;
|
|
|
|
|
esac
|
|
|
|
@ -191,7 +200,7 @@ execute() {
|
|
|
|
|
|
|
|
|
|
# shellcheck disable=SC2034
|
|
|
|
|
fixMissingUseStatements() {
|
|
|
|
|
declare check_uses='false' check_needs='false' file="$1"
|
|
|
|
|
declare check_uses='false' check_needs='false' file="$1" namespace="$2"
|
|
|
|
|
declare -A uses=() needs=() namespace=()
|
|
|
|
|
declare -a classes=()
|
|
|
|
|
|
|
|
|
@ -634,6 +643,7 @@ fillIndex() {
|
|
|
|
|
[[ -n $NAMESPACES ]] || return 1
|
|
|
|
|
[[ -n $USES ]] || return 1
|
|
|
|
|
[[ -n $USES_LOOKUP ]] || return 1
|
|
|
|
|
[[ -n $USES_LOOKUP_OWN ]] || return 1
|
|
|
|
|
[[ -n $FILE_PATHS ]] || return 1
|
|
|
|
|
[[ -n $NAMESPACE_FILE_PATHS ]] || return 1
|
|
|
|
|
[[ -n $INDEXED ]] || return 1
|
|
|
|
@ -723,4 +733,114 @@ checkCache() {
|
|
|
|
|
fi
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
##
|
|
|
|
|
# Find use statements and needed classes in a file.
|
|
|
|
|
|
|
|
|
|
findUsesAndNeeds() {
|
|
|
|
|
declare -p needs &>>/dev/null || return 1
|
|
|
|
|
declare -p uses &>>/dev/null || return 1
|
|
|
|
|
# shellcheck disable=SC2154
|
|
|
|
|
declare -p namespace &>>/dev/null || return 1
|
|
|
|
|
|
|
|
|
|
while read -r line; do
|
|
|
|
|
[[ $line == namespace* ]] && check_uses='true'
|
|
|
|
|
if [[ $line == ?(@(abstract|final) )@(class|interface|trait)* ]]; then
|
|
|
|
|
check_uses='false'
|
|
|
|
|
check_needs='true'
|
|
|
|
|
|
|
|
|
|
read -ra line_array <<<"$line"
|
|
|
|
|
set -- "${line_array[@]}"
|
|
|
|
|
while shift && [[ "$1" != @(extends|implements) ]]; do :; done;
|
|
|
|
|
while shift && [[ -n $1 ]]; do
|
|
|
|
|
[[ $1 == 'implements' ]] && shift
|
|
|
|
|
[[ $1 == \\* ]] || _set_needed_if_not_used "$1"
|
|
|
|
|
done
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
if $check_uses; then
|
|
|
|
|
if [[ $line == use* ]]; then
|
|
|
|
|
declare class_name="${line##*\\}"
|
|
|
|
|
[[ $class_name == *as* ]] && class_name="${class_name##*as }"
|
|
|
|
|
debug "Class name: $class_name"
|
|
|
|
|
class_name="${class_name%%[^a-zA-Z]*}"
|
|
|
|
|
uses["$class_name"]='used'
|
|
|
|
|
fi
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
if $check_needs; then
|
|
|
|
|
if [[ $line == *function*([[:space:]])*([[:alnum:]_])\(* ]]; then
|
|
|
|
|
_check_function_needs "$line"
|
|
|
|
|
continue
|
|
|
|
|
fi
|
|
|
|
|
_check_needs "$line"
|
|
|
|
|
fi
|
|
|
|
|
done
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_check_function_needs() {
|
|
|
|
|
# Strip everything up until function name and argument declaration.
|
|
|
|
|
declare line="${1#*function}" function_declaration="${1#*function}"
|
|
|
|
|
|
|
|
|
|
# Collect the entire argument declaration
|
|
|
|
|
while [[ $line != *'{'* ]] && read -r line; do
|
|
|
|
|
function_declaration="$function_declaration $line"
|
|
|
|
|
done
|
|
|
|
|
|
|
|
|
|
declare -a words=()
|
|
|
|
|
read -ra words <<<"$function_declaration"
|
|
|
|
|
for i in "${!words[@]}"; do
|
|
|
|
|
if [[ "${words[$i]}" =~ ^'$'[a-zA-Z_]+ ]]; then
|
|
|
|
|
declare prev_word="${words[$((i-1))]}"
|
|
|
|
|
if [[ $prev_word =~ ^([^\(]*\()?([A-Za-z]+)$ ]]; then
|
|
|
|
|
declare class_name="${BASH_REMATCH[2]}"
|
|
|
|
|
debugf 'Found parameter type "%s" for function "%s"\n' "$class_name" "$function_declaration"
|
|
|
|
|
_set_needed_if_not_used "$class_name"
|
|
|
|
|
fi
|
|
|
|
|
fi
|
|
|
|
|
done
|
|
|
|
|
if [[ "$function_declaration" =~ \):[[:space:]]+([a-zA-Z]+) ]]; then
|
|
|
|
|
declare class_name="${BASH_REMATCH[1]}"
|
|
|
|
|
debugf 'Found return type "%s" for function "%s"\n' "$class_name" "$function_declaration"
|
|
|
|
|
_set_needed_if_not_used "$class_name"
|
|
|
|
|
fi
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_check_needs() {
|
|
|
|
|
declare line="$1" match=''
|
|
|
|
|
if _line_matches "$line"; then
|
|
|
|
|
declare class_name="${match//[^a-zA-Z]/}"
|
|
|
|
|
|
|
|
|
|
debugf 'Extracted type "%s" from line "%s". Entire match: "%s"\n' "$class_name" "$line" "${BASH_REMATCH[0]}"
|
|
|
|
|
_set_needed_if_not_used "$class_name"
|
|
|
|
|
|
|
|
|
|
line="${line/"${BASH_REMATCH[0]/}"}"
|
|
|
|
|
_check_needs "$line"
|
|
|
|
|
fi
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# shellcheck disable=SC2049
|
|
|
|
|
_line_matches() {
|
|
|
|
|
if [[ $line =~ 'new'[[:space:]]+([^\\][A-Za-z]+)\( ]] \
|
|
|
|
|
|| [[ $line =~ 'instanceof'[[:space:]]+([A-Za-z]+) ]] \
|
|
|
|
|
|| [[ $line =~ catch[[:space:]]*\(([A-Za-z]+) ]] \
|
|
|
|
|
|| [[ $line =~ \*[[:blank:]]*@([A-Z][a-zA-Z]*) ]]; then
|
|
|
|
|
match="${BASH_REMATCH[1]}"
|
|
|
|
|
return $?
|
|
|
|
|
elif [[ $line =~ @(var|param|return|throws)[[:space:]]+([A-Za-z]+) ]] \
|
|
|
|
|
|| [[ $line =~ (^|[\(\[\{[:blank:]])([A-Za-z]+)'::' ]]; then
|
|
|
|
|
match="${BASH_REMATCH[2]}"
|
|
|
|
|
return $?
|
|
|
|
|
fi
|
|
|
|
|
return 1
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_set_needed_if_not_used() {
|
|
|
|
|
declare class_name="$1"
|
|
|
|
|
if [[ -z ${uses["$class_name"]} ]] \
|
|
|
|
|
&& [[ -z ${namespace["$class_name"]} ]] \
|
|
|
|
|
&& [[ "$class_name" != @(static|self|string|int|float|array|object|bool|mixed|parent|void) ]]; then
|
|
|
|
|
needs["$class_name"]='needed'
|
|
|
|
|
fi
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
execute "$@"
|
|
|
|
|