Package com.google.javascript.jscomp

Source Code of com.google.javascript.jscomp.GatherExternProperties$ExtractRecordTypePropertyNames

/*
* Copyright 2014 The Closure Compiler Authors.
*
* 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.javascript.jscomp;

import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback;
import com.google.javascript.rhino.JSDocInfo;
import com.google.javascript.rhino.Node;
import com.google.javascript.rhino.Token;
import com.google.javascript.rhino.jstype.EnumElementType;
import com.google.javascript.rhino.jstype.FunctionType;
import com.google.javascript.rhino.jstype.JSType;
import com.google.javascript.rhino.jstype.NamedType;
import com.google.javascript.rhino.jstype.NoType;
import com.google.javascript.rhino.jstype.ObjectType;
import com.google.javascript.rhino.jstype.ProxyObjectType;
import com.google.javascript.rhino.jstype.TemplateType;
import com.google.javascript.rhino.jstype.TemplatizedType;
import com.google.javascript.rhino.jstype.UnionType;
import com.google.javascript.rhino.jstype.Visitor;
import java.util.Set;

/**
* Gathers property names defined in externs.
*/
class GatherExternProperties extends AbstractPostOrderCallback
    implements CompilerPass {
  private final Set<String> externProperties = Sets.newHashSet();
  private final AbstractCompiler compiler;
  private final boolean gatherPropertiesFromTypes;
  private final ExtractRecordTypePropertyNames typeVisitor =
      new ExtractRecordTypePropertyNames();

  public GatherExternProperties(AbstractCompiler compiler,
      boolean gatherPropertiesFromTypes) {
    this.compiler = compiler;
    this.gatherPropertiesFromTypes = gatherPropertiesFromTypes;
  }

  @Override
  public void process(Node externs, Node root) {
    NodeTraversal.traverse(compiler, externs, this);
    compiler.setExternProperties(ImmutableSet.copyOf(externProperties));
  }

  @Override
  public void visit(NodeTraversal t, Node n, Node parent) {
    switch (n.getType()) {
      case Token.GETPROP:
        // Gathers "name" from (someObject.name).
        Node dest = n.getFirstChild().getNext();
        if (dest.isString()) {
          externProperties.add(dest.getString());
        }
        break;
      case Token.OBJECTLIT:
        // Gathers "name" and "address" from ({name: null, address: null}).
        for (Node child = n.getFirstChild();
             child != null;
             child = child.getNext()) {
          externProperties.add(child.getString());
        }
        break;
    }

    if (gatherPropertiesFromTypes) {
      // Gather field names from the type of the node (if any).
      JSType type = n.getJSType();
      if (type != null) {
        typeVisitor.visitOnce(type);
      }

      // Gather field names from the @typedef declaration.
      // Typedefs are declared on qualified name nodes.
      if (n.isQualifiedName()) {
        // Get the JSDoc for the current node and check if it contains a
        // typedef.
        JSDocInfo jsDoc = NodeUtil.getBestJSDocInfo(n);
        if (jsDoc != null && jsDoc.hasTypedefType()) {
          // Get the corresponding type by looking at the type registry.
          JSType typedefType =
              compiler.getTypeRegistry().getType(n.getQualifiedName());
          if (typedefType != null) {
            typeVisitor.visitOnce(typedefType);
          }
        }
      }
    }
  }

  private class ExtractRecordTypePropertyNames
      implements Visitor<Set<String>> {
    private final Set<JSType> seenTypes = Sets.newIdentityHashSet();

    public void visitOnce(JSType type) {
      // Handle recursive types by only ever visiting the same type once.
      if (!seenTypes.contains(type)) {
        seenTypes.add(type);
        type.visit(this);
      }
    }

    // Interesting cases first, no-ops later.

    public Set<String> caseEnumElementType(EnumElementType type) {
      // Descend into the enum's element type.
      // @enum {T}
      visitOnce(type.getPrimitiveType());

      return externProperties;
    }

    public Set<String> caseFunctionType(FunctionType type) {
      // Visit parameter types.
      // function(T1, T2), as well as @param {T}
      for (Node param : type.getParameters()) {
        visitOnce(param.getJSType());
      }

      // Visit the return type.
      // function(): T, as well as @return {T}
      visitOnce(type.getReturnType());

      // @interface
      if (type.isInterface()) {
        // Visit the extended interfaces.
        // @extends {T}
        for (JSType extendedType : type.getExtendedInterfaces()) {
          visitOnce(extendedType);
        }
      }

      // @constructor
      if (type.isConstructor()) {
        // Visit the implemented interfaces.
        // @implements {T}
        for (JSType implementedType : type.getOwnImplementedInterfaces()) {
          visitOnce(implementedType);
        }

        // Visit the parent class (if any).
        // @extends {T}
        JSType superClass = type.getPrototype().getImplicitPrototype();
        if (superClass != null) {
          visitOnce(superClass);
        }
      }
      return externProperties;
    }

    public Set<String> caseObjectType(ObjectType type) {
      // Record types.
      // {a: T1, b: T2}.
      if (type.isRecordType()) {
        for (String propertyName : type.getOwnPropertyNames()) {
          // After type inference it is possible that some nodes in externs
          // can have types which are defined in non-extern code. To avoid
          // bleeding property names of such types into externs we check that
          // the node for each property was defined in externs.
          if (type.getPropertyNode(propertyName).isFromExterns()) {
            externProperties.add(propertyName);
            visitOnce(type.getPropertyType(propertyName));
          }
        }
      }

      return externProperties;
    }

    public Set<String> caseNamedType(NamedType type) {
      // Treat as all other proxy objects.
      return caseProxyObjectType(type);
    }

    public Set<String> caseProxyObjectType(ProxyObjectType type) {
      // Visit the proxied type.
      // @typedef {T}
      type.visitReferenceType(this);

      return externProperties;
    }

    public Set<String> caseUnionType(UnionType type) {
      // Visit the alternatives.
      // T1|T2|T3
      for (JSType alternateType : type.getAlternates()) {
        visitOnce(alternateType);
      }
      return externProperties;
    }

    public Set<String> caseTemplatizedType(TemplatizedType type) {
      // Visit the type arguments.
      // SomeType.<T1, T2>
      for (JSType templateType : type.getTemplateTypes()) {
        visitOnce(templateType);
      }
      return externProperties;
    }

    public Set<String> caseNoType(NoType type) {
      return externProperties;
    }

    public Set<String> caseAllType() {
      return externProperties;
    }

    public Set<String> caseBooleanType() {
      return externProperties;
    }

    public Set<String> caseNoObjectType() {
      return externProperties;
    }

    public Set<String> caseUnknownType() {
      return externProperties;
    }

    public Set<String> caseNullType() {
      return externProperties;
    }

    public Set<String> caseNumberType() {
      return externProperties;
    }

    public Set<String> caseStringType() {
      return externProperties;
    }

    public Set<String> caseVoidType() {
      return externProperties;
    }

    public Set<String> caseTemplateType(TemplateType templateType) {
      return externProperties;
    }
  }
}
TOP

Related Classes of com.google.javascript.jscomp.GatherExternProperties$ExtractRecordTypePropertyNames

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.