Merge "Don't pass same argument twice for defaults modules initialization"
diff --git a/Android.bp b/Android.bp
index 68b379c..82be0fa 100644
--- a/Android.bp
+++ b/Android.bp
@@ -203,6 +203,9 @@
         "java/java.go",
         "java/resources.go",
     ],
+    testSrcs: [
+        "java/java_test.go",
+    ],
     pluginFor: ["soong_build"],
 }
 
diff --git a/androidmk/cmd/androidmk/android.go b/androidmk/cmd/androidmk/android.go
index 78395c3..194b2c9 100644
--- a/androidmk/cmd/androidmk/android.go
+++ b/androidmk/cmd/androidmk/android.go
@@ -102,11 +102,11 @@
 			"LOCAL_RENDERSCRIPT_INCLUDES": "renderscript.include_dirs",
 			"LOCAL_RENDERSCRIPT_FLAGS":    "renderscript.flags",
 
-			"LOCAL_JAVA_RESOURCE_DIRS":    "java_resource_dirs",
+			"LOCAL_JAVA_RESOURCE_DIRS":    "resource_dirs",
 			"LOCAL_JAVACFLAGS":            "javacflags",
 			"LOCAL_DX_FLAGS":              "dxflags",
-			"LOCAL_JAVA_LIBRARIES":        "java_libs",
-			"LOCAL_STATIC_JAVA_LIBRARIES": "java_static_libs",
+			"LOCAL_JAVA_LIBRARIES":        "libs",
+			"LOCAL_STATIC_JAVA_LIBRARIES": "static_libs",
 			"LOCAL_AIDL_INCLUDES":         "aidl.include_dirs",
 			"LOCAL_AAPT_FLAGS":            "aaptflags",
 			"LOCAL_PACKAGE_SPLITS":        "package_splits",
diff --git a/java/app.go b/java/app.go
index 2f2b899..fccd382 100644
--- a/java/app.go
+++ b/java/app.go
@@ -68,17 +68,14 @@
 func (a *AndroidApp) DepsMutator(ctx android.BottomUpMutatorContext) {
 	a.Module.deps(ctx)
 
-	var deps []string
 	if !a.properties.No_standard_libraries {
 		switch a.deviceProperties.Sdk_version { // TODO: Res_sdk_version?
 		case "current", "system_current", "":
-			deps = append(deps, "framework-res")
+			ctx.AddDependency(ctx.Module(), frameworkResTag, "framework-res")
 		default:
 			// We'll already have a dependency on an sdk prebuilt android.jar
 		}
 	}
-
-	ctx.AddDependency(ctx.Module(), nil, deps...)
 }
 
 func (a *AndroidApp) GenerateAndroidBuildActions(ctx android.ModuleContext) {
diff --git a/java/java.go b/java/java.go
index adb3d7b..3d2e960 100644
--- a/java/java.go
+++ b/java/java.go
@@ -35,8 +35,8 @@
 	android.RegisterModuleType("java_library_host", JavaLibraryHostFactory)
 	android.RegisterModuleType("java_binary", JavaBinaryFactory)
 	android.RegisterModuleType("java_binary_host", JavaBinaryHostFactory)
-	android.RegisterModuleType("prebuilt_java_library", JavaPrebuiltFactory)
-	android.RegisterModuleType("prebuilt_sdk", SdkPrebuiltFactory)
+	android.RegisterModuleType("java_prebuilt_library", JavaPrebuiltFactory)
+	android.RegisterModuleType("android_prebuilt_sdk", SdkPrebuiltFactory)
 	android.RegisterModuleType("android_app", AndroidAppFactory)
 
 	android.RegisterSingletonType("logtags", LogtagsSingleton)
@@ -65,10 +65,10 @@
 	Exclude_srcs []string `android:"arch_variant"`
 
 	// list of directories containing Java resources
-	Java_resource_dirs []string `android:"arch_variant"`
+	Resource_dirs []string `android:"arch_variant"`
 
-	// list of directories that should be excluded from java_resource_dirs
-	Exclude_java_resource_dirs []string `android:"arch_variant"`
+	// list of directories that should be excluded from resource_dirs
+	Exclude_resource_dirs []string `android:"arch_variant"`
 
 	// don't build against the default libraries (legacy-test, core-junit,
 	// ext, and framework for device targets)
@@ -78,10 +78,10 @@
 	Javacflags []string `android:"arch_variant"`
 
 	// list of of java libraries that will be in the classpath
-	Java_libs []string `android:"arch_variant"`
+	Libs []string `android:"arch_variant"`
 
 	// list of java libraries that will be compiled into the resulting jar
-	Java_static_libs []string `android:"arch_variant"`
+	Static_libs []string `android:"arch_variant"`
 
 	// manifest file to be included in resulting jar
 	Manifest *string
@@ -147,45 +147,46 @@
 	AidlIncludeDirs() android.Paths
 }
 
