diff options
Diffstat (limited to 'src')
26 files changed, 874 insertions, 656 deletions
diff --git a/src/main/java/BUILD b/src/main/java/BUILD index f1cc25377f..b51694e22d 100644 --- a/src/main/java/BUILD +++ b/src/main/java/BUILD @@ -525,7 +525,7 @@ filegroup( java_library( name = "docgen_javalib", srcs = glob( - ["com/google/devtools/build/docgen/*.java"], + ["com/google/devtools/build/docgen/**/*.java"], exclude = [ "com/google/devtools/build/docgen/BuildEncyclopediaGenerator.java", "com/google/devtools/build/docgen/SkylarkDocumentationGenerator.java", @@ -586,8 +586,10 @@ genrule( genrule( name = "gen_skylarklibrary", - outs = ["skylark-library.html"], - cmd = "$(location :skydoc_bin) $@", + outs = ["skylark-library.zip"], + cmd = "mkdir -p $(@D)/skylark-lib &&" + + "$(location :skydoc_bin) $(@D)/skylark-lib &&" + + "zip -qj $@ $(@D)/skylark-lib/*", tools = [":skydoc_bin"], ) 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()) ? "…" : 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()) ? "…" : 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" |