Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Develop #26

Merged
merged 2 commits into from
May 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading