From: Robert Griesemer Date: Thu, 22 Jan 2015 18:43:16 +0000 (-0800) Subject: go/printer, cmd/gofmt: print import paths in double quotes X-Git-Tag: go1.5beta1~2279 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=ad54a16b1583bf3102c5d087de587e7144a0bf11;p=gostls13.git go/printer, cmd/gofmt: print import paths in double quotes Fixes #9644. Change-Id: Ia2e42befa20233107ac5409e79f9dce794983a3f Reviewed-on: https://go-review.googlesource.com/3200 Reviewed-by: Alan Donovan --- diff --git a/src/go/printer/nodes.go b/src/go/printer/nodes.go index d5a69349be..fe047053af 100644 --- a/src/go/printer/nodes.go +++ b/src/go/printer/nodes.go @@ -12,6 +12,9 @@ import ( "bytes" "go/ast" "go/token" + "strconv" + "strings" + "unicode" "unicode/utf8" ) @@ -1334,6 +1337,49 @@ func (p *printer) valueSpec(s *ast.ValueSpec, keepType bool) { } } +func sanitizeImportPath(lit *ast.BasicLit) *ast.BasicLit { + // Note: An unmodified AST generated by go/parser will already + // contain a backward- or double-quoted path string that does + // not contain any invalid characters, and most of the work + // here is not needed. However, a modified or generated AST + // may possibly contain non-canonical paths. Do the work in + // all cases since it's not too hard and not speed-critical. + + // if we don't have a proper string, be conservative and return whatever we have + if lit.Kind != token.STRING { + return lit + } + s, err := strconv.Unquote(lit.Value) + if err != nil { + return lit + } + + // if the string is an invalid path, return whatever we have + // + // spec: "Implementation restriction: A compiler may restrict + // ImportPaths to non-empty strings using only characters belonging + // to Unicode's L, M, N, P, and S general categories (the Graphic + // characters without spaces) and may also exclude the characters + // !"#$%&'()*,:;<=>?[\]^`{|} and the Unicode replacement character + // U+FFFD." + if s == "" { + return lit + } + const illegalChars = `!"#$%&'()*,:;<=>?[\]^{|}` + "`\uFFFD" + for _, r := range s { + if !unicode.IsGraphic(r) || unicode.IsSpace(r) || strings.ContainsRune(illegalChars, r) { + return lit + } + } + + // otherwise, return the double-quoted path + s = strconv.Quote(s) + if s == lit.Value { + return lit // nothing wrong with lit + } + return &ast.BasicLit{ValuePos: lit.ValuePos, Kind: token.STRING, Value: s} +} + // The parameter n is the number of specs in the group. If doIndent is set, // multi-line identifier lists in the spec are indented when the first // linebreak is encountered. @@ -1346,7 +1392,7 @@ func (p *printer) spec(spec ast.Spec, n int, doIndent bool) { p.expr(s.Name) p.print(blank) } - p.expr(s.Path) + p.expr(sanitizeImportPath(s.Path)) p.setComment(s.Comment) p.print(s.EndPos) diff --git a/src/go/printer/testdata/declarations.golden b/src/go/printer/testdata/declarations.golden index 9acd41b7d2..b7be6f80ad 100644 --- a/src/go/printer/testdata/declarations.golden +++ b/src/go/printer/testdata/declarations.golden @@ -110,6 +110,12 @@ import ( "package_dddd" // comment ) +// print import paths as double-quoted strings +import ( + "fmt" + "math" +) + // at least one empty line between declarations of different kind import _ "io" diff --git a/src/go/printer/testdata/declarations.input b/src/go/printer/testdata/declarations.input index 45beec25fc..a0a3783b84 100644 --- a/src/go/printer/testdata/declarations.input +++ b/src/go/printer/testdata/declarations.input @@ -111,6 +111,15 @@ import ( "package_dddd" // comment ) +// print import paths as double-quoted strings +// (we would like more test cases but the go/parser +// already excludes most incorrect paths, and we don't +// bother setting up test-ASTs manually) +import ( + `fmt` + "math" +) + // at least one empty line between declarations of different kind import _ "io" var _ int