class FlattenScope {

    public static List<Node> flattenScope( TypeResolver typeResolver, Expression expressionWithScope ) {
        List<Node> res = new ArrayList<>();
        if (expressionWithScope instanceof FieldAccessExpr) {
            FieldAccessExpr fieldAccessExpr = (FieldAccessExpr) expressionWithScope;
            res.addAll(flattenScope( typeResolver, fieldAccessExpr.getScope() ));
            res.add(fieldAccessExpr.getName());
        } else if (expressionWithScope instanceof NullSafeFieldAccessExpr) {
            NullSafeFieldAccessExpr fieldAccessExpr = (NullSafeFieldAccessExpr) expressionWithScope;
            res.addAll(flattenScope( typeResolver, fieldAccessExpr.getScope() ));
            res.add(fieldAccessExpr.getName());
        } else if (expressionWithScope instanceof MethodCallExpr) {
            MethodCallExpr methodCallExpr = (MethodCallExpr) expressionWithScope;
            if (methodCallExpr.getScope().isPresent()) {
                Expression scope = methodCallExpr.getScope().get();
                if (isFullyQualifiedClassName( typeResolver, scope )) {
                    res.add(scope);
                } else {
                    res.addAll( flattenScope( typeResolver, scope ) );
                }
            }
            res.add(methodCallExpr);
        } else if (expressionWithScope instanceof NullSafeMethodCallExpr) {
            NullSafeMethodCallExpr methodCallExpr = (NullSafeMethodCallExpr) expressionWithScope;
            if (methodCallExpr.getScope().isPresent()) {
                res.addAll(flattenScope(typeResolver, methodCallExpr.getScope().orElseThrow(() -> new IllegalStateException("Scope expression is not present!"))));
            }
            res.add(methodCallExpr);
        } else if (expressionWithScope instanceof InlineCastExpr && ((InlineCastExpr) expressionWithScope).getExpression() instanceof FieldAccessExpr) {
            InlineCastExpr inlineCastExpr = (InlineCastExpr) expressionWithScope;
            Expression internalScope = ((FieldAccessExpr) inlineCastExpr.getExpression()).getScope();
            res.addAll(flattenScope( typeResolver, internalScope ));
            res.add(expressionWithScope);
        } else if (expressionWithScope instanceof ArrayAccessExpr) {
            ArrayAccessExpr arrayAccessExpr = (ArrayAccessExpr) expressionWithScope;
            res.addAll(flattenScope( typeResolver, arrayAccessExpr.getName()) );
            res.add(arrayAccessExpr);
        } else {
            res.add(expressionWithScope);
        }
        return res;
    }

    private  FlattenScope();

}