Look up the line number range for a method.

@param className
name of class containing the method
@param methodName
name of method
@param methodSignature
signature of method
@return the line number range, or null if no line number is known for the
method
352706
public @CheckForNull
    SourceLineRange getMethodLine(String className, String methodName, String methodSignature) {
        return methodLineMap.get(new MethodDescriptor(className, methodName, methodSignature));
    }
1279800
private static String getClassMethod(Class clazz, Method method) {
		StringBuilder builder = new StringBuilder();
		builder.append(clazz.getName()).append(".").append(method.getName());
		builder.append("(");
		if (method.getParameterCount() > 0) {
			for (int i = 0; i < method.getParameterCount(); i++) {
				Parameter param = method.getParameters()[i];
				builder.append(param.getType().getSimpleName()).append(" ").append(param.getName());

				if (i + 1 < method.getParameterCount()) {
					builder.append(", ");
				}
			}
		}
		builder.append(")");
		return builder.toString();
	}
478525
public static Method findMethod(Method methodToFind, Class<?> cls) {
        if (cls == null) {
            return null;
        }
        String methodToSearch = methodToFind.getName();
        Class<?>[] soughtForParameterType = methodToFind.getParameterTypes();
        Type[] soughtForGenericParameterType = methodToFind.getGenericParameterTypes();
        for (Method method : cls.getMethods()) {
            if (method.getName().equals(methodToSearch) && method.getReturnType().isAssignableFrom(methodToFind.getReturnType())) {
                Class<?>[] srcParameterTypes = method.getParameterTypes();
                Type[] srcGenericParameterTypes = method.getGenericParameterTypes();
                if (soughtForParameterType.length == srcParameterTypes.length &&
                    soughtForGenericParameterType.length == srcGenericParameterTypes.length) {
                    if (hasIdenticalParameters(srcParameterTypes, soughtForParameterType, srcGenericParameterTypes, soughtForGenericParameterType)) {
                        return method;
                    }
                }
            }
        }
        return null;
    }
1211540
@Override
  public MethodVisitor visitMethod(int access, final String name, String desc,
                                   String signature, String[] exceptions) {
    MethodVisitor mv = cv.visitMethod(access | Opcodes.ACC_SYNTHETIC,
                                      name, desc, signature, exceptions);
    return new LineNumberingMethodAdapter(mv, access | Opcodes.ACC_SYNTHETIC,
                                          name, desc) {
      @Override
      protected void onMethodEnter() {
        this.lineNumbers = LineNumberingClassAdapter.this.lineNumbers;
        super.onMethodEnter();
      }
    };
  }
714580
@Override
    public void visitLineNumber(int line, Label start) {
        // If we haven't given a line number to the method entry, do so now.
        if (!methodEntryHasLineNumber) {
            methodEntryHasLineNumber = true;
            start = methodEntryLabel;
        }

        lineNumber = line;
        super.visitLineNumber(line, start);
    }
605800
public static String convertMethodSignature(XMethod xmethod) {
        @DottedClassName
        String className = xmethod.getClassName();
        assert className.indexOf('/') == -1;
        return convertMethodSignature(className, xmethod.getName(), xmethod.getSignature());
    }
62965
@Deprecated
  @Override
  public TraceMethod entry(String methodSignature)
  {
    TraceMethod traceMethod = super.entry(methodSignature);

    if (traceMethod != null) {
      String className = "STATIC";
      Logger logger = Logger.getLogger(className);
      logger.log(getClass().getName(), Level.DEBUG, "ENTRY--" + methodSignature, null);
    }
    
    return traceMethod;
  }
980002
private static String getSignature(MethodLiteral<?, ?> method, String[] paramNames,
      String overrideName, int overrideModifiers) throws NoSourceNameException {
    if (paramNames.length != method.getParameterTypes().size()) {
      throw new IllegalArgumentException(
          String.format("Wrong number of parameters provided for method signature, "
              + "expected %d but got %d.", method.getParameterTypes().size(), paramNames.length));
    }

    StringBuilder sb = new StringBuilder();

    if (overrideModifiers != 0) {
      sb.append(Modifier.toString(overrideModifiers)).append(" ");
    }

    if (method.getTypeParameters().length > 0) {
      List<String> typeParameters = new ArrayList<String>();
      for (TypeVariable<?> typeVariable : method.getTypeParameters()) {
        typeParameters.add(getTypeVariableDefinition(typeVariable));
      }
      sb.append("<").append(join(", ", typeParameters)).append("> ");
    }

    if (!method.isConstructor()) {
      sb.append(getSourceName(method.getReturnType())).append(" ");
      if (overrideName != null) {
        sb.append(overrideName);
      } else {
        sb.append(method.getName());
      }
    } else {
      sb.append(getSourceName(method.getRawDeclaringType()));
    }
    sb.append("(");

    // TODO(schmitt): We are not respecting varargs here.
    List<String> parameters = new ArrayList<String>();
    int i = 0;
    for (TypeLiteral<?> parameterType : method.getParameterTypes()) {
      parameters.add(
          String.format("%s %s", getSourceName(parameterType), paramNames[i]));
      i++;
    }
    sb.append(join(", ", parameters)).append(")");

    if (method.getExceptionTypes().size() > 0) {
      List<String> exceptions = new ArrayList<String>();
      for (TypeLiteral<?> exceptionType : method.getExceptionTypes()) {
        exceptions.add(getSourceName(exceptionType));
      }
      sb.append(" throws ").append(join(", ", exceptions));
    }

    return sb.toString();
  }
