// OverwriteStructTag overwrites the struct tag completely func OverwriteStructTag(tag *ast.BasicLit, tagName string, offset *int, data []byte) []byte { val := tag.Value start := int(tag.Pos()) + *offset - 1 end := int(tag.End()) + *offset - 1 length := len(val) oldLength := end - start // Delete the original tag data = DeleteRange(data, start, end) var newTag string if options.AppendMode == Append { oldTag := removeIndex(removeIndex(val, 0), len(val)-2) newTag = fmt.Sprintf("`%s:\"%s\" %s`", options.Tag, tagName, oldTag) } else { newTag = fmt.Sprintf("`%s:\"%s\"`", options.Tag, tagName) } numSpaces := len(newTag) - oldLength - 1 var spaces string // Can't pass a negative number to strings.Repeat() // it will cause a panic because it passes this number directly to make() if numSpaces > 0 { spaces = strings.Repeat(" ", numSpaces) } newTag = fmt.Sprintf("%s%s", spaces, newTag) localOffset := len(newTag) - length *offset += localOffset // Insert new tag data = Insert(data, []byte(newTag), start) return data }
func (check *checker) tag(t *ast.BasicLit) string { if t != nil { if t.Kind == token.STRING { if val, err := strconv.Unquote(t.Value); err == nil { return val } } check.invalidAST(t.Pos(), "incorrect tag syntax: %q", t.Value) } return "" }
// compiles a basic literal, like numbers and strings func (w *World) compileBasicLit(n *ast.BasicLit) Expr { switch n.Kind { default: panic(err(n.Pos(), "not allowed:", n.Value, "(", typ(n), ")")) case token.FLOAT: return floatLit(parseFloat(n.Value)) case token.INT: return intLit(parseInt(n.Value)) case token.STRING: return stringLit(n.Value[1 : len(n.Value)-1]) // remove quotes } }
func (file *File) basicLitToMessage(node *ast.BasicLit) Message { if node.Kind != token.STRING { panic("only call basicLitToMessage with a string node") } val, _ := strconv.Unquote(node.Value) pos := file.FSet.Position(node.Pos()) xcomment := file.cmap.Get(node, pos) return Message{ XComment: xcomment, Reference: []token.Position{pos}, Flags: []string{}, MsgCtxt: nil, MsgID: val, MsgIDPlural: nil, } }
func TestExtractsLiteral(t *testing.T) { var root ast.BasicLit root.Kind = token.INT root.Value = "0" replace, fn := ExtractFnFromExpr("t", &root) if replace.Fun.(*ast.Ident).Name != "t" { t.Fail() } if fn.Recv != nil { t.Fail() } if fn.Name.Name != "t" { t.Fail() } if len(fn.Body.List) != 1 { t.Fail() } switch x := fn.Body.List[0].(type) { case *ast.ReturnStmt: if len(x.Results) != 1 { t.Fail() } else { if x.Results[0].(*ast.BasicLit).Kind != token.INT { t.Fail() } if x.Results[0].(*ast.BasicLit).Value != "0" { t.Fail() } } default: t.Fail() } printer.Fprint(os.Stdout, token.NewFileSet(), fn) printer.Fprint(os.Stdout, token.NewFileSet(), replace) }
func (rp *rewritePackage) wrapCallExprWithInterpolatedT(basicLit *ast.BasicLit, callExpr *ast.CallExpr, argIndex int) { valueWithoutQuotes, _ := strconv.Unquote(basicLit.Value) i18nStringInfo, ok := rp.ExtractedStrings[valueWithoutQuotes] if !ok && rp.ExtractedStrings != nil { rp.wrapExprArgs(callExpr.Args) return } templatedString := common.ConvertToTemplatedString(valueWithoutQuotes) basicLit.Value = strconv.Quote(templatedString) if rp.ExtractedStrings != nil { rp.updateExtractedStrings(i18nStringInfo, templatedString) } rp.wrapCallExprWithTemplatedT(basicLit, callExpr, argIndex) }
func (rp *rewritePackage) wrapBasicLitWithTemplatedT(basicLit *ast.BasicLit, args []ast.Expr, callExpr *ast.CallExpr, argIndex int) ast.Expr { valueWithoutQuotes, _ := strconv.Unquote(basicLit.Value) //basicLit.Value[1 : len(basicLit.Value)-1] _, ok := rp.ExtractedStrings[valueWithoutQuotes] if !ok && rp.ExtractedStrings != nil { return callExpr } rp.TotalStrings++ tIdent := &ast.Ident{Name: "T"} argNames := common.GetTemplatedStringArgs(valueWithoutQuotes) compositeExpr := []ast.Expr{} processedArgsMap := make(map[string]bool) for i, argName := range argNames { if callExpr, ok := args[argIndex+i+1].(*ast.CallExpr); ok { rp.callExprTFunc(callExpr) } else if basicLit, ok := args[argIndex+i+1].(*ast.BasicLit); ok { args[argIndex+i] = rp.wrapBasicLitWithT(basicLit) } if processedArgsMap[argName] != true { quotedArgName := "\"" + argName + "\"" basicLit.ValuePos = 0 valueExpr := args[argIndex+i+1] if basicLit, ok := args[argIndex+i+1].(*ast.BasicLit); ok { valueExpr = rp.wrapBasicLitWithT(basicLit) } keyValueExpr := &ast.KeyValueExpr{Key: &ast.BasicLit{Kind: 9, Value: quotedArgName}, Value: valueExpr} processedArgsMap[argName] = true compositeExpr = append(compositeExpr, keyValueExpr) } } mapInterfaceType := &ast.InterfaceType{Interface: 142, Methods: &ast.FieldList{List: nil, Opening: 1, Closing: 2}, Incomplete: false} mapType := &ast.MapType{Map: 131, Key: &ast.Ident{Name: "string"}, Value: mapInterfaceType} compositeLit := &ast.CompositeLit{Type: mapType, Elts: compositeExpr} return &ast.CallExpr{Fun: tIdent, Args: []ast.Expr{basicLit, compositeLit}} }
// Visit browses the AST tree for strings that could be potentially // replaced by constants. // A map of existing constants is built as well (-match-constant). func (v *treeVisitor) Visit(node ast.Node) ast.Visitor { if node == nil { return v } // A single case with "ast.BasicLit" would be much easier // but then we wouldn't be able to tell in which context // the string is defined (could be a constant definition). switch t := node.(type) { // Scan for constants in an attempt to match strings with existing constants case *ast.GenDecl: if !v.p.matchConstant { return v } if t.Tok != token.CONST { return v } for _, spec := range t.Specs { val := spec.(*ast.ValueSpec) for i, str := range val.Values { lit, ok := str.(*ast.BasicLit) if !ok || !v.isSupported(lit.Kind) { continue } v.addConst(val.Names[i].Name, lit.Value, val.Names[i].Pos()) } } // foo := "moo" case *ast.AssignStmt: for _, rhs := range t.Rhs { lit, ok := rhs.(*ast.BasicLit) if !ok || !v.isSupported(lit.Kind) { continue } v.addString(lit.Value, rhs.(*ast.BasicLit).Pos()) } // if foo == "moo" case *ast.BinaryExpr: if t.Op != token.EQL && t.Op != token.NEQ { return v } var lit *ast.BasicLit var ok bool lit, ok = t.X.(*ast.BasicLit) if ok && v.isSupported(lit.Kind) { v.addString(lit.Value, lit.Pos()) } lit, ok = t.Y.(*ast.BasicLit) if ok && v.isSupported(lit.Kind) { v.addString(lit.Value, lit.Pos()) } // case "foo": case *ast.CaseClause: for _, item := range t.List { lit, ok := item.(*ast.BasicLit) if ok && v.isSupported(lit.Kind) { v.addString(lit.Value, lit.Pos()) } } // return "boo" case *ast.ReturnStmt: for _, item := range t.Results { lit, ok := item.(*ast.BasicLit) if ok && v.isSupported(lit.Kind) { v.addString(lit.Value, lit.Pos()) } } } return v }