build/analysis/importsort: init

This adds an analyzer which enforces import sorting as per
CODING_STANDARDS.md. It is not yet enabled in nogo.

This effectively duplicates some logic that is present in goimports.
However, that logic is mostly within an 'internal' package in x/tools,
and would be somewhat tricky to make work within the framework of an
analysis.Analyser (as it expects to also mutate a file). Thus, we
end up writing the analysis logic ourselves. Tests are provided to make
sure this logic doesn't rot away.

We also move some common logic from 'noioutil' to a new 'lib' package,
and implement the last piece of the puzzle there: a code generator to
provide information about the toolchain's stdlib as a map/set.

Change-Id: Ia0f32d6f9122e13117d18ae781d8255c6e3a887d
Reviewed-on: https://review.monogon.dev/c/monogon/+/494
Reviewed-by: Leopold Schabel <leo@nexantic.com>
diff --git a/build/analysis/noioutil/BUILD.bazel b/build/analysis/noioutil/BUILD.bazel
index 1770430..e627a0c 100644
--- a/build/analysis/noioutil/BUILD.bazel
+++ b/build/analysis/noioutil/BUILD.bazel
@@ -5,5 +5,8 @@
     srcs = ["noioutil.go"],
     importpath = "source.monogon.dev/build/analysis/noioutil",
     visibility = ["//visibility:public"],
-    deps = ["@org_golang_x_tools//go/analysis:go_default_library"],
+    deps = [
+        "//build/analysis/lib:go_default_library",
+        "@org_golang_x_tools//go/analysis:go_default_library",
+    ],
 )
diff --git a/build/analysis/noioutil/noioutil.go b/build/analysis/noioutil/noioutil.go
index 96286e3..b98a921 100644
--- a/build/analysis/noioutil/noioutil.go
+++ b/build/analysis/noioutil/noioutil.go
@@ -3,11 +3,11 @@
 package noioutil
 
 import (
-	"go/ast"
 	"strconv"
-	"strings"
 
 	"golang.org/x/tools/go/analysis"
+
+	alib "source.monogon.dev/build/analysis/lib"
 )
 
 var Analyzer = &analysis.Analyzer{
@@ -18,7 +18,7 @@
 
 func run(p *analysis.Pass) (interface{}, error) {
 	for _, file := range p.Files {
-		if isGeneratedFile(file) {
+		if alib.IsGeneratedFile(file) {
 			continue
 		}
 		for _, i := range file.Imports {
@@ -38,21 +38,3 @@
 
 	return nil, nil
 }
-
-const (
-	genPrefix = "// Code generated"
-	genSuffix = "DO NOT EDIT."
-)
-
-// isGeneratedFile returns true if the file is generated
-// according to https://golang.org/s/generatedcode.
-func isGeneratedFile(file *ast.File) bool {
-	for _, c := range file.Comments {
-		for _, t := range c.List {
-			if strings.HasPrefix(t.Text, genPrefix) && strings.HasSuffix(t.Text, genSuffix) {
-				return true
-			}
-		}
-	}
-	return false
-}