private void generateShapeValidationFunctions()

in codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/integration/ValidationGenerator.java [132:297]


    private void generateShapeValidationFunctions(
            GoWriter writer,
            Model model, SymbolProvider symbolProvider,
            Set<Shape> operationInputShapes,
            Set<ShapeId> shapesWithHelpers
    ) {
        GoPointableIndex pointableIndex = GoPointableIndex.of(model);

        for (ShapeId shapeId : shapesWithHelpers) {
            Shape shape = model.expectShape(shapeId);
            boolean topLevelShape = operationInputShapes.contains(shape);
            String functionName = getShapeValidationFunctionName(shape, topLevelShape);
            Symbol shapeSymbol = symbolProvider.toSymbol(shape);
            writer.openBlock("func $L(v $P) error {", "}", functionName, shapeSymbol, () -> {
                writer.addUseImports(SmithyGoDependency.SMITHY);

                if (pointableIndex.isNillable(shape)) {
                    writer.openBlock("if v == nil {", "}", () -> writer.write("return nil"));
                }

                writer.write("invalidParams := smithy.InvalidParamsError{Context: $S}", shapeSymbol.getName());
                switch (shape.getType()) {
                    case STRUCTURE:
                        shape.members().forEach(memberShape -> {
                            if (StreamingTrait.isEventStream(model, memberShape)) {
                                return;
                            }

                            String memberName = symbolProvider.toMemberName(memberShape);
                            Shape targetShape = model.expectShape(memberShape.getTarget());
                            boolean required = GoValidationIndex.isRequiredParameter(model, memberShape, topLevelShape);
                            boolean hasHelper = shapesWithHelpers.contains(targetShape.getId());
                            boolean isEnum = targetShape.getTrait(EnumTrait.class).isPresent();

                            if (required) {
                                Runnable runnable = () -> {
                                    writer.write("invalidParams.Add(smithy.NewErrParamRequired($S))", memberName);
                                    if (hasHelper) {
                                        writer.writeInline("} else ");
                                    } else {
                                        writer.write("}");
                                    }
                                };

                                if (isEnum) {
                                    writer.write("if len(v.$L) == 0 {", memberName);
                                    runnable.run();
                                } else if (pointableIndex.isNillable(memberShape)) {
                                    writer.write("if v.$L == nil {", memberName);
                                    runnable.run();
                                }
                            }

                            if (hasHelper) {
                                Runnable runnable = () -> {
                                    String helperName = getShapeValidationFunctionName(targetShape, false);
                                    writer.openBlock("if err := $L(v.$L); err != nil {", "}", helperName, memberName,
                                            () -> {
                                                writer.addUseImports(SmithyGoDependency.SMITHY);
                                                writer.write(
                                                        "invalidParams.AddNested($S, err.(smithy.InvalidParamsError))",
                                                        memberName);
                                            });
                                };

                                if (isEnum) {
                                    writer.openBlock("if len(v.$L) > 0 {", "}", memberName, runnable);
                                } else if (pointableIndex.isNillable(memberShape)) {
                                    writer.openBlock("if v.$L != nil {", "}", memberName, runnable);
                                }
                            }
                        });
                        break;

                    case LIST:
                    case SET:
                        CollectionShape collectionShape = CodegenUtils.expectCollectionShape(shape);
                        MemberShape member = collectionShape.getMember();
                        Shape memberTarget = model.expectShape(member.getTarget());
                        String helperName = getShapeValidationFunctionName(memberTarget, false);

                        writer.openBlock("for i := range v {", "}", () -> {
                            String addr = "";
                            if (!pointableIndex.isPointable(member) && pointableIndex.isPointable(memberTarget)) {
                                addr = "&";
                            }
                            writer.openBlock("if err := $L($Lv[i]); err != nil {", "}", helperName, addr, () -> {
                                writer.addUseImports(SmithyGoDependency.SMITHY);
                                writer.write("invalidParams.AddNested(fmt.Sprintf(\"[%d]\", i), "
                                        + "err.(smithy.InvalidParamsError))");
                            });
                        });
                        break;

                    case MAP:
                        MapShape mapShape = shape.asMapShape().get();
                        MemberShape mapValue = mapShape.getValue();
                        Shape valueTarget = model.expectShape(mapValue.getTarget());
                        helperName = getShapeValidationFunctionName(valueTarget, false);

                        writer.openBlock("for key := range v {", "}", () -> {
                            String valueVar = "v[key]";
                            if (!pointableIndex.isPointable(mapValue) && pointableIndex.isPointable(valueTarget)) {
                                writer.write("value := $L", valueVar);
                                valueVar = "&value";
                            }
                            writer.openBlock("if err := $L($L); err != nil {", "}", helperName, valueVar, () -> {
                                writer.addUseImports(SmithyGoDependency.SMITHY);
                                writer.write("invalidParams.AddNested(fmt.Sprintf(\"[%q]\", key), "
                                        + "err.(smithy.InvalidParamsError))");
                            });
                        });
                        break;

                    case UNION:
                        UnionShape unionShape = shape.asUnionShape().get();
                        Symbol unionSymbol = symbolProvider.toSymbol(unionShape);

                        Set<MemberShape> memberShapes = unionShape.getAllMembers().values().stream()
                                .filter(memberShape ->
                                        shapesWithHelpers.contains(model.expectShape(memberShape.getTarget()).getId()))
                                .collect(Collectors.toCollection(TreeSet::new));

                        if (memberShapes.size() > 0) {
                            writer.openBlock("switch uv := v.(type) {", "}", () -> {
                                // Use a TreeSet to sort the members.
                                for (MemberShape unionMember : memberShapes) {
                                    Shape target = model.expectShape(unionMember.getTarget());
                                    Symbol memberSymbol = SymbolUtils.createValueSymbolBuilder(
                                            symbolProvider.toMemberName(unionMember),
                                            unionSymbol.getNamespace()
                                    ).build();
                                    String memberHelper = getShapeValidationFunctionName(target, false);

                                    writer.openBlock("case *$T:", "", memberSymbol, () -> {
                                        String addr = "";
                                        if (!pointableIndex.isPointable(unionMember)
                                                && pointableIndex.isPointable(target)) {
                                            addr = "&";
                                        }
                                        writer.openBlock("if err := $L($Luv.Value); err != nil {", "}", memberHelper,
                                                addr, () -> {
                                                    writer.addUseImports(SmithyGoDependency.SMITHY);
                                                    writer.write("invalidParams.AddNested(\"[$L]\", "
                                                                    + "err.(smithy.InvalidParamsError))",
                                                            unionMember.getMemberName());
                                                });
                                    });
                                }
                            });
                        }
                        break;

                    default:
                        throw new CodegenException("Unexpected validation helper shape type " + shape.getType());
                }

                writer.write("if invalidParams.Len() > 0 {");
                writer.write("return invalidParams");
                writer.write("} else {");
                writer.write("return nil");
                writer.write("}");
            });
            writer.write("");
        }
    }