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 017package org.jetbrains.jet.lang.resolve.java.wrapper; 018 019import com.google.common.collect.Lists; 020import com.intellij.openapi.util.Pair; 021import com.intellij.psi.PsiClass; 022import com.intellij.psi.PsiMember; 023import org.jetbrains.annotations.NotNull; 024import org.jetbrains.annotations.Nullable; 025import org.jetbrains.jet.lang.resolve.java.JvmAbi; 026import org.jetbrains.jet.lang.resolve.java.TypeSource; 027 028import java.util.Collection; 029import java.util.HashMap; 030import java.util.List; 031import java.util.Map; 032 033 034/* 035* Data from PSI related to one property used to resolve this property. 036*/ 037public final class PropertyPsiData { 038 039 @NotNull 040 public static Collection<PropertyPsiData> assemblePropertyPsiDataFromElements(@NotNull List<PropertyPsiDataElement> elements) { 041 Map<String, PropertyPsiData> map = new HashMap<String, PropertyPsiData>(); 042 for (PropertyPsiDataElement element : elements) { 043 String key = propertyKeyForGrouping(element); 044 045 PropertyPsiData value = map.get(key); 046 if (value == null) { 047 value = new PropertyPsiData(); 048 map.put(key, value); 049 } 050 051 if (element.isGetter()) { 052 checkDuplicatePropertyComponent(element, "getter", value.getter); 053 value.getter = element; 054 } 055 else if (element.isSetter()) { 056 checkDuplicatePropertyComponent(element, "setter", value.setter); 057 value.setter = element; 058 } 059 else if (element.isField()) { 060 checkDuplicatePropertyComponent(element, "field", value.field); 061 value.field = element; 062 } 063 else { 064 throw new IllegalStateException(); 065 } 066 } 067 068 return map.values(); 069 } 070 071 private static void checkDuplicatePropertyComponent( 072 @NotNull PropertyPsiDataElement checked, @NotNull String componentTypeName, @Nullable PropertyPsiDataElement existent) { 073 if (existent != null) { 074 PsiClass checkedElementClass = checked.getMember().getPsiMember().getContainingClass(); 075 PsiClass existentElementClass = existent.getMember().getPsiMember().getContainingClass(); 076 077 throw new IllegalStateException( 078 String.format("Psi element '%s' in class '%s' overwrites '%s' in class '%s' while generating %s component for property", 079 checked.getMember().getPsiMember(), checkedElementClass != null ? checkedElementClass.getQualifiedName() : "<no-class>", 080 existent.getMember().getPsiMember(), existentElementClass != null ? existentElementClass.getQualifiedName() : "<no-class>", 081 componentTypeName)); 082 } 083 } 084 085 @NotNull 086 private static String propertyKeyForGrouping(@NotNull PropertyPsiDataElement propertyAccessor) { 087 String type = key(propertyAccessor.getType()); 088 String receiverType = key(propertyAccessor.getReceiverType()); 089 return Pair.create(type, receiverType).toString(); 090 } 091 092 @NotNull 093 private static String key(@Nullable TypeSource typeSource) { 094 if (typeSource == null) { 095 return ""; 096 } 097 else if (typeSource.getTypeString().length() > 0) { 098 return typeSource.getTypeString(); 099 } 100 else { 101 return typeSource.getPsiType().getPresentableText(); 102 } 103 } 104 105 @Nullable 106 private PropertyPsiDataElement getter = null; 107 @Nullable 108 private PropertyPsiDataElement setter = null; 109 @Nullable 110 private PropertyPsiDataElement field = null; 111 @Nullable 112 private Collection<PropertyPsiDataElement> elements = null; 113 114 @Nullable 115 public PropertyPsiDataElement getGetter() { 116 return getter; 117 } 118 119 @Nullable 120 public PropertyPsiDataElement getSetter() { 121 return setter; 122 } 123 124 @SuppressWarnings("ConstantConditions") 125 @NotNull 126 private Collection<PropertyPsiDataElement> getElements() { 127 if (elements == null) { 128 elements = Lists.newArrayList(); 129 if (getter != null) { 130 elements.add(getter); 131 } 132 if (setter != null) { 133 elements.add(setter); 134 } 135 if (field != null) { 136 elements.add(field); 137 } 138 assert !elements.isEmpty(); 139 } 140 return elements; 141 } 142 143 public boolean isExtension() { 144 boolean isExtension = getCharacteristicMember().isExtension(); 145 for (PropertyPsiDataElement element : getElements()) { 146 assert (element.isExtension() == isExtension); 147 } 148 return isExtension; 149 } 150 151 public boolean isStatic() { 152 boolean isStatic = getCharacteristicMember().getMember().isStatic(); 153 for (PropertyPsiDataElement element : getElements()) { 154 assert (element.getMember().isStatic() == isStatic); 155 } 156 return isStatic; 157 } 158 159 @NotNull 160 public PropertyPsiDataElement getCharacteristicMember() { 161 if (getter != null) { 162 return getter; 163 } 164 if (field != null) { 165 return field; 166 } 167 if (setter != null) { 168 return setter; 169 } 170 throw new IllegalStateException(); 171 } 172 173 @NotNull 174 public PsiMember getCharacteristicPsi() { 175 return getCharacteristicMember().getMember().getPsiMember(); 176 } 177 178 public boolean isVar() { 179 if (getter == null && setter == null) { 180 assert field != null; 181 return !field.getMember().isFinal(); 182 } 183 return setter != null; 184 } 185 186 public boolean isStaticFinalField() { 187 if (getter != null || setter != null) { 188 return false; 189 } 190 assert field != null; 191 return field.getMember().isFinal() && field.getMember().isStatic(); 192 } 193 194 public boolean isPropertyForNamedObject() { 195 return field != null && JvmAbi.INSTANCE_FIELD.equals(field.getMember().getName()); 196 } 197 198 public boolean isFinal() { 199 if (getter != null) { 200 return getter.getMember().isFinal(); 201 } 202 203 if (setter != null) { 204 return setter.getMember().isFinal(); 205 } 206 return false; 207 } 208}