/* Copyright (C) 2009 Versant Inc. http://www.db4o.com */ package sharpen.core.internal; import static sharpen.core.framework.Environments.my; import org.eclipse.jdt.core.dom.*; import sharpen.core.*; import sharpen.core.Configuration.MemberMapping; import sharpen.core.csharp.ast.CSCompilationUnit; import sharpen.core.csharp.ast.CSUsing; import sharpen.core.framework.BindingUtils; import sharpen.core.framework.CSharpDriver; import sharpen.core.framework.JavadocUtility; import java.util.ArrayList; import java.util.List; public class MappingsImpl implements Mappings { private final List<String> _namespaces = new ArrayList<String>(); private final Configuration _configuration = my(Configuration.class); private final CSCompilationUnit _compilationUnit = my(CSCompilationUnit.class); private final NameScope _nameScope = my(NameScope.class); private final Annotations _annotations = my(Annotations.class); private final Bindings _bindings = my(Bindings.class); private final PreserveFullyQualifiedNamesState _preserveFQNState = my(PreserveFullyQualifiedNamesState.class); public String mappedFieldName(IVariableBinding binding) { if (!binding.isField()) return null; String mapped = my(CSharpDriver.class).mappedVariableName(binding); if (mapped != null) return mapped; String qualifiedName = BindingUtils.qualifiedName(binding); Configuration.MemberMapping renaming = _configuration.renamedMember(qualifiedName, MemberKind.Field); if (renaming != null) return renaming.name; Configuration.MemberMapping mapping = _configuration.mappedMember(qualifiedName); if (mapping != null) return mapping.name; ITypeBinding declaringType = binding.getDeclaringClass(); if ((declaringType != null) && declaringType.isInterface()) { final String extracted = extractedInterfaceName(declaringType); return extracted + "." + identifier(binding.getName()); } if ((declaringType != null) && declaringType.getTypeDeclaration().isGenericType()) { if (binding.getConstantValue() == null) return null; final String declaringName = mappedTypeName(declaringType.getTypeDeclaration()); return declaringName + "." + identifier(binding.getName()); } return null; } public String mappedMethodName(IMethodBinding binding) { Configuration.MemberMapping mapping = effectiveMappingFor(binding); return computeMethodName(binding, mapping); } public String mappedTypeName(ITypeBinding type) { if (type.isArray() || type.isWildcardType()) { return type.getQualifiedName(); } if (!hasMapping(type)) { String annotatedRenaming = annotatedRenaming(type); if (annotatedRenaming != null) { return registerMappedType(type, fullyQualifyIfNeeded(annotatedRenaming, type)); } ITypeBinding declaringType = type.getDeclaringClass(); if (type.isNested() && declaringType.isInterface()) { final String extracted = extractedInterfaceName(declaringType); return registerMappedType(type, extracted + "." + identifier(type.getName())); } if (type.isNested() && declaringType.getTypeDeclaration().isGenericType()) { if (type.isInterface() || (type.isClass() && Modifier.isStatic(type.getModifiers()))) { final String rawName = mappedTypeName(declaringType.getTypeDeclaration()); return registerMappedType(type, rawName + "." + identifier(type.getName())); } } } String mappedTypeName = mappedTypeName(BindingUtils.typeMappingKey(type), qualifiedName(type)); if (mappedTypeName.length() == 0) mappedTypeName = "_T" + Math.abs(type.getKey().hashCode()); if (shouldPrefixInterface(type)) { return registerMappedType(type, mappedInterfaceName(mappedTypeName)); } return registerMappedType(type, mappedTypeName); } public String extractedInterfaceName(ITypeBinding type) { if (!type.isInterface()) throw new IllegalArgumentException(); final String mappedTypeName = mappedTypeName(type); if (hasMapping(type)) return mappedTypeName; return mappedTypeName + "Class"; } private String fullyQualifyIfNeeded(String typeName, ITypeBinding type) { if (isFullyQualified(typeName)) { return typeName; } final String originalNamespace = namespace(qualifiedName(type)); final String mappedNamespace = _configuration.mappedNamespace(originalNamespace); if (originalNamespace.equals(mappedNamespace)) { return typeName; } return mappedNamespace + "." + typeName; } private String namespace(final String typeName) { return substringBeforeLast(typeName, '.'); } private String substringBeforeLast(String s, char marker) { return s.substring(0, s.lastIndexOf(marker)); } private boolean isFullyQualified(String typeName) { return typeName.contains("."); } private String annotatedRenaming(ITypeBinding type) { if (type.isTypeVariable()) return null; final ASTNode node = findDeclaringNode(type); AbstractTypeDeclaration typeDeclaration = node instanceof AbstractTypeDeclaration ? (AbstractTypeDeclaration) node: null; return (typeDeclaration != null && isAnnotatedWith(typeDeclaration, SharpenAnnotations.SHARPEN_RENAME)) ? annotatedRenaming(typeDeclaration) : null; } private boolean shouldPrefixInterface(ITypeBinding type) { return _configuration.nativeInterfaces() && type.isInterface() && !type.isAnnotation() && !hasMapping(type); } private String registerMappedType(ITypeBinding type, String fullName) { if (_preserveFQNState.value()) return fullName; if (!_configuration.organizeUsings()) return fullName; int pos = fullName.lastIndexOf("."); if (pos == -1) return fullName; if (!hasMapping(type)) { pos = nameSpaceLength(type, fullName, pos); } String namespace = fullName.substring(0, pos); registerNamespace(namespace); String name = fullName.substring(pos + 1); if (keepFullyQualified(name)) return fullName; _compilationUnit.addUsing(new CSUsing(namespace)); return name; } private int nameSpaceLength(ITypeBinding type, String fullName, int pos) { while (type.isNested()) { pos = fullName.lastIndexOf(".", pos - 1); type = type.getDeclaringClass(); } return pos; } private boolean keepFullyQualified(String name) { return _configuration.shouldFullyQualifyTypeName(name) || _namespaces.contains(name) || _nameScope.contains(name); } private void registerNamespace(String namespace) { if (_namespaces.contains(namespace)) return; int pos = namespace.lastIndexOf("."); if (pos == -1) { _namespaces.add(namespace); return; } _namespaces.add(namespace.substring(pos + 1)); registerNamespace(namespace.substring(0, pos)); } private boolean hasMapping(ITypeBinding type) { return _configuration.typeHasMapping(BindingUtils.typeMappingKey(type)); } private String mappedInterfaceName(String name) { int pos = name.lastIndexOf('.'); return name.substring(0, pos) + "." + interfaceName(name.substring(pos + 1)); } private String interfaceName(String name) { return _configuration.toInterfaceName(name); } public Configuration.MemberMapping effectiveMappingFor(final IMethodBinding binding) { return configuredMappingFor(binding); } private String annotatedRenaming(BodyDeclaration method) { return _annotations.annotatedRenaming(method); } private <T extends ASTNode> T findDeclaringNode(IBinding binding) { return (T) _bindings.findDeclaringNode(binding); } private boolean isAnnotatedWith(final BodyDeclaration node, final String annotation) { return JavadocUtility.containsJavadoc(node, annotation); } private Configuration.MemberMapping configuredMappingFor(final IMethodBinding binding) { final IMethodBinding actual = originalMethodBinding(binding); final MemberMapping customMapping = my(CSharpDriver.class).mappedMethod(binding); if (customMapping != null) return customMapping; final MemberMapping mapping = _configuration.mappedMember(BindingUtils.qualifiedSignature(actual)); if (null != mapping) return mapping; return _configuration.mappedMember(qualifiedName(actual)); } private String qualifiedName(IMethodBinding actual) { return BindingUtils.qualifiedName(actual); } private String qualifiedName(ITypeBinding type) { return BindingUtils.qualifiedName(type); } private String computeMethodName(IMethodBinding binding, Configuration.MemberMapping mapping) { if (isStaticVoidMain(binding)) return "Main"; String name = isNameMapping(mapping) ? mapping.name : binding.getName(); return methodName(name); } private boolean isStaticVoidMain(IMethodBinding binding) { return isStatic(binding) && "main".equals(binding.getName()); } private boolean isStatic(IMethodBinding binding) { return Modifier.isStatic(binding.getModifiers()); } private boolean isNameMapping(Configuration.MemberMapping mapping) { return null != mapping && null != mapping.name; } private String methodName(String name) { return _configuration.getNamingStrategy().methodName(name); } private String identifier(String name) { return _configuration.getNamingStrategy().identifier(name); } private IMethodBinding originalMethodBinding(IMethodBinding binding) { return _bindings.originalBindingFor(binding); } private String mappedTypeName(String typeName, String defaultValue) { return _configuration.mappedTypeName(typeName, defaultValue); } }