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.codegen;
018    
019    import com.google.common.collect.Sets;
020    import com.intellij.util.containers.MultiMap;
021    import org.jetbrains.annotations.NotNull;
022    import org.jetbrains.kotlin.codegen.state.GenerationState;
023    import org.jetbrains.kotlin.fileClasses.JvmFileClassInfo;
024    import org.jetbrains.kotlin.name.FqName;
025    import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus;
026    import org.jetbrains.kotlin.psi.KtFile;
027    
028    import java.util.Collection;
029    import java.util.HashSet;
030    import java.util.Set;
031    
032    public class KotlinCodegenFacade {
033    
034        public static void compileCorrectFiles(
035                @NotNull GenerationState state,
036                @NotNull CompilationErrorHandler errorHandler
037        ) {
038            ProgressIndicatorAndCompilationCanceledStatus.checkCanceled();
039    
040            state.beforeCompile();
041    
042            ProgressIndicatorAndCompilationCanceledStatus.checkCanceled();
043    
044            doGenerateFiles(state.getFiles(), state, errorHandler);
045        }
046    
047        public static void doGenerateFiles(
048                @NotNull Collection<KtFile> files,
049                @NotNull GenerationState state,
050                @NotNull CompilationErrorHandler errorHandler
051        ) {
052            MultiMap<FqName, KtFile> filesInPackages = new MultiMap<FqName, KtFile>();
053            MultiMap<FqName, KtFile> filesInMultifileClasses = new MultiMap<FqName, KtFile>();
054    
055            for (KtFile file : files) {
056                if (file == null) throw new IllegalArgumentException("A null file given for compilation");
057    
058                JvmFileClassInfo fileClassInfo = state.getFileClassesProvider().getFileClassInfo(file);
059    
060                if (fileClassInfo.getWithJvmMultifileClass()) {
061                    filesInMultifileClasses.putValue(fileClassInfo.getFacadeClassFqName(), file);
062                }
063                else {
064                    filesInPackages.putValue(file.getPackageFqName(), file);
065                }
066            }
067    
068            Set<FqName> obsoleteMultifileClasses = new HashSet<FqName>(state.getObsoleteMultifileClasses());
069            for (FqName multifileClassFqName : Sets.union(filesInMultifileClasses.keySet(), obsoleteMultifileClasses)) {
070                doCheckCancelled(state);
071                generateMultifileClass(state, multifileClassFqName, filesInMultifileClasses.get(multifileClassFqName), errorHandler);
072            }
073    
074            Set<FqName> packagesWithObsoleteParts = new HashSet<FqName>(state.getPackagesWithObsoleteParts());
075            for (FqName packageFqName : Sets.union(packagesWithObsoleteParts, filesInPackages.keySet())) {
076                doCheckCancelled(state);
077                generatePackage(state, packageFqName, filesInPackages.get(packageFqName), errorHandler);
078            }
079    
080            doCheckCancelled(state);
081            state.getFactory().done();
082        }
083    
084        private static void doCheckCancelled(GenerationState state) {
085            if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
086                ProgressIndicatorAndCompilationCanceledStatus.checkCanceled();
087            }
088        }
089    
090        public static void generatePackage(
091                @NotNull GenerationState state,
092                @NotNull FqName packageFqName,
093                @NotNull Collection<KtFile> jetFiles,
094                @NotNull CompilationErrorHandler errorHandler
095        ) {
096            // We do not really generate package class, but use old package fqName to identify package in module-info.
097            //FqName packageClassFqName = PackageClassUtils.getPackageClassFqName(packageFqName);
098            PackageCodegen codegen = state.getFactory().forPackage(packageFqName, jetFiles);
099            codegen.generate(errorHandler);
100        }
101    
102        private static void generateMultifileClass(
103                @NotNull GenerationState state,
104                @NotNull FqName multifileClassFqName,
105                @NotNull Collection<KtFile> files,
106                @NotNull CompilationErrorHandler handler
107        ) {
108            MultifileClassCodegen codegen = state.getFactory().forMultifileClass(multifileClassFqName, files);
109            codegen.generate(handler);
110        }
111    
112        private KotlinCodegenFacade() {}
113    }