...
  
  Source file src/pkg/go/ast/import.go
     1	
     2	
     3	
     4	
     5	package ast
     6	
     7	import (
     8		"go/token"
     9		"sort"
    10		"strconv"
    11	)
    12	
    13	
    14	
    15	func SortImports(fset *token.FileSet, f *File) {
    16		for _, d := range f.Decls {
    17			d, ok := d.(*GenDecl)
    18			if !ok || d.Tok != token.IMPORT {
    19				
    20				
    21				break
    22			}
    23	
    24			if !d.Lparen.IsValid() {
    25				
    26				continue
    27			}
    28	
    29			
    30			i := 0
    31			specs := d.Specs[:0]
    32			for j, s := range d.Specs {
    33				if j > i && fset.Position(s.Pos()).Line > 1+fset.Position(d.Specs[j-1].End()).Line {
    34					
    35					specs = append(specs, sortSpecs(fset, f, d.Specs[i:j])...)
    36					i = j
    37				}
    38			}
    39			specs = append(specs, sortSpecs(fset, f, d.Specs[i:])...)
    40			d.Specs = specs
    41	
    42			
    43			if len(d.Specs) > 0 {
    44				lastSpec := d.Specs[len(d.Specs)-1]
    45				lastLine := fset.Position(lastSpec.Pos()).Line
    46				rParenLine := fset.Position(d.Rparen).Line
    47				for rParenLine > lastLine+1 {
    48					rParenLine--
    49					fset.File(d.Rparen).MergeLine(rParenLine)
    50				}
    51			}
    52		}
    53	}
    54	
    55	func importPath(s Spec) string {
    56		t, err := strconv.Unquote(s.(*ImportSpec).Path.Value)
    57		if err == nil {
    58			return t
    59		}
    60		return ""
    61	}
    62	
    63	func importName(s Spec) string {
    64		n := s.(*ImportSpec).Name
    65		if n == nil {
    66			return ""
    67		}
    68		return n.Name
    69	}
    70	
    71	func importComment(s Spec) string {
    72		c := s.(*ImportSpec).Comment
    73		if c == nil {
    74			return ""
    75		}
    76		return c.Text()
    77	}
    78	
    79	
    80	func collapse(prev, next Spec) bool {
    81		if importPath(next) != importPath(prev) || importName(next) != importName(prev) {
    82			return false
    83		}
    84		return prev.(*ImportSpec).Comment == nil
    85	}
    86	
    87	type posSpan struct {
    88		Start token.Pos
    89		End   token.Pos
    90	}
    91	
    92	func sortSpecs(fset *token.FileSet, f *File, specs []Spec) []Spec {
    93		
    94		
    95		
    96		if len(specs) <= 1 {
    97			return specs
    98		}
    99	
   100		
   101		pos := make([]posSpan, len(specs))
   102		for i, s := range specs {
   103			pos[i] = posSpan{s.Pos(), s.End()}
   104		}
   105	
   106		
   107		
   108		lastLine := fset.Position(pos[len(pos)-1].End).Line
   109		cstart := len(f.Comments)
   110		cend := len(f.Comments)
   111		for i, g := range f.Comments {
   112			if g.Pos() < pos[0].Start {
   113				continue
   114			}
   115			if i < cstart {
   116				cstart = i
   117			}
   118			if fset.Position(g.End()).Line > lastLine {
   119				cend = i
   120				break
   121			}
   122		}
   123		comments := f.Comments[cstart:cend]
   124	
   125		
   126		importComments := map[*ImportSpec][]*CommentGroup{}
   127		specIndex := 0
   128		for _, g := range comments {
   129			for specIndex+1 < len(specs) && pos[specIndex+1].Start <= g.Pos() {
   130				specIndex++
   131			}
   132			s := specs[specIndex].(*ImportSpec)
   133			importComments[s] = append(importComments[s], g)
   134		}
   135	
   136		
   137		
   138		
   139		
   140		
   141		sort.Slice(specs, func(i, j int) bool {
   142			ipath := importPath(specs[i])
   143			jpath := importPath(specs[j])
   144			if ipath != jpath {
   145				return ipath < jpath
   146			}
   147			iname := importName(specs[i])
   148			jname := importName(specs[j])
   149			if iname != jname {
   150				return iname < jname
   151			}
   152			return importComment(specs[i]) < importComment(specs[j])
   153		})
   154	
   155		
   156		
   157		deduped := specs[:0]
   158		for i, s := range specs {
   159			if i == len(specs)-1 || !collapse(s, specs[i+1]) {
   160				deduped = append(deduped, s)
   161			} else {
   162				p := s.Pos()
   163				fset.File(p).MergeLine(fset.Position(p).Line)
   164			}
   165		}
   166		specs = deduped
   167	
   168		
   169		for i, s := range specs {
   170			s := s.(*ImportSpec)
   171			if s.Name != nil {
   172				s.Name.NamePos = pos[i].Start
   173			}
   174			s.Path.ValuePos = pos[i].Start
   175			s.EndPos = pos[i].End
   176			for _, g := range importComments[s] {
   177				for _, c := range g.List {
   178					c.Slash = pos[i].End
   179				}
   180			}
   181		}
   182	
   183		sort.Slice(comments, func(i, j int) bool {
   184			return comments[i].Pos() < comments[j].Pos()
   185		})
   186	
   187		return specs
   188	}
   189	
View as plain text