600703
public boolean usesMethod(String className, String methodName) {
		int classIndex = findClass(className);
		if (classIndex == NOT_FOUND) return false;
		int methodNameIndex = findUtf8(methodName);
		if (methodNameIndex == NOT_FOUND) return false;
		
		for (int i = 1; i < maxPoolSize; i++) {
			if (isMethod(i) && readValue(offsets[i]) == classIndex) {
				int nameAndTypeIndex = readValue(offsets[i] + 2);
				if (readValue(offsets[nameAndTypeIndex]) == methodNameIndex) return true;
			}
		}
		return false;
	}
203710
public static @CheckForNull
    ClassDescriptor createClassDescriptorFromFieldSignature(String signature) {
        int start = signature.indexOf('L');
        if (start < 0) {
            return null;
        }
        int end = signature.indexOf(';', start);
        if (end < 0) {
            return null;
        }
        return createClassDescriptor(signature.substring(start + 1, end));
    }
1370279
public static String convertMethodSignature(String className, String methodName, String methodSig) {
        return convertMethodSignature(className, methodName, methodSig, "");
    }
1137511
public static List<String> getParameters(final String methodDesc) {
//        final String[] types = resolveMethodSignature(methodDesc);
//        return IntStream.range(0, types.length).mapToObj(i -> types[i]).collect(Collectors.toList());
        if (methodDesc == null)
            return emptyList();

        final char[] buffer = methodDesc.toCharArray();
        final List<String> args = new ArrayList<>();

        // TODO resolve type parameters correctly -> information useful? -> maybe use ASM's SignatureReader/Visitor
        int offset = methodDesc.indexOf('(') + 1;
        while (buffer[offset] != ')') {
            final String type = getNextType(buffer, offset);
            args.add(type);
            offset += type.length();// + (type.charAt(0) == 'L' ? 2 : 0);
        }

        // TODO change, see type parameters
        // prevent type parameter identifiers
        final ListIterator<String> iterator = args.listIterator();
        while (iterator.hasNext()) {
            final String arg = iterator.next();
            if (arg.charAt(0) == 'T')
                iterator.set(OBJECT);
        }

        return args;
    }
1357764
public static @CheckForNull
    JavaClassAndMethod findMethod(JavaClass javaClass, String methodName, String methodSig) {
        return findMethod(javaClass, methodName, methodSig, ANY_METHOD);
    }
107192
private String createMethodSignature(Method method)
   {
      StringBuilder sb = new StringBuilder();
      sb.append("(");
      for (Class<?> type : method.getParameterTypes())
      {
         sb.append(getTypeString(type));
      }
      sb.append(")");
      Class<?> type = method.getReturnType();
      if (type.getName().equals("void"))
      {
         sb.append("V");
      }
      else
      {
         sb.append(getTypeString(type));
      }
      return sb.toString();
   }
