(buf *bytes.Buffer, structInfo StructInfo)
| 46 | } |
| 47 | |
| 48 | func generateStructGuard(buf *bytes.Buffer, structInfo StructInfo) { |
| 49 | typeName := structInfo.Name |
| 50 | expectedTypeName := fmt.Sprintf("_%s_expected", typeName) |
| 51 | |
| 52 | // Generate the snapshot struct |
| 53 | buf.WriteString(fmt.Sprintf("// Snapshot of %s's underlying type at generation time.\n", typeName)) |
| 54 | buf.WriteString(fmt.Sprintf("type %s struct {\n", expectedTypeName)) |
| 55 | |
| 56 | // Sort fields by their original index to match the struct definition |
| 57 | // This is important for the compile-time guard to work correctly |
| 58 | originalFields := make([]*FieldInfo, len(structInfo.Fields)) |
| 59 | copy(originalFields, structInfo.Fields) |
| 60 | sort.Slice(originalFields, func(i, j int) bool { |
| 61 | return originalFields[i].Index < originalFields[j].Index |
| 62 | }) |
| 63 | |
| 64 | for _, field := range originalFields { |
| 65 | buf.WriteString(fmt.Sprintf("\t%s %s", field.GoName, formatFieldType(*field))) |
| 66 | |
| 67 | // Add struct tag if present (we'll extract it from the original struct) |
| 68 | // For now, skip tags - they would require access to the original AST |
| 69 | |
| 70 | buf.WriteString("\n") |
| 71 | } |
| 72 | |
| 73 | buf.WriteString("}\n\n") |
| 74 | |
| 75 | // Generate the compile-time check function with better error message |
| 76 | buf.WriteString(fmt.Sprintf("// Compile-time check: this conversion is legal only if %s's underlying type\n", typeName)) |
| 77 | buf.WriteString(fmt.Sprintf("// is identical to %s (names, order, types, tags).\n", expectedTypeName)) |
| 78 | buf.WriteString(fmt.Sprintf("//\n")) |
| 79 | buf.WriteString(fmt.Sprintf("// If compilation fails here, it means you've modified the %s struct but haven't\n", typeName)) |
| 80 | buf.WriteString(fmt.Sprintf("// regenerated the code. Please run: go generate\n")) |
| 81 | buf.WriteString(fmt.Sprintf("//\n")) |
| 82 | buf.WriteString(fmt.Sprintf("// If go generate also fails, delete this file first: rm %s_fory_gen.go\n", strings.ToLower(typeName))) |
| 83 | buf.WriteString(fmt.Sprintf("// Then run: go generate\n")) |
| 84 | buf.WriteString(fmt.Sprintf("var _ = func(x %s) {\n", typeName)) |
| 85 | buf.WriteString(fmt.Sprintf("\t// ERROR: %s struct has changed! Run 'go generate' to fix this.\n", typeName)) |
| 86 | buf.WriteString(fmt.Sprintf("\t_ = %s(x)\n", expectedTypeName)) |
| 87 | buf.WriteString("}\n\n") |
| 88 | } |
| 89 | |
| 90 | func formatFieldType(field FieldInfo) string { |
| 91 | return formatGoType(field.Type) |
no test coverage detected