001    /*
002     * Copyright 2010-2014 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.codegen.state;
018    
019    import com.intellij.openapi.project.Project;
020    import org.jetbrains.annotations.NotNull;
021    import org.jetbrains.annotations.Nullable;
022    import org.jetbrains.jet.codegen.*;
023    import org.jetbrains.jet.codegen.binding.CodegenBinding;
024    import org.jetbrains.jet.codegen.inline.InlineCodegenUtil;
025    import org.jetbrains.jet.codegen.intrinsics.IntrinsicMethods;
026    import org.jetbrains.jet.lang.descriptors.ModuleDescriptor;
027    import org.jetbrains.jet.lang.descriptors.PackageFragmentDescriptor;
028    import org.jetbrains.jet.lang.descriptors.ScriptDescriptor;
029    import org.jetbrains.jet.lang.psi.JetClassOrObject;
030    import org.jetbrains.jet.lang.psi.JetFile;
031    import org.jetbrains.jet.lang.reflect.ReflectionTypes;
032    import org.jetbrains.jet.lang.resolve.BindingContext;
033    import org.jetbrains.jet.lang.resolve.BindingTrace;
034    import org.jetbrains.jet.lang.resolve.DelegatingBindingTrace;
035    import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
036    
037    import java.util.List;
038    
039    public class GenerationState {
040        public interface GenerateClassFilter {
041            boolean shouldProcess(JetClassOrObject classOrObject);
042    
043            GenerateClassFilter ONLY_PACKAGE_CLASS = new GenerateClassFilter() {
044                @Override
045                public boolean shouldProcess(JetClassOrObject classOrObject) {
046                    return false;
047                }
048            };
049    
050            GenerateClassFilter GENERATE_ALL = new GenerateClassFilter() {
051                @Override
052                public boolean shouldProcess(JetClassOrObject classOrObject) {
053                    return true;
054                }
055            };
056        }
057    
058        private boolean used = false;
059    
060        @NotNull
061        private final Progress progress;
062    
063        @NotNull
064        private final List<JetFile> files;
065    
066        @NotNull
067        private final ClassBuilderMode classBuilderMode;
068    
069        @NotNull
070        private final BindingContext bindingContext;
071    
072        @NotNull
073        private final ClassFileFactory classFileFactory;
074    
075        @NotNull
076        private final Project project;
077    
078        @NotNull
079        private final IntrinsicMethods intrinsics;
080    
081        @NotNull
082        private final SamWrapperClasses samWrapperClasses = new SamWrapperClasses(this);
083    
084        @NotNull
085        private final BindingTrace bindingTrace;
086    
087        @NotNull
088        private final JetTypeMapper typeMapper;
089    
090        private final boolean generateNotNullAssertions;
091    
092        private final boolean generateNotNullParamAssertions;
093    
094        private final GenerateClassFilter generateClassFilter;
095    
096        private final boolean inlineEnabled;
097    
098        @Nullable
099        private List<ScriptDescriptor> earlierScriptsForReplInterpreter;
100    
101        private final JvmFunctionImplTypes functionImplTypes;
102    
103        public GenerationState(
104                @NotNull Project project,
105                @NotNull ClassBuilderFactory builderFactory,
106                @NotNull BindingContext bindingContext,
107                @NotNull List<JetFile> files
108        ) {
109            this(project, builderFactory, Progress.DEAF, bindingContext, files, true, false, GenerateClassFilter.GENERATE_ALL,
110                 InlineCodegenUtil.DEFAULT_INLINE_FLAG);
111        }
112    
113        public GenerationState(
114                @NotNull Project project,
115                @NotNull ClassBuilderFactory builderFactory,
116                @NotNull Progress progress,
117                @NotNull BindingContext bindingContext,
118                @NotNull List<JetFile> files,
119                boolean generateNotNullAssertions,
120                boolean generateNotNullParamAssertions,
121                GenerateClassFilter generateClassFilter,
122                boolean inlineEnabled
123        ) {
124            this.project = project;
125            this.progress = progress;
126            this.files = files;
127            this.classBuilderMode = builderFactory.getClassBuilderMode();
128            this.inlineEnabled = inlineEnabled;
129    
130            this.bindingTrace = new DelegatingBindingTrace(bindingContext, "trace in GenerationState");
131            this.bindingContext = bindingTrace.getBindingContext();
132    
133            this.typeMapper = new JetTypeMapper(this.bindingContext, classBuilderMode);
134    
135            this.intrinsics = new IntrinsicMethods();
136            this.classFileFactory = new ClassFileFactory(this, builderFactory);
137    
138            this.generateNotNullAssertions = generateNotNullAssertions;
139            this.generateNotNullParamAssertions = generateNotNullParamAssertions;
140            this.generateClassFilter = generateClassFilter;
141    
142            ReflectionTypes reflectionTypes = new ReflectionTypes(getAnyModule());
143            this.functionImplTypes = new JvmFunctionImplTypes(reflectionTypes);
144        }
145    
146        @NotNull
147        private ModuleDescriptor getAnyModule() {
148            // TODO: this shouldn't be happening once we have modules in the compiler (there simply will be a ModuleDescriptor instance here)
149    
150            if (files.isEmpty()) {
151                // This is a hackish workaround for this code not to fail when invoked for an empty file list. Technically it doesn't matter
152                // which module we return here: if we're not compiling anything, we should never reach a point where we need this module
153                return KotlinBuiltIns.getInstance().getBuiltInsModule();
154            }
155    
156            PackageFragmentDescriptor descriptor = bindingContext.get(BindingContext.FILE_TO_PACKAGE_FRAGMENT, files.get(0));
157            assert descriptor != null : "File is not under any module: " + files.get(0);
158            return descriptor.getContainingDeclaration();
159        }
160    
161        @NotNull
162        public ClassFileFactory getFactory() {
163            return classFileFactory;
164        }
165    
166        @NotNull
167        public Progress getProgress() {
168            return progress;
169        }
170    
171        @NotNull
172        public BindingContext getBindingContext() {
173            return bindingContext;
174        }
175    
176        @NotNull
177        public ClassBuilderMode getClassBuilderMode() {
178            return classBuilderMode;
179        }
180    
181        @NotNull
182        public List<JetFile> getFiles() {
183            return files;
184        }
185    
186        @NotNull
187        public BindingTrace getBindingTrace() {
188            return bindingTrace;
189        }
190    
191        @NotNull
192        public JetTypeMapper getTypeMapper() {
193            return typeMapper;
194        }
195    
196        @NotNull
197        public Project getProject() {
198            return project;
199        }
200    
201        @NotNull
202        public IntrinsicMethods getIntrinsics() {
203            return intrinsics;
204        }
205    
206        @NotNull
207        public SamWrapperClasses getSamWrapperClasses() {
208            return samWrapperClasses;
209        }
210    
211        public boolean isGenerateNotNullAssertions() {
212            return generateNotNullAssertions;
213        }
214    
215        public boolean isGenerateNotNullParamAssertions() {
216            return generateNotNullParamAssertions;
217        }
218    
219        @NotNull
220        public GenerateClassFilter getGenerateDeclaredClassFilter() {
221            return generateClassFilter;
222        }
223    
224        @NotNull
225        public JvmFunctionImplTypes getJvmFunctionImplTypes() {
226            return functionImplTypes;
227        }
228    
229        public boolean isInlineEnabled() {
230            return inlineEnabled;
231        }
232    
233        public void beforeCompile() {
234            markUsed();
235    
236            CodegenBinding.initTrace(this);
237        }
238    
239        private void markUsed() {
240            if (used) {
241                throw new IllegalStateException(GenerationState.class + " cannot be used more than once");
242            }
243            used = true;
244        }
245    
246        public void destroy() {
247        }
248    
249        @Nullable
250        public List<ScriptDescriptor> getEarlierScriptsForReplInterpreter() {
251            return earlierScriptsForReplInterpreter;
252        }
253    
254        public void setEarlierScriptsForReplInterpreter(@Nullable List<ScriptDescriptor> earlierScriptsForReplInterpreter) {
255            this.earlierScriptsForReplInterpreter = earlierScriptsForReplInterpreter;
256        }
257    }