-func (j *Module) BootClasspath(ctx android.BaseContext) string {
-	if ctx.Device() {
-		switch j.deviceProperties.Sdk_version {
-		case "":
-			return "core-libart"
-		case "current":
-			// TODO: !TARGET_BUILD_APPS
-			// TODO: export preprocessed framework.aidl from android_stubs_current
-			return "android_stubs_current"
-		case "system_current":
-			return "android_system_stubs_current"
-		default:
-			return "sdk_v" + j.deviceProperties.Sdk_version
-		}
-	} else {
-		if j.deviceProperties.Dex {
-			return "core-libart"
-		} else {
-			return ""
-		}
-	}
+type dependencyTag struct {
+	blueprint.BaseDependencyTag
+	name string
 }
 
-func (j *Module) deps(ctx android.BottomUpMutatorContext) {
-	var deps []string
+var (
+	javaStaticLibTag = dependencyTag{name: "staticlib"}
+	javaLibTag       = dependencyTag{name: "javalib"}
+	bootClasspathTag = dependencyTag{name: "bootclasspath"}
+	frameworkResTag  = dependencyTag{name: "framework-res"}
+	sdkDependencyTag = dependencyTag{name: "sdk"}
+)
 
+func (j *Module) deps(ctx android.BottomUpMutatorContext) {
 	if !j.properties.No_standard_libraries {
-		bootClasspath := j.BootClasspath(ctx)
-		if bootClasspath != "" {
-			deps = append(deps, bootClasspath)
+		if ctx.Device() {
+			switch j.deviceProperties.Sdk_version {
+			case "":
+				ctx.AddDependency(ctx.Module(), bootClasspathTag, "core-libart")
+			case "current":
+				// TODO: !TARGET_BUILD_APPS
+				// TODO: export preprocessed framework.aidl from android_stubs_current
+				ctx.AddDependency(ctx.Module(), bootClasspathTag, "android_stubs_current")
+			case "system_current":
+				ctx.AddDependency(ctx.Module(), bootClasspathTag, "android_system_stubs_current")
+			default:
+				ctx.AddDependency(ctx.Module(), sdkDependencyTag, "sdk_v"+j.deviceProperties.Sdk_version)
+			}
+		} else {
+			if j.deviceProperties.Dex {
+				ctx.AddDependency(ctx.Module(), bootClasspathTag, "core-libart")
+			}
 		}
+
 		if ctx.Device() && j.deviceProperties.Sdk_version == "" {
-			deps = append(deps, config.DefaultLibraries...)
+			ctx.AddDependency(ctx.Module(), javaLibTag, config.DefaultLibraries...)
 		}
 	}
-	deps = append(deps, j.properties.Java_libs...)
-	deps = append(deps, j.properties.Java_static_libs...)
-
-	ctx.AddDependency(ctx.Module(), nil, deps...)
+	ctx.AddDependency(ctx.Module(), javaLibTag, j.properties.Libs...)
+	ctx.AddDependency(ctx.Module(), javaStaticLibTag, j.properties.Static_libs...)
 }
 
 func (j *Module) aidlFlags(ctx android.ModuleContext, aidlPreprocess android.OptionalPath,
@@ -216,38 +217,48 @@
 
 	ctx.VisitDirectDeps(func(module blueprint.Module) {
 		otherName := ctx.OtherModuleName(module)
-		if javaDep, ok := module.(JavaDependency); ok {
-			if otherName == j.BootClasspath(ctx) {
-				bootClasspath = android.OptionalPathForPath(javaDep.ClasspathFile())
-			} else if inList(otherName, config.DefaultLibraries) {
-				classpath = append(classpath, javaDep.ClasspathFile())
-			} else if inList(otherName, j.properties.Java_libs) {
-				classpath = append(classpath, javaDep.ClasspathFile())
-			} else if inList(otherName, j.properties.Java_static_libs) {
-				classpath = append(classpath, javaDep.ClasspathFile())
-				classJarSpecs = append(classJarSpecs, javaDep.ClassJarSpecs()...)
-				resourceJarSpecs = append(resourceJarSpecs, javaDep.ResourceJarSpecs()...)
-			} else if otherName == "framework-res" {
-				if ctx.ModuleName() == "framework" {
-					// framework.jar has a one-off dependency on the R.java and Manifest.java files
-					// generated by framework-res.apk
-					srcFileLists = append(srcFileLists, module.(*AndroidApp).aaptJavaFileList)
-				}
-			} else {
-				panic(fmt.Errorf("unknown dependency %q for %q", otherName, ctx.ModuleName()))
+		tag := ctx.OtherModuleDependencyTag(module)
+
+		javaDep, _ := module.(JavaDependency)
+		if javaDep == nil {
+			switch tag {
+			case android.DefaultsDepTag, android.SourceDepTag:
+			default:
+				ctx.ModuleErrorf("depends on non-java module %q", otherName)
 			}
-			aidlIncludeDirs = append(aidlIncludeDirs, javaDep.AidlIncludeDirs()...)
-			if sdkDep, ok := module.(sdkDependency); ok {
-				if sdkDep.AidlPreprocessed().Valid() {
-					if aidlPreprocess.Valid() {
-						ctx.ModuleErrorf("multiple dependencies with preprocessed aidls:\n %q\n %q",
-							aidlPreprocess, sdkDep.AidlPreprocessed())
-					} else {
-						aidlPreprocess = sdkDep.AidlPreprocessed()
-					}
-				}
-			}
+			return
 		}
+
+		switch tag {
+		case bootClasspathTag:
+			bootClasspath = android.OptionalPathForPath(javaDep.ClasspathFile())
+		case javaLibTag:
+			classpath = append(classpath, javaDep.ClasspathFile())
+		case javaStaticLibTag:
+			classpath = append(classpath, javaDep.ClasspathFile())
+			classJarSpecs = append(classJarSpecs, javaDep.ClassJarSpecs()...)
+			resourceJarSpecs = append(resourceJarSpecs, javaDep.ResourceJarSpecs()...)
+		case frameworkResTag:
+			if ctx.ModuleName() == "framework" {
+				// framework.jar has a one-off dependency on the R.java and Manifest.java files
+				// generated by framework-res.apk
+				srcFileLists = append(srcFileLists, module.(*AndroidApp).aaptJavaFileList)
+			}
+		case sdkDependencyTag:
+			sdkDep := module.(sdkDependency)
+			if sdkDep.AidlPreprocessed().Valid() {
+				if aidlPreprocess.Valid() {
+					ctx.ModuleErrorf("multiple dependencies with preprocessed aidls:\n %q\n %q",
+						aidlPreprocess, sdkDep.AidlPreprocessed())
+				} else {
+					aidlPreprocess = sdkDep.AidlPreprocessed()
+				}
+			}
+		default:
+			panic(fmt.Errorf("unknown dependency %q for %q", otherName, ctx.ModuleName()))
+		}
+
+		aidlIncludeDirs = append(aidlIncludeDirs, javaDep.AidlIncludeDirs()...)
 	})
 
 	return classpath, bootClasspath, classJarSpecs, resourceJarSpecs, aidlPreprocess,
@@ -309,7 +320,7 @@
 		classJarSpecs = append([]jarSpec{classes}, classJarSpecs...)
 	}
 
-	resourceJarSpecs = append(ResourceDirsToJarSpecs(ctx, j.properties.Java_resource_dirs, j.properties.Exclude_java_resource_dirs),
+	resourceJarSpecs = append(ResourceDirsToJarSpecs(ctx, j.properties.Resource_dirs, j.properties.Exclude_resource_dirs),
 		resourceJarSpecs...)
 
 	manifest := android.OptionalPathForModuleSrc(ctx, j.properties.Manifest)
@@ -500,28 +511,23 @@
 // Java prebuilts
 //
 
-type javaPrebuiltProperties struct {
-	Srcs []string
-}
-
 type JavaPrebuilt struct {
 	android.ModuleBase
-
-	properties javaPrebuiltProperties
+	prebuilt android.Prebuilt
 
 	classpathFile                   android.Path
 	classJarSpecs, resourceJarSpecs []jarSpec
 }
 
+func (j *JavaPrebuilt) Prebuilt() *android.Prebuilt {
+	return &j.prebuilt
+}
+
 func (j *JavaPrebuilt) DepsMutator(ctx android.BottomUpMutatorContext) {
 }
 
 func (j *JavaPrebuilt) GenerateAndroidBuildActions(ctx android.ModuleContext) {
-	if len(j.properties.Srcs) != 1 {
-		ctx.ModuleErrorf("expected exactly one jar in srcs")
-		return
-	}
-	prebuilt := android.PathForModuleSrc(ctx, j.properties.Srcs[0])
+	prebuilt := j.prebuilt.Path(ctx)
 
 	classJarSpec, resourceJarSpec := TransformPrebuiltJarToClasses(ctx, prebuilt)
 
@@ -552,7 +558,7 @@
 func JavaPrebuiltFactory() android.Module {
 	module := &JavaPrebuilt{}
 
-	module.AddProperties(&module.properties)
+	module.AddProperties(&module.prebuilt.Properties)
 
 	android.InitAndroidArchModule(module, android.HostAndDeviceSupported, android.MultilibCommon)
 	return module
@@ -595,7 +601,7 @@
 	module := &sdkPrebuilt{}
 
 	module.AddProperties(
-		&module.properties,
+		&module.prebuilt.Properties,
 		&module.sdkProperties)
 
 	android.InitAndroidArchModule(module, android.HostAndDeviceSupported, android.MultilibCommon)
diff --git a/java/java_test.go b/java/java_test.go
new file mode 100644
index 0000000..bd6451c
--- /dev/null
+++ b/java/java_test.go
@@ -0,0 +1,240 @@
+// Copyright 2017 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package java
+
+import (
+	"android/soong/android"
+	"fmt"
+	"io/ioutil"
+	"os"
+	"path/filepath"
+	"strings"
+	"testing"
+)
+
+var buildDir string
+
+func setUp() {
+	var err error
+	buildDir, err = ioutil.TempDir("", "soong_java_test")
+	if err != nil {
+		panic(err)
+	}
+}
+
+func tearDown() {
+	os.RemoveAll(buildDir)
+}
+
+func TestMain(m *testing.M) {
+	run := func() int {
+		setUp()
+		defer tearDown()
+
+		return m.Run()
+	}
+
+	os.Exit(run())
+}
+
+func testJava(t *testing.T, bp string) *android.TestContext {
+	config := android.TestConfig(buildDir)
+
+	ctx := android.NewTestContext()
+	ctx.RegisterModuleType("android_app", android.ModuleFactoryAdaptor(AndroidAppFactory))
+	ctx.RegisterModuleType("java_library", android.ModuleFactoryAdaptor(JavaLibraryFactory))
+	ctx.RegisterModuleType("java_prebuilt_library", android.ModuleFactoryAdaptor(JavaPrebuiltFactory))
+	ctx.Register()
+
+	extraModules := []string{"core-libart", "frameworks", "sdk_v14"}
+
+	for _, extra := range extraModules {
+		bp += fmt.Sprintf(`
+			java_library {
+				name: "%s",
+				no_standard_libraries: true,
+			}
+		`, extra)
+	}
+
+	ctx.MockFileSystem(map[string][]byte{
+		"Android.bp": []byte(bp),
+		"a.java":     nil,
+		"b.java":     nil,
+		"c.java":     nil,
+		"a.jar":      nil,
+		"b.jar":      nil,
+	})
+
+	_, errs := ctx.ParseBlueprintsFiles("Android.bp")
+	fail(t, errs)
+	_, errs = ctx.PrepareBuildActions(config)
+	fail(t, errs)
+
+	return ctx
+}
+
+func TestSimple(t *testing.T) {
+	ctx := testJava(t, `
+		java_library {
+			name: "foo",
+			srcs: ["a.java"],
+			libs: ["bar"],
+			static_libs: ["baz"],
+		}
+
+		java_library {
+			name: "bar",
+			srcs: ["b.java"],
+		}
+
+		java_library {
+			name: "baz",
+			srcs: ["c.java"],
+		}
+		`)
+
+	javac := ctx.ModuleForTests("foo", "").Rule("javac")
+	jar := ctx.ModuleForTests("foo", "").Rule("jar")
+
+	if len(javac.Inputs) != 1 || javac.Inputs[0].String() != "a.java" {
+		t.Errorf(`foo inputs %v != ["a.java"]`, javac.Inputs)
+	}
+
+	bar := filepath.Join(buildDir, ".intermediates", "bar", "classes-full-debug.jar")
+	if !strings.Contains(javac.Args["classpath"], bar) {
+		t.Errorf("foo classpath %v does not contain %q", javac.Args["classpath"], bar)
+	}
+
+	baz := filepath.Join(buildDir, ".intermediates", "baz", "classes.list")
+	if !strings.Contains(jar.Args["jarArgs"], baz) {
+		t.Errorf("foo jarArgs %v does not contain %q", jar.Args["jarArgs"], baz)
+	}
+}
+
+func TestSdk(t *testing.T) {
+	ctx := testJava(t, `
+		java_library {
+			name: "foo1",
+			srcs: ["a.java"],
+		}
+
+		java_library {
+			name: "foo2",
+			srcs: ["a.java"],
+			sdk_version: "",
+		}
+
+		java_library {
+			name: "foo3",
+			srcs: ["a.java"],
+			sdk_version: "14",
+		}
+
+		java_library {
+			name: "foo4",
+			srcs: ["a.java"],
+			sdk_version: "current",
+		}
+
+		java_library {
+			name: "foo5",
+			srcs: ["a.java"],
+			sdk_version: "system_current",
+		}
+
+		java_library {
+			name: "foo6",
+			srcs: ["a.java"],
+			sdk_version: "test_current",
+		}
+		`)
+
+	type depType int
+	const (
+		staticLib = iota
+		classpathLib
+		bootclasspathLib
+	)
+
+	check := func(module, dep string, depType depType) {
+		if dep != "" {
+			dep = filepath.Join(buildDir, ".intermediates", dep, "classes-full-debug.jar")
+		}
+
+		javac := ctx.ModuleForTests(module, "").Rule("javac")
+
+		if depType == bootclasspathLib {
+			got := strings.TrimPrefix(javac.Args["bootClasspath"], "-bootclasspath ")
+			if got != dep {
+				t.Errorf("module %q bootclasspath %q != %q", module, got, dep)
+			}
+		} else if depType == classpathLib {
+			got := strings.TrimPrefix(javac.Args["classpath"], "-classpath ")
+			if got != dep {
+				t.Errorf("module %q classpath %q != %q", module, got, dep)
+			}
+		}
+
+		if len(javac.Implicits) != 1 || javac.Implicits[0].String() != dep {
+			t.Errorf("module %q implicits != [%q]", dep)
+		}
+	}
+
+	check("foo1", "core-libart", bootclasspathLib)
+}
+
+func TestPrebuilts(t *testing.T) {
+	ctx := testJava(t, `
+		java_library {
+			name: "foo",
+			srcs: ["a.java"],
+			libs: ["bar"],
+			static_libs: ["baz"],
+		}
+
+		java_prebuilt_library {
+			name: "bar",
+			srcs: ["a.jar"],
+		}
+
+		java_prebuilt_library {
+			name: "baz",
+			srcs: ["b.jar"],
+		}
+		`)
+
+	javac := ctx.ModuleForTests("foo", "").Rule("javac")
+	jar := ctx.ModuleForTests("foo", "").Rule("jar")
+
+	bar := "a.jar"
+	if !strings.Contains(javac.Args["classpath"], bar) {
+		t.Errorf("foo classpath %v does not contain %q", javac.Args["classpath"], bar)
+	}
+
+	baz := filepath.Join(buildDir, ".intermediates", "baz", "extracted", "classes.list")
+	if !strings.Contains(jar.Args["jarArgs"], baz) {
+		t.Errorf("foo jarArgs %v does not contain %q", jar.Args["jarArgs"], baz)
+	}
+}
+
+func fail(t *testing.T, errs []error) {
+	if len(errs) > 0 {
+		for _, err := range errs {
+			t.Error(err)
+		}
+		t.FailNow()
+	}
+}