use of com.google.javascript.jscomp.TypeMatchingStrategy.MatchResult in project closure-compiler by google.
the class TemplateAstMatcher method matchesNode.
/**
* Returns whether two nodes are equivalent, taking into account the template parameters that were
* provided to this matcher. If the template comparison node is a parameter node, then only the
* types of the node must match. If the template node is a string literal, only match string
* literals. Otherwise, the node must be equal and the child nodes must be equivalent according to
* the same function. This differs from the built in Node equivalence function with the special
* comparison.
*/
private boolean matchesNode(Node template, Node ast) {
if (isTemplateParameterNode(template)) {
int paramIndex = (int) (template.getDouble());
Node previousMatch = paramNodeMatches.get(paramIndex);
if (previousMatch != null) {
// subsequent usages of the same named node are equivalent.
return ast.isEquivalentTo(previousMatch);
}
// Only the types need to match for the template parameters, which allows
// the template function to express arbitrary expressions.
JSType templateType = template.getJSType();
checkNotNull(templateType, "null template parameter type.");
// we should treat them as "unknown" and perform loose matches.
if (isUnresolvedType(templateType)) {
return false;
}
MatchResult matchResult = typeMatchingStrategy.match(templateType, ast.getJSType());
isLooseMatch = matchResult.isLooseMatch();
boolean isMatch = matchResult.isMatch();
if (isMatch && previousMatch == null) {
paramNodeMatches.set(paramIndex, ast);
}
return isMatch;
} else if (isTemplateLocalNameNode(template)) {
// If this template name node was already matched against, then make sure
// all subsequent usages of the same template name node are equivalent in
// the matched code.
// For example, this code will handle the case:
// function template() {
// var a = 'str';
// fn(a);
// }
//
// will only match test code:
// var b = 'str';
// fn(b);
//
// but it will not match:
// var b = 'str';
// fn('str');
int paramIndex = (int) (template.getDouble());
boolean previouslyMatched = this.localVarMatches.get(paramIndex) != null;
if (previouslyMatched) {
// subsequent usages of the same named node are equivalent.
return ast.getString().equals(this.localVarMatches.get(paramIndex));
} else {
String originalName = ast.getOriginalName();
String name = (originalName != null) ? originalName : ast.getString();
this.localVarMatches.set(paramIndex, name);
}
} else if (isTemplateParameterStringLiteralNode(template)) {
int paramIndex = (int) (template.getDouble());
Node previousMatch = paramNodeMatches.get(paramIndex);
if (previousMatch != null) {
return ast.isEquivalentTo(previousMatch);
}
if (NodeUtil.isSomeCompileTimeConstStringValue(ast)) {
paramNodeMatches.set(paramIndex, ast);
return true;
}
return false;
}
// Template and AST shape has already been checked, but continue look for
// other template variables (parameters and locals) that must be checked.
Node templateChild = template.getFirstChild();
Node astChild = ast.getFirstChild();
while (templateChild != null) {
if (!matchesNode(templateChild, astChild)) {
return false;
}
templateChild = templateChild.getNext();
astChild = astChild.getNext();
}
return true;
}
use of com.google.javascript.jscomp.TypeMatchingStrategy.MatchResult in project closure-compiler by google.
the class TypeMatchingStrategyTest method assertMatch.
private static void assertMatch(TypeMatchingStrategy typeMatchingStrategy, String templateType, String type, boolean isMatch, boolean isLooseMatch) {
// It's important that the test uses the same compiler to compile the template type and the
// type to be matched. Otherwise, equal types won't be considered equal.
Compiler compiler = new Compiler();
compiler.disableThreads();
CompilerOptions options = new CompilerOptions();
options.setCheckTypes(true);
options.setChecksOnly(true);
compiler.compile(ImmutableList.of(SourceFile.fromCode("externs", EXTERNS)), ImmutableList.of(SourceFile.fromCode("test", String.format("/** @type {%s} */ var x; /** @type {%s} */ var y;", templateType, type))), options);
Node script = compiler.getRoot().getLastChild().getFirstChild();
Node xNode = script.getFirstChild();
Node yNode = script.getLastChild();
JSType templateJsType = xNode.getFirstChild().getJSType();
JSType jsType = yNode.getFirstChild().getJSType();
MatchResult matchResult = typeMatchingStrategy.match(templateJsType, jsType);
assertWithMessage(isMatch ? "'" + templateJsType + "' should match '" + jsType + "'" : "'" + templateType + "' should not match '" + type + "'").that(matchResult.isMatch()).isEqualTo(isMatch);
assertWithMessage(isLooseMatch ? "'" + templateType + "' should loosely match '" + type + "'" : "'" + templateType + "' should not loosely match '" + type + "'").that(matchResult.isLooseMatch()).isEqualTo(isLooseMatch);
}
Aggregations