001    /*
002     * Copyright 2010-2015 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.kotlin.js.translate.reference;
018    
019    import com.google.dart.compiler.backend.js.ast.JsExpression;
020    import org.jetbrains.annotations.NotNull;
021    import org.jetbrains.kotlin.descriptors.ClassDescriptor;
022    import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
023    import org.jetbrains.kotlin.js.translate.context.Namer;
024    import org.jetbrains.kotlin.js.translate.context.TemporaryVariable;
025    import org.jetbrains.kotlin.js.translate.context.TranslationContext;
026    import org.jetbrains.kotlin.js.translate.general.AbstractTranslator;
027    import org.jetbrains.kotlin.js.translate.intrinsic.objects.ObjectIntrinsic;
028    import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils;
029    import org.jetbrains.kotlin.psi.KtReferenceExpression;
030    import org.jetbrains.kotlin.psi.KtSimpleNameExpression;
031    
032    import java.util.Collections;
033    import java.util.List;
034    
035    import static org.jetbrains.kotlin.js.translate.reference.ReferenceTranslator.translateAsFQReference;
036    import static org.jetbrains.kotlin.js.translate.utils.BindingUtils.getDescriptorForReferenceExpression;
037    import static org.jetbrains.kotlin.resolve.DescriptorUtils.isEnumEntry;
038    import static org.jetbrains.kotlin.resolve.DescriptorUtils.isNonCompanionObject;
039    
040    public class CompanionObjectAccessTranslator extends AbstractTranslator implements CachedAccessTranslator {
041        @NotNull
042        /*package*/ static CompanionObjectAccessTranslator newInstance(
043                @NotNull KtSimpleNameExpression expression,
044                @NotNull TranslationContext context
045        ) {
046            DeclarationDescriptor referenceDescriptor = getDescriptorForReferenceExpression(context.bindingContext(), expression);
047            assert referenceDescriptor != null : "JetSimpleName expression must reference a descriptor " + expression.getText();
048            return new CompanionObjectAccessTranslator(referenceDescriptor, context);
049        }
050    
051        /*package*/ static boolean isCompanionObjectReference(
052                @NotNull KtReferenceExpression expression,
053                @NotNull TranslationContext context
054        ) {
055            DeclarationDescriptor descriptor = getDescriptorForReferenceExpression(context.bindingContext(), expression);
056            return descriptor instanceof ClassDescriptor && !AnnotationsUtils.isNativeObject(descriptor);
057        }
058    
059        @NotNull
060        private final JsExpression referenceToCompanionObject;
061    
062        private CompanionObjectAccessTranslator(@NotNull DeclarationDescriptor descriptor, @NotNull TranslationContext context) {
063            super(context);
064            this.referenceToCompanionObject = generateReferenceToCompanionObject(descriptor, context);
065        }
066    
067        @NotNull
068        private static JsExpression generateReferenceToCompanionObject(@NotNull DeclarationDescriptor descriptor, @NotNull TranslationContext context) {
069            if (descriptor instanceof ClassDescriptor) {
070                ObjectIntrinsic objectIntrinsic = context.intrinsics().getObjectIntrinsic((ClassDescriptor) descriptor);
071                if (objectIntrinsic.exists()) {
072                    return objectIntrinsic.apply(context);
073                }
074            }
075    
076            JsExpression fqReference = translateAsFQReference(descriptor, context);
077            if (isNonCompanionObject(descriptor) || isEnumEntry(descriptor)) {
078                return fqReference;
079            }
080    
081            return Namer.getCompanionObjectAccessor(fqReference);
082        }
083    
084        @Override
085        @NotNull
086        public JsExpression translateAsGet() {
087            return referenceToCompanionObject;
088        }
089    
090        @Override
091        @NotNull
092        public JsExpression translateAsSet(@NotNull JsExpression toSetTo) {
093            throw new IllegalStateException("companion object can't be set");
094        }
095    
096        @NotNull
097        @Override
098        public CachedAccessTranslator getCached() {
099            return this;
100        }
101    
102        @NotNull
103        @Override
104        public List<TemporaryVariable> declaredTemporaries() {
105            return Collections.emptyList();
106        }
107    }