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;
018
019 import org.jetbrains.annotations.NotNull;
020 import org.jetbrains.annotations.Nullable;
021 import org.jetbrains.jet.lang.cfg.JetFlowInformationProvider;
022 import org.jetbrains.jet.lang.descriptors.PropertyAccessorDescriptor;
023 import org.jetbrains.jet.lang.descriptors.PropertyDescriptor;
024 import org.jetbrains.jet.lang.descriptors.SimpleFunctionDescriptor;
025 import org.jetbrains.jet.lang.psi.*;
026 import org.jetbrains.jet.lang.types.JetType;
027
028 import javax.inject.Inject;
029 import java.util.Map;
030
031 import static org.jetbrains.jet.lang.types.TypeUtils.NO_EXPECTED_TYPE;
032
033 public class ControlFlowAnalyzer {
034 private BindingTrace trace;
035
036 @Inject
037 public void setTrace(BindingTrace trace) {
038 this.trace = trace;
039 }
040
041 public void process(@NotNull BodiesResolveContext c) {
042 for (JetFile file : c.getFiles()) {
043 if (!c.completeAnalysisNeeded(file)) continue;
044 checkDeclarationContainer(c, file);
045 }
046 for (JetClassOrObject aClass : c.getClasses().keySet()) {
047 if (!c.completeAnalysisNeeded(aClass)) continue;
048 checkDeclarationContainer(c, aClass);
049 }
050 for (Map.Entry<JetNamedFunction, SimpleFunctionDescriptor> entry : c.getFunctions().entrySet()) {
051 JetNamedFunction function = entry.getKey();
052 SimpleFunctionDescriptor functionDescriptor = entry.getValue();
053 if (!c.completeAnalysisNeeded(function)) continue;
054 JetType expectedReturnType = !function.hasBlockBody() && !function.hasDeclaredReturnType()
055 ? NO_EXPECTED_TYPE
056 : functionDescriptor.getReturnType();
057 checkFunction(c, function, expectedReturnType);
058 }
059 for (Map.Entry<JetProperty, PropertyDescriptor> entry : c.getProperties().entrySet()) {
060 JetProperty property = entry.getKey();
061 if (!c.completeAnalysisNeeded(property)) continue;
062 PropertyDescriptor propertyDescriptor = entry.getValue();
063 checkProperty(c, property, propertyDescriptor);
064 }
065 }
066
067 private void checkDeclarationContainer(@NotNull BodiesResolveContext c, JetDeclarationContainer declarationContainer) {
068 // A pseudocode of class/object initialization corresponds to a class/object
069 // or initialization of properties corresponds to a package declared in a file
070 JetFlowInformationProvider flowInformationProvider = new JetFlowInformationProvider((JetElement) declarationContainer, trace);
071 if (c.getTopDownAnalysisParameters().isDeclaredLocally()) {
072 flowInformationProvider.checkForLocalClassOrObjectMode();
073 return;
074 }
075 flowInformationProvider.checkDeclaration();
076 }
077
078 private void checkProperty(@NotNull BodiesResolveContext c, JetProperty property, PropertyDescriptor propertyDescriptor) {
079 for (JetPropertyAccessor accessor : property.getAccessors()) {
080 PropertyAccessorDescriptor accessorDescriptor = accessor.isGetter()
081 ? propertyDescriptor.getGetter()
082 : propertyDescriptor.getSetter();
083 assert accessorDescriptor != null : "no property accessor descriptor " + accessor.getText();
084 JetType returnType = accessorDescriptor.getReturnType();
085 checkFunction(c, accessor, returnType);
086 }
087 }
088
089 private void checkFunction(@NotNull BodiesResolveContext c, @NotNull JetDeclarationWithBody function, @Nullable JetType expectedReturnType) {
090 JetExpression bodyExpression = function.getBodyExpression();
091 if (bodyExpression == null) return;
092 JetFlowInformationProvider flowInformationProvider = new JetFlowInformationProvider(function, trace);
093 if (c.getTopDownAnalysisParameters().isDeclaredLocally()) {
094 flowInformationProvider.checkForLocalClassOrObjectMode();
095 return;
096 }
097 flowInformationProvider.checkDeclaration();
098 flowInformationProvider.checkFunction(expectedReturnType);
099 }
100 }