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.k2js.translate.reference; 018 019import com.google.dart.compiler.backend.js.ast.JsExpression; 020import org.jetbrains.annotations.NotNull; 021import org.jetbrains.annotations.Nullable; 022import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; 023import org.jetbrains.jet.lang.descriptors.PropertyDescriptor; 024import org.jetbrains.jet.lang.psi.JetExpression; 025import org.jetbrains.jet.lang.psi.JetQualifiedExpression; 026import org.jetbrains.jet.lang.psi.JetSimpleNameExpression; 027import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall; 028import org.jetbrains.k2js.translate.context.TranslationContext; 029import org.jetbrains.k2js.translate.general.AbstractTranslator; 030 031import static org.jetbrains.k2js.translate.utils.AnnotationsUtils.isNativeObject; 032import static org.jetbrains.k2js.translate.utils.BindingUtils.getDescriptorForReferenceExpression; 033import static org.jetbrains.k2js.translate.utils.BindingUtils.getResolvedCallForProperty; 034import static org.jetbrains.k2js.translate.utils.PsiUtils.getSelectorAsSimpleName; 035import static org.jetbrains.jet.lang.psi.JetPsiUtil.isBackingFieldReference; 036 037public 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}