Implementation of AndroidStudioIdeInfoAspect.

--
MOS_MIGRATED_REVID=102057837
diff --git a/src/main/java/BUILD b/src/main/java/BUILD
index 424a80d..8297abd 100644
--- a/src/main/java/BUILD
+++ b/src/main/java/BUILD
@@ -184,6 +184,7 @@
         [
             "com/google/devtools/build/lib/analysis/**/*.java",
             "com/google/devtools/build/lib/exec/*.java",
+            "com/google/devtools/build/lib/ideinfo/**/*.java",
             "com/google/devtools/build/lib/rules/**/*.java",
             "com/google/devtools/build/lib/skyframe/*.java",
         ],
@@ -206,6 +207,7 @@
         ":shell",
         ":skyframe-base",
         ":vfs",
+        "//src/main/protobuf:proto_android_studio_ide_info",
         "//src/main/protobuf:proto_bundlemerge",
         "//src/main/protobuf:proto_crosstool_config",
         "//src/main/protobuf:proto_extra_actions_base",
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java
index f337c25..f2e2c2b 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java
@@ -70,6 +70,7 @@
 import com.google.devtools.build.lib.bazel.rules.workspace.NewHttpArchiveRule;
 import com.google.devtools.build.lib.bazel.rules.workspace.NewLocalRepositoryRule;
 import com.google.devtools.build.lib.bazel.rules.workspace.WorkspaceBaseRule;
+import com.google.devtools.build.lib.ideinfo.AndroidStudioInfoAspect;
 import com.google.devtools.build.lib.packages.Attribute;
 import com.google.devtools.build.lib.packages.PackageGroup;
 import com.google.devtools.build.lib.packages.Rule;
@@ -353,6 +354,8 @@
     builder.addRuleDefinition(new AndroidRepositoryRules.AndroidLocalRepositoryRule());
     builder.addRuleDefinition(new AndroidHttpToolsRepositoryRule());
 
+    builder.addAspectFactory(AndroidStudioInfoAspect.NAME, AndroidStudioInfoAspect.class);
+
     builder.addConfigurationFragment(new BazelConfiguration.Loader());
     builder.addConfigurationFragment(new CppConfigurationLoader(
         Functions.<String>identity()));
diff --git a/src/main/java/com/google/devtools/build/lib/ideinfo/AndroidStudioInfoAspect.java b/src/main/java/com/google/devtools/build/lib/ideinfo/AndroidStudioInfoAspect.java
new file mode 100644
index 0000000..6316f1a
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/ideinfo/AndroidStudioInfoAspect.java
@@ -0,0 +1,196 @@
+// Copyright 2014 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 com.google.devtools.build.lib.ideinfo;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.io.ByteSource;
+import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.actions.Root;
+import com.google.devtools.build.lib.analysis.Aspect;
+import com.google.devtools.build.lib.analysis.ConfiguredAspectFactory;
+import com.google.devtools.build.lib.analysis.ConfiguredTarget;
+import com.google.devtools.build.lib.analysis.RuleConfiguredTarget.Mode;
+import com.google.devtools.build.lib.analysis.RuleContext;
+import com.google.devtools.build.lib.analysis.actions.BinaryFileWriteAction;
+import com.google.devtools.build.lib.collect.nestedset.NestedSet;
+import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
+import com.google.devtools.build.lib.ideinfo.androidstudio.AndroidStudioIdeInfo.ArtifactLocation;
+import com.google.devtools.build.lib.ideinfo.androidstudio.AndroidStudioIdeInfo.JavaRuleIdeInfo;
+import com.google.devtools.build.lib.ideinfo.androidstudio.AndroidStudioIdeInfo.LibraryArtifact;
+import com.google.devtools.build.lib.ideinfo.androidstudio.AndroidStudioIdeInfo.RuleIdeInfo;
+import com.google.devtools.build.lib.packages.AspectDefinition;
+import com.google.devtools.build.lib.packages.Rule;
+import com.google.devtools.build.lib.rules.java.JavaRuleOutputJarsProvider;
+import com.google.devtools.build.lib.rules.java.JavaSourceInfoProvider;
+import com.google.devtools.build.lib.vfs.PathFragment;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Collection;
+
+/**
+ * Generates ide-build information for Android Studio.
+ */
+public class AndroidStudioInfoAspect implements ConfiguredAspectFactory {
+  public static final String NAME = "AndroidStudioInfoAspect";
+  public static final String IDE_RESOLVE = "ide-resolve";
+  public static final String IDE_BUILD = "ide-build";
+  public static final String IDE_BUILD_SUFFIX = ".aswb-build";
+
+  @Override
+  public AspectDefinition getDefinition() {
+    return new AspectDefinition.Builder(NAME)
+        .requireProvider(JavaSourceInfoProvider.class)
+        .attributeAspect("deps", AndroidStudioInfoAspect.class)
+        .build();
+  }
+
+  @Override
+  public Aspect create(ConfiguredTarget base, RuleContext ruleContext) {
+    NestedSetBuilder<Artifact> ideBuildFilesBuilder = NestedSetBuilder.stableOrder();
+    Iterable<AndroidStudioInfoFilesProvider> deps =
+        ruleContext.getPrerequisites("deps", Mode.TARGET, AndroidStudioInfoFilesProvider.class);
+    for (AndroidStudioInfoFilesProvider dep : deps) {
+      ideBuildFilesBuilder.addTransitive(dep.getIdeBuildFiles());
+    }
+
+    RuleIdeInfo.Kind ruleKind = getRuleKind(ruleContext.getRule());
+    if (ruleKind != RuleIdeInfo.Kind.UNRECOGNIZED) {
+      Artifact ideBuildFile = createIdeBuildArtifact(base, ruleContext, ruleKind);
+      ideBuildFilesBuilder.add(ideBuildFile);
+    }
+
+    NestedSet<Artifact> ideBuildFiles = ideBuildFilesBuilder.build();
+    return new Aspect.Builder(NAME)
+        .addOutputGroup(IDE_BUILD, ideBuildFiles)
+        .addProvider(
+            AndroidStudioInfoFilesProvider.class, new AndroidStudioInfoFilesProvider(ideBuildFiles))
+        .build();
+  }
+
+  private Artifact createIdeBuildArtifact(
+      ConfiguredTarget base, RuleContext ruleContext, RuleIdeInfo.Kind ruleKind) {
+    PathFragment ideBuildFilePath = getOutputFilePath(base, ruleContext);
+    Root genfilesDirectory = ruleContext.getConfiguration().getGenfilesDirectory();
+    Artifact ideBuildFile =
+        ruleContext
+            .getAnalysisEnvironment()
+            .getDerivedArtifact(ideBuildFilePath, genfilesDirectory);
+
+    RuleIdeInfo.Builder outputBuilder = RuleIdeInfo.newBuilder();
+
+    outputBuilder.setLabel(base.getLabel().toString());
+
+    outputBuilder.setBuildFile(
+        ruleContext
+            .getRule()
+            .getPackage()
+            .getBuildFile()
+            .getPath()
+            .toString());
+
+    outputBuilder.setKind(ruleKind);
+
+    // Calculate source files.
+    JavaSourceInfoProvider sourceInfoProvider = base.getProvider(JavaSourceInfoProvider.class);
+    Collection<Artifact> sourceFiles =
+        sourceInfoProvider != null
+            ? sourceInfoProvider.getSourceFiles()
+            : ImmutableList.<Artifact>of();
+    for (Artifact sourceFile : sourceFiles) {
+      outputBuilder.addSources(makeArtifactLocation(sourceFile));
+    }
+
+    outputBuilder.setJavaRuleIdeInfo(makeJavaRuleIdeInfo(base));
+
+    final RuleIdeInfo ruleIdeInfo = outputBuilder.build();
+    ruleContext.registerAction(
+        new BinaryFileWriteAction(
+            ruleContext.getActionOwner(),
+            ideBuildFile,
+            new ByteSource() {
+              @Override
+              public InputStream openStream() throws IOException {
+                return ruleIdeInfo.toByteString().newInput();
+              }
+            },
+            /*makeExecutable =*/ false));
+    return ideBuildFile;
+  }
+
+  private static ArtifactLocation makeArtifactLocation(Artifact artifact) {
+    return ArtifactLocation.newBuilder()
+        .setRootPath(artifact.getRoot().getPath().toString())
+        .setRelativePath(artifact.getRootRelativePathString())
+        .build();
+  }
+
+  private static JavaRuleIdeInfo makeJavaRuleIdeInfo(ConfiguredTarget base) {
+    JavaRuleIdeInfo.Builder builder = JavaRuleIdeInfo.newBuilder();
+    JavaRuleOutputJarsProvider outputJarsProvider =
+        base.getProvider(JavaRuleOutputJarsProvider.class);
+    if (outputJarsProvider != null) {
+      {
+        LibraryArtifact.Builder jarsBuilder = LibraryArtifact.newBuilder();
+        Artifact classJar = outputJarsProvider.getClassJar();
+        if (classJar != null) {
+          jarsBuilder.setJar(makeArtifactLocation(classJar));
+        }
+        Artifact srcJar = outputJarsProvider.getSrcJar();
+        if (srcJar != null) {
+          jarsBuilder.setSourceJar(makeArtifactLocation(srcJar));
+        }
+        if (jarsBuilder.hasJar() || jarsBuilder.hasSourceJar()) {
+          builder.addJars(jarsBuilder.build());
+        }
+      }
+
+      {
+        LibraryArtifact.Builder genjarsBuilder = LibraryArtifact.newBuilder();
+
+        Artifact genClassJar = outputJarsProvider.getGenClassJar();
+        if (genClassJar != null) {
+          genjarsBuilder.setJar(makeArtifactLocation(genClassJar));
+        }
+        Artifact gensrcJar = outputJarsProvider.getGensrcJar();
+        if (gensrcJar != null) {
+          genjarsBuilder.setSourceJar(makeArtifactLocation(gensrcJar));
+        }
+        if (genjarsBuilder.hasJar() || genjarsBuilder.hasSourceJar()) {
+          builder.addJars(genjarsBuilder.build());
+        }
+      }
+    }
+
+    return builder.build();
+  }
+
+  private PathFragment getOutputFilePath(ConfiguredTarget base, RuleContext ruleContext) {
+    PathFragment packagePathFragment =
+        ruleContext.getLabel().getPackageIdentifier().getPathFragment();
+    String name = base.getLabel().getName();
+    return new PathFragment(packagePathFragment, new PathFragment(name + IDE_BUILD_SUFFIX));
+  }
+
+  private RuleIdeInfo.Kind getRuleKind(Rule rule) {
+    RuleIdeInfo.Kind kind;
+    if ("java_library".equals(rule.getRuleClassObject().getName())) {
+      kind = RuleIdeInfo.Kind.JAVA_LIBRARY;
+    } else {
+      kind = RuleIdeInfo.Kind.UNRECOGNIZED;
+    }
+    return kind;
+  }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/ideinfo/AndroidStudioInfoFilesProvider.java b/src/main/java/com/google/devtools/build/lib/ideinfo/AndroidStudioInfoFilesProvider.java
new file mode 100644
index 0000000..5795ae5
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/ideinfo/AndroidStudioInfoFilesProvider.java
@@ -0,0 +1,36 @@
+// Copyright 2014 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 com.google.devtools.build.lib.ideinfo;
+
+import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.analysis.TransitiveInfoProvider;
+import com.google.devtools.build.lib.collect.nestedset.NestedSet;
+import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
+
+/**
+ * File provider for Android Studio ide build files.
+ */
+@Immutable
+public final class AndroidStudioInfoFilesProvider implements TransitiveInfoProvider {
+  private final NestedSet<Artifact> ideBuildFiles;
+
+  public AndroidStudioInfoFilesProvider(NestedSet<Artifact> ideBuildFiles) {
+    this.ideBuildFiles = ideBuildFiles;
+  }
+
+  public NestedSet<Artifact> getIdeBuildFiles() {
+    return ideBuildFiles;
+  }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaLibrary.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaLibrary.java
index 60afde4..5dcb16d 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaLibrary.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaLibrary.java
@@ -215,6 +215,10 @@
         ruleContext, common, ImmutableList.<String>of(), classJar, srcJar, genClassJar, gensrcJar,
         ImmutableMap.<Artifact, Artifact>of(), helper, filesBuilder, builder);
 
+    builder.add(
+        JavaRuleOutputJarsProvider.class,
+        new JavaRuleOutputJarsProvider(classJar, srcJar, genClassJar, gensrcJar));
+
     NestedSet<Artifact> filesToBuild = filesBuilder.build();
     common.addTransitiveInfoProviders(builder, filesToBuild, classJar);
 
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaRuleOutputJarsProvider.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaRuleOutputJarsProvider.java
new file mode 100644
index 0000000..e553010
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaRuleOutputJarsProvider.java
@@ -0,0 +1,57 @@
+// Copyright 2014 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 com.google.devtools.build.lib.rules.java;
+
+import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.analysis.TransitiveInfoProvider;
+import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
+
+import javax.annotation.Nullable;
+
+/**
+ * Provides information about jar files produced by a Java rule.
+ */
+@Immutable
+public final class JavaRuleOutputJarsProvider implements TransitiveInfoProvider {
+  @Nullable private final Artifact classJar;
+  private final Artifact srcJar;
+  private final Artifact genClassJar;
+  private final Artifact gensrcJar;
+
+  public JavaRuleOutputJarsProvider(
+      Artifact classJar, Artifact srcJar, Artifact genClassJar, Artifact gensrcJar) {
+    this.classJar = classJar;
+    this.srcJar = srcJar;
+    this.genClassJar = genClassJar;
+    this.gensrcJar = gensrcJar;
+  }
+
+  @Nullable
+  public Artifact getClassJar() {
+    return classJar;
+  }
+
+  public Artifact getSrcJar() {
+    return srcJar;
+  }
+
+  public Artifact getGenClassJar() {
+    return genClassJar;
+  }
+
+  public Artifact getGensrcJar() {
+    return gensrcJar;
+  }
+}
diff --git a/src/main/protobuf/BUILD b/src/main/protobuf/BUILD
index 719bd7b..2fca35a 100644
--- a/src/main/protobuf/BUILD
+++ b/src/main/protobuf/BUILD
@@ -9,6 +9,7 @@
     "java_compilation",
     "crosstool_config",
     "extra_actions_base",
+    "android_studio_ide_info",
     "test_status",
     "bundlemerge",
     "xcodegen",
diff --git a/src/main/protobuf/android_studio_ide_info.proto b/src/main/protobuf/android_studio_ide_info.proto
new file mode 100644
index 0000000..cdbe236
--- /dev/null
+++ b/src/main/protobuf/android_studio_ide_info.proto
@@ -0,0 +1,58 @@
+// Copyright 2015 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.
+
+syntax = "proto3";
+
+package blaze;
+
+
+option java_package = "com.google.devtools.build.lib.ideinfo.androidstudio";
+
+message ArtifactLocation {
+  string root_path = 1;
+  string relative_path = 2;
+}
+
+message LibraryArtifact {
+  ArtifactLocation jar = 1;
+  ArtifactLocation interface_jar = 2;
+  ArtifactLocation source_jar = 3;
+}
+
+message JavaRuleIdeInfo {
+  repeated LibraryArtifact jars = 1;
+  repeated LibraryArtifact generated_jars = 2;
+  ArtifactLocation package_manifest = 3;
+}
+
+message RuleIdeInfo {
+  enum Kind {
+    ANDROID_BINARY = 0;
+    ANDROID_LIBRARY = 1;
+    ANDROID_TEST = 2;
+    ANDROID_ROBOELECTRIC_TEST = 3;
+    JAVA_LIBRARY = 4;
+    JAVA_TEST = 5;
+    JAVA_IMPORT = 6;
+    PROTO_LIBRARY = 7;
+  }
+
+  string label = 1;
+  Kind kind = 2;
+  string build_file = 3;
+  repeated string dependencies = 4;
+  repeated string transitive_dependencies = 5;
+  repeated ArtifactLocation sources = 6;
+  JavaRuleIdeInfo java_rule_ide_info = 7;
+}