Skip to content

Significant formatting change in checkstyle 10.24.0+ #17163

@wendigo

Description

@wendigo

I have read check documentation: https://checkstyle.org/checks/xxxxxx/nameofaffectedcheck.html
I have downloaded the latest checkstyle from: https://checkstyle.org/cmdline.html#Download_and_Run
I have executed the cli and showed it below, as cli describes the problem better than 1,000 words

/var/tmp $ javac YOUR_FILE.java


/var/tmp $ cat config.xml
<module name="FileTabCharacter" />
<module name="NewlineAtEndOfFile">
    <property name="lineSeparator" value="lf" />
</module>
<module name="RegexpMultiline">
    <property name="format" value="\r" />
    <property name="message" value="Line contains carriage return" />
</module>
<module name="RegexpMultiline">
    <property name="format" value=" \n" />
    <property name="message" value="Line has trailing whitespace" />
</module>
<module name="RegexpMultiline">
    <property name="format" value="\n\n\n" />
    <property name="message" value="Multiple consecutive blank lines" />
</module>
<module name="RegexpMultiline">
    <property name="format" value="\n\n\Z" />
    <property name="message" value="Blank line before end of file" />
</module>

<module name="RegexpMultiline">
    <property name="format" value="\{\n\n" />
    <property name="message" value="Blank line after opening brace" />
</module>
<module name="RegexpMultiline">
    <property name="format" value="\n\n\s*\}" />
    <property name="message" value="Blank line before closing brace" />
</module>
<module name="RegexpMultiline">
    <property name="format" value="[^;]\s\)+\s*[\{;,]?\s*\n" />
    <property name="message" value="Whitespace character before closing parenthesis" />
</module>
<module name="RegexpMultiline">
    <property name="format" value="->\s*\{\s+\}" />
    <property name="message" value="Whitespace inside empty lambda body" />
</module>
<module name="RegexpMultiline">
    <property name="format" value="->(\s*+(//.*+)?\n)++\s*+\{" />
    <property name="message" value="Lambda opening brace should be on the same line as ->" />
</module>

<module name="RegexpSingleline">
    <property name="format" value="^import static .*\.(of|copyOf|valueOf|builder);$" />
    <property name="message" value="The following methods may not be statically imported: of, copyOf, valueOf, builder" />
</module>
<module name="RegexpSingleline">
    <property name="format" value="^import static (?!java\.lang\.String\.format;).*\.format;" />
    <property name="message" value="Only 'format' from java.lang.String may be statically imported" />
</module>
<module name="RegexpSingleline">
    <property name="format" value="^import static java\.util\.Optional\." />
    <property name="message" value="Members of Optional may not be statically imported" />
</module>

<module name="RegexpSingleline">
    <property name="format" value="^(?!import ).*Objects\.requireNonNull" />
    <property name="message" value="Objects.requireNonNull should only be used with static imports" />
</module>
<module name="RegexpSingleline">
    <property name="format" value="^(?!import ).*Math\.toIntExact" />
    <property name="message" value="Math.toIntExact should only be used with static imports" />
</module>
<module name="RegexpSingleline">
    <property name="format" value="^(?!import ).*ImmutableMap\.toImmutableMap" />
    <property name="message" value="ImmutableMap.toImmutableMap should only be used with static imports" />
</module>
<module name="RegexpSingleline">
    <property name="format" value="^(?!import ).*ImmutableList\.toImmutableList" />
    <property name="message" value="ImmutableList.toImmutableList should only be used with static imports" />
</module>
<module name="RegexpSingleline">
    <property name="format" value="^(?!import ).*ImmutableSet\.toImmutableSet" />
    <property name="message" value="ImmutableSet.toImmutableSet should only be used with static imports" />
</module>
<module name="RegexpMultiline">
    <property name="format" value="^[ \t]*import org\.testng\.Assert;$" />
    <property name="message" value="org.testng.Assert should only be used with static imports" />
</module>
<module name="RegexpMultiline">
    <property name="format" value="^[ \t]*import com\.google\.common\.base\.MoreObjects;$" />
    <property name="message" value="com.google.common.base.MoreObjects should only be used with static imports" />
</module>
<module name="RegexpMultiline">
    <property name="format" value="^[ \t]*import com\.google\.common\.base\.Preconditions;$" />
    <property name="message" value="com.google.common.base.Preconditions should only be used with static imports" />
</module>
<module name="RegexpMultiline">
    <property name="format" value="^[ \t]*import com\.google\.common\.base\.Verify;$" />
    <property name="message" value="com.google.common.base.Verify should only be used with static imports" />
</module>

<module name="SuppressWarningsFilter" />

