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.lang.resolve.java.wrapper;
018
019 import com.google.common.collect.Lists;
020 import com.intellij.openapi.util.Pair;
021 import com.intellij.psi.PsiClass;
022 import com.intellij.psi.PsiMember;
023 import org.jetbrains.annotations.NotNull;
024 import org.jetbrains.annotations.Nullable;
025 import org.jetbrains.jet.lang.resolve.java.JvmAbi;
026 import org.jetbrains.jet.lang.resolve.java.TypeSource;
027
028 import java.util.Collection;
029 import java.util.HashMap;
030 import java.util.List;
031 import java.util.Map;
032
033
034 /*
035 * Data from PSI related to one property used to resolve this property.
036 */
037 public 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 }