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

com.google.javascript.jscomp.TypeMismatch 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 2017 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.auto.value.AutoValue;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableCollection;
import com.google.common.collect.ImmutableList;
import com.google.javascript.rhino.IR;
import com.google.javascript.rhino.Node;
import com.google.javascript.rhino.jstype.FunctionType;
import com.google.javascript.rhino.jstype.JSType;
import com.google.javascript.rhino.jstype.ObjectType;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Iterator;

/**
 * Signals that the first type and the second type have been used interchangeably.
 *
 * 

Type-based optimizations should take this into account so that they don't wreck code with type * warnings. */ @AutoValue public abstract class TypeMismatch implements Serializable { /** The RHS type; the type of the assignment target. */ public abstract JSType getFound(); /** The LHS type; the type being assigned. */ public abstract JSType getRequired(); /** The location of the assignment. */ abstract Node getLocation(); private static TypeMismatch create(JSType found, JSType required, Node location) { return new AutoValue_TypeMismatch(found, required, location); } @VisibleForTesting public static TypeMismatch createForTesting(JSType found, JSType required) { return create(found, required, TEST_LOCATION); } private static final Node TEST_LOCATION = IR.empty(); /** Collects a set of related mismatches. */ static class Accumulator implements Serializable { private final ArrayList mismatches = new ArrayList<>(); private final ArrayList implicitInterfaceUses = new ArrayList<>(); void registerMismatch(Node location, JSType found, JSType required) { // Don't register a mismatch for differences in null or undefined or if the // code didn't downcast. found = removeNullUndefinedAndTemplates(found); required = removeNullUndefinedAndTemplates(required); if (found.isSubtypeOf(required) || required.isSubtypeOf(found)) { boolean strictMismatch = !found.isSubtypeWithoutStructuralTyping(required) && !required.isSubtypeWithoutStructuralTyping(found); if (strictMismatch && bothAreNotTemplateTypes(found, required)) { this.implicitInterfaceUses.add(TypeMismatch.create(found, required, location)); } return; } if (bothAreNotTemplateTypes(found, required)) { this.mismatches.add(TypeMismatch.create(found, required, location)); } if (found.isFunctionType() && required.isFunctionType()) { FunctionType fnTypeA = found.toMaybeFunctionType(); FunctionType fnTypeB = required.toMaybeFunctionType(); Iterator paramItA = fnTypeA.getParameters().iterator(); Iterator paramItB = fnTypeB.getParameters().iterator(); while (paramItA.hasNext() && paramItB.hasNext()) { this.registerIfMismatch( location, paramItA.next().getJSType(), paramItB.next().getJSType()); } this.registerIfMismatch(location, fnTypeA.getReturnType(), fnTypeB.getReturnType()); } } void recordImplicitUseOfNativeObject(Node location, JSType found, JSType required) { found = found.restrictByNotNullOrUndefined(); required = required.restrictByNotNullOrUndefined(); if (isInstanceOfObject(found) && !isInstanceOfObject(required) && !required.isUnknownType() && bothAreNotTemplateTypes(found, required)) { this.mismatches.add(TypeMismatch.create(found, required, location)); } } void recordImplicitInterfaceUses(Node location, JSType found, JSType required) { found = removeNullUndefinedAndTemplates(found); required = removeNullUndefinedAndTemplates(required); if (required.isUnknownType()) { return; } boolean strictMismatch = !found.isSubtypeWithoutStructuralTyping(required) && !required.isSubtypeWithoutStructuralTyping(found); boolean mismatch = !found.isSubtypeOf(required) && !required.isSubtypeOf(found); if ((strictMismatch || mismatch) && bothAreNotTemplateTypes(found, required)) { this.implicitInterfaceUses.add(TypeMismatch.create(found, required, location)); } } ImmutableCollection getMismatches() { return ImmutableList.copyOf(this.mismatches); } ImmutableCollection getImplicitInterfaceUses() { return ImmutableList.copyOf(this.implicitInterfaceUses); } private void registerIfMismatch(Node location, JSType found, JSType required) { if (found != null && required != null && !found.isSubtypeWithoutStructuralTyping(required)) { this.registerMismatch(location, found, required); } } /** * A type variable is considered unknown, so other types can be used as type variables, and vice * versa, without warning. Otherwise, to get good disambiguation, we would have to add casts all * over the code base. * *

TODO(dimvar): this can be made safe in the distant future where we have bounded generics * *and* we have switched all the unsafe uses of type variables in the code base to use bounded * generics. */ private static boolean bothAreNotTemplateTypes(JSType found, JSType required) { return !found.isTemplateType() && !required.isTemplateType(); } private static boolean isInstanceOfObject(JSType type) { // Some type whose class is Object ObjectType obj = type.toMaybeObjectType(); if (obj != null && obj.isNativeObjectType() && "Object".equals(obj.getReferenceName())) { return true; } return type.isRecordType() || type.isLiteralObject(); } private static JSType removeNullUndefinedAndTemplates(JSType t) { JSType result = t.restrictByNotNullOrUndefined(); ObjectType obj = result.toMaybeObjectType(); if (obj != null && obj.isTemplatizedType()) { // We don't care about the specific specalization involved in the mismatch because all // specializations share the same JS code. return obj.toMaybeTemplatizedType().getRawType(); } return result; } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy