All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.javascript.jscomp.TypedScope Maven / Gradle / Ivy

Go to download

Closure Compiler is a JavaScript optimizing compiler. It parses your JavaScript, analyzes it, removes dead code and rewrites and minimizes what's left. It also checks syntax, variable references, and types, and warns about common JavaScript pitfalls. It is used in many of Google's JavaScript apps, including Gmail, Google Web Search, Google Maps, and Google Docs.

There is a newer version: v20240317
Show newest version
/*
 * Copyright 2015 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 static com.google.common.base.Preconditions.checkState;

import com.google.common.collect.Iterables;
import com.google.javascript.rhino.JSDocInfo;
import com.google.javascript.rhino.Node;
import com.google.javascript.rhino.TypeIEnv;
import com.google.javascript.rhino.jstype.JSType;
import com.google.javascript.rhino.jstype.ObjectType;
import com.google.javascript.rhino.jstype.StaticTypedScope;
import com.google.javascript.rhino.jstype.StaticTypedSlot;

/**
 * TypedScope contains information about variables and their types.
 * Scopes can be nested, a scope points back to its parent scope.
 * 

* TypedScope is also used as a lattice element for flow-sensitive type inference. * As a lattice element, a scope is viewed as a map from names to types. A name * not in the map is considered to have the bottom type. The join of two maps m1 * and m2 is the map of the union of names with {@link JSType#getLeastSupertype} * to meet the m1 type and m2 type. * * @see NodeTraversal * @see DataFlowAnalysis * * Several methods in this class, such as {@code isBlockScope} throw an exception when called. * The reason for this is that we want to shadow methods from the parent class, to avoid calling * them accidentally. */ public class TypedScope extends AbstractScope implements StaticTypedScope, TypeIEnv { private final TypedScope parent; private final int depth; /** Whether this is a bottom scope for the purposes of type inference. */ private final boolean isBottom; // Scope.java contains an arguments field. // We haven't added it here because it's unused by the passes that need typed scopes. TypedScope(TypedScope parent, Node rootNode) { super(rootNode); checkChildScope(parent); this.parent = parent; this.depth = parent.depth + 1; this.isBottom = false; } /** * Creates a empty Scope (bottom of the lattice). * @param rootNode Typically a FUNCTION node or the global BLOCK node. * @param isBottom Whether this is the bottom of a lattice. Otherwise, * it must be a global scope. */ private TypedScope(Node rootNode, boolean isBottom) { super(rootNode); checkRootScope(); this.parent = null; this.depth = 0; this.isBottom = isBottom; } static TypedScope createGlobalScope(Node rootNode) { return new TypedScope(rootNode, false); } static TypedScope createLatticeBottom(Node rootNode) { return new TypedScope(rootNode, true); } @Override public TypedScope typed() { return this; } /** Whether this is the bottom of the lattice. */ boolean isBottom() { return isBottom; } @Override public int getDepth() { return depth; } @Override public TypedScope getParent() { return parent; } /** * Gets the type of {@code this} in the current scope. */ @Override public JSType getTypeOfThis() { if (isGlobal()) { return ObjectType.cast(getRootNode().getJSType()); } else if (!getRootNode().isFunction()) { return getClosestContainerScope().getTypeOfThis(); } checkState(getRootNode().isFunction()); JSType nodeType = getRootNode().getJSType(); if (nodeType != null && nodeType.isFunctionType()) { return nodeType.toMaybeFunctionType().getTypeOfThis(); } else { // Executed when the current scope has not been typechecked. return null; } } TypedVar declare(String name, Node nameNode, JSType type, CompilerInput input) { return declare(name, nameNode, type, input, true); } TypedVar declare(String name, Node nameNode, JSType type, CompilerInput input, boolean inferred) { checkState(name != null && !name.isEmpty()); TypedVar var = new TypedVar(inferred, name, nameNode, type, this, getVarCount(), input); declareInternal(name, var); return var; } @Override TypedVar makeImplicitVar(ImplicitVar var) { if (this.isGlobal()) { // TODO(sdh): This is incorrect for 'global this', but since that's currently not handled // by this code, it's okay to bail out now until we find the root cause. See b/74980936. return null; } return new TypedVar(false, var.name, null, getImplicitVarType(var), this, -1, null); } private JSType getImplicitVarType(ImplicitVar var) { if (var == ImplicitVar.ARGUMENTS) { // Look for an extern named "arguments" and use its type if available. // TODO(sdh): consider looking for "Arguments" ctor rather than "arguments" var: this could // allow deleting the variable, which doesn't really belong in externs in the first place. TypedVar globalArgs = getGlobalScope().getVar(Var.ARGUMENTS); return globalArgs != null && globalArgs.isExtern() ? globalArgs.getType() : null; } // TODO(sdh): get the superclass for super? return getTypeOfThis(); } public Iterable getDeclarativelyUnboundVarsWithoutTypes() { return Iterables.filter( getVarIterable(), var -> // declaratively unbound vars without types var.getParentNode() != null && var.getType() == null && var.getParentNode().isVar() && !var.isExtern()); } static interface TypeResolver { void resolveTypes(); } private TypeResolver typeResolver; /** Resolve all type references. Only used on typed scopes. */ void resolveTypes() { if (typeResolver != null) { typeResolver.resolveTypes(); typeResolver = null; } } void setTypeResolver(TypeResolver resolver) { this.typeResolver = resolver; } @Override public JSType getNamespaceOrTypedefType(String typeName) { StaticTypedSlot slot = getSlot(typeName); return slot == null ? null : slot.getType(); } @Override public JSDocInfo getJsdocOfTypeDeclaration(String typeName) { StaticTypedSlot slot = getSlot(typeName); return slot == null ? null : slot.getJSDocInfo(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy