reman3/scripts/re3lib/DataTypeWriter.java

843 lines
27 KiB
Java

// Source code is decompiled from a .class file using FernFlower decompiler.
package re3lib;
import ghidra.program.model.data.*;
import ghidra.program.model.data.Enum;
import ghidra.util.Msg;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayDeque;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class DataTypeWriter {
public HashSet<String> blacklistedTypes;
private static String[] INTEGRAL_TYPES = new String[] { "char", "short", "int", "long", "long long", "__int64",
"float", "double", "long double", "void" };
private static String[] INTEGRAL_MODIFIERS = new String[] { "signed", "unsigned", "const", "static", "volatile",
"mutable" };
private static String EOL = System.getProperty("line.separator");
private Set<DataType> resolved;
private Map<String, DataType> resolvedTypeMap;
private Set<Composite> deferredCompositeDeclarations;
private ArrayDeque<DataType> deferredTypeFIFO;
private Set<DataType> deferredTypes;
private int writerDepth;
private Writer writer;
private DataTypeManager dtm;
private DataOrganization dataOrganization;
private AnnotationHandler annotator;
private boolean cppStyleComments;
public DataTypeWriter(DataTypeManager dtm, Writer writer) throws IOException {
this(dtm, writer, new DefaultAnnotationHandler());
}
public DataTypeWriter(DataTypeManager dtm, Writer writer, boolean cppStyleComments) throws IOException {
this(dtm, writer, new DefaultAnnotationHandler(), cppStyleComments);
}
public DataTypeWriter(DataTypeManager dtm, Writer writer, AnnotationHandler annotator) throws IOException {
this(dtm, writer, annotator, false);
}
public DataTypeWriter(DataTypeManager dtm, Writer writer, AnnotationHandler annotator, boolean cppStyleComments)
throws IOException {
this.blacklistedTypes = new HashSet<>();
this.resolved = new HashSet();
this.resolvedTypeMap = new HashMap();
this.deferredCompositeDeclarations = new HashSet();
this.deferredTypeFIFO = new ArrayDeque();
this.deferredTypes = new HashSet();
this.writerDepth = 0;
this.cppStyleComments = false;
this.dtm = dtm;
if (dtm != null) {
this.dataOrganization = dtm.getDataOrganization();
}
if (this.dataOrganization == null) {
this.dataOrganization = DataOrganizationImpl.getDefaultOrganization();
}
this.writer = writer;
this.annotator = annotator;
this.cppStyleComments = cppStyleComments;
if (dtm != null) {
// this.writeBuiltInDeclarations(dtm);
}
}
private String comment(String text) {
if (text == null) {
return "";
} else {
return this.cppStyleComments ? "// " + text : "/* " + text + " */";
}
}
public void write(DataTypeManager dataTypeManager, TaskMonitor monitor) throws IOException, CancelledException {
this.write(dataTypeManager.getRootCategory(), monitor);
}
public void write(Category category, TaskMonitor monitor) throws IOException, CancelledException {
DataType[] dataTypes = category.getDataTypes();
this.write(dataTypes, monitor);
Category[] subCategories = category.getCategories();
Category[] var5 = subCategories;
int var6 = subCategories.length;
for (int var7 = 0; var7 < var6; ++var7) {
Category subCategory = var5[var7];
if (monitor.isCancelled()) {
return;
}
this.write(subCategory, monitor);
}
}
public void write(DataType[] dataTypes, TaskMonitor monitor) throws IOException, CancelledException {
monitor.initialize((long) dataTypes.length);
int cnt = 0;
DataType[] var4 = dataTypes;
int var5 = dataTypes.length;
for (int var6 = 0; var6 < var5; ++var6) {
DataType dataType = var4[var6];
monitor.checkCancelled();
this.write(dataType, monitor);
++cnt;
monitor.setProgress((long) cnt);
}
}
public void write(List<DataType> dataTypes, TaskMonitor monitor) throws IOException, CancelledException {
this.write(dataTypes, monitor, true);
}
public void write(List<DataType> dataTypes, TaskMonitor monitor, boolean throwExceptionOnInvalidType)
throws IOException, CancelledException {
monitor.initialize((long) dataTypes.size());
int cnt = 0;
Iterator var5 = dataTypes.iterator();
while (var5.hasNext()) {
DataType dataType = (DataType) var5.next();
monitor.checkCancelled();
this.write(dataType, monitor, throwExceptionOnInvalidType);
++cnt;
monitor.setProgress((long) cnt);
}
}
private void deferWrite(DataType dt) {
if (!this.resolved.contains(dt) && !this.deferredTypes.contains(dt)) {
this.deferredTypes.add(dt);
this.deferredTypeFIFO.addLast(dt);
}
}
void write(DataType dt, TaskMonitor monitor) throws IOException, CancelledException {
this.doWrite(dt, monitor, true);
}
void write(DataType dt, TaskMonitor monitor, boolean throwExceptionOnInvalidType)
throws IOException, CancelledException {
this.doWrite(dt, monitor, throwExceptionOnInvalidType);
}
private void doWrite(DataType dt, TaskMonitor monitor, boolean throwExceptionOnInvalidType)
throws IOException, CancelledException {
if (dt != null) {
if (blacklistedTypes.contains(dt.getDisplayName()))
return;
if (!(dt instanceof FunctionDefinition)) {
if (dt instanceof FactoryDataType) {
IllegalArgumentException iae = new IllegalArgumentException("Factory data types may not be written");
if (throwExceptionOnInvalidType) {
throw iae;
}
Msg.error(this, "Factory data types may not be written - type: " + dt);
}
if (!(dt instanceof Pointer) && !(dt instanceof Array) && !(dt instanceof BitFieldDataType)) {
dt = dt.clone(this.dtm);
if (!this.resolved.contains(dt)) {
this.resolved.add(dt);
DataType resolvedType = (DataType) this.resolvedTypeMap.get(dt.getName());
if (resolvedType != null) {
if (!resolvedType.isEquivalent(dt)) {
if (dt instanceof TypeDef) {
DataType baseType = ((TypeDef) dt).getBaseDataType();
if ((resolvedType instanceof Composite || resolvedType instanceof Enum)
&& baseType.isEquivalent(resolvedType)) {
return;
}
}
this.writer.write(EOL);
Writer var10000 = this.writer;
String var10002 = dt.getPathName();
var10000.write(this
.comment("WARNING! conflicting data type names: " + var10002 + " - " + resolvedType.getPathName()));
this.writer.write(EOL);
this.writer.write(EOL);
}
} else {
this.resolvedTypeMap.put(dt.getName(), dt);
++this.writerDepth;
if (dt.equals(DataType.DEFAULT)) {
this.writer.write("typedef unsigned char " + DataType.DEFAULT.getName() + ";");
this.writer.write(EOL);
this.writer.write(EOL);
} else if (dt instanceof Dynamic) {
this.writeDynamicBuiltIn((Dynamic) dt, monitor);
} else if (dt instanceof Structure) {
Structure struct = (Structure) dt;
this.writeCompositePreDeclaration(struct, monitor);
this.deferredCompositeDeclarations.add(struct);
} else if (dt instanceof Union) {
Union union = (Union) dt;
this.writeCompositePreDeclaration(union, monitor);
this.deferredCompositeDeclarations.add(union);
} else if (dt instanceof Enum) {
this.writeEnum((Enum) dt, monitor);
} else if (dt instanceof TypeDef) {
this.writeTypeDef((TypeDef) dt, monitor);
} else if (dt instanceof BuiltInDataType) {
this.writeBuiltIn((BuiltInDataType) dt, monitor);
} else if (!(dt instanceof BitFieldDataType)) {
this.writer.write(EOL);
this.writer.write(EOL);
this.writer.write(this.comment("Unable to write datatype. Type unrecognized: " + dt.getClass()));
this.writer.write(EOL);
this.writer.write(EOL);
}
if (this.writerDepth == 1) {
this.writeDeferredDeclarations(monitor);
}
--this.writerDepth;
}
}
} else {
this.write(this.getBaseDataType(dt), monitor);
}
}
}
}
private void writeDeferredDeclarations(TaskMonitor monitor) throws IOException, CancelledException {
while (!this.deferredTypes.isEmpty()) {
DataType dt = (DataType) this.deferredTypeFIFO.removeFirst();
this.deferredTypes.remove(dt);
this.write(dt, monitor);
}
this.writeDeferredCompositeDeclarations(monitor);
this.deferredCompositeDeclarations.clear();
}
private DataType getBaseArrayTypedefType(DataType dt) {
while (true) {
if (dt != null) {
if (dt instanceof TypeDef) {
dt = ((TypeDef) dt).getBaseDataType();
continue;
}
if (dt instanceof Array) {
dt = ((Array) dt).getDataType();
continue;
}
}
return dt;
}
}
private boolean containsComposite(Composite container, Composite contained) {
DataTypeComponent[] var3 = container.getDefinedComponents();
int var4 = var3.length;
for (int var5 = 0; var5 < var4; ++var5) {
DataTypeComponent component = var3[var5];
DataType dt = this.getBaseArrayTypedefType(component.getDataType());
if (dt instanceof Composite && dt.getName().equals(contained.getName()) && dt.isEquivalent(contained)) {
return true;
}
}
return false;
}
private void writeDeferredCompositeDeclarations(TaskMonitor monitor) throws IOException, CancelledException {
int cnt = this.deferredCompositeDeclarations.size();
if (cnt != 0) {
LinkedList<Composite> list = new LinkedList(this.deferredCompositeDeclarations);
if (list.size() > 1) {
int sortChange = 1;
while (sortChange != 0) {
sortChange = 0;
for (int i = cnt - 1; i > 0; --i) {
if (this.resortComposites(list, i)) {
++sortChange;
}
}
}
}
Iterator var6 = list.iterator();
while (var6.hasNext()) {
Composite composite = (Composite) var6.next();
this.writeCompositeBody(composite, monitor);
}
}
}
private boolean resortComposites(List<Composite> list, int index) {
int listSize = list.size();
if (listSize <= 0) {
return false;
} else {
Composite composite = (Composite) list.get(index);
for (int i = 0; i < index; ++i) {
Composite other = (Composite) list.get(i);
if (this.containsComposite(other, composite)) {
list.remove(index);
list.add(i, composite);
composite = null;
return true;
}
}
return false;
}
}
private String getDynamicComponentString(Dynamic dynamicType, String fieldName, int length) {
if (dynamicType.canSpecifyLength()) {
DataType replacementBaseType = dynamicType.getReplacementBaseType();
if (replacementBaseType != null) {
replacementBaseType = replacementBaseType.clone(this.dtm);
int elementLen = replacementBaseType.getLength();
if (elementLen > 0) {
int elementCnt = (length + elementLen - 1) / elementLen;
return replacementBaseType.getDisplayName() + " " + fieldName + "[" + elementCnt + "]";
}
String var10001 = dynamicType.getClass().getSimpleName();
Msg.error(this,
var10001 + " returned bad replacementBaseType: " + replacementBaseType.getClass().getSimpleName());
}
}
return null;
}
private void writeCompositePreDeclaration(Composite composite, TaskMonitor monitor)
throws IOException, CancelledException {
String compositeType = composite instanceof Structure ? "struct" : "union";
this.writer.write("typedef " + compositeType + " " + composite.getDisplayName() + " " + composite.getDisplayName()
+ ", *P" + composite.getDisplayName() + ";");
this.writer.write(EOL);
this.writer.write(EOL);
DataTypeComponent[] var4 = composite.getComponents();
int var5 = var4.length;
for (int var6 = 0; var6 < var5; ++var6) {
DataTypeComponent component = var4[var6];
if (monitor.isCancelled()) {
break;
}
DataType componentType = component.getDataType();
this.deferWrite(componentType);
this.getTypeDeclaration((String) null, componentType, component.getLength(), true, monitor);
}
}
private void writeCompositeBody(Composite composite, TaskMonitor monitor) throws IOException, CancelledException {
String compositeType = composite instanceof Structure ? "struct" : "union";
StringBuilder sb = new StringBuilder();
sb.append(compositeType + " " + composite.getDisplayName() + " {");
String descrip = composite.getDescription();
if (descrip != null && descrip.length() > 0) {
String var10001 = this.comment(descrip);
sb.append(" " + var10001);
}
sb.append(EOL);
DataTypeComponent[] var6 = composite.getComponents();
int var7 = var6.length;
for (int var8 = 0; var8 < var7; ++var8) {
DataTypeComponent component = var6[var8];
monitor.checkCancelled();
this.writeComponent(component, composite, sb, monitor);
}
sb.append(this.annotator.getSuffix(composite, (DataTypeComponent) null));
sb.append("};");
this.writer.write(sb.toString());
this.writer.write(EOL);
this.writer.write(EOL);
}
private void writeComponent(DataTypeComponent component, Composite composite, StringBuilder sb, TaskMonitor monitor)
throws IOException, CancelledException {
sb.append(" ");
sb.append(this.annotator.getPrefix(composite, component));
String fieldName = component.getFieldName();
if (fieldName == null || fieldName.length() == 0) {
fieldName = component.getDefaultFieldName();
}
DataType componentDataType = component.getDataType();
sb.append(this.getTypeDeclaration(fieldName, componentDataType, component.getLength(), false, monitor));
sb.append(";");
sb.append(this.annotator.getSuffix(composite, component));
String comment = component.getComment();
if (comment != null && comment.length() > 0) {
String var10001 = this.comment(comment);
sb.append(" " + var10001);
}
sb.append(EOL);
}
private String getTypeDeclaration(String name, DataType dataType, int instanceLength, boolean writeEnabled,
TaskMonitor monitor) throws IOException, CancelledException {
if (name == null) {
name = "";
}
StringBuilder sb = new StringBuilder();
String componentString = null;
if (dataType instanceof Dynamic) {
componentString = this.getDynamicComponentString((Dynamic) dataType, name, instanceLength);
if (componentString != null) {
sb.append(componentString);
} else {
sb.append(this.comment("ignoring dynamic datatype inside composite: " + dataType.getDisplayName()));
sb.append(EOL);
}
}
if (componentString == null) {
if (dataType instanceof BitFieldDataType) {
BitFieldDataType bfDt = (BitFieldDataType) dataType;
name = name + ":" + bfDt.getDeclaredBitSize();
dataType = bfDt.getBaseDataType();
}
label44: while (true) {
while (!(dataType instanceof Array)) {
if (!(dataType instanceof Pointer)) {
break label44;
}
Pointer pointer = (Pointer) dataType;
DataType elem = pointer.getDataType();
if (elem == null) {
break label44;
}
name = "*" + name;
dataType = elem;
if (elem instanceof Array) {
name = "(" + name + ")";
}
}
Array array = (Array) dataType;
name = name + "[" + array.getNumElements() + "]";
dataType = array.getDataType();
}
DataType baseDataType = this.getBaseDataType(dataType);
if (baseDataType instanceof FunctionDefinition) {
componentString = this.getFunctionPointerString((FunctionDefinition) baseDataType, name, dataType, writeEnabled,
monitor);
} else {
String var10000 = this.getDataTypePrefix(dataType);
componentString = var10000 + dataType.getDisplayName();
if (name.length() != 0) {
componentString = componentString + " " + name;
}
}
sb.append(componentString);
}
return sb.toString();
}
private String getDataTypePrefix(DataType dataType) {
dataType = this.getBaseDataType(dataType);
if (dataType instanceof Structure) {
return "struct ";
} else if (dataType instanceof Union) {
return "union ";
} else {
return dataType instanceof Enum ? "enum " : "";
}
}
private void writeEnum(Enum enumm, TaskMonitor monitor) throws IOException {
String enumName = enumm.getDisplayName();
Writer var10000;
String var10001;
if (enumName.startsWith("define_") && enumName.length() > 7 && enumm.getCount() == 1) {
long val = enumm.getValues()[0];
var10000 = this.writer;
var10001 = enumName.substring(7);
var10000.append("#define " + var10001 + " " + Long.toString(val));
this.writer.write(EOL);
this.writer.write(EOL);
} else {
this.writer.write("enum " + enumName + " {");
String description = enumm.getDescription();
if (description != null && description.length() != 0) {
var10000 = this.writer;
var10001 = this.comment(description);
var10000.write(" " + var10001);
}
this.writer.write(EOL);
String[] names = enumm.getNames();
for (int j = 0; j < names.length; ++j) {
this.writer.write(" ");
this.writer.write(this.annotator.getPrefix(enumm, names[j]));
this.writer.write(names[j]);
this.writer.write("=");
this.writer.write(Long.toString(enumm.getValue(names[j])));
String comment = enumm.getComment(names[j]);
if (!comment.isBlank()) {
var10000 = this.writer;
var10001 = this.comment(comment);
var10000.write(" " + var10001);
}
this.writer.write(this.annotator.getSuffix(enumm, names[j]));
if (j < names.length - 1) {
this.writer.write(",");
}
this.writer.write(EOL);
}
this.writer.write("};");
this.writer.write(EOL);
this.writer.write(EOL);
}
}
private void writeTypeDef(TypeDef typeDef, TaskMonitor monitor) throws IOException, CancelledException {
String typedefName = typeDef.getDisplayName();
DataType dataType = typeDef.getDataType();
String dataTypeName = dataType.getDisplayName();
if (!this.isIntegral(typedefName, dataTypeName)) {
DataType baseType = typeDef.getBaseDataType();
label125: {
try {
if (!(baseType instanceof Composite) && !(baseType instanceof Enum)) {
if (!(baseType instanceof Pointer) || !typedefName.startsWith("P")) {
break label125;
}
DataType dt = ((Pointer) baseType).getDataType();
if (dt instanceof TypeDef) {
dt = ((TypeDef) dt).getBaseDataType();
}
if (!(dt instanceof Composite) || !dt.getName().equals(typedefName.substring(1))) {
break label125;
}
this.resolvedTypeMap.remove(typedefName);
return;
}
if (!typedefName.equals(baseType.getName())) {
break label125;
}
this.resolvedTypeMap.remove(typedefName);
} finally {
this.write(dataType, monitor);
}
return;
}
if (baseType instanceof Array && this.getBaseArrayTypedefType(baseType) instanceof Composite) {
this.writeDeferredDeclarations(monitor);
}
String typedefString = this.getTypeDeclaration(typedefName, dataType, -1, true, monitor);
this.writer.write("typedef " + typedefString + ";");
this.writer.write(EOL);
this.writer.write(EOL);
}
}
private boolean isIntegral(String typedefName, String basetypeName) {
String[] var3 = INTEGRAL_TYPES;
int var4 = var3.length;
int var5;
for (var5 = 0; var5 < var4; ++var5) {
String type = var3[var5];
if (typedefName.equals(type)) {
return true;
}
}
boolean endsWithIntegralType = false;
String[] var10 = INTEGRAL_TYPES;
var5 = var10.length;
int var13;
for (var13 = 0; var13 < var5; ++var13) {
String type = var10[var13];
if (typedefName.endsWith(" " + type)) {
endsWithIntegralType = true;
break;
}
}
boolean containsIntegralModifier = false;
String[] var12 = INTEGRAL_MODIFIERS;
var13 = var12.length;
for (int var14 = 0; var14 < var13; ++var14) {
String modifier = var12[var14];
if (typedefName.indexOf(modifier + " ") >= 0 || typedefName.indexOf(" " + modifier) >= 0) {
return true;
}
}
if (endsWithIntegralType && containsIntegralModifier) {
return true;
} else if (typedefName.endsWith(" " + basetypeName)) {
return containsIntegralModifier;
} else {
return false;
}
}
private void writeDynamicBuiltIn(Dynamic dt, TaskMonitor monitor) throws IOException, CancelledException {
DataType baseDt = dt.getReplacementBaseType();
if (baseDt != null) {
this.write(baseDt, monitor);
}
}
private void writeBuiltIn(BuiltInDataType dt, TaskMonitor monitor) throws IOException {
String declaration = dt.getCTypeDeclaration(this.dataOrganization);
if (declaration != null) {
if (dt.getDisplayName() == "bool")
return;
this.writer.write(declaration);
this.writer.write(EOL);
}
}
private void writeBuiltInDeclarations(DataTypeManager manager) throws IOException {
try {
this.write(DataType.DEFAULT, TaskMonitor.DUMMY);
SourceArchive builtInArchive = manager.getSourceArchive(DataTypeManager.BUILT_IN_ARCHIVE_UNIVERSAL_ID);
if (builtInArchive == null) {
return;
}
Iterator var3 = manager.getDataTypes(builtInArchive).iterator();
while (var3.hasNext()) {
DataType dt = (DataType) var3.next();
if (!(dt instanceof Pointer) && !(dt instanceof FactoryDataType) && !(dt instanceof Dynamic)) {
this.write(dt, TaskMonitor.DUMMY);
}
}
} catch (CancelledException var5) {
}
this.writer.flush();
}
private static String getArrayDimensions(Array arrayDt) {
String dimensionString = "[" + arrayDt.getNumElements() + "]";
DataType dataType = arrayDt.getDataType();
if (dataType instanceof Array) {
dimensionString = dimensionString + getArrayDimensions((Array) dataType);
}
return dimensionString;
}
private DataType getBaseDataType(DataType dt) {
while (true) {
if (dt != null) {
if (dt instanceof Array) {
Array array = (Array) dt;
dt = array.getDataType();
continue;
}
if (dt instanceof Pointer) {
Pointer pointer = (Pointer) dt;
dt = pointer.getDataType();
continue;
}
if (dt instanceof BitFieldDataType) {
BitFieldDataType bitfieldDt = (BitFieldDataType) dt;
dt = bitfieldDt.getBaseDataType();
continue;
}
}
return dt;
}
}
private DataType getArrayBaseType(Array arrayDt) {
DataType dataType;
for (dataType = arrayDt.getDataType(); dataType instanceof Array; dataType = ((Array) dataType).getDataType()) {
}
return dataType;
}
private DataType getPointerBaseDataType(Pointer p) {
DataType dt;
for (dt = p.getDataType(); dt instanceof Pointer; dt = ((Pointer) dt).getDataType()) {
}
return dt;
}
private int getPointerDepth(Pointer p) {
int depth = 1;
for (DataType dt = p.getDataType(); dt instanceof Pointer; dt = ((Pointer) dt).getDataType()) {
++depth;
}
return depth;
}
private String getFunctionPointerString(FunctionDefinition fd, String name, DataType functionPointerArrayType,
boolean writeEnabled, TaskMonitor monitor) throws IOException, CancelledException {
DataType originalType = functionPointerArrayType;
StringBuilder sb = new StringBuilder();
DataType returnType = fd.getReturnType();
if (writeEnabled) {
this.write(returnType, monitor);
}
sb.append("(");
String arrayDecorations = "";
if (functionPointerArrayType instanceof Array a) {
functionPointerArrayType = this.getArrayBaseType(a);
arrayDecorations = getArrayDimensions(a);
}
if (functionPointerArrayType instanceof Pointer p) {
for (int i = 0; i < this.getPointerDepth(p); ++i) {
sb.append('*');
}
if (name != null) {
sb.append(' ');
}
functionPointerArrayType = this.getPointerBaseDataType(p);
}
if (!(functionPointerArrayType instanceof FunctionDefinition)) {
this.writer.append(this
.comment("Attempting output of invalid function pointer type declaration: " + originalType.getDisplayName()));
}
if (name != null) {
sb.append(name);
}
if (arrayDecorations.length() != 0) {
sb.append(arrayDecorations);
}
sb.append(")");
sb.append(this.getParameterListString(fd, false, writeEnabled, monitor));
DataType baseReturnType = this.getBaseDataType(returnType);
if (baseReturnType instanceof FunctionDefinition) {
return this.getFunctionPointerString((FunctionDefinition) baseReturnType, sb.toString(), returnType, writeEnabled,
monitor);
} else {
String var10000 = returnType.getDisplayName();
return var10000 + " " + sb.toString();
}
}
private String getParameterListString(FunctionDefinition fd, boolean includeParamNames, boolean writeEnabled,
TaskMonitor monitor) throws IOException, CancelledException {
StringBuilder buf = new StringBuilder();
buf.append("(");
boolean hasVarArgs = fd.hasVarArgs();
ParameterDefinition[] parameters = fd.getArguments();
int n = parameters.length;
for (int i = 0; i < n; ++i) {
ParameterDefinition param = parameters[i];
String paramName = includeParamNames ? param.getName() : null;
DataType dataType = param.getDataType();
if (writeEnabled) {
this.write(dataType, monitor);
}
String argument = this.getTypeDeclaration(paramName, dataType, param.getLength(), writeEnabled, monitor);
buf.append(argument);
if (i < n - 1 || hasVarArgs) {
buf.append(", ");
}
}
if (hasVarArgs) {
buf.append("...");
}
if (n == 0 && !hasVarArgs) {
buf.append(VoidDataType.dataType.getName());
}
buf.append(")");
return buf.toString();
}
}