<module name="TreeWalker">
    <module name="SuppressWarningsHolder" />

    <module name="SuppressionXpathSingleFilter">
        <property name="checks" value="RedundantModifier"/>
        <property name="query" value="//(CLASS_DEF|RECORD_DEF)/OBJBLOCK/*/MODIFIERS/*"/>
    </module>
    <module name="RedundantModifier" />

    <module name="EmptyBlock">
        <property name="option" value="text" />
        <property name="tokens" value="
            LITERAL_DO, LITERAL_ELSE, LITERAL_FINALLY, LITERAL_IF,
            LITERAL_FOR, LITERAL_TRY, LITERAL_WHILE, INSTANCE_INIT, STATIC_INIT" />
    </module>
    <module name="EmptyStatement" />
    <module name="EmptyForInitializerPad" />
    <module name="EmptyForIteratorPad">
        <property name="option" value="space" />
    </module>
    <module name="MethodParamPad">
        <property name="allowLineBreaks" value="true" />
        <property name="option" value="nospace" />
    </module>
    <module name="ParenPad" />
    <module name="TypecastParenPad" />
    <module name="NeedBraces" />
    <module name="LeftCurly">
        <property name="option" value="nl" />
        <property name="tokens" value="CLASS_DEF, CTOR_DEF, INTERFACE_DEF, METHOD_DEF, RECORD_DEF" />
    </module>
    <module name="LeftCurly">
        <property name="option" value="eol" />
        <property name="tokens" value="
             LITERAL_CATCH, LITERAL_DO, LITERAL_ELSE, LITERAL_FINALLY, LITERAL_FOR,
             LITERAL_IF, LITERAL_SWITCH, LITERAL_SYNCHRONIZED, LITERAL_TRY, LITERAL_WHILE" />
    </module>
    <module name="RightCurly">
        <property name="option" value="alone" />
    </module>
    <module name="EmptyLineSeparator">
        <property name="allowNoEmptyLineBetweenFields" value="true" />
        <property name="tokens" value="
            IMPORT, STATIC_IMPORT, CLASS_DEF, INTERFACE_DEF, ENUM_DEF, RECORD_DEF,
            STATIC_INIT, INSTANCE_INIT, METHOD_DEF, CTOR_DEF, VARIABLE_DEF" />
    </module>
    <module name="GenericWhitespace" />
    <module name="WhitespaceAfter" />
    <module name="NoWhitespaceAfter" />
    <module name="NoWhitespaceBefore" />
    <module name="SingleSpaceSeparator" />
    <module name="Indentation">
        <property name="throwsIndent" value="8" />
        <property name="lineWrappingIndentation" value="8" />
    </module>

    <module name="UpperEll" />
    <module name="DefaultComesLast" />
    <module name="ArrayTypeStyle" />
    <module name="MultipleVariableDeclarations" />
    <module name="ModifierOrder" />
    <module name="OneStatementPerLine" />
    <module name="StringLiteralEquality" />
    <module name="MutableException" />
    <module name="EqualsHashCode" />
    <module name="InnerAssignment" />
    <module name="HideUtilityClassConstructor" />
    <module name="ExplicitInitialization" />
    <module name="OneTopLevelClass" />

    <module name="MemberName" />
    <module name="LocalVariableName">
        <property name="format" value="^([a-z][a-zA-Z0-9]*|_)$" />
    </module>
    <module name="LocalFinalVariableName">
        <property name="format" value="^([a-z][a-zA-Z0-9]*|_)$" />
    </module>
    <module name="TypeName" />
    <module name="PackageName">
        <property name="format" value="^[a-z][a-z0-9]*(\.[a-z][a-z0-9]*)*$" />
    </module>
    <module name="PackageDeclaration" />
    <module name="ParameterName" />
    <module name="StaticVariableName" />
    <module name="ClassTypeParameterName">
        <property name="format" value="^[A-Z][A-Za-z0-9]*$" />
    </module>
    <module name="MethodTypeParameterName">
        <property name="format" value="^[A-Z][A-Za-z0-9]*$" />
    </module>

    <module name="AnnotationUseStyle">
        <property name="trailingArrayComma" value="ignore" />
    </module>

    <module name="AvoidStarImport" />
    <module name="RedundantImport" />
    <module name="UnusedImports" />
    <module name="ImportOrder">
        <property name="groups" value="*,javax,java" />
        <property name="separated" value="true" />
        <property name="option" value="bottom" />
        <property name="sortStaticImportsAlphabetically" value="true" />
    </module>

    <module name="SuppressionXpathSingleFilter">
        <property name="checks" value="WhitespaceAround"/>
        <property name="query" value="//LITERAL_SWITCH//SLIST"/>
    </module>
    <module name="SuppressionXpathSingleFilter">
        <property name="checks" value="WhitespaceAround"/>
        <property name="query" value="//LITERAL_SWITCH//RCURLY"/>
    </module>
    <module name="WhitespaceAround">
        <property name="allowEmptyConstructors" value="true" />
        <property name="allowEmptyMethods" value="true" />
        <property name="allowEmptyLambdas" value="true" />
        <property name="allowEmptyTypes" value="true" />
        <property name="ignoreEnhancedForColon" value="false" />
        <property name="tokens" value="
            ASSIGN, BAND, BAND_ASSIGN, BOR, BOR_ASSIGN, BSR, BSR_ASSIGN,
            BXOR, BXOR_ASSIGN, COLON, DIV, DIV_ASSIGN, DO_WHILE, EQUAL, GE, GT,
            LAMBDA, LAND, LCURLY, LE, LITERAL_ASSERT, LITERAL_CATCH, LITERAL_DO, LITERAL_ELSE,
            LITERAL_FINALLY, LITERAL_FOR, LITERAL_IF, LITERAL_RETURN,
            LITERAL_SYNCHRONIZED, LITERAL_TRY, LITERAL_WHILE,
            LOR, LT, MINUS, MINUS_ASSIGN, MOD, MOD_ASSIGN, NOT_EQUAL,
            PLUS, PLUS_ASSIGN, QUESTION, SL, SLIST, SL_ASSIGN, SR, SR_ASSIGN,
            STAR, STAR_ASSIGN, TYPE_EXTENSION_AND" />
    </module>

    <module name="WhitespaceAfter" />

    <module name="NoWhitespaceAfter">
        <property name="tokens" value="DOT" />
        <property name="allowLineBreaks" value="false" />
    </module>

    <module name="IllegalToken">
        <property name="tokens" value="LITERAL_ASSERT" />
    </module>

    <module name="MethodName">
        <property name="format" value="^[a-z][a-zA-Z0-9_]*$"/>
    </module>

    <module name="RegexpSinglelineJava">
        <property name="format" value="(class|interface) ([a-zA-Z0-9_])+(&lt;.*&gt;)? (extends|implements)" />
        <property name="message" value="No new line before extends/implements" />
        <property name="ignoreComments" value="true" />
    </module>

    <module name="RegexpSinglelineJava">
        <property name="format" value="\)\s*throws\b" />
        <property name="message" value="No new line before throws" />
        <property name="ignoreComments" value="true" />
    </module>

    <module name="RegexpSinglelineJava">
        <!-- Forbid "new Type[]{",  IntelliJ would reformat adding a space -->
        <!-- Forbid "new Type[]  {",  IntelliJ would reformat removing a space -->
        <property name="format" value="new\s++\w++(&lt;\?&gt;)?(\[\])++(\s{2,})?\{" />
        <property name="message" value="Incorrect whitespace before array initializer" />
        <property name="ignoreComments" value="true" />
    </module>

    <!-- javadoc -->
    <module name="RequireEmptyLineBeforeBlockTagGroup" />
    <module name="NonEmptyAtclauseDescription" />
</module>

/var/tmp $ cat YOUR_FILE.java

/*

  • 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.
    */
    package io.trino.spi.function;

import io.airlift.slice.Slice;
import io.trino.spi.ErrorCodeSupplier;
import io.trino.spi.StandardErrorCode;
import io.trino.spi.TrinoException;
import io.trino.spi.block.Block;
import io.trino.spi.block.BlockBuilder;
import io.trino.spi.block.ValueBlock;
import io.trino.spi.function.InvocationConvention.InvocationArgumentConvention;
import io.trino.spi.function.InvocationConvention.InvocationReturnConvention;
import io.trino.spi.type.Type;
import io.trino.spi.type.TypeOperators;

import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.util.List;
import java.util.Objects;
import java.util.stream.IntStream;

