
io.vertx.codegen.overloadcheck.MethodOverloadChecker Maven / Gradle / Ivy
/*
* Copyright 2014 Red Hat, Inc.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Apache License v2.0 which accompanies this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* The Apache License v2.0 is available at
* http://www.opensource.org/licenses/apache2.0.php
*
* You may elect to redistribute this code under either of these licenses.
*/
package io.vertx.codegen.overloadcheck;
import io.vertx.codegen.MethodInfo;
import io.vertx.codegen.ParamInfo;
import io.vertx.codegen.type.TypeInfo;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
/**
*
* @author Tim Fox
*/
public class MethodOverloadChecker {
private final Map> typeMappingsMap = new HashMap<>();
public MethodOverloadChecker() {
loadTypeMappings();
}
public void checkAmbiguous(List meths) {
checkAmbiguousSimple(convert(meths));
}
public void checkAmbiguousSimple(List meths) {
List methods = new ArrayList<>(meths);
Map> byNumParams = new HashMap<>();
for (SimpleMethod meth: methods) {
int numParams = meth.params.size();
List list = byNumParams.get(numParams);
if (list == null) {
list = new ArrayList<>();
byNumParams.put(numParams, list);
}
list.add(meth);
}
for (Map.Entry> entry: byNumParams.entrySet()) {
List list = entry.getValue();
if (list.size() == 1) {
// Ignore - no overloaded methods
} else {
for (Map.Entry> mappingEntry: typeMappingsMap.entrySet()) {
checkMethodList(mappingEntry.getKey(), list, mappingEntry.getValue());
}
}
}
}
// We convert to simpler types - this makes it much easier to test
private List convert(List meths) {
List simpleMethods = new ArrayList<>(meths.size());
for (MethodInfo meth: meths) {
List simpleParams = new ArrayList<>();
for (ParamInfo param: meth.getParams()) {
TypeInfo type = param.getType();
simpleParams.add(new SimpleParam(param.getName(), type.getKind(), param.isNullable(), type.getName()));
}
simpleMethods.add(new SimpleMethod(meth.getName(), simpleParams));
}
return simpleMethods;
}
private void checkMethodList(String targetLang, List meths, Map typeMapping) {
List> paramsTypesList = new ArrayList<>();
for (SimpleMethod meth: meths) {
// For each meth, convert it to the param types it would have in each lang
List paramTypes = convertToLangParamTypes(meth, typeMapping);
paramsTypesList.add(paramTypes);
}
// Now check if we have any two which are equal
int index1 = 0;
for (List paramTypes: paramsTypesList) {
int index2 = 0;
for (List paramTypesToCompare: paramsTypesList) {
if (index1 != index2) {
boolean matched = true;
for (int i = 0; i < paramTypes.size(); i++) {
SimpleType paramType = paramTypes.get(i);
SimpleType paramTypeToCompare = paramTypesToCompare.get(i);
if (!(paramType.matches(paramTypeToCompare))) {
matched = false;
break;
}
}
if (matched) {
SimpleMethod clashing1 = meths.get(index1);
SimpleMethod clashing2 = meths.get(index2);
String msg = "Failed to generate because it would be impossible in target language " + targetLang +
" at runtime to resolve which of the following overloaded methods to call in the Java API: " + clashing1 +
" and " + clashing2;
throw new IllegalArgumentException(msg);
}
}
index2++;
}
index1++;
}
}
private List convertToLangParamTypes(SimpleMethod meth, Map typeMapping) {
List langParamTypes = new ArrayList<>();
for (SimpleParam param: meth.params) {
String langType = typeMapping.get(param.classKind.toString());
if (langType == null) {
// Try with type name appended
String lhs = param.classKind.toString() + "." + param.typeName;
langType = typeMapping.get(lhs);
if (langType == null) {
throw new IllegalStateException("No type mapping found for param type " + lhs);
}
}
String nullable = null;
if (param.nullable) {
nullable = typeMapping.get("NULL");
}
langParamTypes.add(new SimpleType(langType, nullable));
}
return langParamTypes;
}
private void loadTypeMappings() {
try (InputStream is = MethodOverloadChecker.class.getClassLoader().getResourceAsStream("lang-type-mapping.properties")) {
Properties props = new Properties();
props.load(is);
for (Map.Entry
© 2015 - 2025 Weber Informatics LLC | Privacy Policy