1202703
public MethodParameterInfo[] getParameterInfo() {
        if (parameterInfo == null) {
            // Get params from the type descriptor, and from the type signature if available
            final List<TypeSignature> paramTypeDescriptors = getTypeDescriptor().getParameterTypeSignatures();
            final List<TypeSignature> paramTypeSignatures = getTypeSignature() != null
                    ? getTypeSignature().getParameterTypeSignatures()
                    : null;

            // Figure out the number of params in the alignment (should be num params in type descriptor)
            final int numParams = paramTypeDescriptors.size();
            if (paramTypeSignatures != null && paramTypeSignatures.size() > numParams) {
                // Should not happen
                throw ClassGraphException.newClassGraphException(
                        "typeSignatureParamTypes.size() > typeDescriptorParamTypes.size() for method "
                                + declaringClassName + "." + name);
            }

            // Figure out number of other fields that need alignment, and check length for consistency 
            final int otherParamMax = Math.max(parameterNames == null ? 0 : parameterNames.length,
                    Math.max(parameterModifiers == null ? 0 : parameterModifiers.length,
                            parameterAnnotationInfo == null ? 0 : parameterAnnotationInfo.length));
            if (otherParamMax > numParams) {
                // Should not happen
                throw ClassGraphException.newClassGraphException("Type descriptor for method " + declaringClassName
                        + "." + name + " has insufficient parameters");
            }

            // Kotlin is very inconsistent about the arity of each of the parameter metadata types, see:
            // https://github.com/classgraph/classgraph/issues/175#issuecomment-363031510
            // As a workaround, we assume that any synthetic / mandated parameters must come first in the
            // parameter list, when the arities don't match, and we right-align the metadata fields.
            // This is probably the safest assumption across JVM languages, even though this convention
            // is by no means the only possibility. (Unfortunately we can't just rely on the modifier
            // bits to find synthetic / mandated parameters, because these bits are not always available,
            // and even when they are, they don't always give the right alignment, at least for Kotlin-
            // generated code).

            String[] paramNamesAligned = null;
            if (parameterNames != null && numParams > 0) {
                if (parameterNames.length == numParams) {
                    // No alignment necessary
                    paramNamesAligned = parameterNames;
                } else {
                    // Right-align when not the right length
                    paramNamesAligned = new String[numParams];
                    for (int i = 0, lenDiff = numParams - parameterNames.length; i < parameterNames.length; i++) {
                        paramNamesAligned[lenDiff + i] = parameterNames[i];
                    }
                }
            }
            int[] paramModifiersAligned = null;
            if (parameterModifiers != null && numParams > 0) {
                if (parameterModifiers.length == numParams) {
                    // No alignment necessary
                    paramModifiersAligned = parameterModifiers;
                } else {
                    // Right-align when not the right length
                    paramModifiersAligned = new int[numParams];
                    for (int i = 0, lenDiff = numParams
                            - parameterModifiers.length; i < parameterModifiers.length; i++) {
                        paramModifiersAligned[lenDiff + i] = parameterModifiers[i];
                    }
                }
            }
            AnnotationInfo[][] paramAnnotationInfoAligned = null;
            if (parameterAnnotationInfo != null && numParams > 0) {
                if (parameterAnnotationInfo.length == numParams) {
                    // No alignment necessary
                    paramAnnotationInfoAligned = parameterAnnotationInfo;
                } else {
                    // Right-align when not the right length
                    paramAnnotationInfoAligned = new AnnotationInfo[numParams][];
                    for (int i = 0, lenDiff = numParams
                            - parameterAnnotationInfo.length; i < parameterAnnotationInfo.length; i++) {
                        paramAnnotationInfoAligned[lenDiff + i] = parameterAnnotationInfo[i];
                    }
                }
            }
            List<TypeSignature> paramTypeSignaturesAligned = null;
            if (paramTypeSignatures != null && numParams > 0) {
                if (paramTypeSignatures.size() == paramTypeDescriptors.size()) {
                    // No alignment necessary
                    paramTypeSignaturesAligned = paramTypeSignatures;
                } else {
                    // Right-align when not the right length
                    paramTypeSignaturesAligned = new ArrayList<>(numParams);
                    for (int i = 0, n = numParams - paramTypeSignatures.size(); i < n; i++) {
                        // Left-pad with nulls
                        paramTypeSignaturesAligned.add(null);
                    }
                    paramTypeSignaturesAligned.addAll(paramTypeSignatures);
                }
            }

            // Generate MethodParameterInfo entries
            parameterInfo = new MethodParameterInfo[numParams];
            for (int i = 0; i < numParams; i++) {
                parameterInfo[i] = new MethodParameterInfo(this,
                        paramAnnotationInfoAligned == null ? null : paramAnnotationInfoAligned[i],
                        paramModifiersAligned == null ? 0 : paramModifiersAligned[i], paramTypeDescriptors.get(i),
                        paramTypeSignaturesAligned == null ? null : paramTypeSignaturesAligned.get(i),
                        paramNamesAligned == null ? null : paramNamesAligned[i]);
                parameterInfo[i].setScanResult(scanResult);
            }
        }
        return parameterInfo;
    }
474713
public String createMethodTypeSignature(ExecutableElement method) {
    if (!hasGenericSignature(method)) {
      return null;
    }
    StringBuilder sb = new StringBuilder();
    genMethodTypeSignature(method, sb);
    return sb.toString();
  }
1270429
public static String getQualifiedMethodName(Method method) {
		Assert.notNull(method, "Method must not be null");
		return method.getDeclaringClass().getName() + "." + method.getName();
	}