import static io.trino.spi.function.InvocationConvention.InvocationArgumentConvention.BLOCK_POSITION;
import static io.trino.spi.function.InvocationConvention.InvocationArgumentConvention.BLOCK_POSITION_NOT_NULL;
import static io.trino.spi.function.InvocationConvention.InvocationArgumentConvention.BOXED_NULLABLE;
import static io.trino.spi.function.InvocationConvention.InvocationArgumentConvention.FLAT;
import static io.trino.spi.function.InvocationConvention.InvocationArgumentConvention.FUNCTION;
import static io.trino.spi.function.InvocationConvention.InvocationArgumentConvention.IN_OUT;
import static io.trino.spi.function.InvocationConvention.InvocationArgumentConvention.NEVER_NULL;
import static io.trino.spi.function.InvocationConvention.InvocationArgumentConvention.NULL_FLAG;
import static io.trino.spi.function.InvocationConvention.InvocationArgumentConvention.VALUE_BLOCK_POSITION;
import static io.trino.spi.function.InvocationConvention.InvocationArgumentConvention.VALUE_BLOCK_POSITION_NOT_NULL;
import static io.trino.spi.function.InvocationConvention.InvocationReturnConvention.BLOCK_BUILDER;
import static io.trino.spi.function.InvocationConvention.InvocationReturnConvention.DEFAULT_ON_NULL;
import static io.trino.spi.function.InvocationConvention.InvocationReturnConvention.FAIL_ON_NULL;
import static io.trino.spi.function.InvocationConvention.InvocationReturnConvention.FLAT_RETURN;
import static io.trino.spi.function.InvocationConvention.InvocationReturnConvention.NULLABLE_RETURN;
import static java.lang.invoke.MethodHandles.collectArguments;
import static java.lang.invoke.MethodHandles.dropArguments;
import static java.lang.invoke.MethodHandles.empty;
import static java.lang.invoke.MethodHandles.explicitCastArguments;
import static java.lang.invoke.MethodHandles.filterArguments;
import static java.lang.invoke.MethodHandles.guardWithTest;
import static java.lang.invoke.MethodHandles.identity;
import static java.lang.invoke.MethodHandles.insertArguments;
import static java.lang.invoke.MethodHandles.lookup;
import static java.lang.invoke.MethodHandles.permuteArguments;
import static java.lang.invoke.MethodHandles.throwException;
import static java.lang.invoke.MethodType.methodType;
import static java.util.Objects.requireNonNull;

public final class ScalarFunctionAdapter
{
private static final MethodHandle OBJECT_IS_NULL_METHOD;
private static final MethodHandle APPEND_NULL_METHOD;
private static final MethodHandle BLOCK_IS_NULL_METHOD;
private static final MethodHandle IN_OUT_IS_NULL_METHOD;
private static final MethodHandle GET_UNDERLYING_VALUE_BLOCK_METHOD;
private static final MethodHandle GET_UNDERLYING_VALUE_POSITION_METHOD;
private static final MethodHandle NEW_NEVER_NULL_IS_NULL_EXCEPTION;
// This is needed to convert flat arguments to stack types
private static final TypeOperators READ_VALUE_TYPE_OPERATORS = new TypeOperators();

static {
    try {
        MethodHandles.Lookup lookup = lookup();
        OBJECT_IS_NULL_METHOD = lookup.findStatic(Objects.class, "isNull", methodType(boolean.class, Object.class));
        APPEND_NULL_METHOD = lookup.findVirtual(BlockBuilder.class, "appendNull", methodType(BlockBuilder.class))
                .asType(methodType(void.class, BlockBuilder.class));
        BLOCK_IS_NULL_METHOD = lookup.findVirtual(Block.class, "isNull", methodType(boolean.class, int.class));
        IN_OUT_IS_NULL_METHOD = lookup.findVirtual(InOut.class, "isNull", methodType(boolean.class));

        GET_UNDERLYING_VALUE_BLOCK_METHOD = lookup().findVirtual(Block.class, "getUnderlyingValueBlock", methodType(ValueBlock.class));
        GET_UNDERLYING_VALUE_POSITION_METHOD = lookup().findVirtual(Block.class, "getUnderlyingValuePosition", methodType(int.class, int.class));

        NEW_NEVER_NULL_IS_NULL_EXCEPTION = lookup.findConstructor(TrinoException.class, methodType(void.class, ErrorCodeSupplier.class, String.class))
                .bindTo(StandardErrorCode.INVALID_FUNCTION_ARGUMENT)
                .bindTo("A never null argument is null");
    }
    catch (ReflectiveOperationException e) {
        throw new ExceptionInInitializerError(e);
    }
}

private ScalarFunctionAdapter() {}

/**
 * Can the actual calling convention of a method be converted to the expected calling convention?
 */
public static boolean canAdapt(InvocationConvention actualConvention, InvocationConvention expectedConvention)
{
    requireNonNull(actualConvention, "actualConvention is null");
    requireNonNull(expectedConvention, "expectedConvention is null");
    if (actualConvention.getArgumentConventions().size() != expectedConvention.getArgumentConventions().size()) {
        throw new IllegalArgumentException("Actual and expected conventions have different number of arguments");
    }

    if (actualConvention.supportsSession() && !expectedConvention.supportsSession()) {
        return false;
    }

    if (actualConvention.supportsInstanceFactory() && !expectedConvention.supportsInstanceFactory()) {
        return false;
    }

    if (!canAdaptReturn(actualConvention.getReturnConvention(), expectedConvention.getReturnConvention())) {
        return false;
    }

    for (int argumentIndex = 0; argumentIndex < actualConvention.getArgumentConventions().size(); argumentIndex++) {
        InvocationArgumentConvention actualArgumentConvention = actualConvention.getArgumentConvention(argumentIndex);
        InvocationArgumentConvention expectedArgumentConvention = expectedConvention.getArgumentConvention(argumentIndex);
        if (!canAdaptParameter(
                actualArgumentConvention,
                expectedArgumentConvention,
                expectedConvention.getReturnConvention())) {
            return false;
        }
    }
    return true;
}

private static boolean canAdaptReturn(
        InvocationReturnConvention actualReturnConvention,
        InvocationReturnConvention expectedReturnConvention)
{
    if (actualReturnConvention == expectedReturnConvention) {
        return true;
    }

    return switch (actualReturnConvention) {
        case FAIL_ON_NULL -> expectedReturnConvention != FLAT_RETURN;
        case NULLABLE_RETURN -> expectedReturnConvention.isNullable() || expectedReturnConvention == DEFAULT_ON_NULL;
        case BLOCK_BUILDER, FLAT_RETURN -> false;
        case DEFAULT_ON_NULL -> throw new IllegalArgumentException("actual return convention cannot be DEFAULT_ON_NULL");
    };
}

private static boolean canAdaptParameter(
        InvocationArgumentConvention actualArgumentConvention,
        InvocationArgumentConvention expectedArgumentConvention,
        InvocationReturnConvention returnConvention)
{
    // not a conversion
    if (actualArgumentConvention == expectedArgumentConvention) {
        return true;
    }

    // function cannot be adapted
    if (expectedArgumentConvention == FUNCTION || actualArgumentConvention == FUNCTION) {
        return false;
    }

    return switch (actualArgumentConvention) {
        case NEVER_NULL -> switch (expectedArgumentConvention) {
            case BLOCK_POSITION_NOT_NULL, VALUE_BLOCK_POSITION_NOT_NULL, FLAT -> true;
            case BOXED_NULLABLE, NULL_FLAG -> returnConvention != FAIL_ON_NULL;
            case BLOCK_POSITION, VALUE_BLOCK_POSITION, IN_OUT -> true; // todo only support these if the return convention is nullable
            case FUNCTION -> throw new IllegalStateException("Unexpected value: " + expectedArgumentConvention);
            // this is not needed as the case where actual and expected are the same is covered above,
            // but this means we will get a compile time error if a new convention is added in the future
            //noinspection DataFlowIssue
            case NEVER_NULL -> true;
        };
        case BLOCK_POSITION_NOT_NULL, VALUE_BLOCK_POSITION_NOT_NULL -> switch (expectedArgumentConvention) {
            case BLOCK_POSITION_NOT_NULL, VALUE_BLOCK_POSITION_NOT_NULL -> true;
            case BLOCK_POSITION, VALUE_BLOCK_POSITION -> returnConvention.isNullable() || returnConvention == DEFAULT_ON_NULL;
            case NEVER_NULL, NULL_FLAG, BOXED_NULLABLE, FLAT, IN_OUT -> false;
            case FUNCTION -> throw new IllegalStateException("Unexpected value: " + expectedArgumentConvention);
        };
        case BLOCK_POSITION, VALUE_BLOCK_POSITION -> switch (expectedArgumentConvention) {
            case BLOCK_POSITION_NOT_NULL, VALUE_BLOCK_POSITION_NOT_NULL, BLOCK_POSITION, VALUE_BLOCK_POSITION -> true;
            case NEVER_NULL, NULL_FLAG, BOXED_NULLABLE, FLAT, IN_OUT -> false;
            case FUNCTION -> throw new IllegalStateException("Unexpected value: " + expectedArgumentConvention);
        };
        case BOXED_NULLABLE, NULL_FLAG -> true;
        case FLAT, IN_OUT -> false;
        case FUNCTION -> throw new IllegalArgumentException("Unsupported argument convention: " + actualArgumentConvention);
    };
}

/**
 * Adapt the method handle from the actual calling convention of a method be converted to the expected calling convention?
 */
public static MethodHandle adapt(
        MethodHandle methodHandle,
        Type returnType,
        List<Type> actualArgumentTypes,
        InvocationConvention actualConvention,
        InvocationConvention expectedConvention)
{
    requireNonNull(methodHandle, "methodHandle is null");
    requireNonNull(actualConvention, "actualConvention is null");
    requireNonNull(expectedConvention, "expectedConvention is null");
    if (actualConvention.getArgumentConventions().size() != expectedConvention.getArgumentConventions().size()) {
        throw new IllegalArgumentException("Actual and expected conventions have different number of arguments");
    }

    if (actualConvention.supportsSession() && !expectedConvention.supportsSession()) {
        throw new IllegalArgumentException("Session method cannot be adapted to no session");
    }
    if (!(expectedConvention.supportsInstanceFactory() || !actualConvention.supportsInstanceFactory())) {
        throw new IllegalArgumentException("Instance method cannot be adapted to no instance");
    }

    // adapt return first, since return-null-on-null parameter convention must know if the return type is nullable
    methodHandle = adaptReturn(methodHandle, returnType, actualConvention.getReturnConvention(), expectedConvention.getReturnConvention());

    // adapt parameters one at a time
    int parameterIndex = 0;

    if (actualConvention.supportsInstanceFactory()) {
        parameterIndex++;
    }
    if (actualConvention.supportsSession()) {
        parameterIndex++;
    }

    for (int argumentIndex = 0; argumentIndex < actualConvention.getArgumentConventions().size(); argumentIndex++) {
        Type argumentType = actualArgumentTypes.get(argumentIndex);
        InvocationArgumentConvention actualArgumentConvention = actualConvention.getArgumentConvention(argumentIndex);
        InvocationArgumentConvention expectedArgumentConvention = expectedConvention.getArgumentConvention(argumentIndex);
        methodHandle = adaptParameter(
                methodHandle,
                parameterIndex,
                argumentType,
                actualArgumentConvention,
                expectedArgumentConvention,
                expectedConvention.getReturnConvention());
        parameterIndex += expectedArgumentConvention.getParameterCount();
    }
    return methodHandle;
}

private static MethodHandle adaptReturn(
        MethodHandle methodHandle,
        Type returnType,
        InvocationReturnConvention actualReturnConvention,
        InvocationReturnConvention expectedReturnConvention)
{
    if (actualReturnConvention == expectedReturnConvention) {
        return methodHandle;
    }

    if (expectedReturnConvention == NULLABLE_RETURN) {
        if (actualReturnConvention == FAIL_ON_NULL) {
            // box return
            return explicitCastArguments(methodHandle, methodHandle.type().changeReturnType(wrap(methodHandle.type().returnType())));
        }
    }

    if (expectedReturnConvention == BLOCK_BUILDER) {
        // write the result to block builder
        // type.writeValue(BlockBuilder, value), f(a,b)::value => method(BlockBuilder, a, b)::void
        methodHandle = collectArguments(writeBlockValue(returnType, actualReturnConvention.isNullable()), 1, methodHandle);
        // f(BlockBuilder, a, b)::void => f(a, b, BlockBuilder)
        MethodType newType = methodHandle.type()
                .dropParameterTypes(0, 1)
                .appendParameterTypes(BlockBuilder.class);
        int[] reorder = IntStream.range(0, newType.parameterCount())
                .map(i -> i > 0 ? i - 1 : newType.parameterCount() - 1)
                .toArray();
        methodHandle = permuteArguments(methodHandle, newType, reorder);
        return methodHandle;
    }

    if (expectedReturnConvention == FAIL_ON_NULL && actualReturnConvention == NULLABLE_RETURN) {
        throw new IllegalArgumentException("Nullable return cannot be adapted fail on null");
    }

    if (expectedReturnConvention == DEFAULT_ON_NULL) {
        if (actualReturnConvention == FAIL_ON_NULL) {
            return methodHandle;
        }
        if (actualReturnConvention == NULLABLE_RETURN) {
            // perform unboxing, which converts nulls to Java primitive default value
            methodHandle = explicitCastArguments(methodHandle, methodHandle.type().changeReturnType(unwrap(returnType.getJavaType())));
            return methodHandle;
        }
    }
    throw new IllegalArgumentException("%s return convention cannot be adapted to %s".formatted(actualReturnConvention, expectedReturnConvention));
}

private static MethodHandle adaptParameter(
        MethodHandle methodHandle,
        int parameterIndex,
        Type argumentType,
        InvocationArgumentConvention actualArgumentConvention,
        InvocationArgumentConvention expectedArgumentConvention,
        InvocationReturnConvention returnConvention)
{
    // For value block, cast specialized parameter to ValueBlock
    if ((actualArgumentConvention == VALUE_BLOCK_POSITION || actualArgumentConvention == VALUE_BLOCK_POSITION_NOT_NULL) && methodHandle.type().parameterType(parameterIndex) != ValueBlock.class) {
        methodHandle = methodHandle.asType(methodHandle.type().changeParameterType(parameterIndex, ValueBlock.class));
    }

    if (actualArgumentConvention == expectedArgumentConvention) {
        return methodHandle;
    }
    if (actualArgumentConvention == IN_OUT) {
        throw new IllegalArgumentException("In-out argument cannot be adapted");
    }
    if (actualArgumentConvention == FUNCTION || expectedArgumentConvention == FUNCTION) {
        throw new IllegalArgumentException("Function argument cannot be adapted");
    }
    if (actualArgumentConvention == FLAT) {
        throw new IllegalArgumentException("Flat argument cannot be adapted");
    }

    // caller will never pass null
    if (expectedArgumentConvention == NEVER_NULL) {
        if (actualArgumentConvention == BOXED_NULLABLE) {
            // if actual argument is boxed primitive, change method handle to accept a primitive and then box to actual method
            if (isWrapperType(methodHandle.type().parameterType(parameterIndex))) {
                MethodType targetType = methodHandle.type().changeParameterType(parameterIndex, unwrap(methodHandle.type().parameterType(parameterIndex)));
                methodHandle = explicitCastArguments(methodHandle, targetType);
            }
            return methodHandle;
        }

        if (actualArgumentConvention == NULL_FLAG) {
            // actual method takes value and null flag, so change method handles to not have the flag and always pass false to the actual method
            return insertArguments(methodHandle, parameterIndex + 1, false);
        }
    }

    // caller will pass Java null for SQL null
    if (expectedArgumentConvention == BOXED_NULLABLE) {
        if (actualArgumentConvention == NEVER_NULL) {
            // box argument
            Class<?> boxedType = wrap(methodHandle.type().parameterType(parameterIndex));
            MethodType targetType = methodHandle.type().changeParameterType(parameterIndex, boxedType);
            methodHandle = explicitCastArguments(methodHandle, targetType);

            if (returnConvention == FAIL_ON_NULL) {
                throw new IllegalArgumentException("RETURN_NULL_ON_NULL adaptation cannot be used with FAIL_ON_NULL return convention");
            }
            return guardWithTest(
                    isNullArgument(methodHandle.type(), parameterIndex),
                    getNullShortCircuitResult(methodHandle, returnConvention),
                    methodHandle);
        }

        if (actualArgumentConvention == NULL_FLAG) {
            // The conversion is described below in reverse order as this is how method handle adaptation works.  The provided example
            // signature is based on a boxed Long argument.

            // 3. unbox the value (if null, the java default is sent)
            // long, boolean => Long, boolean
            Class<?> parameterType = methodHandle.type().parameterType(parameterIndex);
            methodHandle = explicitCastArguments(methodHandle, methodHandle.type().changeParameterType(parameterIndex, wrap(parameterType)));

            // 2. replace second argument with the result of isNull
            // long, boolean => Long, Long
            methodHandle = filterArguments(
                    methodHandle,
                    parameterIndex + 1,
                    explicitCastArguments(OBJECT_IS_NULL_METHOD, methodType(boolean.class, wrap(parameterType))));

            // 1. Duplicate the argument, so we have two copies of the value
            // Long, Long => Long
            int[] reorder = IntStream.range(0, methodHandle.type().parameterCount())
                    .map(i -> i <= parameterIndex ? i : i - 1)
                    .toArray();
            MethodType newType = methodHandle.type().dropParameterTypes(parameterIndex + 1, parameterIndex + 2);
            methodHandle = permuteArguments(methodHandle, newType, reorder);
            return methodHandle;
        }
    }

    // caller will pass boolean true in the next argument for SQL null
    if (expectedArgumentConvention == NULL_FLAG) {
        if (actualArgumentConvention == NEVER_NULL) {
            // if caller sets the null flag, return null, otherwise invoke target
            if (returnConvention == FAIL_ON_NULL) {
                throw new IllegalArgumentException("RETURN_NULL_ON_NULL adaptation cannot be used with FAIL_ON_NULL return convention");
            }
            // add a null flag to call
            methodHandle = dropArguments(methodHandle, parameterIndex + 1, boolean.class);

            return guardWithTest(
                    isTrueNullFlag(methodHandle.type(), parameterIndex),
                    getNullShortCircuitResult(methodHandle, returnConvention),
                    methodHandle);
        }

        if (actualArgumentConvention == BOXED_NULLABLE) {
            return collectArguments(methodHandle, parameterIndex, boxedToNullFlagFilter(methodHandle.type().parameterType(parameterIndex)));
        }
    }

    if (expectedArgumentConvention == BLOCK_POSITION_NOT_NULL) {
        if (actualArgumentConvention == VALUE_BLOCK_POSITION_NOT_NULL || actualArgumentConvention == VALUE_BLOCK_POSITION) {
            return adaptValueBlockArgumentToBlock(methodHandle, parameterIndex);
        }

        return adaptParameterToBlockPositionNotNull(methodHandle, parameterIndex, argumentType, actualArgumentConvention, expectedArgumentConvention, returnConvention);
    }

    if (expectedArgumentConvention == VALUE_BLOCK_POSITION_NOT_NULL) {
        if (actualArgumentConvention == VALUE_BLOCK_POSITION) {
            return methodHandle;
        }

        methodHandle = adaptParameterToBlockPositionNotNull(methodHandle, parameterIndex, argumentType, actualArgumentConvention, expectedArgumentConvention, returnConvention);
        methodHandle = methodHandle.asType(methodHandle.type().changeParameterType(parameterIndex, ValueBlock.class));
        return methodHandle;
    }

    // caller passes block and position which may contain a null
    if (expectedArgumentConvention == BLOCK_POSITION) {
        // convert ValueBlock argument to Block
        if (actualArgumentConvention == VALUE_BLOCK_POSITION || actualArgumentConvention == VALUE_BLOCK_POSITION_NOT_NULL) {
            adaptValueBlockArgumentToBlock(methodHandle, parameterIndex);
            methodHandle = adaptValueBlockArgumentToBlock(methodHandle, parameterIndex);
        }

        if (actualArgumentConvention == VALUE_BLOCK_POSITION) {
            return methodHandle;
        }

        return adaptParameterToBlockPosition(methodHandle, parameterIndex, argumentType, actualArgumentConvention, expectedArgumentConvention, returnConvention);
    }

    // caller passes value block and position which may contain a null
    if (expectedArgumentConvention == VALUE_BLOCK_POSITION) {
        if (actualArgumentConvention != BLOCK_POSITION) {
            methodHandle = adaptParameterToBlockPosition(methodHandle, parameterIndex, argumentType, actualArgumentConvention, expectedArgumentConvention, returnConvention);
        }
        methodHandle = methodHandle.asType(methodHandle.type().changeParameterType(parameterIndex, ValueBlock.class));
        return methodHandle;
    }

    // caller will pass boolean true in the next argument for SQL null
    if (expectedArgumentConvention == FLAT) {
        if (actualArgumentConvention != NEVER_NULL && actualArgumentConvention != BOXED_NULLABLE && actualArgumentConvention != NULL_FLAG) {
            throw new IllegalArgumentException(actualArgumentConvention + " cannot be adapted to " + expectedArgumentConvention);
        }

        // if the actual method has a null flag, set the flag to false
        if (actualArgumentConvention == NULL_FLAG) {
            // actual method takes value and null flag, so change method handles to not have the flag and always pass false to the actual method
            methodHandle = insertArguments(methodHandle, parameterIndex + 1, false);
        }

        // if the actual method has a boxed argument, change it to accept the unboxed value
        if (actualArgumentConvention == BOXED_NULLABLE) {
            // if actual argument is boxed primitive, change method handle to accept a primitive and then box to actual method
            if (isWrapperType(methodHandle.type().parameterType(parameterIndex))) {
                MethodType targetType = methodHandle.type().changeParameterType(parameterIndex, unwrap(methodHandle.type().parameterType(parameterIndex)));
                methodHandle = explicitCastArguments(methodHandle, targetType);
            }
        }

        // read the value from flat memory
        return collectArguments(methodHandle, parameterIndex, getFlatValueNeverNull(argumentType, methodHandle.type().parameterType(parameterIndex)));
    }

    // caller passes in-out which may contain a null
    if (expectedArgumentConvention == IN_OUT) {
        MethodHandle getInOutValue = getInOutValue(argumentType, methodHandle.type().parameterType(parameterIndex));

        if (actualArgumentConvention == NEVER_NULL) {
            if (returnConvention != FAIL_ON_NULL) {
                // if caller sets the null flag, return null, otherwise invoke target
                methodHandle = collectArguments(methodHandle, parameterIndex, getInOutValue);

                return guardWithTest(
                        isInOutNull(methodHandle.type(), parameterIndex),
                        getNullShortCircuitResult(methodHandle, returnConvention),
                        methodHandle);
            }

            MethodHandle adapter = guardWithTest(
                    isInOutNull(getInOutValue.type(), 0),
                    throwTrinoNullArgumentException(getInOutValue.type()),
                    getInOutValue);

            return collectArguments(methodHandle, parameterIndex, adapter);
        }

        if (actualArgumentConvention == BOXED_NULLABLE) {
            getInOutValue = explicitCastArguments(getInOutValue, getInOutValue.type().changeReturnType(wrap(getInOutValue.type().returnType())));
            getInOutValue = guardWithTest(
                    isInOutNull(getInOutValue.type(), 0),
                    empty(getInOutValue.type()),
                    getInOutValue);
            methodHandle = collectArguments(methodHandle, parameterIndex, getInOutValue);
            return methodHandle;
        }

        if (actualArgumentConvention == NULL_FLAG) {
            // long, boolean => long, InOut
            MethodHandle isNull = isInOutNull(getInOutValue.type(), 0);
            methodHandle = collectArguments(methodHandle, parameterIndex + 1, isNull);

            // long, InOut => InOut, InOut
            getInOutValue = guardWithTest(
                    isInOutNull(getInOutValue.type(), 0),
                    empty(getInOutValue.type()),
                    getInOutValue);
            methodHandle = collectArguments(methodHandle, parameterIndex, getInOutValue);

            // InOut, InOut => InOut
            int[] reorder = IntStream.range(0, methodHandle.type().parameterCount())
                    .map(i -> i <= parameterIndex ? i : i - 1)
                    .toArray();
            MethodType newType = methodHandle.type().dropParameterTypes(parameterIndex + 1, parameterIndex + 2);
            methodHandle = permuteArguments(methodHandle, newType, reorder);
            return methodHandle;
        }
    }

    throw unsupportedArgumentAdaptation(actualArgumentConvention, expectedArgumentConvention, returnConvention);
}

private static MethodHandle adaptParameterToBlockPosition(MethodHandle methodHandle, int parameterIndex, Type argumentType, InvocationArgumentConvention actualArgumentConvention, InvocationArgumentConvention expectedArgumentConvention, InvocationReturnConvention returnConvention)
{
    MethodHandle getBlockValue = getBlockValue(argumentType, methodHandle.type().parameterType(parameterIndex));
    if (actualArgumentConvention == NEVER_NULL) {
        if (returnConvention != FAIL_ON_NULL) {
            // if caller sets the null flag, return null, otherwise invoke target
            methodHandle = collectArguments(methodHandle, parameterIndex, getBlockValue);

            return guardWithTest(
                    isBlockPositionNull(methodHandle.type(), parameterIndex),
                    getNullShortCircuitResult(methodHandle, returnConvention),
                    methodHandle);
        }

        MethodHandle adapter = guardWithTest(
                isBlockPositionNull(getBlockValue.type(), 0),
                throwTrinoNullArgumentException(getBlockValue.type()),
                getBlockValue);

        return collectArguments(methodHandle, parameterIndex, adapter);
    }

    if (actualArgumentConvention == BOXED_NULLABLE) {
        getBlockValue = explicitCastArguments(getBlockValue, getBlockValue.type().changeReturnType(wrap(getBlockValue.type().returnType())));
        getBlockValue = guardWithTest(
                isBlockPositionNull(getBlockValue.type(), 0),
                empty(getBlockValue.type()),
                getBlockValue);
        methodHandle = collectArguments(methodHandle, parameterIndex, getBlockValue);
        return methodHandle;
    }

    if (actualArgumentConvention == NULL_FLAG) {
        // long, boolean => long, Block, int
        MethodHandle isNull = isBlockPositionNull(getBlockValue.type(), 0);
        methodHandle = collectArguments(methodHandle, parameterIndex + 1, isNull);

        // convert get block value to be null safe
        getBlockValue = guardWithTest(
                isBlockPositionNull(getBlockValue.type(), 0),
                empty(getBlockValue.type()),
                getBlockValue);

        // long, Block, int => Block, int, Block, int
        methodHandle = collectArguments(methodHandle, parameterIndex, getBlockValue);

        int[] reorder = IntStream.range(0, methodHandle.type().parameterCount())
                .map(i -> i <= parameterIndex + 1 ? i : i - 2)
                .toArray();
        MethodType newType = methodHandle.type().dropParameterTypes(parameterIndex + 2, parameterIndex + 4);
        methodHandle = permuteArguments(methodHandle, newType, reorder);
        return methodHandle;
    }

    if (actualArgumentConvention == BLOCK_POSITION_NOT_NULL || actualArgumentConvention == VALUE_BLOCK_POSITION_NOT_NULL) {
        if (returnConvention != FAIL_ON_NULL) {
            MethodHandle nullReturnValue = getNullShortCircuitResult(methodHandle, returnConvention);
            return guardWithTest(
                    isBlockPositionNull(methodHandle.type(), parameterIndex),
                    nullReturnValue,
                    methodHandle);
        }
    }
    throw unsupportedArgumentAdaptation(actualArgumentConvention, expectedArgumentConvention, returnConvention);
}

private static MethodHandle adaptParameterToBlockPositionNotNull(MethodHandle methodHandle, int parameterIndex, Type argumentType, InvocationArgumentConvention actualArgumentConvention, InvocationArgumentConvention expectedArgumentConvention, InvocationReturnConvention returnConvention)
{
    if (actualArgumentConvention == BLOCK_POSITION || actualArgumentConvention == BLOCK_POSITION_NOT_NULL) {
        return methodHandle;
    }

    MethodHandle getBlockValue = getBlockValue(argumentType, methodHandle.type().parameterType(parameterIndex));
    if (actualArgumentConvention == NEVER_NULL) {
        return collectArguments(methodHandle, parameterIndex, getBlockValue);
    }
    if (actualArgumentConvention == BOXED_NULLABLE) {
        MethodType targetType = getBlockValue.type().changeReturnType(wrap(getBlockValue.type().returnType()));
        return collectArguments(methodHandle, parameterIndex, explicitCastArguments(getBlockValue, targetType));
    }
    if (actualArgumentConvention == NULL_FLAG) {
        // actual method takes value and null flag, so change method handles to not have the flag and always pass false to the actual method
        return collectArguments(insertArguments(methodHandle, parameterIndex + 1, false), parameterIndex, getBlockValue);
    }
    throw unsupportedArgumentAdaptation(actualArgumentConvention, expectedArgumentConvention, returnConvention);
}

private static IllegalArgumentException unsupportedArgumentAdaptation(InvocationArgumentConvention actualArgumentConvention, InvocationArgumentConvention expectedArgumentConvention, InvocationReturnConvention returnConvention)
{
    return new IllegalArgumentException("Cannot convert argument %s to %s with return convention %s".formatted(actualArgumentConvention, expectedArgumentConvention, returnConvention));
}

private static MethodHandle adaptValueBlockArgumentToBlock(MethodHandle methodHandle, int parameterIndex)
{
    // someValueBlock, position => valueBlock, position
    methodHandle = explicitCastArguments(methodHandle, methodHandle.type().changeParameterType(parameterIndex, ValueBlock.class));
    // valueBlock, position => block, position
    methodHandle = collectArguments(methodHandle, parameterIndex, GET_UNDERLYING_VALUE_BLOCK_METHOD);
    // block, position => block, block, position
    methodHandle = collectArguments(methodHandle, parameterIndex + 1, GET_UNDERLYING_VALUE_POSITION_METHOD);

    // block, block, position => block, position
    methodHandle = permuteArguments(
            methodHandle,
            methodHandle.type().dropParameterTypes(parameterIndex, parameterIndex + 1),
            IntStream.range(0, methodHandle.type().parameterCount())
                    .map(i -> i <= parameterIndex ? i : i - 1)
                    .toArray());
    return methodHandle;
}

private static MethodHandle getBlockValue(Type argumentType, Class<?> expectedType)
{
    Class<?> methodArgumentType = argumentType.getJavaType();
    String getterName;
    if (methodArgumentType == boolean.class) {
        getterName = "getBoolean";
    }
    else if (methodArgumentType == long.class) {
        getterName = "getLong";
    }
    else if (methodArgumentType == double.class) {
        getterName = "getDouble";
    }
    else if (methodArgumentType == Slice.class) {
        getterName = "getSlice";
    }
    else {
        getterName = "getObject";
        methodArgumentType = Object.class;
    }

    try {
        MethodHandle getValue = lookup().findVirtual(Type.class, getterName, methodType(methodArgumentType, Block.class, int.class))
                .bindTo(argumentType);
        return explicitCastArguments(getValue, getValue.type().changeReturnType(expectedType));
    }
    catch (ReflectiveOperationException e) {
        throw new AssertionError(e);
    }
}

private static MethodHandle writeBlockValue(Type type, boolean nullable)
{
    Class<?> methodArgumentType = type.getJavaType();
    String getterName;
    if (methodArgumentType == boolean.class) {
        getterName = "writeBoolean";
    }
    else if (methodArgumentType == long.class) {
        getterName = "writeLong";
    }
    else if (methodArgumentType == double.class) {
        getterName = "writeDouble";
    }
    else if (methodArgumentType == Slice.class) {
        getterName = "writeSlice";
    }
    else {
        getterName = "writeObject";
        methodArgumentType = Object.class;
    }

    MethodHandle methodHandle;
    try {
        methodHandle = lookup().findVirtual(Type.class, getterName, methodType(void.class, BlockBuilder.class, methodArgumentType))
                .bindTo(type)
                .asType(methodType(void.class, BlockBuilder.class, type.getJavaType()));
    }
    catch (ReflectiveOperationException e) {
        throw new AssertionError(e);
    }

    if (!nullable) {
        return methodHandle;
    }

    methodHandle = methodHandle.asType(methodType(void.class, BlockBuilder.class, wrap(type.getJavaType())));
    return guardWithTest(
            isNullArgument(methodHandle.type(), 1),
            permuteArguments(APPEND_NULL_METHOD, methodHandle.type(), 0),
            methodHandle);
}

private static MethodHandle getFlatValueNeverNull(Type argumentType, Class<?> expectedType)
{
    MethodHandle readValueOperator = READ_VALUE_TYPE_OPERATORS.getReadValueOperator(argumentType, InvocationConvention.simpleConvention(FAIL_ON_NULL, FLAT));
    readValueOperator = explicitCastArguments(readValueOperator, readValueOperator.type().changeReturnType(expectedType));
    return readValueOperator;
}

private static MethodHandle getInOutValue(Type argumentType, Class<?> expectedType)
{
    Class<?> methodArgumentType = argumentType.getJavaType();
    String getterName;
    if (methodArgumentType == boolean.class) {
        getterName = "getBooleanValue";
    }
    else if (methodArgumentType == long.class) {
        getterName = "getLongValue";
    }
    else if (methodArgumentType == double.class) {
        getterName = "getDoubleValue";
    }
    else {
        getterName = "getObjectValue";
        methodArgumentType = Object.class;
    }

    try {
        MethodHandle getValue = lookup().findVirtual(InternalDataAccessor.class, getterName, methodType(methodArgumentType));
        return explicitCastArguments(getValue, methodType(expectedType, InOut.class));
    }
    catch (ReflectiveOperationException e) {
        throw new AssertionError(e);
    }
}

private static MethodHandle boxedToNullFlagFilter(Class<?> argumentType)
{
    // Start with identity
    MethodHandle handle = identity(argumentType);
    // if argument is a primitive, box it
    if (isWrapperType(argumentType)) {
        handle = explicitCastArguments(handle, handle.type().changeParameterType(0, unwrap(argumentType)));
    }
    // Add boolean null flag
    handle = dropArguments(handle, 1, boolean.class);
    // if the flag is true, return null, otherwise invoke identity
    return guardWithTest(
            isTrueNullFlag(handle.type(), 0),
            empty(handle.type()),
            handle);
}

private static MethodHandle isTrueNullFlag(MethodType methodType, int index)
{
    return permuteArguments(identity(boolean.class), methodType.changeReturnType(boolean.class), index + 1);
}

private static MethodHandle isNullArgument(MethodType methodType, int index)
{
    // Start with Objects.isNull(Object):boolean
    MethodHandle isNull = OBJECT_IS_NULL_METHOD;
    // Cast in incoming type: isNull(T):boolean
    isNull = explicitCastArguments(isNull, methodType(boolean.class, methodType.parameterType(index)));
    // Add extra argument to match the expected method type
    isNull = permuteArguments(isNull, methodType.changeReturnType(boolean.class), index);
    return isNull;
}

private static MethodHandle isBlockPositionNull(MethodType methodType, int index)
{
    // Add extra argument to Block.isNull(int):boolean match the expected method type
    MethodHandle blockIsNull = BLOCK_IS_NULL_METHOD.asType(BLOCK_IS_NULL_METHOD.type().changeParameterType(0, methodType.parameterType(index)));
    return permuteArguments(blockIsNull, methodType.changeReturnType(boolean.class), index, index + 1);
}

private static MethodHandle isInOutNull(MethodType methodType, int index)
{
    // Add extra argument to InOut.isNull(int):boolean match the expected method type
    return permuteArguments(IN_OUT_IS_NULL_METHOD, methodType.changeReturnType(boolean.class), index);
}

private static MethodHandle getNullShortCircuitResult(MethodHandle methodHandle, InvocationReturnConvention returnConvention)
{
    if (returnConvention == BLOCK_BUILDER) {
        return permuteArguments(APPEND_NULL_METHOD, methodHandle.type(), methodHandle.type().parameterCount() - 1);
    }
    return empty(methodHandle.type());
}

private static MethodHandle throwTrinoNullArgumentException(MethodType type)
{
    MethodHandle throwException = collectArguments(throwException(type.returnType(), TrinoException.class), 0, NEW_NEVER_NULL_IS_NULL_EXCEPTION);
    return permuteArguments(throwException, type);
}

private static boolean isWrapperType(Class<?> type)
{
    return type != unwrap(type);
}

private static Class<?> wrap(Class<?> type)
{
    return methodType(type).wrap().returnType();
}

private static Class<?> unwrap(Class<?> type)
{
    return methodType(type).unwrap().returnType();
}

}


/var/tmp $ RUN_LOCALE="-Duser.language=en -Duser.country=US"
/var/tmp $ java $RUN_LOCALE -jar checkstyle-X.XX-all.jar -c config.xml YOUR_FILE.java

[ERROR] src/main/java/io/trino/spi/function/ScalarFunctionAdapter.java:[168,17] (indentation) Indentation: 'case' child has incorrect indentation level 16, expected level should be 24.
[ERROR] src/main/java/io/trino/spi/function/ScalarFunctionAdapter.java:[169,17] (indentation) Indentation: 'case' child has incorrect indentation level 16, expected level should be 24.
[ERROR] src/main/java/io/trino/spi/function/ScalarFunctionAdapter.java:[170,17] (indentation) Indentation: 'case' child has incorrect indentation level 16, expected level should be 24.
[ERROR] src/main/java/io/trino/spi/function/ScalarFunctionAdapter.java:[171,17] (indentation) Indentation: 'case' child has incorrect indentation level 16, expected level should be 24.
[ERROR] src/main/java/io/trino/spi/function/ScalarFunctionAdapter.java:[175,17] (indentation) Indentation: 'case' child has incorrect indentation level 16, expected level should be 24.
[ERROR] src/main/java/io/trino/spi/function/ScalarFunctionAdapter.java:[176,13] (indentation) Indentation: 'switch rcurly' has incorrect indentation level 12, expected level should be 20.
[ERROR] src/main/java/io/trino/spi/function/ScalarFunctionAdapter.java:[178,17] (indentation) Indentation: 'case' child has incorrect indentation level 16, expected level should be 24.
[ERROR] src/main/java/io/trino/spi/function/ScalarFunctionAdapter.java:[179,17] (indentation) Indentation: 'case' child has incorrect indentation level 16, expected level should be 24.
[ERROR] src/main/java/io/trino/spi/function/ScalarFunctionAdapter.java:[180,17] (indentation) Indentation: 'case' child has incorrect indentation level 16, expected level should be 24.
[ERROR] src/main/java/io/trino/spi/function/ScalarFunctionAdapter.java:[181,17] (indentation) Indentation: 'case' child has incorrect indentation level 16, expected level should be 24.
[ERROR] src/main/java/io/trino/spi/function/ScalarFunctionAdapter.java:[182,13] (indentation) Indentation: 'switch rcurly' has incorrect indentation level 12, expected level should be 20.
[ERROR] src/main/java/io/trino/spi/function/ScalarFunctionAdapter.java:[184,17] (indentation) Indentation: 'case' child has incorrect indentation level 16, expected level should be 24.
[ERROR] src/main/java/io/trino/spi/function/ScalarFunctionAdapter.java:[185,17] (indentation) Indentation: 'case' child has incorrect indentation level 16, expected level should be 24.
[ERROR] src/main/java/io/trino/spi/function/ScalarFunctionAdapter.java:[186,17] (indentation) Indentation: 'case' child has incorrect indentation level 16, expected level should be 24.
[ERROR] src/main/java/io/trino/spi/function/ScalarFunctionAdapter.java:[187,13] (indentation) Indentation: 'switch rcurly' has incorrect indentation level 12, expected level should be 20.

