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.jet.lang.cfg.JetFlowInformationProvider;
021 import org.jetbrains.jet.lang.descriptors.PropertyAccessorDescriptor;
022 import org.jetbrains.jet.lang.descriptors.PropertyDescriptor;
023 import org.jetbrains.jet.lang.descriptors.SimpleFunctionDescriptor;
024 import org.jetbrains.jet.lang.psi.*;
025 import org.jetbrains.jet.lang.types.JetType;
026
027 import javax.inject.Inject;
028 import java.util.List;
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 TopDownAnalysisParameters topDownAnalysisParameters;
035 private BindingTrace trace;
036
037 @Inject
038 public void setTopDownAnalysisParameters(TopDownAnalysisParameters topDownAnalysisParameters) {
039 this.topDownAnalysisParameters = topDownAnalysisParameters;
040 }
041
042 @Inject
043 public void setTrace(BindingTrace trace) {
044 this.trace = trace;
045 }
046
047 public void process(@NotNull BodiesResolveContext bodiesResolveContext) {
048 for (JetFile file : bodiesResolveContext.getFiles()) {
049 if (!bodiesResolveContext.completeAnalysisNeeded(file)) continue;
050 checkDeclarationContainer(file);
051 }
052 for (JetClass aClass : bodiesResolveContext.getClasses().keySet()) {
053 if (!bodiesResolveContext.completeAnalysisNeeded(aClass)) continue;
054 checkDeclarationContainer(aClass);
055 }
056 for (JetObjectDeclaration objectDeclaration : bodiesResolveContext.getObjects().keySet()) {
057 if (!bodiesResolveContext.completeAnalysisNeeded(objectDeclaration)) continue;
058 checkDeclarationContainer(objectDeclaration);
059 }
060 for (Map.Entry<JetNamedFunction, SimpleFunctionDescriptor> entry : bodiesResolveContext.getFunctions().entrySet()) {
061 JetNamedFunction function = entry.getKey();
062 SimpleFunctionDescriptor functionDescriptor = entry.getValue();
063 if (!bodiesResolveContext.completeAnalysisNeeded(function)) continue;
064 JetType expectedReturnType = !function.hasBlockBody() && !function.hasDeclaredReturnType()
065 ? NO_EXPECTED_TYPE
066 : functionDescriptor.getReturnType();
067 checkFunction(function, expectedReturnType);
068 }
069 for (Map.Entry<JetProperty, PropertyDescriptor> entry : bodiesResolveContext.getProperties().entrySet()) {
070 JetProperty property = entry.getKey();
071 if (!bodiesResolveContext.completeAnalysisNeeded(property)) continue;
072 PropertyDescriptor propertyDescriptor = entry.getValue();
073 checkProperty(property, propertyDescriptor);
074 }
075 }
076
077 private void checkDeclarationContainer(JetDeclarationContainer declarationContainer) {
078 // A pseudocode of class/object initialization corresponds to a class/object
079 // or initialization of properties corresponds to a package declared in a file
080 JetFlowInformationProvider flowInformationProvider = new JetFlowInformationProvider((JetElement) declarationContainer, trace);
081 flowInformationProvider.recordInitializedVariables();
082
083 if (topDownAnalysisParameters.isDeclaredLocally()) return;
084
085 flowInformationProvider.markUninitializedVariables();
086 }
087
088 private void checkProperty(JetProperty property, PropertyDescriptor propertyDescriptor) {
089 for (JetPropertyAccessor accessor : property.getAccessors()) {
090 PropertyAccessorDescriptor accessorDescriptor = accessor.isGetter()
091 ? propertyDescriptor.getGetter()
092 : propertyDescriptor.getSetter();
093 assert accessorDescriptor != null;
094 checkFunction(accessor, accessorDescriptor.getReturnType());
095 }
096 }
097
098 private void checkFunction(JetDeclarationWithBody function, @NotNull JetType expectedReturnType) {
099 assert function instanceof JetDeclaration;
100
101 JetExpression bodyExpression = function.getBodyExpression();
102 if (bodyExpression == null) return;
103 JetFlowInformationProvider flowInformationProvider = new JetFlowInformationProvider((JetDeclaration) function, trace);
104
105 boolean isPropertyAccessor = function instanceof JetPropertyAccessor;
106 if (!isPropertyAccessor) {
107 flowInformationProvider.recordInitializedVariables();
108 }
109
110 if (topDownAnalysisParameters.isDeclaredLocally()) return;
111
112 flowInformationProvider.checkDefiniteReturn(expectedReturnType);
113
114 if (!isPropertyAccessor) {
115 // Property accessor is checked through initialization of a class/object or package properties (at 'checkDeclarationContainer')
116 flowInformationProvider.markUninitializedVariables();
117 }
118
119 flowInformationProvider.markUnusedVariables();
120
121 flowInformationProvider.markUnusedLiteralsInBlock();
122 }
123 }