aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/github.com/julz/importas/analyzer.go
diff options
context:
space:
mode:
authorTaras Madan <tarasmadan@google.com>2022-09-05 14:27:54 +0200
committerGitHub <noreply@github.com>2022-09-05 12:27:54 +0000
commitb2f2446b46bf02821d90ebedadae2bf7ae0e880e (patch)
tree923cf42842918d6bebca1d6bbdc08abed54d274d /vendor/github.com/julz/importas/analyzer.go
parente6654faff4bcca4be92e9a8596fd4b77f747c39e (diff)
go.mod, vendor: update (#3358)
* go.mod, vendor: remove unnecessary dependencies Commands: 1. go mod tidy 2. go mod vendor * go.mod, vendor: update cloud.google.com/go Commands: 1. go get -u cloud.google.com/go 2. go mod tidy 3. go mod vendor * go.mod, vendor: update cloud.google.com/* Commands: 1. go get -u cloud.google.com/storage cloud.google.com/logging 2. go mod tidy 3. go mod vendor * go.mod, .golangci.yml, vendor: update *lint* Commands: 1. go get -u golang.org/x/tools github.com/golangci/golangci-lint@v1.47.0 2. go mod tidy 3. go mod vendor 4. edit .golangci.yml to suppress new errors (resolved in the same PR later) * all: fix lint errors hash.go: copy() recommended by gosimple parse.go: ent is never nil verifier.go: signal.Notify() with unbuffered channel is bad. Have no idea why. * .golangci.yml: adjust godot rules check-all is deprecated, but still work if you're hesitating too - I'll remove this commit
Diffstat (limited to 'vendor/github.com/julz/importas/analyzer.go')
-rw-r--r--vendor/github.com/julz/importas/analyzer.go141
1 files changed, 141 insertions, 0 deletions
diff --git a/vendor/github.com/julz/importas/analyzer.go b/vendor/github.com/julz/importas/analyzer.go
new file mode 100644
index 000000000..f19653478
--- /dev/null
+++ b/vendor/github.com/julz/importas/analyzer.go
@@ -0,0 +1,141 @@
+package importas
+
+import (
+ "fmt"
+ "go/ast"
+ "go/types"
+ "strconv"
+ "strings"
+
+ "golang.org/x/tools/go/analysis"
+ "golang.org/x/tools/go/analysis/passes/inspect"
+ "golang.org/x/tools/go/ast/inspector"
+)
+
+var config = &Config{
+ RequiredAlias: make(map[string]string),
+}
+
+var Analyzer = &analysis.Analyzer{
+ Name: "importas",
+ Doc: "Enforces consistent import aliases",
+ Run: run,
+
+ Flags: flags(config),
+
+ Requires: []*analysis.Analyzer{inspect.Analyzer},
+}
+
+func run(pass *analysis.Pass) (interface{}, error) {
+ return runWithConfig(config, pass)
+}
+
+func runWithConfig(config *Config, pass *analysis.Pass) (interface{}, error) {
+ if err := config.CompileRegexp(); err != nil {
+ return nil, err
+ }
+
+ inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
+ inspect.Preorder([]ast.Node{(*ast.ImportSpec)(nil)}, func(n ast.Node) {
+ visitImportSpecNode(config, n.(*ast.ImportSpec), pass)
+ })
+
+ return nil, nil
+}
+
+func visitImportSpecNode(config *Config, node *ast.ImportSpec, pass *analysis.Pass) {
+ if !config.DisallowUnaliased && node.Name == nil {
+ return
+ }
+
+ alias := ""
+ if node.Name != nil {
+ alias = node.Name.String()
+ }
+
+ if alias == "." {
+ return // Dot aliases are generally used in tests, so ignore.
+ }
+
+ if strings.HasPrefix(alias, "_") {
+ return // Used by go test and for auto-includes, not a conflict.
+ }
+
+ path, err := strconv.Unquote(node.Path.Value)
+ if err != nil {
+ pass.Reportf(node.Pos(), "import not quoted")
+ }
+
+ if required, exists := config.AliasFor(path); exists && required != alias {
+ message := fmt.Sprintf("import %q imported as %q but must be %q according to config", path, alias, required)
+ if alias == "" {
+ message = fmt.Sprintf("import %q imported without alias but must be with alias %q according to config", path, required)
+ }
+
+ pass.Report(analysis.Diagnostic{
+ Pos: node.Pos(),
+ End: node.End(),
+ Message: message,
+ SuggestedFixes: []analysis.SuggestedFix{{
+ Message: "Use correct alias",
+ TextEdits: findEdits(node, pass.TypesInfo.Uses, path, alias, required),
+ }},
+ })
+ } else if !exists && config.DisallowExtraAliases {
+ pass.Report(analysis.Diagnostic{
+ Pos: node.Pos(),
+ End: node.End(),
+ Message: fmt.Sprintf("import %q has alias %q which is not part of config", path, alias),
+ SuggestedFixes: []analysis.SuggestedFix{{
+ Message: "remove alias",
+ TextEdits: findEdits(node, pass.TypesInfo.Uses, path, alias, ""),
+ }},
+ })
+ }
+}
+
+func findEdits(node ast.Node, uses map[*ast.Ident]types.Object, importPath, original, required string) []analysis.TextEdit {
+ // Edit the actual import line.
+ importLine := strconv.Quote(importPath)
+ if required != "" {
+ importLine = required + " " + importLine
+ }
+ result := []analysis.TextEdit{{
+ Pos: node.Pos(),
+ End: node.End(),
+ NewText: []byte(importLine),
+ }}
+
+ packageReplacement := required
+ if required == "" {
+ packageParts := strings.Split(importPath, "/")
+ if len(packageParts) != 0 {
+ packageReplacement = packageParts[len(packageParts)-1]
+ } else {
+ // fall back to original
+ packageReplacement = original
+ }
+ }
+
+ // Edit all the uses of the alias in the code.
+ for use, pkg := range uses {
+ pkgName, ok := pkg.(*types.PkgName)
+ if !ok {
+ // skip identifiers that aren't pointing at a PkgName.
+ continue
+ }
+
+ if pkgName.Pos() != node.Pos() {
+ // skip identifiers pointing to a different import statement.
+ continue
+ }
+
+ result = append(result, analysis.TextEdit{
+ Pos: use.Pos(),
+ End: use.End(),
+ NewText: []byte(packageReplacement),
+ })
+ }
+
+ return result
+}