001 /* 002 * Copyright 2010-2013 JetBrains s.r.o. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017 package org.jetbrains.jet.codegen; 018 019 import com.intellij.openapi.util.Pair; 020 import org.jetbrains.annotations.NotNull; 021 import org.jetbrains.annotations.Nullable; 022 import org.jetbrains.asm4.Type; 023 import org.jetbrains.asm4.commons.Method; 024 import org.jetbrains.jet.descriptors.serialization.JavaProtoBuf; 025 import org.jetbrains.jet.descriptors.serialization.NameTable; 026 import org.jetbrains.jet.descriptors.serialization.ProtoBuf; 027 import org.jetbrains.jet.descriptors.serialization.SerializerExtension; 028 import org.jetbrains.jet.lang.descriptors.*; 029 import org.jetbrains.jet.lang.resolve.name.FqName; 030 import org.jetbrains.jet.lang.resolve.name.Name; 031 032 import java.util.Arrays; 033 034 public class JavaSerializerExtension extends SerializerExtension { 035 private final MemberMap memberMap; 036 037 public JavaSerializerExtension(@NotNull MemberMap memberMap) { 038 this.memberMap = memberMap; 039 } 040 041 @Override 042 public void serializeCallable( 043 @NotNull CallableMemberDescriptor callable, 044 @NotNull ProtoBuf.Callable.Builder proto, 045 @NotNull NameTable nameTable 046 ) { 047 saveSignature(callable, proto, nameTable); 048 saveImplClassName(callable, proto, nameTable); 049 } 050 051 private void saveSignature( 052 @NotNull CallableMemberDescriptor callable, 053 @NotNull ProtoBuf.Callable.Builder proto, 054 @NotNull NameTable nameTable 055 ) { 056 if (callable instanceof FunctionDescriptor) { 057 Method method = memberMap.getMethodOfDescriptor((FunctionDescriptor) callable); 058 if (method != null) { 059 proto.setExtension(JavaProtoBuf.methodSignature, new SignatureSerializer(nameTable).methodSignature(method)); 060 } 061 } 062 else if (callable instanceof PropertyDescriptor) { 063 PropertyDescriptor property = (PropertyDescriptor) callable; 064 065 PropertyGetterDescriptor getter = property.getGetter(); 066 PropertySetterDescriptor setter = property.getSetter(); 067 Method getterMethod = getter == null ? null : memberMap.getMethodOfDescriptor(getter); 068 Method setterMethod = setter == null ? null : memberMap.getMethodOfDescriptor(setter); 069 070 Pair<Type, String> field = memberMap.getFieldOfProperty(property); 071 Type fieldType; 072 String fieldName; 073 boolean isStaticInOuter; 074 Method syntheticMethod; 075 if (field != null) { 076 fieldType = field.first; 077 fieldName = field.second; 078 isStaticInOuter = memberMap.isStaticFieldInOuterClass(property); 079 syntheticMethod = null; 080 } 081 else { 082 fieldType = null; 083 fieldName = null; 084 isStaticInOuter = false; 085 syntheticMethod = memberMap.getSyntheticMethodOfProperty(property); 086 } 087 088 JavaProtoBuf.JavaPropertySignature signature = new SignatureSerializer(nameTable) 089 .propertySignature(fieldType, fieldName, isStaticInOuter, syntheticMethod, getterMethod, setterMethod); 090 proto.setExtension(JavaProtoBuf.propertySignature, signature); 091 } 092 } 093 094 private void saveImplClassName( 095 @NotNull CallableMemberDescriptor callable, 096 @NotNull ProtoBuf.Callable.Builder proto, 097 @NotNull NameTable nameTable 098 ) { 099 String name = memberMap.getImplClassNameOfCallable(callable); 100 if (name != null) { 101 proto.setExtension(JavaProtoBuf.implClassName, nameTable.getSimpleNameIndex(Name.identifier(name))); 102 } 103 } 104 105 private static class SignatureSerializer { 106 private final NameTable nameTable; 107 108 public SignatureSerializer(@NotNull NameTable nameTable) { 109 this.nameTable = nameTable; 110 } 111 112 @NotNull 113 public JavaProtoBuf.JavaMethodSignature methodSignature(@NotNull Method method) { 114 JavaProtoBuf.JavaMethodSignature.Builder signature = JavaProtoBuf.JavaMethodSignature.newBuilder(); 115 116 signature.setName(nameTable.getSimpleNameIndex(Name.guess(method.getName()))); 117 118 signature.setReturnType(type(method.getReturnType())); 119 120 for (Type type : method.getArgumentTypes()) { 121 signature.addParameterType(type(type)); 122 } 123 124 return signature.build(); 125 } 126 127 @NotNull 128 public JavaProtoBuf.JavaPropertySignature propertySignature( 129 @Nullable Type fieldType, 130 @Nullable String fieldName, 131 boolean isStaticInOuter, 132 @Nullable Method syntheticMethod, 133 @Nullable Method getter, 134 @Nullable Method setter 135 ) { 136 JavaProtoBuf.JavaPropertySignature.Builder signature = JavaProtoBuf.JavaPropertySignature.newBuilder(); 137 138 if (fieldType != null) { 139 assert fieldName != null : "Field name shouldn't be null when there's a field type: " + fieldType; 140 signature.setField(fieldSignature(fieldType, fieldName, isStaticInOuter)); 141 } 142 143 if (syntheticMethod != null) { 144 signature.setSyntheticMethod(methodSignature(syntheticMethod)); 145 } 146 147 if (getter != null) { 148 signature.setGetter(methodSignature(getter)); 149 } 150 if (setter != null) { 151 signature.setSetter(methodSignature(setter)); 152 } 153 154 return signature.build(); 155 } 156 157 @NotNull 158 public JavaProtoBuf.JavaFieldSignature fieldSignature(@NotNull Type type, @NotNull String name, boolean isStaticInOuter) { 159 JavaProtoBuf.JavaFieldSignature.Builder signature = JavaProtoBuf.JavaFieldSignature.newBuilder(); 160 signature.setName(nameTable.getSimpleNameIndex(Name.guess(name))); 161 signature.setType(type(type)); 162 if (isStaticInOuter) { 163 signature.setIsStaticInOuter(true); 164 } 165 return signature.build(); 166 } 167 168 @NotNull 169 public JavaProtoBuf.JavaType type(@NotNull Type givenType) { 170 JavaProtoBuf.JavaType.Builder builder = JavaProtoBuf.JavaType.newBuilder(); 171 172 int arrayDimension = 0; 173 Type type = givenType; 174 while (type.getSort() == Type.ARRAY) { 175 arrayDimension++; 176 type = type.getElementType(); 177 } 178 if (arrayDimension != 0) { 179 builder.setArrayDimension(arrayDimension); 180 } 181 182 if (type.getSort() == Type.OBJECT) { 183 FqName fqName = internalNameToFqName(type.getInternalName()); 184 builder.setClassFqName(nameTable.getFqNameIndex(fqName)); 185 } 186 else { 187 builder.setPrimitiveType(JavaProtoBuf.JavaType.PrimitiveType.valueOf(type.getSort())); 188 } 189 190 return builder.build(); 191 } 192 193 @NotNull 194 private static FqName internalNameToFqName(@NotNull String internalName) { 195 return FqName.fromSegments(Arrays.asList(internalName.split("/"))); 196 } 197 } 198 }