@Nullable
  private static AnalysisResult analyze(
      @NotNull final KotlinCoreEnvironment environment, @Nullable String targetDescription) {
    MessageCollector collector =
        environment.getConfiguration().get(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY);
    assert collector != null;

    long analysisStart = PerformanceCounter.Companion.currentTime();
    AnalyzerWithCompilerReport analyzerWithCompilerReport =
        new AnalyzerWithCompilerReport(collector);
    analyzerWithCompilerReport.analyzeAndReport(
        environment.getSourceFiles(),
        new Function0<AnalysisResult>() {
          @NotNull
          @Override
          public AnalysisResult invoke() {
            BindingTrace sharedTrace =
                new CliLightClassGenerationSupport.NoScopeRecordCliBindingTrace();
            ModuleContext moduleContext =
                TopDownAnalyzerFacadeForJVM.createContextWithSealedModule(
                    environment.getProject(), ModuleNameKt.getModuleName(environment));

            return TopDownAnalyzerFacadeForJVM.analyzeFilesWithJavaIntegrationWithCustomContext(
                moduleContext,
                environment.getSourceFiles(),
                sharedTrace,
                environment.getConfiguration().get(JVMConfigurationKeys.MODULES),
                environment
                    .getConfiguration()
                    .get(JVMConfigurationKeys.INCREMENTAL_COMPILATION_COMPONENTS),
                new JvmPackagePartProvider(environment));
          }
        });
    long analysisNanos = PerformanceCounter.Companion.currentTime() - analysisStart;
    String message =
        "ANALYZE: "
            + environment.getSourceFiles().size()
            + " files ("
            + environment.getSourceLinesOfCode()
            + " lines) "
            + (targetDescription != null ? targetDescription : "")
            + "in "
            + TimeUnit.NANOSECONDS.toMillis(analysisNanos)
            + " ms";
    K2JVMCompiler.Companion.reportPerf(environment.getConfiguration(), message);

    AnalysisResult result = analyzerWithCompilerReport.getAnalysisResult();
    assert result != null
        : "AnalysisResult should be non-null, compiling: " + environment.getSourceFiles();

    CompilerPluginContext context =
        new CompilerPluginContext(
            environment.getProject(), result.getBindingContext(), environment.getSourceFiles());
    for (CompilerPlugin plugin :
        environment.getConfiguration().getList(CLIConfigurationKeys.COMPILER_PLUGINS)) {
      plugin.processFiles(context);
    }

    return analyzerWithCompilerReport.hasErrors() ? null : result;
  }
  @Nullable
  public static GenerationState analyzeAndGenerate(@NotNull KotlinCoreEnvironment environment) {
    AnalysisResult result = analyze(environment, null);

    if (result == null) {
      return null;
    }

    if (!result.getShouldGenerateCode()) return null;

    result.throwIfError();

    return generate(environment, result, environment.getSourceFiles(), null, null, null);
  }
  @NotNull
  private PackageViewDescriptor analyzeFileToPackageView(@NotNull File... extraClassPath)
      throws IOException {
    Project project = createEnvironment(Arrays.asList(extraClassPath)).getProject();

    AnalysisResult result =
        JvmResolveUtil.analyzeOneFileWithJavaIntegrationAndCheckForErrors(
            KotlinTestUtils.loadJetFile(project, getTestDataFileWithExtension("kt")));

    PackageViewDescriptor packageView =
        result.getModuleDescriptor().getPackage(LoadDescriptorUtil.TEST_PACKAGE_FQNAME);
    assertFalse(
        "Failed to find package: " + LoadDescriptorUtil.TEST_PACKAGE_FQNAME, packageView.isEmpty());
    return packageView;
  }
  public void testNoWarningsOnJavaKotlinInheritance() throws Exception {
    // This test checks that there are no PARAMETER_NAME_CHANGED_ON_OVERRIDE or
    // DIFFERENT_NAMES_FOR_THE_SAME_PARAMETER_IN_SUPERTYPES
    // warnings when subclassing in Kotlin from Java binaries (in case when no parameter names are
    // available for Java classes)

    KotlinTestUtils.compileJavaFiles(
        Collections.singletonList(getTestDataFileWithExtension("java")),
        Arrays.asList("-d", tmpdir.getPath()));

    Project project = createEnvironment(Collections.singletonList(tmpdir)).getProject();

    AnalysisResult result =
        JvmResolveUtil.analyzeOneFileWithJavaIntegration(
            KotlinTestUtils.loadJetFile(project, getTestDataFileWithExtension("kt")));
    result.throwIfError();

    BindingContext bindingContext = result.getBindingContext();
    AnalyzerWithCompilerReport.Companion.reportDiagnostics(
        bindingContext.getDiagnostics(), PrintingMessageCollector.PLAIN_TEXT_TO_SYSTEM_ERR);

    assertEquals(
        "There should be no diagnostics", 0, Iterables.size(bindingContext.getDiagnostics()));
  }
  @NotNull
  private static GenerationState generate(
      @NotNull KotlinCoreEnvironment environment,
      @NotNull AnalysisResult result,
      @NotNull List<KtFile> sourceFiles,
      @Nullable Module module,
      File outputDirectory,
      String moduleName) {
    CompilerConfiguration configuration = environment.getConfiguration();
    IncrementalCompilationComponents incrementalCompilationComponents =
        configuration.get(JVMConfigurationKeys.INCREMENTAL_COMPILATION_COMPONENTS);

    Collection<FqName> packagesWithObsoleteParts;
    List<FqName> obsoleteMultifileClasses;
    TargetId targetId = null;

    if (module == null || incrementalCompilationComponents == null) {
      packagesWithObsoleteParts = Collections.emptySet();
      obsoleteMultifileClasses = Collections.emptyList();
    } else {
      targetId = TargetIdKt.TargetId(module);
      IncrementalCache incrementalCache =
          incrementalCompilationComponents.getIncrementalCache(targetId);

      packagesWithObsoleteParts = new HashSet<FqName>();
      for (String internalName : incrementalCache.getObsoletePackageParts()) {
        packagesWithObsoleteParts.add(JvmClassName.byInternalName(internalName).getPackageFqName());
      }

      obsoleteMultifileClasses = new ArrayList<FqName>();
      for (String obsoleteFacadeInternalName : incrementalCache.getObsoleteMultifileClasses()) {
        obsoleteMultifileClasses.add(
            JvmClassName.byInternalName(obsoleteFacadeInternalName)
                .getFqNameForClassNameWithoutDollars());
      }
    }
    BindingTraceContext diagnosticHolder = new BindingTraceContext();
    GenerationState generationState =
        new GenerationState(
            environment.getProject(),
            ClassBuilderFactories.BINARIES,
            result.getModuleDescriptor(),
            result.getBindingContext(),
            sourceFiles,
            configuration.get(JVMConfigurationKeys.DISABLE_CALL_ASSERTIONS, false),
            configuration.get(JVMConfigurationKeys.DISABLE_PARAM_ASSERTIONS, false),
            GenerationState.GenerateClassFilter.GENERATE_ALL,
            configuration.get(JVMConfigurationKeys.DISABLE_INLINE, false),
            configuration.get(JVMConfigurationKeys.DISABLE_OPTIMIZATION, false),
            /* useTypeTableInSerializer = */ false,
            diagnosticHolder,
            packagesWithObsoleteParts,
            obsoleteMultifileClasses,
            targetId,
            moduleName,
            outputDirectory,
            incrementalCompilationComponents);
    ProgressIndicatorAndCompilationCanceledStatus.checkCanceled();

    long generationStart = PerformanceCounter.Companion.currentTime();

    KotlinCodegenFacade.compileCorrectFiles(
        generationState, CompilationErrorHandler.THROW_EXCEPTION);

    long generationNanos = PerformanceCounter.Companion.currentTime() - generationStart;
    String desc =
        module != null
            ? "target " + module.getModuleName() + "-" + module.getModuleType() + " "
            : "";
    String message =
        "GENERATE: "
            + sourceFiles.size()
            + " files ("
            + environment.countLinesOfCode(sourceFiles)
            + " lines) "
            + desc
            + "in "
            + TimeUnit.NANOSECONDS.toMillis(generationNanos)
            + " ms";
    K2JVMCompiler.Companion.reportPerf(environment.getConfiguration(), message);
    ProgressIndicatorAndCompilationCanceledStatus.checkCanceled();

    AnalyzerWithCompilerReport.reportDiagnostics(
        new FilteredJvmDiagnostics(
            diagnosticHolder.getBindingContext().getDiagnostics(),
            result.getBindingContext().getDiagnostics()),
        environment.getConfiguration().get(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY));
    ProgressIndicatorAndCompilationCanceledStatus.checkCanceled();
    return generationState;
  }
  public static boolean compileModules(
      @NotNull KotlinCoreEnvironment environment,
      @NotNull CompilerConfiguration configuration,
      @NotNull List<Module> chunk,
      @NotNull File directory,
      @Nullable File jarPath,
      @NotNull List<String> friendPaths,
      boolean jarRuntime) {
    Map<Module, ClassFileFactory> outputFiles = Maps.newHashMap();

    ProgressIndicatorAndCompilationCanceledStatus.checkCanceled();

    ModuleVisibilityManager moduleVisibilityManager =
        ModuleVisibilityManager.SERVICE.getInstance(environment.getProject());

    for (Module module : chunk) {
      moduleVisibilityManager.addModule(module);
    }

    for (String path : friendPaths) {
      moduleVisibilityManager.addFriendPath(path);
    }

    String targetDescription =
        "in targets ["
            + Joiner.on(", ")
                .join(
                    Collections2.transform(
                        chunk,
                        new Function<Module, String>() {
                          @Override
                          public String apply(@Nullable Module input) {
                            return input != null
                                ? input.getModuleName() + "-" + input.getModuleType()
                                : "<null>";
                          }
                        }))
            + "] ";
    AnalysisResult result = analyze(environment, targetDescription);
    if (result == null) {
      return false;
    }

    ProgressIndicatorAndCompilationCanceledStatus.checkCanceled();

    result.throwIfError();

    for (Module module : chunk) {
      ProgressIndicatorAndCompilationCanceledStatus.checkCanceled();
      List<KtFile> jetFiles =
          CompileEnvironmentUtil.getKtFiles(
              environment.getProject(),
              getAbsolutePaths(directory, module),
              new Function1<String, Unit>() {
                @Override
                public Unit invoke(String s) {
                  throw new IllegalStateException("Should have been checked before: " + s);
                }
              });
      File moduleOutputDirectory = new File(module.getOutputDirectory());
      GenerationState generationState =
          generate(
              environment, result, jetFiles, module, moduleOutputDirectory, module.getModuleName());
      outputFiles.put(module, generationState.getFactory());
    }

    for (Module module : chunk) {
      ProgressIndicatorAndCompilationCanceledStatus.checkCanceled();
      writeOutput(
          configuration,
          outputFiles.get(module),
          new File(module.getOutputDirectory()),
          jarPath,
          jarRuntime,
          null);
    }
    return true;
  }