/* * Copyright 2010-2015 JetBrains s.r.o. * * 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 org.jetbrains.kotlin.js.test.utils; import org.jetbrains.annotations.NotNull; import org.jetbrains.kotlin.js.backend.ast.*; import java.util.*; public class CallCounter extends RecursiveJsVisitor { private final List<JsNameRef> callsNameRefs = new ArrayList<>(); @NotNull private final Set<String> exceptFunctionNames; @NotNull private final Set<String> exceptScopes; private int excludedScopeOccurrenceCount; @NotNull public static CallCounter countCalls(@NotNull JsNode node) { return countCalls(node, Collections.emptySet()); } @NotNull public static CallCounter countCalls(@NotNull JsNode node, @NotNull Set<String> exceptFunctionNames) { CallCounter visitor = new CallCounter(new HashSet<>(exceptFunctionNames), Collections.emptySet()); node.accept(visitor); return visitor; } @NotNull public static CallCounter countCallsWithExcludedScopes(@NotNull JsNode node, @NotNull Set<String> exceptScopes) { CallCounter visitor = new CallCounter(Collections.emptySet(), new HashSet<>(exceptScopes)); node.accept(visitor); return visitor; } private CallCounter(@NotNull Set<String> exceptFunctionNames, @NotNull Set<String> exceptScopes) { this.exceptFunctionNames = exceptFunctionNames; this.exceptScopes = exceptScopes; } public int getTotalCallsCount() { return callsNameRefs.size(); } public int getQualifiedCallsCount(String... qualifiers) { int count = 0; List<String> expectedQualifierChain = new ArrayList<>(); Collections.addAll(expectedQualifierChain, qualifiers); for (JsNameRef callNameRef : callsNameRefs) { if (matchesQualifiers(callNameRef, expectedQualifierChain)) { count++; } } return count; } public int getUnqualifiedCallsCount(String expectedName) { int count = 0; for (JsNameRef callNameRef : callsNameRefs) { String name = callNameRef.getIdent(); if (name.equals(expectedName)) { count++; } } return count; } @Override public void visitInvocation(@NotNull JsInvocation invocation) { super.visitInvocation(invocation); JsExpression qualifier = invocation.getQualifier(); if (qualifier instanceof JsNameRef) { JsNameRef nameRef = (JsNameRef) qualifier; if (!exceptFunctionNames.contains(nameRef.getIdent())) { callsNameRefs.add(nameRef); } } } @Override public void visitFunction(@NotNull JsFunction x) { if (x.getName() != null && exceptScopes.contains(x.getName().getIdent())) { excludedScopeOccurrenceCount++; return; } super.visitFunction(x); } @Override public void visitVars(@NotNull JsVars x) { for (JsVars.JsVar jsVar : x.getVars()) { if (jsVar.getInitExpression() == null) continue; if (!exceptScopes.contains(jsVar.getName().getIdent())) { accept(jsVar.getInitExpression()); } else { excludedScopeOccurrenceCount++; } } } private static boolean matchesQualifiers(JsNameRef nameRef, List<String> expectedQualifierChain) { JsExpression currentQualifier = nameRef; for (String expectedQualifier : expectedQualifierChain) { if (!(currentQualifier instanceof JsNameRef)) { return false; } JsNameRef currentNameRef = (JsNameRef) currentQualifier; String name = currentNameRef.getIdent(); if (!name.equals(expectedQualifier)) { return false; } currentQualifier = currentNameRef.getQualifier(); } return true; } public int getExcludedScopeOccurrenceCount() { return excludedScopeOccurrenceCount; } }