Preserve a subset of JSDoc annotations when removing JSTypes
These JSDoc annotations will be serialized & deserialized for the TypedAST project. More annotations will need to be added later on; these annotations are only the ones needed for passes in the main optimization loop.
@@ -18,13 +18,17 @@ package com.google.javascript.jscomp;
import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback;
import com.google.javascript.rhino.JSDocInfo;
+import com.google.javascript.rhino.JSDocInfoBuilder;
+import com.google.javascript.rhino.JSTypeExpression;
import com.google.javascript.rhino.Node;
+import com.google.javascript.rhino.Token;
+import javax.annotation.Nullable;
/**
- * Pass to remove from the AST types and type-based information from typechecking.
+ * Pass to remove from the AST types and type-based information and to delete all JSDoc fields not
+ * needed for optimizations.
*
- * <p>Eventually, we anticipate this pass to run at the beginning of optimizations, and leave a
- * representation of the types as needed for optimizations on the AST.
+ * <p>Eventually, we anticipate this pass to run at the beginning of optimizations.
*/
final class RemoveTypes implements CompilerPass {
private final AbstractCompiler compiler;
@@ -41,12 +45,51 @@ final class RemoveTypes implements CompilerPass {
n.setTypedefTypeProp(null);
n.setDeclaredTypeExpression(null);
JSDocInfo jsdoc = n.getJSDocInfo();
- if (jsdoc != null && jsdoc.getLicense() == null) {
- // Can license jsdocs also contain type declarations?
- // If so, they should be removed here.
- n.setJSDocInfo(null);
+ if (jsdoc != null) {
+ n.setJSDocInfo(convertJSDocInfo(jsdoc));
}
}
+
+ /**
+ * Returns a clone of the input JSDocInfo, modulo fields not needed for optimizations
+ *
+ * <p>This mimics the eventual serialization / deserialization of a subset of JSDoc fields and
+ * ensures optimizations can't accidentally depend on fields that we don't plan to serialize.
+ *
+ * @return a new JSDocInfo object or null if no serializable fields are found
+ */
+ @Nullable
+ private static JSDocInfo convertJSDocInfo(JSDocInfo jsdoc) {
+ JSDocInfoBuilder builder = new JSDocInfoBuilder(/* parseDocumentation= */ false);
+ if (jsdoc.getLicense() != null) {
+ builder.addLicense(jsdoc.getLicense());
+ }
+
+ if (jsdoc.isNoInline()) {
+ builder.recordNoInline();
+ }
+ if (jsdoc.isDefine()) {
+ builder.recordDefineType(createUnknown());
+ }
+
+ // Used by PureFunctionIdentifier
+ if (jsdoc.isNoSideEffects()) {
+ builder.recordNoSideEffects();
+ }
+ if (jsdoc.hasModifies()) {
+ builder.recordModifies(jsdoc.getModifies());
+ }
+ if (!jsdoc.getThrownTypes().isEmpty()) {
+ builder.recordThrowType(createUnknown());
+ }
+ return builder.build();
+ }
+
+ // Optimizations shouldn't care about the contents of JSTypeExpressions but some JSDoc APIs
+ // expect their presense, so just create a dummy '?' type.
+ private static JSTypeExpression createUnknown() {
+ return new JSTypeExpression(new Node(Token.QMARK), "<synthetic serialized type>");
+ }
}
@Override
