/* Copyright (C) 2004 - 2008 Versant Inc. http://www.db4o.com
This file is part of the sharpen open source java to c# translator.
sharpen is free software; you can redistribute it and/or modify it under
the terms of version 2 of the GNU General Public License as published
by the Free Software Foundation and as clarified by db4objects' GPL
interpretation policy, available at
http://www.db4o.com/about/company/legalpolicies/gplinterpretation/
Alternatively you can write to db4objects, Inc., 1900 S Norfolk Street,
Suite 350, San Mateo, CA 94403, USA.
sharpen is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
package sharpen.core;
import java.util.*;
import org.eclipse.jdt.core.dom.*;
import sharpen.core.framework.BindingUtils;
public abstract class Configuration {
public static class MemberMapping {
public String name;
public MemberKind kind;
public MemberMapping(String name, MemberKind kind) {
this.name = name;
this.kind = kind;
}
@Override
public String toString() {
return "MemberMapping(" + name + ", " + kind + ")";
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof MemberMapping)) return false;
MemberMapping other = (MemberMapping)obj;
return name.equals(other.name) && kind.equals(other.kind);
}
}
public static class NameMapping {
public String from;
public String to;
public NameMapping(String from, String to) {
this.from = from;
this.to = to;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof NameMapping)) return false;
NameMapping other = (NameMapping)obj;
return from.equals(other.from) && to.equals(other.to);
}
}
public enum ConversionStrategy{
RefactorInterfaceWithTypes
}
private static final WarningHandler NULL_WARNING_HANDLER = new WarningHandler();
private Map<String, String> _typeMappings = new HashMap<String, String>();
private Map<String, MemberMapping> _memberMappings = new HashMap<String, MemberMapping>();
private Map<String, String> _systemConvertWellKnownTypes = new HashMap<String, String>();
private List<NameMapping> _namespaceMappings = new ArrayList<NameMapping>();
private Map<ConversionStrategy, List<String>> _strategyScopes = new HashMap<ConversionStrategy, List<String>>();
private WarningHandler _warningHandler = Configuration.NULL_WARNING_HANDLER;
private NamingStrategy _namingStrategy = NamingStrategy.DEFAULT;
private boolean _nativeTypeSystem = false;
private boolean _ignoreErrors = false;
private final String _runtimeTypeName;
private boolean _nativeInterfaces;
private boolean _organizeUsings;
private List<String> _fullyQualifiedTypes = new ArrayList<String>();
private boolean _createProblemMarkers = false;
private String _header = "";
private DocumentationOverlay _docOverlay = NullDocumentationOverlay.DEFAULT;
private final List<String> _removedMethods = new ArrayList<String>();
private final Set<String> _mappedEventAdds = new HashSet<String>();
private final Map<String, String> _mappedEvents = new HashMap<String, String>();
/**
* Maps package names to expressions used in conditional compilation.
* Sub-packages will be considered to match also.
*/
private Map<String, String> _conditionalCompilations = new HashMap<String, String>();
public Configuration(String runtimeTypeName) {
_runtimeTypeName = runtimeTypeName;
}
protected void setUpAnnotationMappings() {
mapType("java.lang.Deprecated", "System.Obsolete");
}
protected void setUpStringMappings() {
mapType("java.lang.StringBuffer", "System.Text.StringBuilder");
mapProperty("java.lang.StringBuffer.length", "Length");
mapMethod("java.lang.StringBuffer.append", "Append");
mapMethod("java.lang.StringBuffer.insert", "Insert");
//"append" is also defined in an interface, and that must be mapped as well
//(so that it works with all JREs):
mapMethod("java.lang.Appendable.append", "Append");
mapMethod("java.lang.AbstractStringBuilder.append", "Append");
mapMethod("java.lang.AbstractStringBuilder.insert", "Insert");
mapMethod("java.lang.StringBuffer.deleteCharAt", runtimeMethod("deleteCharAt"));
mapMethod("java.lang.AbstractStringBuilder.deleteCharAt", runtimeMethod("deleteCharAt"));
mapMethod("java.lang.StringBuffer.setCharAt", runtimeMethod("setCharAt"));
mapMethod("java.lang.AbstractStringBuilder.setCharAt", runtimeMethod("setCharAt"));
mapProperty("java.lang.StringBuffer.setLength", "Length");
mapProperty("java.lang.AbstractStringBuilder.setLength", "Length");
mapMethod("java.lang.String.intern", "string.Intern");
mapMethod("java.lang.String.indexOf", "IndexOf");
mapMethod("java.lang.String.lastIndexOf", "LastIndexOf");
mapMethod("java.lang.String.trim", "Trim");
mapMethod("java.lang.String.toUpperCase", "ToUpper");
mapMethod("java.lang.String.toLowerCase", "ToLower");
mapMethod("java.lang.String.compareTo", "CompareTo");
mapMethod("java.lang.Comparable.compareTo(java.lang.String)", runtimeMethod("CompareOrdinal"));
mapMethod("java.lang.String.toCharArray", "ToCharArray");
mapMethod("java.lang.String.replace", "Replace");
mapMethod("java.lang.String.startsWith", "StartsWith");
mapMethod("java.lang.String.endsWith", "EndsWith");
mapMethod("java.lang.String.substring", runtimeMethod("substring"));
mapIndexer("java.lang.String.charAt");
mapIndexer("java.lang.CharSequence.charAt");
mapMethod("java.lang.String.getChars", runtimeMethod("getCharsForString"));
mapMethod("java.lang.String.getBytes", runtimeMethod("getBytesForString"));
mapMethod("java.lang.String.equalsIgnoreCase", runtimeMethod("equalsIgnoreCase"));
mapMethod("java.lang.String.valueOf", runtimeMethod("getStringValueOf"));
mapMethod("java.lang.String.String(byte[],int,int)", runtimeMethod("getStringForBytes"));
mapProperty("java.lang.String.length", "Length");
mapProperty("java.lang.CharSequence.length", "Length");
}
protected void setUpIoMappings() {
mapProperty("java.lang.System.out", "System.Console.Out");
mapProperty("java.lang.System.err", "System.Console.Error");
mapType("java.io.PrintStream", "System.IO.TextWriter");
mapType("java.io.Writer", "System.IO.TextWriter");
mapMethod("java.io.Writer.flush", "Flush");
mapType("java.io.StringWriter", "System.IO.StringWriter");
mapMethod("java.io.PrintStream.print", "Write");
mapMethod("java.io.PrintStream.println", "WriteLine");
}
protected String collectionRuntimeMethod(String methodName) {
return collectionRuntimeType() + "." + methodName;
}
private String collectionRuntimeType() {
return runtimeTypeNamespace() + ".Collections";
}
private String runtimeTypeNamespace() {
return _runtimeTypeName.substring(0, _runtimeTypeName.lastIndexOf('.'));
}
protected String runtimeMethod(String methodName) {
return _runtimeTypeName + "." + methodName;
}
protected void mapPrimitive(String typeName) {
mapType(typeName, typeName);
}
public String getRuntimeTypeName() {
return _runtimeTypeName;
}
public void setDocumentationOverlay(DocumentationOverlay docOverlay) {
if (null == docOverlay) throw new IllegalArgumentException("docOverlay");
_docOverlay = docOverlay;
}
public DocumentationOverlay documentationOverlay() {
return _docOverlay;
}
public void enableNativeTypeSystem() {
_nativeTypeSystem = true;
mapType("java.lang.ClassNotFoundException", "System.TypeLoadException");
mapType("java.lang.reflect.InvocationTargetException", "System.Reflection.TargetInvocationException");
mapProperty("java.lang.reflect.InvocationTargetException.getTargetException", "InnerException");
mapType("java.lang.IllegalAccessException", "System.MemberAccessException");
// mapType("java.lang.reflect.Array", "System.Array");
mapMethod("java.lang.reflect.Array.getLength", runtimeMethod("GetArrayLength"));
mapMethod("java.lang.reflect.Array.get", runtimeMethod("GetArrayValue"));
mapMethod("java.lang.reflect.Array.set", runtimeMethod("SetArrayValue"));
mapMethod("java.lang.reflect.Array.newInstance", "System.Array.CreateInstance");
mapMethod("java.lang.Object.getClass", "GetType");
mapType("java.lang.Class", "System.Type");
mapType("java.lang.Class<>", "System.Type");
mapJavaLangClassProperty("getName", "FullName");
mapJavaLangClassProperty("getSuperclass", "BaseType");
mapJavaLangClassProperty("isArray", "IsArray");
mapJavaLangClassProperty("isPrimitive", "IsPrimitive");
mapJavaLangClassProperty("isInterface", "IsInterface");
mapJavaLangClassMethod("isInstance", "IsInstanceOfType");
mapJavaLangClassMethod("newInstance", "System.Activator.CreateInstance");
mapJavaLangClassMethod("forName", runtimeMethod("GetType"));
mapJavaLangClassMethod("getComponentType", "GetElementType");
mapJavaLangClassMethod("getField", "GetField");
mapJavaLangClassMethod("getFields", "GetFields");
mapJavaLangClassMethod("getDeclaredField", runtimeMethod("GetDeclaredField"));
mapJavaLangClassMethod("getDeclaredFields", runtimeMethod("GetDeclaredFields"));
mapJavaLangClassMethod("getDeclaredMethod", runtimeMethod("GetDeclaredMethod"));
mapJavaLangClassMethod("getDeclaredMethods", runtimeMethod("GetDeclaredMethods"));
mapJavaLangClassMethod("isAssignableFrom", "IsAssignableFrom");
mapProperty("java.lang.reflect.Member.getName", "Name");
mapProperty("java.lang.reflect.Member.getDeclaringClass", "DeclaringType");
mapType("java.lang.reflect.Field", "System.Reflection.FieldInfo");
mapProperty("java.lang.reflect.Field.getName", "Name");
mapMethod("java.lang.reflect.Field.get", "GetValue");
mapMethod("java.lang.reflect.Field.set", "SetValue");
mapType("java.lang.reflect.Method", "System.Reflection.MethodInfo");
mapProperty("java.lang.reflect.Method.getName", "Name");
mapProperty("java.lang.reflect.Method.getReturnType", "ReturnType");
mapMethod("java.lang.reflect.Method.getParameterTypes", runtimeMethod("GetParameterTypes"));
removeMethod("java.lang.reflect.AccessibleObject.setAccessible");
mapType("java.lang.reflect.Constructor", "System.Reflection.ConstructorInfo");
mapType("java.text.DecimalFormat", "Sharpen.Text.DecimalFormat");
mapMethod("java.lang.String.valueOf", "ToString");
}
private void mapJavaLangClassProperty(String methodName, String propertyName) {
mapProperty("java.lang.Class." + methodName, propertyName);
}
private void mapJavaLangClassMethod(String methodName, String newMethodName) {
mapMethod("java.lang.Class." + methodName, newMethodName);
}
public boolean nativeTypeSystem() {
return _nativeTypeSystem;
}
public void setWarningHandler(WarningHandler warningHandler) {
_warningHandler = warningHandler;
}
public WarningHandler getWarningHandler() {
return _warningHandler;
}
public void setNamingStrategy(NamingStrategy namingStrategy) {
_namingStrategy = namingStrategy;
}
public NamingStrategy getNamingStrategy() {
return _namingStrategy;
}
public void mapNamespace(String fromRegex, String to) {
_namespaceMappings.add(new NameMapping(fromRegex, to));
}
public void mapNamespaces(List<NameMapping> namespaceMappings) {
_namespaceMappings.addAll(namespaceMappings);
}
public void mapMembers(Map<String, MemberMapping> memberMappings) {
_memberMappings.putAll(memberMappings);
}
public String mappedNamespace(String namespace) {
String mapped = applyNamespaceMappings(namespace + ".");
return _namingStrategy.namespace(mapped.substring(0, mapped.length()-1));
}
public String mappedTypeName(String typeName, String defaultValue) {
String mappedName = _typeMappings.get(typeName);
return (null != mappedName)
? mappedName
: mappedNamespace(defaultValue);
}
private String applyNamespaceMappings(String typeName) {
for (NameMapping mapping : _namespaceMappings) {
typeName = typeName.replaceFirst(mapping.from + "\\.", mapping.to + ".");
}
return typeName;
}
public MemberMapping mappedMember(String qualifiedName) {
return _memberMappings.get(qualifiedName);
}
public String getConvertRelatedWellKnownTypeName(String mappedConstructor) {
return _systemConvertWellKnownTypes.get(mappedConstructor);
}
public void mapType(String from, String to) {
_typeMappings.put(from, to);
}
public boolean typeHasMapping(String type) {
return _typeMappings.containsKey(type);
}
public void mapField(String fromQualifiedName, String to) {
mapMember(fromQualifiedName, new MemberMapping(to, MemberKind.Field));
}
public void mapMethod(String fromQualifiedName, String to) {
mapMember(fromQualifiedName, new MemberMapping(to, MemberKind.Method));
}
public void mapIndexer(String fromQualifiedName) {
mapMember(fromQualifiedName, new MemberMapping(null, MemberKind.Indexer));
}
public void mapProperty(String fromQualifiedName, String to) {
mapMember(fromQualifiedName, new MemberMapping(to, MemberKind.Property));
}
public void setIgnoreErrors(boolean value) {
_ignoreErrors = value;
}
public boolean getIgnoreErrors() {
return _ignoreErrors;
}
void mapMember(String fromQualifiedName, MemberMapping mapping) {
_memberMappings.put(fromQualifiedName, mapping);
}
protected void mapWrapperConstructor(String from, String to, String wellKnownTypeName) {
mapMethod(from, to);
_systemConvertWellKnownTypes.put(to, wellKnownTypeName);
}
public void addStrategyScope(ConversionStrategy cs, String qualifiedScope){
if(_strategyScopes.containsKey(cs)){
_strategyScopes.get(cs).add(qualifiedScope);
}
else{
List<String> list = new ArrayList<String>();
list.add(qualifiedScope);
_strategyScopes.put(cs, list);
}
}
public boolean shouldApplyConversionStrategy(ConversionStrategy cs, ASTNode node){
ASTNode currentNode = node;
String qualifiedName = "";
while(currentNode != null && qualifiedName == ""){
if(node instanceof AbstractTypeDeclaration){
qualifiedName = BindingUtils.qualifiedName(((AbstractTypeDeclaration)node).resolveBinding());
}
else if(node instanceof PackageDeclaration){
qualifiedName = ((PackageDeclaration)node).resolveBinding().getName();
}
else if(node instanceof MethodDeclaration){
qualifiedName = BindingUtils.qualifiedName(((MethodDeclaration)node).resolveBinding());
}
else if(node instanceof VariableDeclaration){
qualifiedName = BindingUtils.qualifiedName(((VariableDeclaration)node).resolveBinding());
}
currentNode = currentNode.getParent();
}
return shouldApplyConversionStrategy(cs, qualifiedName);
}
public boolean shouldApplyConversionStrategy(ConversionStrategy cs, String qualifiedName){
if(!_strategyScopes.containsKey(cs)){
return false;
}
List<String> scopes = _strategyScopes.get(cs);
if(scopes.contains(".")){
return true;
}
for(String s : scopes){
if(qualifiedName.startsWith(s)){
return true;
}
}
return false;
}
public boolean nativeInterfaces() {
return _nativeInterfaces;
}
public void enableNativeInterfaces() {
_nativeInterfaces = true;
}
public void enableOrganizeUsings() {
_organizeUsings = true;
}
public boolean organizeUsings() {
return _organizeUsings;
}
public void addFullyQualifiedTypeName(String name) {
_fullyQualifiedTypes.add(name);
}
public boolean shouldFullyQualifyTypeName(String name) {
//if a type is configured to be fully qualified,
//then also nested types of it need to be fully qualified
for( String s : _fullyQualifiedTypes ) {
if( name.equals(s) || name.startsWith(s + ".") ) {
return true;
}
}
return false;
}
public void setCreateProblemMarkers(boolean value) {
_createProblemMarkers = value;
}
public boolean createProblemMarkers() {
return _createProblemMarkers;
}
public void setHeader(String header) {
if (null == header) throw new IllegalArgumentException("header");
_header = header;
}
public String header() {
return _header;
}
public void removeMethod(String fullyQualifiedName) {
_removedMethods.add(fullyQualifiedName);
}
public boolean isRemoved(String qualifiedName) {
return _removedMethods.contains(qualifiedName);
}
public void mapEventAdd(String qualifiedMethodName) {
_mappedEventAdds.add(qualifiedMethodName);
}
public boolean isMappedEventAdd(String qualifiedMethodName) {
return _mappedEventAdds.contains(qualifiedMethodName);
}
public void mapEvent(String qualifiedMethodName, String eventArgsTypeName) {
mapProperty(qualifiedMethodName, unqualify(qualifiedMethodName));
_mappedEvents.put(qualifiedMethodName, eventArgsTypeName);
}
public String mappedEvent(String qualifiedMethodName) {
return _mappedEvents.get(qualifiedMethodName);
}
private String unqualify(String qualifiedMethodName) {
final int lastDot = qualifiedMethodName.lastIndexOf('.');
return lastDot == -1
? qualifiedMethodName
: qualifiedMethodName.substring(lastDot+1);
}
public void mapEventAdds(Iterable<String> eventAddMappings) {
for (String m : eventAddMappings) {
mapEventAdd(m);
}
}
public void mapEvents(Iterable<NameMapping> eventMappings) {
for (NameMapping m : eventMappings) {
mapEvent(m.from, m.to);
}
}
public boolean isIgnoredAnnotation(String typeName) {
return typeName.equals("java.lang.Override");
}
public void conditionalCompilation(Map<String, String> conditionalCompilation) {
_conditionalCompilations = conditionalCompilation;
}
public String conditionalCompilationExpressionFor(String packageName) {
for(String current : _conditionalCompilations.keySet()) {
if (isSubPackage(current, packageName)) {
return _conditionalCompilations.get(current);
}
}
return null;
}
private boolean isSubPackage(String parentPackage, String packageName) {
return packageName.startsWith(parentPackage);
}
public String toInterfaceName(String name) {
if (!nativeInterfaces()) {
return name;
}
return "I" + name;
}
public abstract boolean isIgnoredExceptionType(String exceptionType);
public boolean mapProtectedToProtectedInternal() {
return false;
}
public abstract boolean mapByteToSbyte();
}