Add hook to be called after defaults have been applied

Previously, the only way for a module type to create modules (other
than defining its own mutator) was to register a LoadHook. However,
that is called before defaults are applied so any properties used in
that hook cannot take advantage of defaults, e.g. java_sdk_library
cannot use defaults to set its sdk_version property and have that
affect its child modules.

This change adds a new SetDefaultableHook() to DefaultableModule to
register a hook that is called after any defaults have been applied.

Also adds some tests to ensure that errors in the visibility property
introduced in a DefaultableHook are reported in the gather phase of
visibility processing.

A follow up change will switch java_sdk_library to use that instead
of the AddLoadHook() mechanism.

Bug: 155295806
Test: m checkapi
Change-Id: I13df3115f9e225f7324b6725eaeb16a78cc2538a
diff --git a/android/visibility_test.go b/android/visibility_test.go
index 8dd6a8f..4cf41a6 100644
--- a/android/visibility_test.go
+++ b/android/visibility_test.go
@@ -903,6 +903,69 @@
 				}`),
 		},
 	},
+	{
+		name: "ensure visibility properties are checked for correctness",
+		fs: map[string][]byte{
+			"top/Blueprints": []byte(`
+				mock_parent {
+					name: "parent",
+					visibility: ["//top/nested"],
+					child: {
+						name: "libchild",
+						visibility: ["top/other"],
+					},
+				}`),
+		},
+		expectedErrors: []string{
+			`module "parent": child.visibility: invalid visibility pattern "top/other"`,
+		},
+	},
+	{
+		name: "invalid visibility added to child detected during gather phase",
+		fs: map[string][]byte{
+			"top/Blueprints": []byte(`
+				mock_parent {
+					name: "parent",
+					visibility: ["//top/nested"],
+					child: {
+						name: "libchild",
+						invalid_visibility: ["top/other"],
+					},
+				}`),
+		},
+		expectedErrors: []string{
+			// That this error is reported against the child not the parent shows it was
+			// not being detected in the parent which is correct as invalid_visibility is
+			// purposely not added to the list of visibility properties to check, and was
+			// in fact detected in the child in the gather phase. Contrast this error message
+			// with the preceding one.
+			`module "libchild" \(created by module "parent"\): visibility: invalid visibility pattern "top/other"`,
+		},
+	},
+	{
+		name: "automatic visibility inheritance enabled",
+		fs: map[string][]byte{
+			"top/Blueprints": []byte(`
+				mock_parent {
+					name: "parent",
+					visibility: ["//top/nested"],
+					child: {
+						name: "libchild",
+						visibility: ["//top/other"],
+					},
+				}`),
+			"top/nested/Blueprints": []byte(`
+				mock_library {
+					name: "libnested",
+					deps: ["libchild"],
+				}`),
+			"top/other/Blueprints": []byte(`
+				mock_library {
+					name: "libother",
+					deps: ["libchild"],
+				}`),
+		},
+	},
 }
 
 func TestVisibility(t *testing.T) {
@@ -936,6 +999,7 @@
 
 	ctx := NewTestArchContext()
 	ctx.RegisterModuleType("mock_library", newMockLibraryModule)
+	ctx.RegisterModuleType("mock_parent", newMockParentFactory)
 	ctx.RegisterModuleType("mock_defaults", defaultsFactory)
 
 	// Order of the following method calls is significant.
@@ -996,3 +1060,42 @@
 	InitDefaultsModule(m)
 	return m
 }
+
+type mockParentProperties struct {
+	Child struct {
+		Name *string
+
+		// Visibility to pass to the child module.
+		Visibility []string
+
+		// Purposely not validated visibility to pass to the child.
+		Invalid_visibility []string
+	}
+}
+
+type mockParent struct {
+	ModuleBase
+	DefaultableModuleBase
+	properties mockParentProperties
+}
+
+func (p *mockParent) GenerateAndroidBuildActions(ModuleContext) {
+}
+
+func newMockParentFactory() Module {
+	m := &mockParent{}
+	m.AddProperties(&m.properties)
+	InitAndroidArchModule(m, HostAndDeviceSupported, MultilibCommon)
+	InitDefaultableModule(m)
+	AddVisibilityProperty(m, "child.visibility", &m.properties.Child.Visibility)
+
+	m.SetDefaultableHook(func(ctx DefaultableHookContext) {
+		visibility := m.properties.Child.Visibility
+		visibility = append(visibility, m.properties.Child.Invalid_visibility...)
+		ctx.CreateModule(newMockLibraryModule, &struct {
+			Name       *string
+			Visibility []string
+		}{m.properties.Child.Name, visibility})
+	})
+	return m
+}