Avoid Rust source provider rule duplication

Until now, source provider modules duplicated the rule to generate the
source for each variant. Add a inter-variant dependency between the
source and the other variants (e.g. rlib, dylib) to avoid this
duplication. Add documentation on this behaviour.

Bug: 162588681
Test: m
Change-Id: I41c9e2220f8875245415e17374852e540dfd47ec
diff --git a/rust/library.go b/rust/library.go
index 4931f19..2792c5b 100644
--- a/rust/library.go
+++ b/rust/library.go
@@ -15,6 +15,7 @@
 package rust
 
 import (
+	"fmt"
 	"regexp"
 	"strings"
 
@@ -77,6 +78,8 @@
 	VariantIsShared bool `blueprint:"mutated"`
 	// This variant is a static library
 	VariantIsStatic bool `blueprint:"mutated"`
+	// This variant is a source provider
+	VariantIsSource bool `blueprint:"mutated"`
 
 	// This variant is disabled and should not be compiled
 	// (used for SourceProvider variants that produce only source)
@@ -103,6 +106,7 @@
 	static() bool
 	shared() bool
 	sysroot() bool
+	source() bool
 
 	// Returns true if the build options for the module have selected a particular build type
 	buildRlib() bool
@@ -115,6 +119,7 @@
 	setDylib()
 	setShared()
 	setStatic()
+	setSource()
 
 	// Set libstd linkage
 	setRlibStd()
@@ -158,6 +163,10 @@
 	return library.static() || library.MutatedProperties.VariantIsStaticStd
 }
 
+func (library *libraryDecorator) source() bool {
+	return library.MutatedProperties.VariantIsSource
+}
+
 func (library *libraryDecorator) buildRlib() bool {
 	return library.MutatedProperties.BuildRlib && BoolDefault(library.Properties.Rlib.Enabled, true)
 }
@@ -210,13 +219,17 @@
 	library.MutatedProperties.VariantIsDylib = false
 }
 
+func (library *libraryDecorator) setSource() {
+	library.MutatedProperties.VariantIsSource = true
+}
+
 func (library *libraryDecorator) autoDep(ctx BaseModuleContext) autoDep {
 	if library.rlib() || library.static() {
 		return rlibAutoDep
 	} else if library.dylib() || library.shared() {
 		return dylibAutoDep
 	} else {
-		panic("autoDep called on library" + ctx.ModuleName() + "that has no enabled variants.")
+		panic(fmt.Errorf("autoDep called on library %q that has no enabled variants.", ctx.ModuleName()))
 	}
 }
 
@@ -518,41 +531,68 @@
 	}
 }
 
+// LibraryMutator mutates the libraries into variants according to the
+// build{Rlib,Dylib} attributes.
 func LibraryMutator(mctx android.BottomUpMutatorContext) {
-	if m, ok := mctx.Module().(*Module); ok && m.compiler != nil {
-		switch library := m.compiler.(type) {
-		case libraryInterface:
-			if library.buildRlib() && library.buildDylib() {
-				variants := []string{"rlib", "dylib"}
-				if m.sourceProvider != nil {
-					variants = append(variants, "")
-				}
-				modules := mctx.CreateLocalVariations(variants...)
+	// Only mutate on Rust libraries.
+	m, ok := mctx.Module().(*Module)
+	if !ok || m.compiler == nil {
+		return
+	}
+	library, ok := m.compiler.(libraryInterface)
+	if !ok {
+		return
+	}
 
-				rlib := modules[0].(*Module)
-				dylib := modules[1].(*Module)
-				rlib.compiler.(libraryInterface).setRlib()
-				dylib.compiler.(libraryInterface).setDylib()
-				if m.sourceProvider != nil {
-					// This library is SourceProvider generated, so the non-library-producing
-					// variant needs to disable it's compiler and skip installation.
-					sourceProvider := modules[2].(*Module)
-					sourceProvider.compiler.SetDisabled()
-				}
-			} else if library.buildRlib() {
-				modules := mctx.CreateLocalVariations("rlib")
-				modules[0].(*Module).compiler.(libraryInterface).setRlib()
-			} else if library.buildDylib() {
-				modules := mctx.CreateLocalVariations("dylib")
-				modules[0].(*Module).compiler.(libraryInterface).setDylib()
-			}
+	var variants []string
+	// The source variant is used for SourceProvider modules. The other variants (i.e. rlib and dylib)
+	// depend on this variant. It must be the first variant to be declared.
+	sourceVariant := false
+	if m.sourceProvider != nil {
+		variants = append(variants, "source")
+		sourceVariant = true
+	}
+	if library.buildRlib() {
+		variants = append(variants, rlibVariation)
+	}
+	if library.buildDylib() {
+		variants = append(variants, dylibVariation)
+	}
 
-			if m.sourceProvider != nil {
-				// Alias the non-library variant to the empty-string variant.
-				mctx.AliasVariation("")
-			}
+	if len(variants) == 0 {
+		return
+	}
+	modules := mctx.CreateLocalVariations(variants...)
+
+	// The order of the variations (modules) matches the variant names provided. Iterate
+	// through the new variation modules and set their mutated properties.
+	for i, v := range modules {
+		switch variants[i] {
+		case rlibVariation:
+			v.(*Module).compiler.(libraryInterface).setRlib()
+		case dylibVariation:
+			v.(*Module).compiler.(libraryInterface).setDylib()
+		case "source":
+			v.(*Module).compiler.(libraryInterface).setSource()
+			// The source variant does not produce any library.
+			// Disable the compilation steps.
+			v.(*Module).compiler.SetDisabled()
 		}
 	}
+
+	// If a source variant is created, add an inter-variant dependency
+	// between the other variants and the source variant.
+	if sourceVariant {
+		sv := modules[0]
+		for _, v := range modules[1:] {
+			if !v.Enabled() {
+				continue
+			}
+			mctx.AddInterVariantDependency(sourceDepTag, v, sv)
+		}
+		// Alias the source variation so it can be named directly in "srcs" properties.
+		mctx.AliasVariation("source")
+	}
 }
 
 func LibstdMutator(mctx android.BottomUpMutatorContext) {