diff --git a/internal/literals/literals.go b/internal/literals/literals.go index e6ee396..4800e77 100644 --- a/internal/literals/literals.go +++ b/internal/literals/literals.go @@ -10,7 +10,6 @@ import ( "go/token" "go/types" mathrand "math/rand" - "strconv" "golang.org/x/tools/go/ast/astutil" ah "mvdan.cc/garble/internal/asthelper" @@ -130,46 +129,7 @@ func Obfuscate(file *ast.File, info *types.Info, fset *token.FileSet, linkString return true } - // Imports which are used might be marked as unused by only looking at the ast, - // because packages can declare a name different from the last element of their import path. - // - // package main - // - // import "github.com/user/somepackage" - // - // func main(){ - // // this line uses github.com/user/somepackage - // anotherpackage.Foo() - // } - // - // TODO: remove this check and detect used imports with go/types somehow - prevUsedImports := make(map[string]bool) - for _, imp := range file.Imports { - path, err := strconv.Unquote(imp.Path.Value) - if err != nil { - panic(err) - } - prevUsedImports[path] = astutil.UsesImport(file, path) - } - - file = astutil.Apply(file, pre, post).(*ast.File) - - // some imported constants might not be needed anymore, remove unnecessary imports - for _, imp := range file.Imports { - path, err := strconv.Unquote(imp.Path.Value) - if err != nil { - panic(err) - } - if !prevUsedImports[path] || astutil.UsesImport(file, path) { - continue - } - - if !astutil.DeleteImport(fset, file, path) { - panic(fmt.Sprintf("cannot delete unused import: %v", path)) - } - } - - return file + return astutil.Apply(file, pre, post).(*ast.File) } // withPos sets any token.Pos fields under node which affect printing to pos. diff --git a/main.go b/main.go index 0a4eba5..d7f3cec 100644 --- a/main.go +++ b/main.go @@ -1453,6 +1453,50 @@ func (tf *transformer) transformGo(file *ast.File) *ast.File { // and that's not allowed in the runtime itself. if flagLiterals && curPkg.ToObfuscate { file = literals.Obfuscate(file, tf.info, fset, tf.linkerVariableStrings) + + // some imported constants might not be needed anymore, remove unnecessary imports + usedImports := make(map[string]bool) + ast.Inspect(file, func(n ast.Node) bool { + node, ok := n.(*ast.Ident) + if !ok { + return true + } + + uses, ok := tf.info.Uses[node].(*types.PkgName) + if !ok { + return true + } + + usedImports[uses.Imported().Path()] = true + + return true + }) + + for _, imp := range file.Imports { + if imp.Name != nil && (imp.Name.Name == "_" || imp.Name.Name == ".") { + continue + } + + path, err := strconv.Unquote(imp.Path.Value) + if err != nil { + panic(err) + } + + // The import path can't be used directly here, because the actual + // path resolved via go/types might be different from the naive path. + lpkg, err := listPackage(path) + if err != nil { + panic(err) + } + + if usedImports[lpkg.ImportPath] { + continue + } + + if !astutil.DeleteImport(fset, file, path) { + panic(fmt.Sprintf("cannot delete unused import: %q", path)) + } + } } pre := func(cursor *astutil.Cursor) bool { diff --git a/testdata/scripts/literals.txt b/testdata/scripts/literals.txt index 4be97f4..f069e00 100644 --- a/testdata/scripts/literals.txt +++ b/testdata/scripts/literals.txt @@ -64,7 +64,7 @@ package main import ( _ "runtime/debug" - "test/main/imported" + "test/main/imp" ) type structTest struct { @@ -295,7 +295,7 @@ func shadowTest() { println("obfuscated with shadowed builtins (types)") } } --- imported/imported.go -- +-- imp/imported.go -- package imported type ImportedType int