Skip to content

Commit

Permalink
Merge pull request #26 from metal3d/develop
Browse files Browse the repository at this point in the history
Merge from develop - cleanup, simplification, refactorization
  • Loading branch information
metal3d authored May 10, 2024
2 parents f14db9a + b56e350 commit a8c1cbd
Show file tree
Hide file tree
Showing 2 changed files with 137 additions and 100 deletions.
163 changes: 96 additions & 67 deletions ordering/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,60 @@ import (
"strings"
)

const reorderSignature = "// -- "

// DefaultOrder is the default order of elements.
//
// Note, Init and Main are not in the list. If they are present, the init and main functions
// will be moved.
var DefaultOrder = []Order{Const, Var, Interface, Type, Func}

func formatWithCommand(content []byte, output string, opt ReorderConfig) (newcontent []byte, err error) {
// findMissingOrderElement finds the missing order element.
// If the default order is not complete, it will add the missing elements.
func findMissingOrderElement(opt *ReorderConfig) {

if len(opt.DefOrder) != len(DefaultOrder) {
// wich one is missing?
for _, order := range DefaultOrder {
found := false
for _, defOrder := range opt.DefOrder {
if order == defOrder {
found = true
break
}
}
if !found {
// add it to the end
opt.DefOrder = append(opt.DefOrder, order)
}
}
}
}

func formatSource(content, output []byte, opt ReorderConfig) ([]byte, error) {

// write in a temporary file and use "gofmt" to format it
//newcontent := []byte(output)
var newcontent []byte
var err error
switch opt.FormatCommand {
case "gofmt":
// format the temporary file
newcontent, err = format.Source([]byte(output))
if err != nil {
return content, errors.New("Failed to format source: " + err.Error())
}
default:
newcontent, err = formatWithCommand(content, output, opt)
if err != nil {
return content, errors.New("Failed to format source: " + err.Error())
}
}

return newcontent, nil
}

func formatWithCommand(content []byte, output []byte, opt ReorderConfig) (newcontent []byte, err error) {
// we use the format command given by the user
// on a temporary file we need to create and remove
tmpfile, err := os.CreateTemp("", "")
Expand All @@ -27,7 +74,7 @@ func formatWithCommand(content []byte, output string, opt ReorderConfig) (newcon
defer os.Remove(tmpfile.Name())

// write the temporary file
if _, err := tmpfile.Write([]byte(output)); err != nil {
if _, err := tmpfile.Write(output); err != nil {
return content, errors.New("Failed to write temp file: " + err.Error())
}
tmpfile.Close()
Expand All @@ -45,6 +92,16 @@ func formatWithCommand(content []byte, output string, opt ReorderConfig) (newcon
return newcontent, nil
}

func getKeys(m map[string]*GoType) []string {
keys := make([]string, len(m))
i := 0
for k := range m {
keys[i] = k
i++
}
return keys
}

// const and vars
func processConst(
info *ParsedInfo,
Expand All @@ -58,7 +115,7 @@ func processConst(
*lineNumberWhereInject = info.Constants[name].OpeningLine
}
for ln := sourceCode.OpeningLine - 1; ln < sourceCode.ClosingLine; ln++ {
originalContent[ln] = "// -- " + sign
originalContent[ln] = reorderSignature + sign
}
source = append(source, sourceCode.SourceCode)
*removedLines += len(info.Constants)
Expand All @@ -84,7 +141,7 @@ func processExtractedFunction(
*lineNumberWhereInject = info.Functions[name].OpeningLine
}
for ln := sourceCode.OpeningLine - 1; ln < sourceCode.ClosingLine; ln++ {
originalContent[ln] = "// -- " + sign
originalContent[ln] = reorderSignature + sign
}
source = append(source, "\n"+sourceCode.SourceCode)
*removedLines += len(info.Functions)
Expand Down Expand Up @@ -113,7 +170,7 @@ func processFunctions(
*lineNumberWhereInject = info.Functions[name].OpeningLine
}
for ln := sourceCode.OpeningLine - 1; ln < sourceCode.ClosingLine; ln++ {
originalContent[ln] = "// -- " + sign
originalContent[ln] = reorderSignature + sign
}
source = append(source, "\n"+sourceCode.SourceCode)
*removedLines += len(info.Functions)
Expand All @@ -134,7 +191,7 @@ func processInterfaces(
*lineNumberWhereInject = info.Interfaces[name].OpeningLine
}
for ln := sourceCode.OpeningLine - 1; ln < sourceCode.ClosingLine; ln++ {
originalContent[ln] = "// -- " + sign
originalContent[ln] = reorderSignature + sign
}
source = append(source, sourceCode.SourceCode)
*removedLines += len(info.Interfaces)
Expand All @@ -155,7 +212,7 @@ func processTypes(
}
// replace the definitions by "// -- line to remove
for ln := info.Types[typename].OpeningLine - 1; ln < info.Types[typename].ClosingLine; ln++ {
originalContent[ln] = "// -- " + sign
originalContent[ln] = reorderSignature + sign
}
*removedLines += info.Types[typename].ClosingLine - info.Types[typename].OpeningLine
// add the struct definition to "source"
Expand All @@ -164,7 +221,7 @@ func processTypes(
// same for constructors
for _, constructor := range info.Constructors[typename] {
for ln := constructor.OpeningLine - 1; ln < constructor.ClosingLine; ln++ {
originalContent[ln] = "// -- " + sign
originalContent[ln] = reorderSignature + sign
}
// add the constructor to "source"
source = append(source, "\n"+constructor.SourceCode)
Expand All @@ -174,7 +231,7 @@ func processTypes(
// same for methods
for _, method := range info.Methods[typename] {
for ln := method.OpeningLine - 1; ln < method.ClosingLine; ln++ {
originalContent[ln] = "// -- " + sign
originalContent[ln] = reorderSignature + sign
}
// add the method to "source"
source = append(source, "\n"+method.SourceCode)
Expand All @@ -196,14 +253,32 @@ func processVars(
*lineNumberWhereInject = info.Variables[name].OpeningLine
}
for ln := sourceCode.OpeningLine - 1; ln < sourceCode.ClosingLine; ln++ {
originalContent[ln] = "// -- " + sign
originalContent[ln] = reorderSignature + sign
}
source = append(source, sourceCode.SourceCode)
*removedLines += len(info.Variables)
}
return source
}

func removeSignedLine(originalContent []string, sign string) []string {
// remove the lines that were marked as "// -- line to remove"
temp := []string{}
for _, line := range originalContent {
if line != reorderSignature+sign {
temp = append(temp, line)
}
}

return temp
}

func sortGoTypes(v []*GoType) {
sort.Slice(v, func(i, j int) bool {
return v[i].Name < v[j].Name
})
}

// ReorderSource reorders the source code in the given filename.
// It will be helped by the formatCommand (gofmt or goimports).
// If gofmt is used, the source code will be formatted with the go/fmt package in memory.
Expand All @@ -218,22 +293,7 @@ func ReorderSource(opt ReorderConfig) (string, error) {
if opt.DefOrder == nil {
opt.DefOrder = DefaultOrder
}
if len(opt.DefOrder) != len(DefaultOrder) {
// wich one is missing?
for _, order := range DefaultOrder {
found := false
for _, defOrder := range opt.DefOrder {
if order == defOrder {
found = true
break
}
}
if !found {
// add it to the end
opt.DefOrder = append(opt.DefOrder, order)
}
}
}
findMissingOrderElement(&opt)

var content []byte
var err error
Expand All @@ -258,33 +318,18 @@ func ReorderSource(opt ReorderConfig) (string, error) {

// sort methods by name
for _, method := range info.Methods {
sort.Slice(method, func(i, j int) bool {
return method[i].Name < method[j].Name
})
sortGoTypes(method)
}

for _, constructor := range info.Constructors {
sort.Slice(constructor, func(i, j int) bool {
return constructor[i].Name < constructor[j].Name
})
sortGoTypes(constructor)
}

functionNames := make([]string, 0, len(info.Functions))
for functionName := range info.Functions {
functionNames = append(functionNames, functionName)
}
functionNames := getKeys(info.Functions)
varNames := getKeys(info.Variables)
constNames := getKeys(info.Constants)
sort.Strings(functionNames)

varNames := make([]string, 0, len(info.Variables))
for varName := range info.Variables {
varNames = append(varNames, varName)
}
sort.Strings(varNames)

constNames := make([]string, 0, len(info.Constants))
for constName := range info.Constants {
constNames = append(constNames, constName)
}
sort.Strings(constNames)

if opt.ReorderStructs {
Expand Down Expand Up @@ -375,30 +420,14 @@ func ReorderSource(opt ReorderConfig) (string, error) {
originalContent = append(originalContent[:lineNumberWhereInject], append(source, originalContent[lineNumberWhereInject:]...)...)

// remove the lines that were marked as "// -- line to remove"
temp := []string{}
for _, line := range originalContent {
if line != "// -- "+sign {
temp = append(temp, line)
}
}
originalContent = temp
output := strings.Join(originalContent, "\n")
originalContent = removeSignedLine(originalContent, sign)
output := []byte(strings.Join(originalContent, "\n"))

// write in a temporary file and use "gofmt" to format it
//newcontent := []byte(output)
var newcontent []byte
switch opt.FormatCommand {
case "gofmt":
// format the temporary file
newcontent, err = format.Source([]byte(output))
if err != nil {
return string(content), errors.New("Failed to format source: " + err.Error())
}
default:
newcontent, err = formatWithCommand(content, output, opt)
if err != nil {
return string(content), errors.New("Failed to format source: " + err.Error())
}
newcontent, err := formatSource(content, output, opt)
if err != nil {
return string(content), err
}

if opt.Diff {
Expand Down
74 changes: 41 additions & 33 deletions ordering/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ func Parse(filename string, src interface{}) (*ParsedInfo, error) {
for _, decl := range f.Decls {
switch d := decl.(type) {
case *ast.FuncDecl:
findConstructors(d, fset, sourceLines, methods, constructors)
findConstructors(d, fset, sourceLines, constructors)
}
}
// and now functions
Expand Down Expand Up @@ -108,7 +108,7 @@ func GetTypeComments(d *ast.GenDecl) (comments []string) {
return
}

func findConstructors(d *ast.FuncDecl, fset *token.FileSet, sourceLines []string, methods, constructors map[string][]*GoType) {
func findConstructors(d *ast.FuncDecl, fset *token.FileSet, sourceLines []string, constructors map[string][]*GoType) {

if d.Type == nil || d.Type.Results == nil || len(d.Type.Results.List) == 0 { // no return type
return
Expand Down Expand Up @@ -186,37 +186,12 @@ func findGlobalVarsAndConsts(d *ast.GenDecl, fset *token.FileSet, sourceLines []
return
}
for _, spec := range d.Specs {
if s, ok := spec.(*ast.ValueSpec); ok {
for _, name := range s.Names {
// log the source code for the variable or constant
varDef := &GoType{
Name: name.Name,
OpeningLine: fset.Position(d.Pos()).Line,
ClosingLine: fset.Position(d.End()).Line,
}
comments := GetTypeComments(d)
if len(comments) > 0 {
varDef.SourceCode = strings.Join(comments, "\n") + "\n"
}
varDef.SourceCode += strings.Join(sourceLines[varDef.OpeningLine-1:varDef.ClosingLine], "\n")
varDef.OpeningLine -= len(comments)

// this time, if const or vars are defined in a parenthesis, the source code is the same for all
// found var or const. So, what we do is to check if the source code is already in the map, and if
// so, we skip it.
// we will use the source code signature as the key for the map
signature := fmt.Sprintf("%d-%d", varDef.OpeningLine, varDef.ClosingLine)
if _, ok := varTypes[signature]; ok {
continue
}

switch d.Tok {
case token.CONST:
constTypes[signature] = varDef
case token.VAR:
varTypes[signature] = varDef
}
}
s, ok := spec.(*ast.ValueSpec)
if !ok {
continue
}
for _, name := range s.Names {
parseConstantAndVars(name, d, fset, sourceLines, varTypes, constTypes)
}
}
}
Expand Down Expand Up @@ -312,6 +287,39 @@ func findTypes(d *ast.GenDecl, fset *token.FileSet, sourceLines []string, typeNa
}
}

func parseConstantAndVars(name *ast.Ident, d *ast.GenDecl, fset *token.FileSet, sourceLines []string, varTypes, constTypes map[string]*GoType) {

// log the source code for the variable or constant
varDef := &GoType{
Name: name.Name,
OpeningLine: fset.Position(d.Pos()).Line,
ClosingLine: fset.Position(d.End()).Line,
}
comments := GetTypeComments(d)
if len(comments) > 0 {
varDef.SourceCode = strings.Join(comments, "\n") + "\n"
}
varDef.SourceCode += strings.Join(sourceLines[varDef.OpeningLine-1:varDef.ClosingLine], "\n")
varDef.OpeningLine -= len(comments)

// this time, if const or vars are defined in a parenthesis, the source code is the same for all
// found var or const. So, what we do is to check if the source code is already in the map, and if
// so, we skip it.
// we will use the source code signature as the key for the map
signature := fmt.Sprintf("%d-%d", varDef.OpeningLine, varDef.ClosingLine)
if _, ok := varTypes[signature]; ok {
return
}

switch d.Tok {
case token.CONST:
constTypes[signature] = varDef
case token.VAR:
varTypes[signature] = varDef
}

}

func inConstructors(constructorMap map[string][]*GoType, funcname string) bool {
for _, constructors := range constructorMap {
for _, constructor := range constructors {
Expand Down

0 comments on commit a8c1cbd

Please sign in to comment.