private void setFunctionInfo(Function function, MethodInfoJava methodInfo,
			ClassFileJava classFile, DataTypeManager dtManager)
			throws DuplicateNameException, InvalidInputException {
		AbstractConstantPoolInfoJava[] constantPool = classFile.getConstantPool();
		String functionName =
			((ConstantPoolUtf8Info) constantPool[methodInfo.getNameIndex()]).getString();
		String descriptor =
			((ConstantPoolUtf8Info) constantPool[methodInfo.getDescriptorIndex()]).getString();
		//note: the name of a function in java is not necessarily unique, but the name together
		//with the descriptor is.  Hence we append the type names of the parameters and return to 
		//the function name to avoid an exception being thrown for duplicate names.
		List<String> typeNames = DescriptorDecoder.getTypeNameList(descriptor, true, true);
		StringBuilder sb = new StringBuilder();
		sb.append(functionName);
		for (String name : typeNames) {
			sb.append("_");
			sb.append(name);
		}

		function.setName(sb.toString(), SourceType.ANALYSIS);
		function.setCallingConvention(Function.DEFAULT_CALLING_CONVENTION_STRING);

		DataType returnType =
			DescriptorDecoder.getReturnTypeOfMethodDescriptor(descriptor, dtManager);
		function.setReturnType(returnType, SourceType.ANALYSIS);

		List<Variable> params = new ArrayList<>();
		//in order to set the parameters for the method, we need to know whether
		//there is an implicit 'this' parameter.  
		if (!methodInfo.isStatic()) {
			int thisIndex = classFile.getThisClass();
			ConstantPoolClassInfo thisClass = (ConstantPoolClassInfo) constantPool[thisIndex];
			int nameIndex = thisClass.getNameIndex();
			ConstantPoolUtf8Info thisNameInfo = (ConstantPoolUtf8Info) constantPool[nameIndex];
			DataType thisType = DescriptorDecoder.resolveClassForString(thisNameInfo.getString(),
				dtManager, DWordDataType.dataType);
			ParameterImpl thisParam = new ParameterImpl("this", thisType, function.getProgram());
			params.add(thisParam);
		}
		List<DataType> explicitParams = DescriptorDecoder.getDataTypeList(descriptor, dtManager);
		for (int i = 0, max = explicitParams.size(); i < max; ++i) {
			ParameterImpl currentParam = new ParameterImpl("param" + Integer.toString(i + 1),
				explicitParams.get(i), function.getProgram());
			params.add(currentParam);
		}
		MethodParametersAttribute methodParamsAttr = methodInfo.getMethodParameters();
		if (methodParamsAttr != null) {
			MethodParameters[] methodParams = methodParamsAttr.getMethodParameters();
			int indexAdjust = methodInfo.isStatic() ? 0 : 1;
			if (methodParams.length == (params.size() - indexAdjust)) {
				for (int i = 0; i < methodParams.length; ++i) {
					int nameIndex = methodParams[i].getNameIndex();
					if (nameIndex == 0) {
						continue;  // no name
					}
					String name = ((ConstantPoolUtf8Info) constantPool[nameIndex]).getString();
					params.get(i + indexAdjust).setName(name, SourceType.ANALYSIS);
				}
			}
			else {
				Msg.warn(this, "methodParams/params size mismatch for " + function.getName());
				Msg.warn(this,
					"methodParams: " + methodParams.length + "; params: " + params.size());
			}
		}
		function.replaceParameters(params, FunctionUpdateType.DYNAMIC_STORAGE_ALL_PARAMS, true,
			SourceType.ANALYSIS);

		createAccessFlagComments(function, methodInfo, classFile);

	}
Sets the name, return type, and parameter types of a method using the information in the constant pool.
Also overrides the signatures on all method invocations made within the method body.
@param function - the function (method) 
@param methodInfo information about the method from the constant pool
@param classFile class file containing the method
@param dtManager data type manager for program 
@throws DuplicateNameException if there are duplicate name issues with function or parameter names
@throws InvalidInputException if a function or parameter name is invalid
Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/analyzers/JavaAnalyzer.java