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.*; 025 import org.jetbrains.jet.lang.descriptors.*; 026 import org.jetbrains.jet.lang.resolve.name.FqName; 027 import org.jetbrains.jet.lang.resolve.name.Name; 028 029 import java.util.Arrays; 030 031 public class JavaSerializerExtension extends SerializerExtension { 032 private final MemberMap memberMap; 033 034 public JavaSerializerExtension(@NotNull MemberMap memberMap) { 035 this.memberMap = memberMap; 036 } 037 038 @Override 039 public void serializeCallable( 040 @NotNull CallableMemberDescriptor callable, 041 @NotNull ProtoBuf.Callable.Builder proto, 042 @NotNull NameTable nameTable 043 ) { 044 saveSignature(callable, proto, nameTable); 045 saveSrcClassName(callable, proto, nameTable); 046 } 047 048 private void saveSignature( 049 @NotNull CallableMemberDescriptor callable, 050 @NotNull ProtoBuf.Callable.Builder proto, 051 @NotNull NameTable nameTable 052 ) { 053 if (callable instanceof FunctionDescriptor) { 054 Method method = memberMap.getMethodOfDescriptor((FunctionDescriptor) callable); 055 if (method != null) { 056 proto.setExtension(JavaProtoBuf.methodSignature, new SignatureSerializer(nameTable).methodSignature(method)); 057 } 058 } 059 else if (callable instanceof PropertyDescriptor) { 060 PropertyDescriptor property = (PropertyDescriptor) callable; 061 062 PropertyGetterDescriptor getter = property.getGetter(); 063 PropertySetterDescriptor setter = property.getSetter(); 064 Method getterMethod = getter == null ? null : memberMap.getMethodOfDescriptor(getter); 065 Method setterMethod = setter == null ? null : memberMap.getMethodOfDescriptor(setter); 066 067 Pair<Type, String> field = memberMap.getFieldOfProperty(property); 068 Type fieldType; 069 String fieldName; 070 boolean isStaticInOuter; 071 String syntheticMethodName; 072 if (field != null) { 073 fieldType = field.first; 074 fieldName = field.second; 075 isStaticInOuter = memberMap.isStaticFieldInOuterClass(property); 076 syntheticMethodName = null; 077 } 078 else { 079 fieldType = null; 080 fieldName = null; 081 isStaticInOuter = false; 082 syntheticMethodName = memberMap.getSyntheticMethodNameOfProperty(property); 083 } 084 085 JavaProtoBuf.JavaPropertySignature signature = new SignatureSerializer(nameTable) 086 .propertySignature(fieldType, fieldName, isStaticInOuter, syntheticMethodName, getterMethod, setterMethod); 087 proto.setExtension(JavaProtoBuf.propertySignature, signature); 088 } 089 } 090 091 private void saveSrcClassName( 092 @NotNull CallableMemberDescriptor callable, 093 @NotNull ProtoBuf.Callable.Builder proto, 094 @NotNull NameTable nameTable 095 ) { 096 Name name = memberMap.getSrcClassNameOfCallable(callable); 097 if (name != null) { 098 proto.setExtension(JavaProtoBuf.srcClassName, nameTable.getSimpleNameIndex(name)); 099 } 100 } 101 102 private static class SignatureSerializer { 103 private final NameTable nameTable; 104 105 public SignatureSerializer(@NotNull NameTable nameTable) { 106 this.nameTable = nameTable; 107 } 108 109 @NotNull 110 public JavaProtoBuf.JavaMethodSignature methodSignature(@NotNull Method method) { 111 JavaProtoBuf.JavaMethodSignature.Builder signature = JavaProtoBuf.JavaMethodSignature.newBuilder(); 112 113 signature.setName(nameTable.getSimpleNameIndex(Name.guess(method.getName()))); 114 115 signature.setReturnType(type(method.getReturnType())); 116 117 for (Type type : method.getArgumentTypes()) { 118 signature.addParameterType(type(type)); 119 } 120 121 return signature.build(); 122 } 123 124 @NotNull 125 public JavaProtoBuf.JavaPropertySignature propertySignature( 126 @Nullable Type fieldType, 127 @Nullable String fieldName, 128 boolean isStaticInOuter, 129 @Nullable String syntheticMethodName, 130 @Nullable Method getter, 131 @Nullable Method setter 132 ) { 133 JavaProtoBuf.JavaPropertySignature.Builder signature = JavaProtoBuf.JavaPropertySignature.newBuilder(); 134 135 if (fieldType != null) { 136 assert fieldName != null : "Field name shouldn't be null when there's a field type: " + fieldType; 137 signature.setField(fieldSignature(fieldType, fieldName, isStaticInOuter)); 138 } 139 140 if (syntheticMethodName != null) { 141 signature.setSyntheticMethodName(nameTable.getSimpleNameIndex(Name.guess(syntheticMethodName))); 142 } 143 144 if (getter != null) { 145 signature.setGetter(methodSignature(getter)); 146 } 147 if (setter != null) { 148 signature.setSetter(methodSignature(setter)); 149 } 150 151 return signature.build(); 152 } 153 154 @NotNull 155 public JavaProtoBuf.JavaFieldSignature fieldSignature(@NotNull Type type, @NotNull String name, boolean isStaticInOuter) { 156 JavaProtoBuf.JavaFieldSignature.Builder signature = JavaProtoBuf.JavaFieldSignature.newBuilder(); 157 signature.setName(nameTable.getSimpleNameIndex(Name.guess(name))); 158 signature.setType(type(type)); 159 if (isStaticInOuter) { 160 signature.setIsStaticInOuter(true); 161 } 162 return signature.build(); 163 } 164 165 @NotNull 166 public JavaProtoBuf.JavaType type(@NotNull Type givenType) { 167 JavaProtoBuf.JavaType.Builder builder = JavaProtoBuf.JavaType.newBuilder(); 168 169 int arrayDimension = 0; 170 Type type = givenType; 171 while (type.getSort() == Type.ARRAY) { 172 arrayDimension++; 173 type = type.getElementType(); 174 } 175 if (arrayDimension != 0) { 176 builder.setArrayDimension(arrayDimension); 177 } 178 179 if (type.getSort() == Type.OBJECT) { 180 FqName fqName = internalNameToFqName(type.getInternalName()); 181 builder.setClassFqName(nameTable.getFqNameIndex(fqName)); 182 } 183 else { 184 builder.setPrimitiveType(JavaProtoBuf.JavaType.PrimitiveType.valueOf(type.getSort())); 185 } 186 187 return builder.build(); 188 } 189 190 @NotNull 191 private static FqName internalNameToFqName(@NotNull String internalName) { 192 return FqName.fromSegments(Arrays.asList(internalName.split("/"))); 193 } 194 } 195 }