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/lib/generated.go b/build/analysis/lib/generated.go
new file mode 100644
index 0000000..209a73f
--- /dev/null
+++ b/build/analysis/lib/generated.go
@@ -0,0 +1,29 @@
+package lib
+
+import (
+	"go/ast"
+	"strings"
+)
+
+const (
+	genPrefix = "// Code generated"
+	genSuffix = "DO NOT EDIT."
+)
+
+// IsGeneratedFile returns true if the file is generated according to
+// https://golang.org/s/generatedcode and other heuristics.
+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
+			}
+			// Generated testmain.go stubs from rules_go - for some reason, they don't
+			// contain the expected markers.
+			if strings.Contains(t.Text, "This package must be initialized before packages being tested.") {
+				return true
+			}
+		}
+	}
+	return false
+}