For Windows users, please use type instead of cat and run

set RUN_LOCALE="-Duser.language=en -Duser.country=US"
java %RUN_LOCALE% -jar checkstyle-X.XX-all.jar -c config.xml YOUR_FILE.java

in place of the last 2 commands above.


Describe what you expect in detail.

I'd expect nested switch expressions to have identation 12, not 20 which seems like a lot and makes code harder to read than this:

    return switch (actualArgumentConvention) {
        case NEVER_NULL -> switch (expectedArgumentConvention) {
            case BLOCK_POSITION_NOT_NULL, VALUE_BLOCK_POSITION_NOT_NULL, FLAT -> true;
            case BOXED_NULLABLE, NULL_FLAG -> returnConvention != FAIL_ON_NULL;
            case BLOCK_POSITION, VALUE_BLOCK_POSITION, IN_OUT -> true; // todo only support these if the return convention is nullable
            case FUNCTION -> throw new IllegalStateException("Unexpected value: " + expectedArgumentConvention);
            // this is not needed as the case where actual and expected are the same is covered above,
            // but this means we will get a compile time error if a new convention is added in the future
            //noinspection DataFlowIssue
            case NEVER_NULL -> true;
        };
        case BLOCK_POSITION_NOT_NULL, VALUE_BLOCK_POSITION_NOT_NULL -> switch (expectedArgumentConvention) {
            case BLOCK_POSITION_NOT_NULL, VALUE_BLOCK_POSITION_NOT_NULL -> true;
            case BLOCK_POSITION, VALUE_BLOCK_POSITION -> returnConvention.isNullable() || returnConvention == DEFAULT_ON_NULL;
            case NEVER_NULL, NULL_FLAG, BOXED_NULLABLE, FLAT, IN_OUT -> false;
            case FUNCTION -> throw new IllegalStateException("Unexpected value: " + expectedArgumentConvention);
        };
        case BLOCK_POSITION, VALUE_BLOCK_POSITION -> switch (expectedArgumentConvention) {
            case BLOCK_POSITION_NOT_NULL, VALUE_BLOCK_POSITION_NOT_NULL, BLOCK_POSITION, VALUE_BLOCK_POSITION -> true;
            case NEVER_NULL, NULL_FLAG, BOXED_NULLABLE, FLAT, IN_OUT -> false;
            case FUNCTION -> throw new IllegalStateException("Unexpected value: " + expectedArgumentConvention);
        };
        case BOXED_NULLABLE, NULL_FLAG -> true;
        case FLAT, IN_OUT -> false;
        case FUNCTION -> throw new IllegalArgumentException("Unsupported argument convention: " + actualArgumentConvention);
    };

Source code at https://github.com/trinodb/trino/blob/3da377228dd6f7a05eda7e9216407bff59099919/core/trino-spi/src/main/java/io/trino/spi/function/ScalarFunctionAdapter.java#L166


Still not clear ???
see example - https://checkstyle.org/report_issue.html#How_to_report_a_bug.3F

ATTENTION: FAILURE TO FOLLOW THE ABOVE TEMPLATE WILL RESULT IN THE ISSUE BEING CLOSED.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions