mirror of
				https://github.com/mgechev/revive.git
				synced 2025-10-30 23:37:49 +02:00 
			
		
		
		
	feature: support cbor struct tag in struc-tag rule
				
					
				
			This commit is contained in:
		| @@ -24,6 +24,7 @@ type tagKey string | ||||
| const ( | ||||
| 	keyASN1         tagKey = "asn1" | ||||
| 	keyBSON         tagKey = "bson" | ||||
| 	keyCbor         tagKey = "cbor" | ||||
| 	keyCodec        tagKey = "codec" | ||||
| 	keyDatastore    tagKey = "datastore" | ||||
| 	keyDefault      tagKey = "default" | ||||
| @@ -45,6 +46,7 @@ type tagChecker func(checkCtx *checkContext, tag *structtag.Tag, field *ast.Fiel | ||||
| var tagCheckers = map[tagKey]tagChecker{ | ||||
| 	keyASN1:         checkASN1Tag, | ||||
| 	keyBSON:         checkBSONTag, | ||||
| 	keyCbor:         checkCborTag, | ||||
| 	keyCodec:        checkCodecTag, | ||||
| 	keyDatastore:    checkDatastoreTag, | ||||
| 	keyDefault:      checkDefaultTag, | ||||
| @@ -385,6 +387,66 @@ func checkBSONTag(checkCtx *checkContext, tag *structtag.Tag, _ *ast.Field) (mes | ||||
| 	return "", true | ||||
| } | ||||
|  | ||||
| func checkCborTag(checkCtx *checkContext, tag *structtag.Tag, _ *ast.Field) (message string, succeeded bool) { | ||||
| 	hasToArray := false | ||||
| 	hasOmitEmptyOrZero := false | ||||
| 	hasKeyAsInt := false | ||||
|  | ||||
| 	for _, opt := range tag.Options { | ||||
| 		switch opt { | ||||
| 		case "omitempty", "omitzero": | ||||
| 			hasOmitEmptyOrZero = true | ||||
| 		case "toarray": | ||||
| 			if tag.Name != "" { | ||||
| 				return `tag name for option "toarray" should be empty`, false | ||||
| 			} | ||||
| 			hasToArray = true | ||||
| 		case "keyasint": | ||||
| 			intKey, err := strconv.Atoi(tag.Name) | ||||
| 			if err != nil { | ||||
| 				return `tag name for option "keyasint" should be an integer`, false | ||||
| 			} | ||||
|  | ||||
| 			_, ok := checkCtx.usedTagNbr[intKey] | ||||
| 			if ok { | ||||
| 				return fmt.Sprintf("duplicated integer key %d", intKey), false | ||||
| 			} | ||||
|  | ||||
| 			checkCtx.usedTagNbr[intKey] = true | ||||
| 			hasKeyAsInt = true | ||||
| 			continue | ||||
|  | ||||
| 		default: | ||||
| 			if !checkCtx.isUserDefined(keyCbor, opt) { | ||||
| 				return fmt.Sprintf(msgUnknownOption, opt), false | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// Check for duplicated tag names | ||||
| 	if tag.Name != "" { | ||||
| 		_, ok := checkCtx.usedTagName[tag.Name] | ||||
| 		if ok { | ||||
| 			return fmt.Sprintf("duplicated tag name %s", tag.Name), false | ||||
| 		} | ||||
| 		checkCtx.usedTagName[tag.Name] = true | ||||
| 	} | ||||
|  | ||||
| 	// Check for integer tag names without keyasint option | ||||
| 	if !hasKeyAsInt { | ||||
| 		_, err := strconv.Atoi(tag.Name) | ||||
| 		if err == nil { | ||||
| 			return `integer tag names are only allowed in presence of "keyasint" option`, false | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if hasToArray && hasOmitEmptyOrZero { | ||||
| 		return `options "omitempty" and "omitzero" are ignored in presence of "toarray" option`, false | ||||
| 	} | ||||
|  | ||||
| 	return "", true | ||||
| } | ||||
|  | ||||
| const structTagCodecSpecialField = "_struct" | ||||
|  | ||||
| func checkCodecTag(checkCtx *checkContext, tag *structtag.Tag, field *ast.Field) (message string, succeeded bool) { | ||||
|   | ||||
| @@ -23,6 +23,7 @@ func TestStructTagWithUserOptions(t *testing.T) { | ||||
| 			"toml,unknown", | ||||
| 			"spanner,mySpannerOption", | ||||
| 			"codec,myCodecOption", | ||||
| 			"cbor,myCborOption", | ||||
| 		}, | ||||
| 	}) | ||||
| } | ||||
|   | ||||
							
								
								
									
										21
									
								
								testdata/struct_tag.go
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										21
									
								
								testdata/struct_tag.go
									
									
									
									
										vendored
									
									
								
							| @@ -215,3 +215,24 @@ type TestDuplicatedCodecTags struct { | ||||
| 	B       int      `codec:"field_a"` // MATCH /duplicated tag name "field_a" in codec tag/ | ||||
| 	C       int      `codec:"field_c"` | ||||
| } | ||||
|  | ||||
| type Cbor struct { | ||||
| 	RepeatedStr string `cbor:"errors"` | ||||
| 	Repeated    string `cbor:"1,keyasint"` | ||||
| 	Useless     string `cbor:"-,omitempty"`              // MATCH /useless option omitempty for ignored field in cbor tag/ | ||||
| 	Inputs      string `cbor:",keyasint"`                // MATCH /tag name for option "keyasint" should be an integer in cbor tag/ | ||||
| 	Outputs     string `cbor:"inputs,keyasint"`          // MATCH /tag name for option "keyasint" should be an integer in cbor tag/ | ||||
| 	Errors      string `cbor:"errors,optempty,keyasint"` // MATCH /unknown option "optempty" in cbor tag/ | ||||
| 	Inputs2     string `cbor:"-10,omitempty"`            // MATCH /integer tag names are only allowed in presence of "keyasint" option in cbor tag/ | ||||
| 	Outputs2    string `cbor:"-12,toarray"`              // MATCH /tag name for option "toarray" should be empty in cbor tag/ | ||||
| 	RepeatedInt string `cbor:"1,keyasint"`               // MATCH /duplicated integer key 1 in cbor tag/ | ||||
| 	RepeatedStr string `cbor:"errors,omitempty"`         // MATCH /duplicated tag name errors in cbor tag/ | ||||
| 	Useless     string `cbor:",toarray,omitempty"`       // MATCH /options "omitempty" and "omitzero" are ignored in presence of "toarray" option in cbor tag/ | ||||
| 	Useless2    string `cbor:",omitzero,toarray"`        // MATCH /options "omitempty" and "omitzero" are ignored in presence of "toarray" option in cbor tag/ | ||||
| 	// OK | ||||
| 	InputsOk   string `cbor:"8,keyasint"` | ||||
| 	OutputsOk  string `cbor:"-100,keyasint"` | ||||
| 	ErrorsOk   string `cbor:"-1,keyasint"` | ||||
| 	InputsOk2  string `cbor:"inputs,omitempty"` | ||||
| 	OutputsOk2 string `cbor:",toarray"` | ||||
| } | ||||
|   | ||||
							
								
								
									
										8
									
								
								testdata/struct_tag_user_options.go
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								testdata/struct_tag_user_options.go
									
									
									
									
										vendored
									
									
								
							| @@ -102,3 +102,11 @@ type CodecUserOptions struct { | ||||
| 	ID   int    `codec:"user_id,myCodecOption"` | ||||
| 	Name string `codec:"full_name,unknownOption"` // MATCH /unknown option "unknownOption" in codec tag/ | ||||
| } | ||||
|  | ||||
| type CborUserOptions struct { | ||||
| 	InputsOk   string `cbor:"8,keyasint,myCborOption"` | ||||
| 	OutputsOk  string `cbor:"-100,keyasint,unknownOption"` // MATCH /unknown option "unknownOption" in cbor tag/ | ||||
| 	ErrorsOk   string `cbor:"-1,keyasint"` | ||||
| 	InputsOk2  string `cbor:"inputs,omitempty"` | ||||
| 	OutputsOk2 string `cbor:",toarray"` | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user