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