package io.vertx.codegen; /* * 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. */ import io.vertx.codegen.doc.Doc; import io.vertx.codegen.doc.Text; import io.vertx.codegen.type.ClassKind; import io.vertx.codegen.type.ClassTypeInfo; import io.vertx.codegen.type.ParameterizedTypeInfo; import io.vertx.codegen.type.TypeInfo; import io.vertx.codegen.type.TypeVariableInfo; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; /** * @author <a href="http://tfox.org">Tim Fox</a> */ public class MethodInfo implements Comparable<MethodInfo> { final String name; final MethodKind kind; final TypeInfo returnType; final Text returnDescription; final boolean fluent; final boolean cacheReturn; final String comment; final Doc doc; final boolean staticMethod; final boolean defaultMethod; List<TypeParamInfo.Method> typeParams; LinkedHashSet<ClassTypeInfo> ownerTypes; List<ParamInfo> params; public MethodInfo(Set<ClassTypeInfo> ownerTypes, String name, MethodKind kind, TypeInfo returnType, Text returnDescription, boolean fluent, boolean cacheReturn, List<ParamInfo> params, String comment, Doc doc, boolean staticMethod, boolean defaultMethod, List<TypeParamInfo.Method> typeParams) { this.comment = comment; this.kind = kind; this.name = name; this.returnType = returnType; this.returnDescription = returnDescription; this.fluent = fluent; this.cacheReturn = cacheReturn; this.doc = doc; this.staticMethod = staticMethod; this.defaultMethod = defaultMethod; this.params = params; this.typeParams = typeParams; this.ownerTypes = new LinkedHashSet<>(ownerTypes); } public String getName() { return name; } public String getName(Case _case) { return _case.format(Case.CAMEL.parse(name)); } public MethodKind getKind() { return kind; } public TypeInfo getReturnType() { return returnType; } /** * Resolve the method parameter that is of kind {@link ClassKind#CLASS_TYPE} and that matches the specified type variable e.g:<br/> * <br/> * {@code <U> Map.Entry<String, U> getEntry(String s, Class<U> type);} * <br/> * <br/> * returns for {@code <U>} the second method parameter. * * @param typeVar the type variable to check * @return the matching method parameter or null */ public ParamInfo resolveClassTypeParam(TypeVariableInfo typeVar) { TypeArgExpression res = resolveTypeArg(typeVar); if (res != null && res.isClassType()) { return res.getParam(); } return null; } public TypeArgExpression resolveTypeArg(TypeVariableInfo typeVar) { for (TypeParamInfo.Method typeParam : typeParams) { if (typeParam.getName().equals(typeVar.getName())) { for (ParamInfo param : params) { if (param.getType().getKind() == ClassKind.CLASS_TYPE && param.getType().isParameterized()) { TypeInfo arg_ = ((ParameterizedTypeInfo) param.getType()).getArg(0); if (arg_.isVariable()) { TypeVariableInfo ttt = (TypeVariableInfo) arg_; if (ttt.getParam().equals(typeParam)) { return new TypeArgExpression(TypeArgExpression.CLASS_TYPE_ARG, ttt, param, 0); } } } else if (param.getType().getKind() == ClassKind.API && param.getType().isParameterized()) { ParameterizedTypeInfo type = (ParameterizedTypeInfo) param.getType(); int index = 0; for (TypeInfo i : type.getArgs()) { if (i instanceof TypeVariableInfo) { TypeVariableInfo tt = (TypeVariableInfo) i; if (tt.getParam().equals(typeParam)) { return new TypeArgExpression(TypeArgExpression.API_ARG, tt, param, index); } } index++; } } } return null; } } return null; } public Text getReturnDescription() { return returnDescription; } public Set<ClassTypeInfo> getOwnerTypes() { return ownerTypes; } /** * Returns the method signature, the returned object is freely modifiable. * * @return the method signature */ public Signature getSignature() { return new Signature(name, new ArrayList<>(params)); } /** * Return true if the provided type is the sole owner of this method, i.e this method * is only declared by the provided type. * * @param owner the tested type * @return true when this method is owned by the <code>owner</code> argument */ public boolean isOwnedBy(ClassTypeInfo owner) { return ownerTypes.contains(owner) && ownerTypes.size() == 1; } public boolean isFluent() { return fluent; } public boolean isCacheReturn() { return cacheReturn; } /** * @return true if the method has a nullable return */ public boolean isNullableReturn() { return returnType instanceof TypeVariableInfo || returnType.isNullable(); } public List<ParamInfo> getParams() { return params; } public ParamInfo getParam(int index) { return params.get(index); } public String getComment() { return comment; } public Doc getDoc() { return doc; } public boolean isStaticMethod() { return staticMethod; } public boolean isDefaultMethod() { return defaultMethod; } public List<TypeParamInfo.Method> getTypeParams() { return typeParams; } public void mergeTypeParams(List<TypeParamInfo.Method> mergedTypeParams) throws IllegalArgumentException { int l = Math.min(typeParams.size(), mergedTypeParams.size()); if (typeParams.subList(0, l).equals(mergedTypeParams.subList(0, l))) { if (mergedTypeParams.size() > typeParams.size()) { typeParams.addAll(mergedTypeParams.subList(typeParams.size(), mergedTypeParams.size())); } } else { throw new IllegalArgumentException("Merged type params " + mergedTypeParams + " don't match the existing ones " + typeParams); } } public void collectImports(Collection<ClassTypeInfo> imports) { params.stream().map(ParamInfo::getType).forEach(a -> a.collectImports(imports)); } @Override public int compareTo(MethodInfo o) { int cmp = name.compareTo(o.name); if (cmp != 0) { return cmp; } Iterator<ParamInfo> i1 = params.iterator(); Iterator<ParamInfo> i2 = o.params.iterator(); while (i1.hasNext() && i2.hasNext()) { ParamInfo p1 = i1.next(); ParamInfo p2 = i2.next(); cmp = p1.getType().getRaw().getName().compareTo(p2.getType().getRaw().getName()); if (cmp != 0) { return cmp; } } if (i1.hasNext()) { if (!i2.hasNext()) { return 1; } } else if (!i2.hasNext()) { return -1; } return 0; } @Override public String toString() { StringBuilder sb = new StringBuilder(); if (typeParams.size() > 0) { for (int i = 0;i < typeParams.size();i++) { sb.append(i > 0 ? ", " : "<"); sb.append(typeParams.get(i).getName()); } sb.append("> "); } sb.append(returnType.getName()); sb.append(' '); sb.append(getSignature().toString()); return sb.toString(); } }