aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google/devtools
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/com/google/devtools')
-rw-r--r--src/main/java/com/google/devtools/build/docgen/DocgenConsts.java6
-rw-r--r--src/main/java/com/google/devtools/build/docgen/SkylarkDocumentationCollector.java196
-rw-r--r--src/main/java/com/google/devtools/build/docgen/SkylarkDocumentationGenerator.java3
-rw-r--r--src/main/java/com/google/devtools/build/docgen/SkylarkDocumentationProcessor.java456
-rw-r--r--src/main/java/com/google/devtools/build/docgen/SkylarkJavaInterfaceExplorer.java160
-rw-r--r--src/main/java/com/google/devtools/build/docgen/skylark/SkylarkBuiltinMethodDoc.java97
-rw-r--r--src/main/java/com/google/devtools/build/docgen/skylark/SkylarkDoc.java85
-rw-r--r--src/main/java/com/google/devtools/build/docgen/skylark/SkylarkJavaMethodDoc.java71
-rw-r--r--src/main/java/com/google/devtools/build/docgen/skylark/SkylarkMethodDoc.java116
-rw-r--r--src/main/java/com/google/devtools/build/docgen/skylark/SkylarkModuleDoc.java98
-rw-r--r--src/main/java/com/google/devtools/build/docgen/skylark/SkylarkParamDoc.java61
-rw-r--r--src/main/java/com/google/devtools/build/docgen/templates/be-header.vm8
-rw-r--r--src/main/java/com/google/devtools/build/docgen/templates/skylark-body.html58
-rw-r--r--src/main/java/com/google/devtools/build/docgen/templates/skylark-library.vm58
-rw-r--r--src/main/java/com/google/devtools/build/docgen/templates/skylark-nav.vm4
-rw-r--r--src/main/java/com/google/devtools/build/lib/actions/Artifact.java2
-rw-r--r--src/main/java/com/google/devtools/build/lib/analysis/TransitiveInfoCollection.java6
-rw-r--r--src/main/java/com/google/devtools/build/lib/packages/Attribute.java4
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/SkylarkAttr.java9
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/SkylarkFileType.java6
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleClassFunctions.java4
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleContext.java4
-rw-r--r--src/main/java/com/google/devtools/build/lib/syntax/ClassObject.java2
-rw-r--r--src/main/java/com/google/devtools/build/lib/syntax/MethodLibrary.java6
-rw-r--r--src/main/java/com/google/devtools/build/lib/syntax/SkylarkNestedSet.java2
25 files changed, 869 insertions, 653 deletions
diff --git a/src/main/java/com/google/devtools/build/docgen/DocgenConsts.java b/src/main/java/com/google/devtools/build/docgen/DocgenConsts.java
index 31f3359247..e50058854d 100644
--- a/src/main/java/com/google/devtools/build/docgen/DocgenConsts.java
+++ b/src/main/java/com/google/devtools/build/docgen/DocgenConsts.java
@@ -32,7 +32,11 @@ public class DocgenConsts {
public static final String HEADER_TEMPLATE = "templates/be-header.html";
public static final String FOOTER_TEMPLATE = "templates/be-footer.html";
public static final String BODY_TEMPLATE = "templates/be-body.html";
- public static final String SKYLARK_BODY_TEMPLATE = "templates/skylark-body.html";
+
+ public static final String SKYLARK_LIBRARY_TEMPLATE =
+ "com/google/devtools/build/docgen/templates/skylark-library.vm";
+ public static final String SKYLARK_NAV_TEMPLATE =
+ "com/google/devtools/build/docgen/templates/skylark-nav.vm";
public static final String VAR_LEFT_PANEL = "LEFT_PANEL";
diff --git a/src/main/java/com/google/devtools/build/docgen/SkylarkDocumentationCollector.java b/src/main/java/com/google/devtools/build/docgen/SkylarkDocumentationCollector.java
new file mode 100644
index 0000000000..f7ae83b0e4
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/docgen/SkylarkDocumentationCollector.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.docgen;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.collect.ImmutableMap;
+import com.google.devtools.build.docgen.skylark.SkylarkBuiltinMethodDoc;
+import com.google.devtools.build.docgen.skylark.SkylarkJavaMethodDoc;
+import com.google.devtools.build.docgen.skylark.SkylarkModuleDoc;
+import com.google.devtools.build.lib.analysis.TransitiveInfoCollection;
+import com.google.devtools.build.lib.rules.SkylarkModules;
+import com.google.devtools.build.lib.rules.SkylarkRuleContext;
+import com.google.devtools.build.lib.syntax.Environment;
+import com.google.devtools.build.lib.syntax.FuncallExpression;
+import com.google.devtools.build.lib.syntax.MethodLibrary;
+import com.google.devtools.build.lib.syntax.SkylarkCallable;
+import com.google.devtools.build.lib.syntax.SkylarkModule;
+import com.google.devtools.build.lib.syntax.SkylarkSignature;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.Deque;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.TreeMap;
+
+/**
+ * A helper class that collects Skylark module documentation.
+ */
+final class SkylarkDocumentationCollector {
+ @SkylarkModule(name = "globals",
+ doc = "Objects, functions and modules registered in the global environment.")
+ private static final class TopLevelModule {}
+
+ private SkylarkDocumentationCollector() {}
+
+ /**
+ * Returns the SkylarkModule annotation for the top-level Skylark module.
+ */
+ public static SkylarkModule getTopLevelModule() {
+ return TopLevelModule.class.getAnnotation(SkylarkModule.class);
+ }
+
+ /**
+ * Collects the documentation for all Skylark modules and returns a map that maps Skylark
+ * module name to the module documentation.
+ */
+ public static Map<String, SkylarkModuleDoc> collectModules() {
+ Map<String, SkylarkModuleDoc> modules = new TreeMap<>();
+ Map<String, SkylarkModuleDoc> builtinModules = collectBuiltinModules();
+ Map<SkylarkModule, Class<?>> builtinJavaObjects = collectBuiltinJavaObjects();
+
+ modules.putAll(builtinModules);
+ for (SkylarkModuleDoc builtinObject : builtinModules.values()) {
+ // Check the return type for built-in functions, it can be a module previously not added.
+ for (SkylarkBuiltinMethodDoc builtinMethod : builtinObject.getBuiltinMethods().values()) {
+ Class<?> type = builtinMethod.getAnnotation().returnType();
+ if (type.isAnnotationPresent(SkylarkModule.class)) {
+ collectJavaObjects(type.getAnnotation(SkylarkModule.class), type, modules);
+ }
+ }
+ collectJavaObjects(builtinObject.getAnnotation(), builtinObject.getClassObject(), modules);
+ }
+ for (Entry<SkylarkModule, Class<?>> builtinModule : builtinJavaObjects.entrySet()) {
+ collectJavaObjects(builtinModule.getKey(), builtinModule.getValue(), modules);
+ }
+ return modules;
+ }
+
+ /**
+ * Collects and returns all the Java objects reachable in Skylark from (and including)
+ * firstClass with the corresponding SkylarkModule annotation.
+ *
+ * <p>Note that the {@link SkylarkModule} annotation for firstClass - firstModule -
+ * is also an input parameter, because some top level Skylark built-in objects and methods
+ * are not annotated on the class, but on a field referencing them.
+ */
+ @VisibleForTesting
+ static void collectJavaObjects(SkylarkModule firstModule, Class<?> firstClass,
+ Map<String, SkylarkModuleDoc> modules) {
+ Set<Class<?>> done = new HashSet<>();
+ Deque<Class<?>> toProcess = new LinkedList<>();
+ Map<Class<?>, SkylarkModule> annotations = new HashMap<>();
+
+ toProcess.addLast(firstClass);
+ annotations.put(firstClass, firstModule);
+
+ while (!toProcess.isEmpty()) {
+ Class<?> c = toProcess.removeFirst();
+ SkylarkModule annotation = annotations.get(c);
+ done.add(c);
+ if (!modules.containsKey(annotation.name())) {
+ modules.put(annotation.name(), new SkylarkModuleDoc(annotation, c));
+ }
+ SkylarkModuleDoc module = modules.get(annotation.name());
+
+ if (module.javaMethodsNotCollected()) {
+ ImmutableMap<Method, SkylarkCallable> methods =
+ FuncallExpression.collectSkylarkMethodsWithAnnotation(c);
+ for (Map.Entry<Method, SkylarkCallable> entry : methods.entrySet()) {
+ module.addMethod(new SkylarkJavaMethodDoc(module, entry.getKey(), entry.getValue()));
+ }
+
+ for (Map.Entry<Method, SkylarkCallable> method : methods.entrySet()) {
+ Class<?> returnClass = method.getKey().getReturnType();
+ if (returnClass.isAnnotationPresent(SkylarkModule.class)
+ && !done.contains(returnClass)) {
+ toProcess.addLast(returnClass);
+ annotations.put(returnClass, returnClass.getAnnotation(SkylarkModule.class));
+ }
+ }
+ }
+ }
+ }
+
+ private static Map<String, SkylarkModuleDoc> collectBuiltinModules() {
+ Map<String, SkylarkModuleDoc> modules = new HashMap<>();
+ collectBuiltinDoc(modules, Environment.class.getDeclaredFields());
+ collectBuiltinDoc(modules, MethodLibrary.class.getDeclaredFields());
+ for (Class<?> moduleClass : SkylarkModules.MODULES) {
+ collectBuiltinDoc(modules, moduleClass.getDeclaredFields());
+ }
+ return modules;
+ }
+
+ private static void collectBuiltinDoc(Map<String, SkylarkModuleDoc> modules, Field[] fields) {
+ for (Field field : fields) {
+ if (field.isAnnotationPresent(SkylarkSignature.class)) {
+ SkylarkSignature skylarkSignature = field.getAnnotation(SkylarkSignature.class);
+ Class<?> moduleClass = skylarkSignature.objectType();
+ SkylarkModule skylarkModule = moduleClass.equals(Object.class)
+ ? getTopLevelModule()
+ : moduleClass.getAnnotation(SkylarkModule.class);
+ if (!modules.containsKey(skylarkModule.name())) {
+ modules.put(skylarkModule.name(), new SkylarkModuleDoc(skylarkModule, moduleClass));
+ }
+
+ SkylarkModuleDoc module = modules.get(skylarkModule.name());
+ module.addMethod(new SkylarkBuiltinMethodDoc(module, skylarkSignature, field.getType()));
+ }
+ }
+ }
+
+ private static Map<SkylarkModule, Class<?>> collectBuiltinJavaObjects() {
+ Map<SkylarkModule, Class<?>> modules = new HashMap<>();
+ collectBuiltinModule(modules, SkylarkRuleContext.class);
+ collectBuiltinModule(modules, TransitiveInfoCollection.class);
+ return modules;
+ }
+
+ private static void collectBuiltinModule(
+ Map<SkylarkModule, Class<?>> modules, Class<?> moduleClass) {
+ if (moduleClass.isAnnotationPresent(SkylarkModule.class)) {
+ SkylarkModule skylarkModule = moduleClass.getAnnotation(SkylarkModule.class);
+ modules.put(skylarkModule, moduleClass);
+ }
+ }
+
+ /**
+ * Returns the top level modules and functions with their documentation in a command-line
+ * printable format.
+ */
+ public static Map<String, String> collectTopLevelModules() {
+ Map<String, String> modules = new TreeMap<>();
+ for (SkylarkModuleDoc doc : collectBuiltinModules().values()) {
+ if (doc.getAnnotation() == getTopLevelModule()) {
+ for (Map.Entry<String, SkylarkBuiltinMethodDoc> entry :
+ doc.getBuiltinMethods().entrySet()) {
+ if (entry.getValue().documented()) {
+ modules.put(entry.getKey(),
+ DocgenConsts.toCommandLineFormat(entry.getValue().getDocumentation()));
+ }
+ }
+ } else {
+ modules.put(doc.getAnnotation().name(),
+ DocgenConsts.toCommandLineFormat(doc.getAnnotation().doc()));
+ }
+ }
+ return modules;
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/docgen/SkylarkDocumentationGenerator.java b/src/main/java/com/google/devtools/build/docgen/SkylarkDocumentationGenerator.java
index c4f8cf3de7..6e0d572a48 100644
--- a/src/main/java/com/google/devtools/build/docgen/SkylarkDocumentationGenerator.java
+++ b/src/main/java/com/google/devtools/build/docgen/SkylarkDocumentationGenerator.java
@@ -39,9 +39,8 @@ public class SkylarkDocumentationGenerator {
public static void main(String[] args) {
if (checkArgs(args)) {
System.out.println("Generating Skylark documentation...");
- SkylarkDocumentationProcessor processor = new SkylarkDocumentationProcessor();
try {
- processor.generateDocumentation(args[0]);
+ SkylarkDocumentationProcessor.generateDocumentation(args[0]);
} catch (Throwable e) {
fail(e, true);
}
diff --git a/src/main/java/com/google/devtools/build/docgen/SkylarkDocumentationProcessor.java b/src/main/java/com/google/devtools/build/docgen/SkylarkDocumentationProcessor.java
index fa5933415c..816a46524b 100644
--- a/src/main/java/com/google/devtools/build/docgen/SkylarkDocumentationProcessor.java
+++ b/src/main/java/com/google/devtools/build/docgen/SkylarkDocumentationProcessor.java
@@ -13,389 +13,59 @@
// limitations under the License.
package com.google.devtools.build.docgen;
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Function;
-import com.google.common.base.Joiner;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Iterables;
-import com.google.common.io.Files;
-import com.google.devtools.build.docgen.SkylarkJavaInterfaceExplorer.SkylarkBuiltinMethod;
-import com.google.devtools.build.docgen.SkylarkJavaInterfaceExplorer.SkylarkJavaMethod;
-import com.google.devtools.build.docgen.SkylarkJavaInterfaceExplorer.SkylarkModuleDoc;
-import com.google.devtools.build.lib.analysis.TransitiveInfoCollection;
-import com.google.devtools.build.lib.rules.SkylarkModules;
-import com.google.devtools.build.lib.rules.SkylarkRuleContext;
-import com.google.devtools.build.lib.syntax.BaseFunction;
-import com.google.devtools.build.lib.syntax.Environment;
-import com.google.devtools.build.lib.syntax.Environment.NoneType;
-import com.google.devtools.build.lib.syntax.EvalUtils;
-import com.google.devtools.build.lib.syntax.FuncallExpression;
-import com.google.devtools.build.lib.syntax.MethodLibrary;
-import com.google.devtools.build.lib.syntax.SkylarkCallable;
-import com.google.devtools.build.lib.syntax.SkylarkList;
-import com.google.devtools.build.lib.syntax.SkylarkModule;
-import com.google.devtools.build.lib.syntax.SkylarkSignature;
-import com.google.devtools.build.lib.syntax.SkylarkSignature.Param;
-import com.google.devtools.build.lib.syntax.SkylarkSignatureProcessor.HackHackEitherList;
+import com.google.devtools.build.docgen.skylark.SkylarkBuiltinMethodDoc;
+import com.google.devtools.build.docgen.skylark.SkylarkJavaMethodDoc;
+import com.google.devtools.build.docgen.skylark.SkylarkModuleDoc;
-import java.io.BufferedWriter;
import java.io.File;
import java.io.IOException;
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
-import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import java.util.Map.Entry;
-import java.util.TreeMap;
/**
* A class to assemble documentation for Skylark.
*/
-public class SkylarkDocumentationProcessor {
-
- private static final String TOP_LEVEL_ID = "_top_level";
-
- private static final boolean USE_TEMPLATE = false;
-
- @SkylarkModule(name = "Global objects, functions and modules",
- doc = "Objects, functions and modules registered in the global environment.")
- private static final class TopLevelModule {}
-
- static SkylarkModule getTopLevelModule() {
- return TopLevelModule.class.getAnnotation(SkylarkModule.class);
- }
+public final class SkylarkDocumentationProcessor {
+ private SkylarkDocumentationProcessor() {}
/**
* Generates the Skylark documentation to the given output directory.
*/
- public void generateDocumentation(String outputPath) throws IOException,
+ public static void generateDocumentation(String outputDir) throws IOException,
BuildEncyclopediaDocException {
- File skylarkDocPath = new File(outputPath);
- try (BufferedWriter bw = new BufferedWriter(
- Files.newWriter(skylarkDocPath, StandardCharsets.UTF_8))) {
- if (USE_TEMPLATE) {
- bw.write(SourceFileReader.readTemplateContents(DocgenConsts.SKYLARK_BODY_TEMPLATE,
- ImmutableMap.<String, String>of(
- DocgenConsts.VAR_SECTION_SKYLARK_BUILTIN, generateAllBuiltinDoc())));
- } else {
- bw.write(generateAllBuiltinDoc());
- }
- System.out.println("Skylark documentation generated: " + skylarkDocPath.getAbsolutePath());
- }
- }
-
- @VisibleForTesting
- Map<String, SkylarkModuleDoc> collectModules() {
- Map<String, SkylarkModuleDoc> modules = new TreeMap<>();
- Map<String, SkylarkModuleDoc> builtinModules = collectBuiltinModules();
- Map<SkylarkModule, Class<?>> builtinJavaObjects = collectBuiltinJavaObjects();
-
- modules.putAll(builtinModules);
- SkylarkJavaInterfaceExplorer explorer = new SkylarkJavaInterfaceExplorer();
- for (SkylarkModuleDoc builtinObject : builtinModules.values()) {
- // Check the return type for built-in functions, it can be a module previously not added.
- for (SkylarkBuiltinMethod builtinMethod : builtinObject.getBuiltinMethods().values()) {
- Class<?> type = builtinMethod.annotation.returnType();
- if (type.isAnnotationPresent(SkylarkModule.class)) {
- explorer.collect(type.getAnnotation(SkylarkModule.class), type, modules);
- }
- }
- explorer.collect(builtinObject.getAnnotation(), builtinObject.getClassObject(), modules);
- }
- for (Entry<SkylarkModule, Class<?>> builtinModule : builtinJavaObjects.entrySet()) {
- explorer.collect(builtinModule.getKey(), builtinModule.getValue(), modules);
- }
- return modules;
- }
-
- private String generateAllBuiltinDoc() {
- Map<String, SkylarkModuleDoc> modules = collectModules();
+ Map<String, SkylarkModuleDoc> modules = SkylarkDocumentationCollector.collectModules();
+ List<SkylarkModuleDoc> navModules = new ArrayList<>();
- StringBuilder sb = new StringBuilder();
// Generate the top level module first in the doc
- SkylarkModuleDoc topLevelModule = modules.remove(getTopLevelModule().name());
- generateModuleDoc(topLevelModule, sb);
+ SkylarkModuleDoc topLevelModule = modules.remove(
+ SkylarkDocumentationCollector.getTopLevelModule().name());
+ topLevelModule.setTitle("Globals");
+ writePage(outputDir, topLevelModule);
+ navModules.add(topLevelModule);
+
for (SkylarkModuleDoc module : modules.values()) {
if (module.getAnnotation().documented()) {
- sb.append("<hr>");
- generateModuleDoc(module, sb);
+ writePage(outputDir, module);
+ navModules.add(module);
}
}
- return sb.toString();
+ writeNavPage(outputDir, navModules);
}
- private void generateModuleDoc(SkylarkModuleDoc module, StringBuilder sb) {
- SkylarkModule annotation = module.getAnnotation();
- sb.append(String.format("<h2 id=\"modules.%s\">%s</h2>\n",
- getModuleId(annotation),
- annotation.name()))
- .append(annotation.doc())
- .append("\n");
- sb.append("<ul>");
- // Sort Java and Skylark builtin methods together. The map key is only used for sorting.
- TreeMap<String, Object> methodMap = new TreeMap<>();
- for (SkylarkJavaMethod method : module.getJavaMethods()) {
- methodMap.put(method.name + method.method.getParameterTypes().length, method);
- }
- for (SkylarkBuiltinMethod builtin : module.getBuiltinMethods().values()) {
- methodMap.put(builtin.annotation.name(), builtin);
- }
- for (Object object : methodMap.values()) {
- if (object instanceof SkylarkJavaMethod) {
- SkylarkJavaMethod method = (SkylarkJavaMethod) object;
- generateDirectJavaMethodDoc(annotation.name(), method.name, method.method,
- method.callable, sb);
- }
- if (object instanceof SkylarkBuiltinMethod) {
- generateBuiltinItemDoc(getModuleId(annotation), (SkylarkBuiltinMethod) object, sb);
- }
- }
- sb.append("</ul>");
+ private static void writePage(String outputDir, SkylarkModuleDoc module) throws IOException {
+ File skylarkDocPath = new File(outputDir + "/" + module.getName() + ".html");
+ Page page = TemplateEngine.newPage(DocgenConsts.SKYLARK_LIBRARY_TEMPLATE);
+ page.add("module", module);
+ page.write(skylarkDocPath);
}
- private String getModuleId(SkylarkModule annotation) {
- if (annotation == getTopLevelModule()) {
- return TOP_LEVEL_ID;
- } else {
- return annotation.name();
- }
- }
-
- private void generateBuiltinItemDoc(
- String moduleId, SkylarkBuiltinMethod method, StringBuilder sb) {
- SkylarkSignature annotation = method.annotation;
- if (!annotation.documented()) {
- return;
- }
- sb.append(String.format("<li><h3 id=\"modules.%s.%s\">%s</h3>\n",
- moduleId,
- annotation.name(),
- annotation.name()));
-
- if (BaseFunction.class.isAssignableFrom(method.fieldClass)) {
- sb.append(getSignature(moduleId, annotation));
- } else {
- if (!annotation.returnType().equals(Object.class)) {
- sb.append("<code>" + getTypeAnchor(annotation.returnType()) + "</code><br>");
- }
- }
-
- sb.append(annotation.doc() + "\n");
- printParams(moduleId, annotation, sb);
- }
-
- // Elide self parameter from mandatoryPositionals in class methods.
- private static Param[] adjustedMandatoryPositionals(SkylarkSignature annotation) {
- Param[] mandatoryPos = annotation.mandatoryPositionals();
- if (mandatoryPos.length > 0
- && annotation.objectType() != Object.class
- && !FuncallExpression.isNamespace(annotation.objectType())) {
- // Skip the self parameter, which is the first mandatory positional parameter.
- return Arrays.copyOfRange(mandatoryPos, 1, mandatoryPos.length);
- } else {
- return mandatoryPos;
- }
- }
-
- private void printParams(String moduleId, SkylarkSignature annotation, StringBuilder sb) {
- Param[] mandatoryPos = adjustedMandatoryPositionals(annotation);
- Param[] optionalPos = annotation.optionalPositionals();
- Param[] optionalKey = annotation.optionalNamedOnly();
- Param[] mandatoryKey = annotation.mandatoryNamedOnly();
- Param[] star = annotation.extraPositionals();
- Param[] starStar = annotation.extraKeywords();
-
- if (mandatoryPos.length + optionalPos.length + optionalKey.length + mandatoryKey.length
- + star.length + starStar.length > 0) {
- sb.append("<h4>Parameters</h4>\n");
- printParams(moduleId, annotation.name(), mandatoryPos, sb);
- printParams(moduleId, annotation.name(), optionalPos, sb);
- printParams(moduleId, annotation.name(), star, sb);
- printParams(moduleId, annotation.name(), mandatoryKey, sb);
- printParams(moduleId, annotation.name(), optionalKey, sb);
- printParams(moduleId, annotation.name(), starStar, sb);
- } else {
- sb.append("<br/>\n");
- }
- }
-
- private void generateDirectJavaMethodDoc(String objectName, String methodName,
- Method method, SkylarkCallable annotation, StringBuilder sb) {
- if (!annotation.documented()) {
- return;
- }
- if (annotation.doc().isEmpty()) {
- throw new RuntimeException(String.format(
- "empty SkylarkCallable.doc() for object %s, method %s", objectName, methodName));
- }
-
- sb.append(String.format("<li><h3 id=\"modules.%s.%s\">%s</h3>\n%s\n",
- objectName,
- methodName,
- methodName,
- getSignature(objectName, methodName, method)))
- .append(annotation.doc())
- .append(getReturnTypeExtraMessage(annotation))
- .append("\n");
- }
-
- private String getReturnTypeExtraMessage(SkylarkCallable annotation) {
- if (annotation.allowReturnNones()) {
- return " May return <code>None</code>.\n";
- }
- return "";
- }
-
- private String getSignature(String objectName, String methodName, Method method) {
- String args = method.getAnnotation(SkylarkCallable.class).structField()
- ? "" : "(" + getParameterString(method) + ")";
-
- return String.format("<code>%s %s.%s%s</code><br>",
- getTypeAnchor(method.getReturnType()), objectName, methodName, args);
- }
-
- private String getSignature(String objectName, SkylarkSignature method) {
- List<String> argList = new ArrayList<>();
- for (Param param : adjustedMandatoryPositionals(method)) {
- argList.add(param.name());
- }
- for (Param param : method.optionalPositionals()) {
- argList.add(formatOptionalParameter(param));
- }
- for (Param param : method.extraPositionals()) {
- argList.add("*" + param.name());
- }
- if (argList.size() > 0 && method.extraPositionals().length == 0
- && (method.optionalNamedOnly().length > 0 || method.mandatoryNamedOnly().length > 0)) {
- argList.add("*");
- }
- for (Param param : method.mandatoryNamedOnly()) {
- argList.add(param.name());
- }
- for (Param param : method.optionalNamedOnly()) {
- argList.add(formatOptionalParameter(param));
- }
- for (Param param : method.extraKeywords()) {
- argList.add("**" + param.name());
- }
- String args = "(" + Joiner.on(", ").join(argList) + ")";
- if (!objectName.equals(TOP_LEVEL_ID)) {
- return String.format("<code>%s %s.%s%s</code><br>\n",
- getTypeAnchor(method.returnType()), objectName, method.name(), args);
- } else {
- return String.format("<code>%s %s%s</code><br>\n",
- getTypeAnchor(method.returnType()), method.name(), args);
- }
- }
-
- private String formatOptionalParameter(Param param) {
- String defaultValue = param.defaultValue();
-
- return String.format("%s=%s", param.name(),
- (defaultValue == null || defaultValue.isEmpty()) ? "&hellip;" : defaultValue);
- }
-
- private String getTypeAnchor(Class<?> returnType, Class<?> generic1) {
- return getTypeAnchor(returnType) + " of " + getTypeAnchor(generic1) + "s";
- }
-
- private String getTypeAnchor(Class<?> type) {
- if (type.equals(Boolean.class) || type.equals(boolean.class)) {
- return "<a class=\"anchor\" href=\"#modules._top_level.bool\">bool</a>";
- } else if (type.equals(String.class)) {
- return "<a class=\"anchor\" href=\"#modules.string\">string</a>";
- } else if (Map.class.isAssignableFrom(type)) {
- return "<a class=\"anchor\" href=\"#modules.dict\">dict</a>";
- } else if (List.class.isAssignableFrom(type) || SkylarkList.class.isAssignableFrom(type)
- || type == HackHackEitherList.class) {
- // Annotated Java methods can return simple java.util.Lists (which get auto-converted).
- return "<a class=\"anchor\" href=\"#modules.list\">list</a>";
- } else if (type.equals(Void.TYPE) || type.equals(NoneType.class)) {
- return "<a class=\"anchor\" href=\"#modules." + TOP_LEVEL_ID + ".None\">None</a>";
- } else if (type.isAnnotationPresent(SkylarkModule.class)) {
- // TODO(bazel-team): this can produce dead links for types don't show up in the doc.
- // The correct fix is to generate those types (e.g. SkylarkFileType) too.
- String module = type.getAnnotation(SkylarkModule.class).name();
- return "<a class=\"anchor\" href=\"#modules." + module + "\">" + module + "</a>";
- } else {
- return EvalUtils.getDataTypeNameFromClass(type);
- }
- }
-
- private String getParameterString(Method method) {
- return Joiner.on(", ").join(Iterables.transform(
- ImmutableList.copyOf(method.getParameterTypes()), new Function<Class<?>, String>() {
- @Override
- public String apply(Class<?> input) {
- return getTypeAnchor(input);
- }
- }));
- }
-
- private void printParams(String moduleId, String methodName,
- Param[] params, StringBuilder sb) {
- if (params.length > 0) {
- sb.append("<ul>\n");
- for (Param param : params) {
- String paramType = param.type().equals(Object.class) ? ""
- : (param.generic1().equals(Object.class)
- ? " (" + getTypeAnchor(param.type()) + ")"
- : " (" + getTypeAnchor(param.type(), param.generic1()) + ")");
- sb.append(String.format("\t<li id=\"modules.%s.%s.%s\"><code>%s%s</code>: ",
- moduleId,
- methodName,
- param.name(),
- param.name(),
- paramType))
- .append(param.doc())
- .append("\n\t</li>\n");
- }
- sb.append("</ul>\n");
- }
- }
-
- private Map<String, SkylarkModuleDoc> collectBuiltinModules() {
- Map<String, SkylarkModuleDoc> modules = new HashMap<>();
- collectBuiltinDoc(modules, Environment.class.getDeclaredFields());
- collectBuiltinDoc(modules, MethodLibrary.class.getDeclaredFields());
- for (Class<?> moduleClass : SkylarkModules.MODULES) {
- collectBuiltinDoc(modules, moduleClass.getDeclaredFields());
- }
- return modules;
- }
-
- private Map<SkylarkModule, Class<?>> collectBuiltinJavaObjects() {
- Map<SkylarkModule, Class<?>> modules = new HashMap<>();
- collectBuiltinModule(modules, SkylarkRuleContext.class);
- collectBuiltinModule(modules, TransitiveInfoCollection.class);
- return modules;
- }
-
- /**
- * Returns the top level modules and functions with their documentation in a command-line
- * printable format.
- */
- public Map<String, String> collectTopLevelModules() {
- Map<String, String> modules = new TreeMap<>();
- for (SkylarkModuleDoc doc : collectBuiltinModules().values()) {
- if (doc.getAnnotation() == getTopLevelModule()) {
- for (Map.Entry<String, SkylarkBuiltinMethod> entry : doc.getBuiltinMethods().entrySet()) {
- if (entry.getValue().annotation.documented()) {
- modules.put(entry.getKey(),
- DocgenConsts.toCommandLineFormat(entry.getValue().annotation.doc()));
- }
- }
- } else {
- modules.put(doc.getAnnotation().name(),
- DocgenConsts.toCommandLineFormat(doc.getAnnotation().doc()));
- }
- }
- return modules;
+ private static void writeNavPage(String outputDir, List<SkylarkModuleDoc> navModules)
+ throws IOException {
+ File navFile = new File(outputDir + "/" + "skylark-nav.html");
+ Page page = TemplateEngine.newPage(DocgenConsts.SKYLARK_NAV_TEMPLATE);
+ page.add("modules", navModules);
+ page.write(navFile);
}
/**
@@ -404,9 +74,10 @@ public class SkylarkDocumentationProcessor {
* method in the module.<br>
* Returns null if no Skylark object is found.
*/
- public String getCommandLineAPIDoc(String[] params) {
- Map<String, SkylarkModuleDoc> modules = collectModules();
- SkylarkModuleDoc toplevelModuleDoc = modules.get(getTopLevelModule().name());
+ public static String getCommandLineAPIDoc(String[] params) {
+ Map<String, SkylarkModuleDoc> modules = SkylarkDocumentationCollector.collectModules();
+ SkylarkModuleDoc toplevelModuleDoc = modules.get(
+ SkylarkDocumentationCollector.getTopLevelModule().name());
if (modules.containsKey(params[0])) {
// Top level module
SkylarkModuleDoc module = modules.get(params[0]);
@@ -415,12 +86,12 @@ public class SkylarkDocumentationProcessor {
StringBuilder sb = new StringBuilder();
sb.append(moduleName).append("\n\t").append(module.getAnnotation().doc()).append("\n");
// Print the signature of all built-in methods
- for (SkylarkBuiltinMethod method : module.getBuiltinMethods().values()) {
- printBuiltinFunctionDoc(moduleName, method.annotation, sb);
+ for (SkylarkBuiltinMethodDoc method : module.getBuiltinMethods().values()) {
+ printBuiltinFunctionDoc(moduleName, method, sb);
}
// Print all Java methods
- for (SkylarkJavaMethod method : module.getJavaMethods()) {
- printJavaFunctionDoc(moduleName, method, sb);
+ for (SkylarkJavaMethodDoc method : module.getJavaMethods()) {
+ printJavaFunctionDoc(method, sb);
}
return DocgenConsts.toCommandLineFormat(sb.toString());
} else {
@@ -433,67 +104,42 @@ public class SkylarkDocumentationProcessor {
return null;
}
- private String getFunctionDoc(String moduleName, String methodName, SkylarkModuleDoc module) {
+ private static String getFunctionDoc(String moduleName, String methodName,
+ SkylarkModuleDoc module) {
if (module.getBuiltinMethods().containsKey(methodName)) {
// Create the doc for the built-in function
- SkylarkBuiltinMethod method = module.getBuiltinMethods().get(methodName);
+ SkylarkBuiltinMethodDoc method = module.getBuiltinMethods().get(methodName);
StringBuilder sb = new StringBuilder();
- printBuiltinFunctionDoc(moduleName, method.annotation, sb);
- printParams(moduleName, method.annotation, sb);
+ printBuiltinFunctionDoc(moduleName, method, sb);
+ sb.append(method.getParams());
return DocgenConsts.removeDuplicatedNewLines(DocgenConsts.toCommandLineFormat(sb.toString()));
} else {
// Search if there are matching Java functions
StringBuilder sb = new StringBuilder();
boolean foundMatchingMethod = false;
- for (SkylarkJavaMethod method : module.getJavaMethods()) {
- if (method.name.equals(methodName)) {
- printJavaFunctionDoc(moduleName, method, sb);
+ for (SkylarkJavaMethodDoc method : module.getJavaMethods()) {
+ if (method.getName().equals(methodName)) {
+ printJavaFunctionDoc(method, sb);
foundMatchingMethod = true;
}
}
if (foundMatchingMethod) {
- return DocgenConsts.toCommandLineFormat(sb.toString());
+ return DocgenConsts.toCommandLineFormat(sb.toString());
}
}
return null;
}
- private void printBuiltinFunctionDoc(
- String moduleName, SkylarkSignature annotation, StringBuilder sb) {
+ private static void printBuiltinFunctionDoc(String moduleName, SkylarkBuiltinMethodDoc method,
+ StringBuilder sb) {
if (moduleName != null) {
sb.append(moduleName).append(".");
}
- sb.append(annotation.name()).append("\n\t").append(annotation.doc()).append("\n");
- }
-
- private void printJavaFunctionDoc(String moduleName, SkylarkJavaMethod method, StringBuilder sb) {
- sb.append(getSignature(moduleName, method.name, method.method))
- .append("\t").append(method.callable.doc()).append("\n");
- }
-
- private void collectBuiltinModule(
- Map<SkylarkModule, Class<?>> modules, Class<?> moduleClass) {
- if (moduleClass.isAnnotationPresent(SkylarkModule.class)) {
- SkylarkModule skylarkModule = moduleClass.getAnnotation(SkylarkModule.class);
- modules.put(skylarkModule, moduleClass);
- }
+ sb.append(method.getName()).append("\n\t").append(method.getDocumentation()).append("\n");
}
- private void collectBuiltinDoc(Map<String, SkylarkModuleDoc> modules, Field[] fields) {
- for (Field field : fields) {
- if (field.isAnnotationPresent(SkylarkSignature.class)) {
- SkylarkSignature skylarkSignature = field.getAnnotation(SkylarkSignature.class);
- Class<?> moduleClass = skylarkSignature.objectType();
- SkylarkModule skylarkModule = moduleClass.equals(Object.class)
- ? getTopLevelModule()
- : moduleClass.getAnnotation(SkylarkModule.class);
- if (!modules.containsKey(skylarkModule.name())) {
- modules.put(skylarkModule.name(), new SkylarkModuleDoc(skylarkModule, moduleClass));
- }
- modules.get(skylarkModule.name()).getBuiltinMethods()
- .put(skylarkSignature.name(),
- new SkylarkBuiltinMethod(skylarkSignature, field.getType()));
- }
- }
+ private static void printJavaFunctionDoc(SkylarkJavaMethodDoc method, StringBuilder sb) {
+ sb.append(method.getSignature())
+ .append("\t").append(method.getDocumentation()).append("\n");
}
}
diff --git a/src/main/java/com/google/devtools/build/docgen/SkylarkJavaInterfaceExplorer.java b/src/main/java/com/google/devtools/build/docgen/SkylarkJavaInterfaceExplorer.java
deleted file mode 100644
index 1118991d66..0000000000
--- a/src/main/java/com/google/devtools/build/docgen/SkylarkJavaInterfaceExplorer.java
+++ /dev/null
@@ -1,160 +0,0 @@
-// 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.docgen;
-
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableMap;
-import com.google.devtools.build.lib.syntax.FuncallExpression;
-import com.google.devtools.build.lib.syntax.SkylarkCallable;
-import com.google.devtools.build.lib.syntax.SkylarkModule;
-import com.google.devtools.build.lib.syntax.SkylarkSignature;
-import com.google.devtools.build.lib.util.StringUtilities;
-
-import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeMap;
-
-/**
- * A helper class to collect all the Java objects / methods reachable from Skylark.
- */
-public class SkylarkJavaInterfaceExplorer {
- /**
- * A class representing a Java method callable from Skylark with annotation.
- */
- static final class SkylarkJavaMethod {
- public final String name;
- public final Method method;
- public final SkylarkCallable callable;
-
- private String getName(Method method, SkylarkCallable callable) {
- return callable.name().isEmpty()
- ? StringUtilities.toPythonStyleFunctionName(method.getName())
- : callable.name();
- }
-
- SkylarkJavaMethod(Method method, SkylarkCallable callable) {
- this.name = getName(method, callable);
- this.method = method;
- this.callable = callable;
- }
- }
-
- /**
- * A class representing a Skylark built-in object or method.
- */
- static final class SkylarkBuiltinMethod {
- public final SkylarkSignature annotation;
- public final Class<?> fieldClass;
-
- public SkylarkBuiltinMethod(SkylarkSignature annotation, Class<?> fieldClass) {
- this.annotation = annotation;
- this.fieldClass = fieldClass;
- }
- }
-
- /**
- * A class representing a Skylark built-in object with its {@link SkylarkSignature} annotation
- * and the {@link SkylarkCallable} methods it might have.
- */
- static final class SkylarkModuleDoc {
-
- private final SkylarkModule module;
- private final Class<?> classObject;
- private final Map<String, SkylarkBuiltinMethod> builtin;
- private ArrayList<SkylarkJavaMethod> methods = null;
-
- SkylarkModuleDoc(SkylarkModule module, Class<?> classObject) {
- this.module = Preconditions.checkNotNull(
- module, "Class has to be annotated with SkylarkModule: %s", classObject);
- this.classObject = classObject;
- this.builtin = new TreeMap<>();
- }
-
- SkylarkModule getAnnotation() {
- return module;
- }
-
- Class<?> getClassObject() {
- return classObject;
- }
-
- private boolean javaMethodsNotCollected() {
- return methods == null;
- }
-
- private void setJavaMethods(ArrayList<SkylarkJavaMethod> methods) {
- this.methods = methods;
- }
-
- Map<String, SkylarkBuiltinMethod> getBuiltinMethods() {
- return builtin;
- }
-
- ArrayList<SkylarkJavaMethod> getJavaMethods() {
- return methods;
- }
- }
-
- /**
- * Collects and returns all the Java objects reachable in Skylark from (and including)
- * firstClassObject with the corresponding SkylarkSignature annotations.
- *
- * <p>Note that the {@link SkylarkSignature} annotation for firstClassObject - firstAnnotation -
- * is also an input parameter, because some top level Skylark built-in objects and methods
- * are not annotated on the class, but on a field referencing them.
- */
- void collect(SkylarkModule firstModule, Class<?> firstClass,
- Map<String, SkylarkModuleDoc> modules) {
- Set<Class<?>> processedClasses = new HashSet<>();
- LinkedList<Class<?>> classesToProcess = new LinkedList<>();
- Map<Class<?>, SkylarkModule> annotations = new HashMap<>();
-
- classesToProcess.addLast(firstClass);
- annotations.put(firstClass, firstModule);
-
- while (!classesToProcess.isEmpty()) {
- Class<?> classObject = classesToProcess.removeFirst();
- SkylarkModule annotation = annotations.get(classObject);
- processedClasses.add(classObject);
- if (!modules.containsKey(annotation.name())) {
- modules.put(annotation.name(), new SkylarkModuleDoc(annotation, classObject));
- }
- SkylarkModuleDoc module = modules.get(annotation.name());
-
- if (module.javaMethodsNotCollected()) {
- ImmutableMap<Method, SkylarkCallable> methods =
- FuncallExpression.collectSkylarkMethodsWithAnnotation(classObject);
- ArrayList<SkylarkJavaMethod> methodList = new ArrayList<>();
- for (Map.Entry<Method, SkylarkCallable> entry : methods.entrySet()) {
- methodList.add(new SkylarkJavaMethod(entry.getKey(), entry.getValue()));
- }
- module.setJavaMethods(methodList);
-
- for (Map.Entry<Method, SkylarkCallable> method : methods.entrySet()) {
- Class<?> returnClass = method.getKey().getReturnType();
- if (returnClass.isAnnotationPresent(SkylarkModule.class)
- && !processedClasses.contains(returnClass)) {
- classesToProcess.addLast(returnClass);
- annotations.put(returnClass, returnClass.getAnnotation(SkylarkModule.class));
- }
- }
- }
- }
- }
-}
diff --git a/src/main/java/com/google/devtools/build/docgen/skylark/SkylarkBuiltinMethodDoc.java b/src/main/java/com/google/devtools/build/docgen/skylark/SkylarkBuiltinMethodDoc.java
new file mode 100644
index 0000000000..553cd1141f
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/docgen/skylark/SkylarkBuiltinMethodDoc.java
@@ -0,0 +1,97 @@
+// 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.docgen.skylark;
+
+import com.google.devtools.build.lib.syntax.BaseFunction;
+import com.google.devtools.build.lib.syntax.SkylarkSignature;
+import com.google.devtools.build.lib.syntax.SkylarkSignature.Param;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A class representing a Skylark built-in object or method.
+ */
+public final class SkylarkBuiltinMethodDoc extends SkylarkMethodDoc {
+ private final SkylarkModuleDoc module;
+ private final SkylarkSignature annotation;
+ private final Class<?> fieldClass;
+ private List<SkylarkParamDoc> params;
+
+ public SkylarkBuiltinMethodDoc(SkylarkModuleDoc module, SkylarkSignature annotation,
+ Class<?> fieldClass) {
+ this.module = module;
+ this.annotation = annotation;
+ this.fieldClass = fieldClass;
+ this.params = new ArrayList<>();
+ processParams();
+ }
+
+ public SkylarkSignature getAnnotation() {
+ return annotation;
+ }
+
+ @Override
+ public boolean documented() {
+ return annotation.documented();
+ }
+
+ @Override
+ public String getName() {
+ return annotation.name();
+ }
+
+ @Override
+ public String getDocumentation() {
+ return annotation.doc();
+ }
+
+ /**
+ * Returns a string representing the method signature with links to the types if
+ * available.
+ *
+ * <p>If the built-in method is a function, the construct the method signature. Otherwise,
+ * return a string containing the return type of the method.
+ */
+ @Override
+ public String getSignature() {
+ if (BaseFunction.class.isAssignableFrom(fieldClass)) {
+ return getSignature(module.getName(), annotation);
+ }
+ if (!annotation.returnType().equals(Object.class)) {
+ return getTypeAnchor(annotation.returnType());
+ }
+ return "";
+ }
+
+ @Override
+ public List<SkylarkParamDoc> getParams() {
+ return params;
+ }
+
+ private void processParams() {
+ processParams(adjustedMandatoryPositionals(annotation));
+ processParams(annotation.optionalPositionals());
+ processParams(annotation.optionalNamedOnly());
+ processParams(annotation.mandatoryNamedOnly());
+ processParams(annotation.extraPositionals());
+ processParams(annotation.extraKeywords());
+ }
+
+ private void processParams(Param[] params) {
+ for (Param param : params) {
+ this.params.add(new SkylarkParamDoc(this, param));
+ }
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/docgen/skylark/SkylarkDoc.java b/src/main/java/com/google/devtools/build/docgen/skylark/SkylarkDoc.java
new file mode 100644
index 0000000000..065ab68c0c
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/docgen/skylark/SkylarkDoc.java
@@ -0,0 +1,85 @@
+// 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.docgen.skylark;
+
+import com.google.devtools.build.lib.syntax.Environment.NoneType;
+import com.google.devtools.build.lib.syntax.EvalUtils;
+import com.google.devtools.build.lib.syntax.FuncallExpression;
+import com.google.devtools.build.lib.syntax.SkylarkList;
+import com.google.devtools.build.lib.syntax.SkylarkModule;
+import com.google.devtools.build.lib.syntax.SkylarkSignature;
+import com.google.devtools.build.lib.syntax.SkylarkSignature.Param;
+import com.google.devtools.build.lib.syntax.SkylarkSignatureProcessor.HackHackEitherList;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Abstract class for containing documentation for a Skylark syntactic entity.
+ */
+abstract class SkylarkDoc {
+ protected static final String TOP_LEVEL_ID = "globals";
+
+ /**
+ * Returns a string containing the name of the entity being documented.
+ */
+ public abstract String getName();
+
+ /**
+ * Returns a string containing the HTML documentation of the entity being
+ * documented.
+ */
+ public abstract String getDocumentation();
+
+ protected String getTypeAnchor(Class<?> returnType, Class<?> generic1) {
+ return getTypeAnchor(returnType) + " of " + getTypeAnchor(generic1) + "s";
+ }
+
+ protected String getTypeAnchor(Class<?> type) {
+ if (type.equals(Boolean.class) || type.equals(boolean.class)) {
+ return "<a class=\"anchor\" href=\"" + TOP_LEVEL_ID + ".html#bool\">bool</a>";
+ } else if (type.equals(String.class)) {
+ return "<a class=\"anchor\" href=\"string.html\">string</a>";
+ } else if (Map.class.isAssignableFrom(type)) {
+ return "<a class=\"anchor\" href=\"dict.html\">dict</a>";
+ } else if (List.class.isAssignableFrom(type) || SkylarkList.class.isAssignableFrom(type)
+ || type == HackHackEitherList.class) {
+ // Annotated Java methods can return simple java.util.Lists (which get auto-converted).
+ return "<a class=\"anchor\" href=\"list.html\">list</a>";
+ } else if (type.equals(Void.TYPE) || type.equals(NoneType.class)) {
+ return "<a class=\"anchor\" href=\"" + TOP_LEVEL_ID + ".html#None\">None</a>";
+ } else if (type.isAnnotationPresent(SkylarkModule.class)) {
+ // TODO(bazel-team): this can produce dead links for types don't show up in the doc.
+ // The correct fix is to generate those types (e.g. SkylarkFileType) too.
+ String module = type.getAnnotation(SkylarkModule.class).name();
+ return "<a class=\"anchor\" href=\"" + module + ".html\">" + module + "</a>";
+ } else {
+ return EvalUtils.getDataTypeNameFromClass(type);
+ }
+ }
+
+ // Elide self parameter from mandatoryPositionals in class methods.
+ protected static Param[] adjustedMandatoryPositionals(SkylarkSignature annotation) {
+ Param[] mandatoryPos = annotation.mandatoryPositionals();
+ if (mandatoryPos.length > 0
+ && annotation.objectType() != Object.class
+ && !FuncallExpression.isNamespace(annotation.objectType())) {
+ // Skip the self parameter, which is the first mandatory positional parameter.
+ return Arrays.copyOfRange(mandatoryPos, 1, mandatoryPos.length);
+ } else {
+ return mandatoryPos;
+ }
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/docgen/skylark/SkylarkJavaMethodDoc.java b/src/main/java/com/google/devtools/build/docgen/skylark/SkylarkJavaMethodDoc.java
new file mode 100644
index 0000000000..d4212f7dc7
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/docgen/skylark/SkylarkJavaMethodDoc.java
@@ -0,0 +1,71 @@
+// 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.docgen.skylark;
+
+import com.google.devtools.build.lib.syntax.SkylarkCallable;
+import com.google.devtools.build.lib.util.StringUtilities;
+
+import java.lang.reflect.Method;
+
+/**
+ * A class representing a Java method callable from Skylark with annotation.
+ */
+public final class SkylarkJavaMethodDoc extends SkylarkMethodDoc {
+ private final SkylarkModuleDoc module;
+ private final String name;
+ private final Method method;
+ private final SkylarkCallable callable;
+
+ public SkylarkJavaMethodDoc(SkylarkModuleDoc module, Method method,
+ SkylarkCallable callable) {
+ this.module = module;
+ this.name = callable.name().isEmpty()
+ ? StringUtilities.toPythonStyleFunctionName(method.getName())
+ : callable.name();
+ this.method = method;
+ this.callable = callable;
+ }
+
+ public Method getMethod() {
+ return method;
+ }
+
+ @Override
+ public boolean documented() {
+ return callable.documented();
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public String getDocumentation() {
+ return callable.doc();
+ }
+
+ @Override
+ public String getSignature() {
+ return getSignature(module.getName(), name, method);
+ }
+
+ @Override
+ public String getReturnTypeExtraMessage() {
+ if (callable.allowReturnNones()) {
+ return " May return <code>None</code>.\n";
+ }
+ return "";
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/docgen/skylark/SkylarkMethodDoc.java b/src/main/java/com/google/devtools/build/docgen/skylark/SkylarkMethodDoc.java
new file mode 100644
index 0000000000..294634f90d
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/docgen/skylark/SkylarkMethodDoc.java
@@ -0,0 +1,116 @@
+// 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.docgen.skylark;
+
+import com.google.common.base.Function;
+import com.google.common.base.Joiner;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+import com.google.devtools.build.lib.syntax.SkylarkCallable;
+import com.google.devtools.build.lib.syntax.SkylarkSignature;
+import com.google.devtools.build.lib.syntax.SkylarkSignature.Param;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * An abstract class containing documentation for a Skylark method.
+ */
+abstract class SkylarkMethodDoc extends SkylarkDoc {
+ /**
+ * Returns whether the Skylark method is documented.
+ */
+ public abstract boolean documented();
+
+ /**
+ * Returns a string representing the method signature of the Skylark method, which contains
+ * HTML links to the documentation of parameter types if available.
+ */
+ public abstract String getSignature();
+
+ /**
+ * Returns a string containing additional documentation about the method's return value.
+ *
+ * <p>Returns an empty string by default.
+ */
+ public String getReturnTypeExtraMessage() {
+ return "";
+ }
+
+ /**
+ * Returns a list containing the documentation for each of the method's parameters.
+ */
+ public List<SkylarkParamDoc> getParams() {
+ return ImmutableList.<SkylarkParamDoc>of();
+ }
+
+ private String getParameterString(Method method) {
+ return Joiner.on(", ").join(Iterables.transform(
+ ImmutableList.copyOf(method.getParameterTypes()), new Function<Class<?>, String>() {
+ @Override
+ public String apply(Class<?> input) {
+ return getTypeAnchor(input);
+ }
+ }));
+ }
+
+ protected String getSignature(String objectName, String methodName, Method method) {
+ String args = method.getAnnotation(SkylarkCallable.class).structField()
+ ? "" : "(" + getParameterString(method) + ")";
+
+ return String.format("%s %s.%s%s",
+ getTypeAnchor(method.getReturnType()), objectName, methodName, args);
+ }
+
+ protected String getSignature(String objectName, SkylarkSignature method) {
+ List<String> argList = new ArrayList<>();
+ for (Param param : adjustedMandatoryPositionals(method)) {
+ argList.add(param.name());
+ }
+ for (Param param : method.optionalPositionals()) {
+ argList.add(formatOptionalParameter(param));
+ }
+ for (Param param : method.extraPositionals()) {
+ argList.add("*" + param.name());
+ }
+ if (argList.size() > 0 && method.extraPositionals().length == 0
+ && (method.optionalNamedOnly().length > 0 || method.mandatoryNamedOnly().length > 0)) {
+ argList.add("*");
+ }
+ for (Param param : method.mandatoryNamedOnly()) {
+ argList.add(param.name());
+ }
+ for (Param param : method.optionalNamedOnly()) {
+ argList.add(formatOptionalParameter(param));
+ }
+ for (Param param : method.extraKeywords()) {
+ argList.add("**" + param.name());
+ }
+ String args = "(" + Joiner.on(", ").join(argList) + ")";
+ if (!objectName.equals(TOP_LEVEL_ID)) {
+ return String.format("%s %s.%s%s\n",
+ getTypeAnchor(method.returnType()), objectName, method.name(), args);
+ } else {
+ return String.format("%s %s%s\n",
+ getTypeAnchor(method.returnType()), method.name(), args);
+ }
+ }
+
+ private String formatOptionalParameter(Param param) {
+ String defaultValue = param.defaultValue();
+ return String.format("%s=%s", param.name(),
+ (defaultValue == null || defaultValue.isEmpty()) ? "&hellip;" : defaultValue);
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/docgen/skylark/SkylarkModuleDoc.java b/src/main/java/com/google/devtools/build/docgen/skylark/SkylarkModuleDoc.java
new file mode 100644
index 0000000000..881f932e14
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/docgen/skylark/SkylarkModuleDoc.java
@@ -0,0 +1,98 @@
+// 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.docgen.skylark;
+
+import com.google.common.base.Preconditions;
+import com.google.devtools.build.lib.syntax.SkylarkModule;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
+/**
+ * A class representing a Skylark built-in object with its {@link SkylarkSignature} annotation
+ * and the {@link SkylarkCallable} methods it might have.
+ */
+public final class SkylarkModuleDoc extends SkylarkDoc {
+ private final SkylarkModule module;
+ private final Class<?> classObject;
+ private final Map<String, SkylarkBuiltinMethodDoc> builtinMethodMap;
+ private ArrayList<SkylarkJavaMethodDoc> javaMethods;
+ private TreeMap<String, SkylarkMethodDoc> methodMap;
+ private String title;
+
+ public SkylarkModuleDoc(SkylarkModule module, Class<?> classObject) {
+ this.module = Preconditions.checkNotNull(
+ module, "Class has to be annotated with SkylarkModule: %s", classObject);
+ this.classObject = classObject;
+ this.builtinMethodMap = new TreeMap<>();
+ this.methodMap = new TreeMap<>();
+ this.javaMethods = new ArrayList<>();
+ this.title = module.name();
+ }
+
+ @Override
+ public String getName() {
+ return module.name();
+ }
+
+ @Override
+ public String getDocumentation() {
+ return module.doc();
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
+ public SkylarkModule getAnnotation() {
+ return module;
+ }
+
+ public Class<?> getClassObject() {
+ return classObject;
+ }
+
+ public void addMethod(SkylarkBuiltinMethodDoc method) {
+ methodMap.put(method.getName(), method);
+ builtinMethodMap.put(method.getName(), method);
+ }
+
+ public void addMethod(SkylarkJavaMethodDoc method) {
+ methodMap.put(method.getName() + "$" + method.getMethod().getParameterTypes().length, method);
+ javaMethods.add(method);
+ }
+
+ public boolean javaMethodsNotCollected() {
+ return javaMethods.isEmpty();
+ }
+
+ public Map<String, SkylarkBuiltinMethodDoc> getBuiltinMethods() {
+ return builtinMethodMap;
+ }
+
+ public List<SkylarkJavaMethodDoc> getJavaMethods() {
+ return javaMethods;
+ }
+
+ public Collection<SkylarkMethodDoc> getMethods() {
+ return methodMap.values();
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/docgen/skylark/SkylarkParamDoc.java b/src/main/java/com/google/devtools/build/docgen/skylark/SkylarkParamDoc.java
new file mode 100644
index 0000000000..d733e7de65
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/docgen/skylark/SkylarkParamDoc.java
@@ -0,0 +1,61 @@
+// 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.docgen.skylark;
+
+import com.google.devtools.build.lib.syntax.SkylarkSignature.Param;
+
+/**
+ * A class containing the documentation for a Skylark method parameter.
+ */
+public final class SkylarkParamDoc extends SkylarkDoc {
+ private SkylarkMethodDoc method;
+ private Param param;
+
+ public SkylarkParamDoc(SkylarkMethodDoc method, Param param) {
+ this.method = method;
+ this.param = param;
+ }
+
+ /**
+ * Returns the string representing the type of this parameter with the link to the
+ * documentation for the type if available.
+ *
+ * <p>If the parameter type is Object, then returns the empty string. If the parameter
+ * type is not a generic, then this method returns a string representing the type name
+ * with a link to the documentation for the type if available. If the parameter type
+ * is a generic, then this method returns a string "CONTAINER of TYPE".
+ */
+ public String getType() {
+ if (param.type().equals(Object.class)) {
+ return "";
+ }
+ if (param.generic1().equals(Object.class)) {
+ return getTypeAnchor(param.type());
+ } else {
+ return getTypeAnchor(param.type(), param.generic1());
+ }
+ }
+
+ public SkylarkMethodDoc getMethod() {
+ return method;
+ }
+
+ public String getName() {
+ return param.name();
+ }
+
+ public String getDocumentation() {
+ return param.doc();
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/docgen/templates/be-header.vm b/src/main/java/com/google/devtools/build/docgen/templates/be-header.vm
index 8e841a626d..3eba02b93e 100644
--- a/src/main/java/com/google/devtools/build/docgen/templates/be-header.vm
+++ b/src/main/java/com/google/devtools/build/docgen/templates/be-header.vm
@@ -20,7 +20,7 @@ ${LEFT_PANEL}
<h3>Concepts and terminology</h3>
<table class="layout"><tr><td>
- <ul class="toc">
+ <ul class="be-toc">
<li><a href="#common-definitions">Common definitions</a>:
<ul>
<li><a href="#sh-tokenization">Bourne shell tokenization</a></li>
@@ -34,9 +34,9 @@ ${LEFT_PANEL}
</li>
</ul>
</td><td>
- <ul class="toc">
+ <ul class="be-toc">
<li><a href="#make_variables">"Make" variables</a>
- <ul class="toc">
+ <ul class="be-toc">
<li><a href="#make-var-substitution">"Make" variable substitution</a></li>
<li><a href="#predefined_variables">Predefined variables</a></li>
@@ -44,7 +44,7 @@ ${LEFT_PANEL}
<li><a href="#predefined-python-variables">Predefined Python Variables</a></li>
</ul>
</td><td>
- <ul class="toc">
+ <ul class="be-toc">
<li><a href="#load">load</a></li>
<li><a href="#package">package</a></li>
diff --git a/src/main/java/com/google/devtools/build/docgen/templates/skylark-body.html b/src/main/java/com/google/devtools/build/docgen/templates/skylark-body.html
deleted file mode 100644
index 5becb1a7cd..0000000000
--- a/src/main/java/com/google/devtools/build/docgen/templates/skylark-body.html
+++ /dev/null
@@ -1,58 +0,0 @@
-<html>
-<head>
- <title>Skylark documentation</title>
-
- <style type="text/css" id="internalStyle">
- h1 { margin-bottom: 5px; }
- .toc { margin: 0px; }
- ul li { margin-bottom: 1em; }
- ul.toc li { margin-bottom: 0px; }
- em.harmful { color: red; }
-
- .deprecated { text-decoration: line-through; }
- .discouraged { text-decoration: line-through; }
-
- #rules { width: 980px; border-collapse: collapse; }
- #rules td { border-top: 1px solid gray; padding: 4px; vertical-align: top; }
- #rules th { text-align: left; padding: 4px; }
-
- table.layout { width: 980px; }
- table.layout td { vertical-align: top; }
-
- #maintainer { text-align: right; }
-
- dt {
- font-weight: bold;
- margin-top: 0.5em;
- margin-bottom: 0.5em;
- }
- dd dt {
- font-weight: normal;
- text-decoration: underline;
- color: gray;
- }
- a.anchor {
- color:inherit;
- text-decoration: none;
- }
- </style>
-
- <style type="text/css">
- .rule-signature {
- color: #006000;
- font-family: monospace;
- }
- </style>
-</head>
-
-<body>
-<h1>Skylark documentation</h1>
-
-<h2>Built-in objects and functions in the Skylark Environment</h2>
-
-
-${SECTION_BUILTIN}
-
-</body>
-</html>
-
diff --git a/src/main/java/com/google/devtools/build/docgen/templates/skylark-library.vm b/src/main/java/com/google/devtools/build/docgen/templates/skylark-library.vm
new file mode 100644
index 0000000000..0cd39e4969
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/docgen/templates/skylark-library.vm
@@ -0,0 +1,58 @@
+<h1 id="modules.${module.name}">${module.title}</h1>
+
+${module.documentation}
+
+#if (!$module.methods.isEmpty())
+<div class="toc">
+ <h1>Methods</h1>
+ <ul>
+ #foreach ($method in $module.methods)
+ #if ($method.documented())
+ <li><a href="#${method.name}">${method.name}</a></li>
+ #end
+ #end
+ </ul>
+</div>
+#end
+#foreach ($method in $module.methods)
+ #if ($method.documented())
+ <h2 id="${method.name}">${method.name}</h2>
+ #if (!$method.signature.isEmpty())
+ <p><pre>${method.signature}</pre></p>
+ #end
+
+ ${method.documentation}
+
+ #if (!$method.params.isEmpty())
+ <h3>Parameters</h3>
+ <table class="table table-bordered table-condensed table-params">
+ <colgroup>
+ <col class="col-param">
+ <col class="param-description">
+ </colgroup>
+ <thead>
+ <tr>
+ <th>Parameter</th>
+ <th>Description</th>
+ </tr>
+ </thead>
+ <tbody>
+ #foreach ($param in $method.params)
+ <tr>
+ <td id="${param.method.name}.${param.name}">
+ <code>${param.name}</code>
+ </td>
+ <td>
+ #if (!$param.type.isEmpty())
+ <p><code>${param.type}</code></p>
+ #end
+ <p>${param.documentation}</p>
+ </td>
+ </tr>
+ #end
+ </tbody>
+ </table>
+ #end
+ ${method.returnTypeExtraMessage}
+ #end
+#end
diff --git a/src/main/java/com/google/devtools/build/docgen/templates/skylark-nav.vm b/src/main/java/com/google/devtools/build/docgen/templates/skylark-nav.vm
new file mode 100644
index 0000000000..54194c0c24
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/docgen/templates/skylark-nav.vm
@@ -0,0 +1,4 @@
+#foreach ($module in $modules)
+
+<li><a href="/docs/skylark/lib/${module.name}.html">${module.title}</a></li>
+#end
diff --git a/src/main/java/com/google/devtools/build/lib/actions/Artifact.java b/src/main/java/com/google/devtools/build/lib/actions/Artifact.java
index 1166cffd8e..e620ef63c6 100644
--- a/src/main/java/com/google/devtools/build/lib/actions/Artifact.java
+++ b/src/main/java/com/google/devtools/build/lib/actions/Artifact.java
@@ -367,7 +367,7 @@ public class Artifact implements FileType.HasFilename, ActionInput {
@SkylarkCallable(name = "path", structField = true,
doc = "The execution path of this file, relative to the execution directory. It consists of "
+ "two parts, an optional first part called the <i>root</i> (see also the <a "
- + "href=\"#modules.root\">root</a> module), and the second part which is the "
+ + "href=\"root.html\">root</a> module), and the second part which is the "
+ "<code>short_path</code>. The root may be empty, which it usually is for non-generated "
+ "files. For generated files it usually contains a configuration-specific path fragment that"
+ " encodes things like the target CPU architecture that was used while building said file.")
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/TransitiveInfoCollection.java b/src/main/java/com/google/devtools/build/lib/analysis/TransitiveInfoCollection.java
index 2ba49d79d9..fcc9c641a2 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/TransitiveInfoCollection.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/TransitiveInfoCollection.java
@@ -86,10 +86,10 @@ import javax.annotation.Nullable;
"A BUILD target. It is essentially a <code>struct</code> with the following fields:"
+ "<ul>"
+ "<li><h3 id=\"modules.Target.label\">label</h3><code><a class=\"anchor\" "
- + "href=\"#modules.Label\">Label</a> Target.label</code><br>The identifier of the target.</li>"
+ + "href=\"Label.html\">Label</a> Target.label</code><br>The identifier of the target.</li>"
+ "<li><h3 id=\"modules.Target.files\">files</h3><code><a class=\"anchor\" "
- + "href=\"#modules.set\">set</a> Target.files </code><br>The (transitive) set of <a "
- + "class=\"anchor\" href=\"#modules.File\">File</a>s produced by this target.</li>"
+ + "href=\"set.html\">set</a> Target.files </code><br>The (transitive) set of <a "
+ + "class=\"anchor\" href=\"File.html\">File</a>s produced by this target.</li>"
+ "<li><h3 id=\"modules.Target.extraproviders\">Extra providers</h3>For rule targets all "
+ "additional providers provided by this target are accessible as <code>struct</code> fields. "
+ "These extra providers are defined in the <code>struct</code> returned by the rule "
diff --git a/src/main/java/com/google/devtools/build/lib/packages/Attribute.java b/src/main/java/com/google/devtools/build/lib/packages/Attribute.java
index 38bab82545..4d31424e46 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/Attribute.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/Attribute.java
@@ -90,8 +90,8 @@ public final class Attribute implements Comparable<Attribute> {
*/
@SkylarkModule(name = "ConfigurationTransition", doc =
"Declares how the configuration should change when following a dependency. "
- + "It can be either <a href=\"#modules._top_level.DATA_CFG\">DATA_CFG</a> or "
- + "<a href=\"#modules._top_level.HOST_CFG\">HOST_CFG</a>.")
+ + "It can be either <a href=\"globals.html#DATA_CFG\">DATA_CFG</a> or "
+ + "<a href=\"globals.html#HOST_CFG\">HOST_CFG</a>.")
public enum ConfigurationTransition implements Transition {
/** No transition, i.e., the same configuration as the current. */
NONE,
diff --git a/src/main/java/com/google/devtools/build/lib/rules/SkylarkAttr.java b/src/main/java/com/google/devtools/build/lib/rules/SkylarkAttr.java
index fc85bb1874..9c3fedf7e1 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/SkylarkAttr.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/SkylarkAttr.java
@@ -44,10 +44,9 @@ import java.util.Map;
/**
* A helper class to provide Attr module in Skylark.
*
- * It exposes functions (e.g. 'attr.string', 'attr.label_list', etc.) to Skylark
+ * <p>It exposes functions (e.g. 'attr.string', 'attr.label_list', etc.) to Skylark
* users. The functions are executed through reflection. As everywhere in Skylark,
* arguments are type-checked with the signature and cannot be null.
- *
*/
@SkylarkModule(
name = "attr",
@@ -55,7 +54,7 @@ import java.util.Map;
onlyLoadingPhase = true,
doc =
"Module for creating new attributes. "
- + "They are only for use with the <a href=\"#modules._top_level.rule\">rule</a> function."
+ + "They are only for use with the <a href=\"globals.html#rule\">rule</a> function."
)
public final class SkylarkAttr {
@@ -463,7 +462,7 @@ public final class SkylarkAttr {
name = "label_list",
doc =
"Creates an attribute of type list of labels. "
- + "See <a href=\"#modules.attr.label\">label</a> for more information.",
+ + "See <a href=\"attr.html#label\">label</a> for more information.",
objectType = SkylarkAttr.class,
returnType = Attribute.Builder.class,
optionalNamedOnly = {
@@ -623,7 +622,7 @@ public final class SkylarkAttr {
name = "output_list",
doc =
"Creates an attribute of type list of outputs. Its default value is <code>[]</code>. "
- + "See <a href=\"#modules.attr.output\">output</a> above for more information.",
+ + "See <a href=\"attr.html#output\">output</a> above for more information.",
objectType = SkylarkAttr.class,
returnType = Attribute.Builder.class,
optionalNamedOnly = {
diff --git a/src/main/java/com/google/devtools/build/lib/rules/SkylarkFileType.java b/src/main/java/com/google/devtools/build/lib/rules/SkylarkFileType.java
index 0571cb410d..e47b47e76c 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/SkylarkFileType.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/SkylarkFileType.java
@@ -47,9 +47,9 @@ public class SkylarkFileType {
@SkylarkCallable(doc =
"Returns a list created from the elements of the parameter containing all the "
- + "<a href=\"#modules.File\"><code>File</code></a>s that match the FileType. The parameter "
- + "must be a <a href=\"#modules.set\"><code>set</code></a> or a "
- + "<a href=\"#modules.list\"><code>list</code></a>.")
+ + "<a href=\"File.html\"><code>File</code></a>s that match the FileType. The parameter "
+ + "must be a <a href=\"set.html\"><code>set</code></a> or a "
+ + "<a href=\"list.html\"><code>list</code></a>.")
public List<Artifact> filter(Iterable<Artifact> files) {
return ImmutableList.copyOf(FileType.filter(files, fileType));
}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleClassFunctions.java b/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleClassFunctions.java
index e128d7eec7..2f129501cb 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleClassFunctions.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleClassFunctions.java
@@ -191,7 +191,7 @@ public class SkylarkRuleClassFunctions {
mandatoryPositionals = {
@Param(name = "implementation", type = BaseFunction.class,
doc = "the function implementing this rule, must have exactly one parameter: "
- + "<a href=\"#modules.ctx\">ctx</a>. The function is called during the analysis phase "
+ + "<a href=\"ctx.html\">ctx</a>. The function is called during the analysis phase "
+ "for each instance of the rule. It can access the attributes provided by the user. "
+ "It must create actions to generate all the declared outputs.")
},
@@ -202,7 +202,7 @@ public class SkylarkRuleClassFunctions {
+ "and there must be an action that generates <code>ctx.outputs.executable</code>."),
@Param(name = "attrs", type = Map.class, noneable = true, defaultValue = "None", doc =
"dictionary to declare all the attributes of the rule. It maps from an attribute name "
- + "to an attribute object (see <a href=\"#modules.attr\">attr</a> module). "
+ + "to an attribute object (see <a href=\"attr.html\">attr</a> module). "
+ "Attributes starting with <code>_</code> are private, and can be used to add "
+ "an implicit dependency on a label. The attribute <code>name</code> is implicitly "
+ "added and must not be specified. Attributes <code>visibility</code>, "
diff --git a/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleContext.java b/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleContext.java
index 385b04d8ca..8221066a3a 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleContext.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleContext.java
@@ -329,14 +329,14 @@ public final class SkylarkRuleContext {
}
@SkylarkCallable(name = "configuration", structField = true,
- doc = "Returns the default configuration. See the <a href=\"#modules.configuration\">"
+ doc = "Returns the default configuration. See the <a href=\"configuration.html\">"
+ "configuration</a> type for more details.")
public BuildConfiguration getConfiguration() {
return ruleContext.getConfiguration();
}
@SkylarkCallable(name = "host_configuration", structField = true,
- doc = "Returns the host configuration. See the <a href=\"#modules.configuration\">"
+ doc = "Returns the host configuration. See the <a href=\"configuration.html\">"
+ "configuration</a> type for more details.")
public BuildConfiguration getHostConfiguration() {
return ruleContext.getHostConfiguration();
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/ClassObject.java b/src/main/java/com/google/devtools/build/lib/syntax/ClassObject.java
index 9ed20cc68a..c38ea774fd 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/ClassObject.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/ClassObject.java
@@ -57,7 +57,7 @@ public interface ClassObject {
@Immutable
@SkylarkModule(name = "struct",
doc = "A special language element to support structs (i.e. simple value objects). "
- + "See the global <a href=\"#modules._top_level.struct\">struct</a> function "
+ + "See the global <a href=\"globals.html#struct\">struct</a> function "
+ "for more details.")
public class SkylarkClassObject implements ClassObject {
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/MethodLibrary.java b/src/main/java/com/google/devtools/build/lib/syntax/MethodLibrary.java
index d8b625e328..2e0d38c4f5 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/MethodLibrary.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/MethodLibrary.java
@@ -952,7 +952,7 @@ public class MethodLibrary {
};
@SkylarkSignature(name = "set", returnType = SkylarkNestedSet.class,
- doc = "Creates a <a href=\"#modules.set\">set</a> from the <code>items</code>."
+ doc = "Creates a <a href=\"set.html\">set</a> from the <code>items</code>."
+ " The set supports nesting other sets of the same element"
+ " type in it. A desired iteration order can also be specified.<br>"
+ " Examples:<br><pre class=\"language-python\">set([\"a\", \"b\"])\n"
@@ -965,7 +965,7 @@ public class MethodLibrary {
doc = "The ordering strategy for the set if it's nested, "
+ "possible values are: <code>stable</code> (default), <code>compile</code>, "
+ "<code>link</code> or <code>naive_link</code>. An explanation of the "
- + "values can be found <a href=\"#modules.set\">here</a>.")},
+ + "values can be found <a href=\"set.html\">here</a>.")},
useLocation = true)
private static final BuiltinFunction set = new BuiltinFunction("set") {
public SkylarkNestedSet invoke(Object items, String order,
@@ -1022,7 +1022,7 @@ public class MethodLibrary {
@SkylarkSignature(name = "union", objectType = SkylarkNestedSet.class,
returnType = SkylarkNestedSet.class,
- doc = "Creates a new <a href=\"#modules.set\">set</a> that contains both "
+ doc = "Creates a new <a href=\"set.html\">set</a> that contains both "
+ "the input set as well as all additional elements.",
mandatoryPositionals = {
@Param(name = "input", type = SkylarkNestedSet.class, doc = "The input set"),
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/SkylarkNestedSet.java b/src/main/java/com/google/devtools/build/lib/syntax/SkylarkNestedSet.java
index e4eeba3333..004d4c4143 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/SkylarkNestedSet.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/SkylarkNestedSet.java
@@ -35,7 +35,7 @@ import javax.annotation.Nullable;
*/
@SkylarkModule(name = "set",
doc = "A language built-in type that supports (nested) sets. "
- + "Sets can be created using the <a href=\"#modules._top_level.set\">set</a> function, and "
+ + "Sets can be created using the <a href=\"globals.html#set\">set</a> function, and "
+ "they support the <code>+</code> operator to extend the set with more elements or "
+ "to nest other sets inside of it. Examples:<br>"
+ "<pre class=language-python>s = set([1, 2])\n"