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.k2js.translate.reference;
018
019 import com.google.dart.compiler.backend.js.ast.JsExpression;
020 import org.jetbrains.annotations.NotNull;
021 import org.jetbrains.annotations.Nullable;
022 import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
023 import org.jetbrains.jet.lang.descriptors.PropertyDescriptor;
024 import org.jetbrains.jet.lang.psi.JetExpression;
025 import org.jetbrains.jet.lang.psi.JetQualifiedExpression;
026 import org.jetbrains.jet.lang.psi.JetSimpleNameExpression;
027 import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
028 import org.jetbrains.k2js.translate.context.TranslationContext;
029 import org.jetbrains.k2js.translate.general.AbstractTranslator;
030
031 import static org.jetbrains.k2js.translate.utils.AnnotationsUtils.isNativeObject;
032 import static org.jetbrains.k2js.translate.utils.BindingUtils.getDescriptorForReferenceExpression;
033 import static org.jetbrains.k2js.translate.utils.BindingUtils.getResolvedCallForProperty;
034 import static org.jetbrains.k2js.translate.utils.PsiUtils.getSelectorAsSimpleName;
035 import static org.jetbrains.jet.lang.psi.JetPsiUtil.isBackingFieldReference;
036
037 public abstract class PropertyAccessTranslator extends AbstractTranslator implements AccessTranslator {
038
039 @NotNull
040 public static PropertyAccessTranslator newInstance(@NotNull JetSimpleNameExpression expression,
041 @Nullable JsExpression qualifier,
042 @NotNull CallType callType,
043 @NotNull TranslationContext context) {
044 PropertyAccessTranslator result;
045 PropertyDescriptor propertyDescriptor = getPropertyDescriptor(expression, context);
046 if (isNativeObject(propertyDescriptor) || isBackingFieldReference(expression)) {
047 result = new NativePropertyAccessTranslator(propertyDescriptor, qualifier, context);
048 }
049 else {
050 ResolvedCall<?> resolvedCall = getResolvedCallForProperty(context.bindingContext(), expression);
051 result = new KotlinPropertyAccessTranslator(propertyDescriptor, qualifier, resolvedCall, context);
052 }
053 result.setCallType(callType);
054 return result;
055 }
056
057 @NotNull
058 private static PropertyDescriptor getPropertyDescriptor(@NotNull JetSimpleNameExpression expression,
059 @NotNull TranslationContext context) {
060 DeclarationDescriptor descriptor =
061 getDescriptorForReferenceExpression(context.bindingContext(), expression);
062 assert descriptor instanceof PropertyDescriptor : "Must be a property descriptor.";
063 return (PropertyDescriptor) descriptor;
064 }
065
066
067 @NotNull
068 public static JsExpression translateAsPropertyGetterCall(@NotNull JetSimpleNameExpression expression,
069 @Nullable JsExpression qualifier,
070 @NotNull CallType callType,
071 @NotNull TranslationContext context) {
072 return (newInstance(expression, qualifier, callType, context))
073 .translateAsGet();
074 }
075
076
077 private static boolean canBePropertyGetterCall(@NotNull JetQualifiedExpression expression,
078 @NotNull TranslationContext context) {
079 JetSimpleNameExpression selector = getSelectorAsSimpleName(expression);
080 assert selector != null : "Only names are allowed after the dot";
081 return canBePropertyGetterCall(selector, context);
082 }
083
084 private static boolean canBePropertyGetterCall(@NotNull JetSimpleNameExpression expression,
085 @NotNull TranslationContext context) {
086 return (getDescriptorForReferenceExpression
087 (context.bindingContext(), expression) instanceof PropertyDescriptor);
088 }
089
090 public static boolean canBePropertyGetterCall(@NotNull JetExpression expression,
091 @NotNull TranslationContext context) {
092 if (expression instanceof JetQualifiedExpression) {
093 return canBePropertyGetterCall((JetQualifiedExpression) expression, context);
094 }
095 if (expression instanceof JetSimpleNameExpression) {
096 return canBePropertyGetterCall((JetSimpleNameExpression) expression, context);
097 }
098 return false;
099 }
100
101 public static boolean canBePropertyAccess(@NotNull JetExpression expression,
102 @NotNull TranslationContext context) {
103 return canBePropertyGetterCall(expression, context);
104 }
105
106 //TODO: we use normal by default but may cause bugs
107 //TODO: inspect
108 private /*var*/ CallType callType = CallType.NORMAL;
109
110 protected PropertyAccessTranslator(@NotNull TranslationContext context) {
111 super(context);
112 }
113
114 public void setCallType(@NotNull CallType callType) {
115 this.callType = callType;
116 }
117
118 @NotNull
119 protected CallType getCallType() {
120 assert callType != null : "CallType not set";
121 return callType;
122 }
123
124 @NotNull
125 protected abstract JsExpression translateAsGet(@Nullable JsExpression receiver);
126
127 @NotNull
128 protected abstract JsExpression translateAsSet(@Nullable JsExpression receiver, @NotNull JsExpression setTo);
129 }