mirror of
https://github.com/woodpecker-ci/woodpecker.git
synced 2024-12-02 06:41:18 +00:00
56a854fe14
* update github.com/docker/cli * update github.com/docker/distribution * update github.com/docker/docker * update github.com/gin-gonic/gin * update github.com/golang-jwt/jwt/v4 * update github.com/golangci/golangci-lint * update github.com/gorilla/securecookie * update github.com/mattn/go-sqlite3 * update github.com/moby/moby * update github.com/prometheus/client_golang * update github.com/xanzy/go-gitlab
141 lines
3.5 KiB
Go
141 lines
3.5 KiB
Go
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
|
|
}
|