private static void doCollectResourceDirs(
      AndroidFacet facet,
      boolean collectResCacheDirs,
      List<String> result,
      CompileContext context) {
    final Module module = facet.getModule();

    if (collectResCacheDirs) {
      final AndroidPlatform platform = facet.getConfiguration().getAndroidPlatform();
      final int platformToolsRevision =
          platform != null ? platform.getSdk().getPlatformToolsRevision() : -1;

      if (platformToolsRevision < 0 || platformToolsRevision > 7) {
        // png cache is supported since platform-tools-r8
        final String resCacheDirOsPath = findResourcesCacheDirectory(module, false, context);
        if (resCacheDirOsPath != null) {
          result.add(resCacheDirOsPath);
        } else {
          LOG.info("PNG cache not found for module " + module.getName());
        }
      }
    }

    final VirtualFile resourcesDir = AndroidAptCompiler.getResourceDirForApkCompiler(module, facet);
    if (resourcesDir != null) {
      result.add(resourcesDir.getPath());
    }
  }
 public static void addMessages(
     @NotNull Map<CompilerMessageCategory, List<String>> messages,
     @NotNull Map<CompilerMessageCategory, List<String>> toAdd) {
   for (Map.Entry<CompilerMessageCategory, List<String>> entry : toAdd.entrySet()) {
     List<String> list = messages.get(entry.getKey());
     if (list == null) {
       list = new ArrayList<String>();
       messages.put(entry.getKey(), list);
     }
     list.addAll(entry.getValue());
   }
 }
  public void compile() throws CompilerException, CacheCorruptedException {
    Application application = ApplicationManager.getApplication();
    try {
      if (!myFilesToCompile.isEmpty()) {
        if (application.isUnitTestMode()) {
          saveTestData();
        }
        compileModules(buildModuleToFilesMap(myFilesToCompile));
      }
    } catch (SecurityException e) {
      throw new CompilerException(
          CompilerBundle.message("error.compiler.process.not.started", e.getMessage()), e);
    } catch (IllegalArgumentException e) {
      throw new CompilerException(e.getMessage(), e);
    } finally {
      for (final VirtualFile file : myModuleToTempDirMap.values()) {
        if (file != null) {
          final File ioFile = new File(file.getPath());
          FileUtil.asyncDelete(ioFile);
        }
      }
      myModuleToTempDirMap.clear();
    }

    if (!myFilesToCompile.isEmpty()
        && myCompileContext.getMessageCount(CompilerMessageCategory.ERROR) == 0) {
      // package-info.java hack
      final List<TranslatingCompiler.OutputItem> outputs =
          new ArrayList<TranslatingCompiler.OutputItem>();
      ApplicationManager.getApplication()
          .runReadAction(
              new Runnable() {
                public void run() {
                  for (final VirtualFile file : myFilesToCompile) {
                    if (PACKAGE_ANNOTATION_FILE_NAME.equals(file.getName())
                        && !myProcessedPackageInfos.contains(file)) {
                      outputs.add(new OutputItemImpl(file));
                    }
                  }
                }
              });
      if (!outputs.isEmpty()) {
        mySink.add(null, outputs, VirtualFile.EMPTY_ARRAY);
      }
    }
  }
 private static VirtualFile[] getFilesToCheckReadonlyStatus(
     GeneratingCompiler.GenerationItem[] items) {
   List<VirtualFile> filesToCheck = new ArrayList<VirtualFile>();
   for (GeneratingCompiler.GenerationItem item : items) {
     if (item instanceof AndroidAptCompiler.AptGenerationItem) {
       final Set<File> generatedFiles =
           ((AndroidAptCompiler.AptGenerationItem) item).getGeneratedFiles().keySet();
       for (File generatedFile : generatedFiles) {
         if (generatedFile.exists()) {
           VirtualFile generatedVFile =
               LocalFileSystem.getInstance().findFileByIoFile(generatedFile);
           if (generatedVFile != null) {
             filesToCheck.add(generatedVFile);
           }
         }
       }
     }
   }
   return VfsUtil.toVirtualFileArray(filesToCheck);
 }
 private static boolean hasNotNullAnnotations(
     final Cache cache, final SymbolTable symbolTable, final int className, Project project)
     throws CacheCorruptedException {
   final NullableNotNullManager manager = NullableNotNullManager.getInstance(project);
   final List<String> notNulls = manager.getNotNulls();
   for (MethodInfo methodId : cache.getMethods(className)) {
     for (AnnotationConstantValue annotation : methodId.getRuntimeInvisibleAnnotations()) {
       if (notNulls.contains(symbolTable.getSymbol(annotation.getAnnotationQName()))) {
         return true;
       }
     }
     final AnnotationConstantValue[][] paramAnnotations =
         methodId.getRuntimeInvisibleParameterAnnotations();
     for (AnnotationConstantValue[] _singleParamAnnotations : paramAnnotations) {
       for (AnnotationConstantValue annotation : _singleParamAnnotations) {
         if (notNulls.contains(symbolTable.getSymbol(annotation.getAnnotationQName()))) {
           return true;
         }
       }
     }
   }
   return false;
 }
 private static void addItem(
     @NotNull final Collection<VirtualFile> sourceFiles,
     @NotNull final AndroidFacet facet,
     @NotNull final String resourceDirPath,
     @NotNull String sdkLocation,
     @NotNull final IAndroidTarget target,
     @NotNull final List<GenerationItem> items) {
   final String sourceRootPath = AndroidRootUtil.getRenderscriptGenSourceRootPath(facet);
   if (sourceRootPath == null) {
     return;
   }
   final String rawDirPath = resourceDirPath + '/' + AndroidConstants.FD_RES_RAW;
   items.add(
       new MyGenerationItem(facet.getModule(), sourceFiles, rawDirPath, sdkLocation, target));
 }
 @Nullable
 private File getOutputDirsToCompileTo(ModuleChunk chunk, final List<OutputDir> dirs)
     throws IOException {
   File fileToDelete = null;
   if (chunk.getModuleCount() == 1) { // optimization
     final Module module = chunk.getModules()[0];
     ApplicationManager.getApplication()
         .runReadAction(
             new Runnable() {
               public void run() {
                 final String sourcesOutputDir = getOutputDir(module);
                 if (shouldCompileTestsSeparately(module)) {
                   if (sourcesOutputDir != null) {
                     dirs.add(new OutputDir(sourcesOutputDir, ModuleChunk.SOURCES));
                   }
                   final String testsOutputDir = getTestsOutputDir(module);
                   if (testsOutputDir == null) {
                     LOG.error("Tests output dir is null for module \"" + module.getName() + "\"");
                   } else {
                     dirs.add(new OutputDir(testsOutputDir, ModuleChunk.TEST_SOURCES));
                   }
                 } else { // both sources and test sources go into the same output
                   if (sourcesOutputDir == null) {
                     LOG.error(
                         "Sources output dir is null for module \"" + module.getName() + "\"");
                   } else {
                     dirs.add(new OutputDir(sourcesOutputDir, ModuleChunk.ALL_SOURCES));
                   }
                 }
               }
             });
   } else { // chunk has several modules
     final File outputDir = FileUtil.createTempDirectory("compile", "output");
     fileToDelete = outputDir;
     dirs.add(new OutputDir(outputDir.getPath(), ModuleChunk.ALL_SOURCES));
   }
   return fileToDelete;
 }
  @Nullable
  private Pair<String, String> moveToRealLocation(
      String tempOutputDir,
      String pathToClass,
      VirtualFile sourceFile,
      final List<File> filesToRefresh) {
    final Module module = myCompileContext.getModuleByFile(sourceFile);
    if (module == null) {
      final String message =
          "Cannot determine module for source file: "
              + sourceFile.getPresentableUrl()
              + ";\nCorresponding output file: "
              + pathToClass;
      LOG.info(message);
      myCompileContext.addMessage(
          CompilerMessageCategory.WARNING, message, sourceFile.getUrl(), -1, -1);
      // do not move: looks like source file has been invalidated, need recompilation
      return new Pair<String, String>(tempOutputDir, pathToClass);
    }
    final String realOutputDir;
    if (myCompileContext.isInTestSourceContent(sourceFile)) {
      realOutputDir = getTestsOutputDir(module);
      LOG.assertTrue(realOutputDir != null);
    } else {
      realOutputDir = getOutputDir(module);
      LOG.assertTrue(realOutputDir != null);
    }

    if (FileUtil.pathsEqual(tempOutputDir, realOutputDir)) { // no need to move
      filesToRefresh.add(new File(pathToClass));
      return new Pair<String, String>(realOutputDir, pathToClass);
    }

    final String realPathToClass = realOutputDir + pathToClass.substring(tempOutputDir.length());
    final File fromFile = new File(pathToClass);
    final File toFile = new File(realPathToClass);

    boolean success = fromFile.renameTo(toFile);
    if (!success) {
      // assuming cause of the fail: intermediate dirs do not exist
      FileUtil.createParentDirs(toFile);
      // retry after making non-existent dirs
      success = fromFile.renameTo(toFile);
    }
    if (!success) { // failed to move the file: e.g. because source and destination reside on
                    // different mountpoints.
      try {
        FileUtil.copy(fromFile, toFile);
        FileUtil.delete(fromFile);
        success = true;
      } catch (IOException e) {
        LOG.info(e);
        success = false;
      }
    }
    if (success) {
      filesToRefresh.add(toFile);
      return new Pair<String, String>(realOutputDir, realPathToClass);
    }
    return null;
  }
  private void runTransformingCompilers(final ModuleChunk chunk) {
    final JavaSourceTransformingCompiler[] transformers =
        CompilerManager.getInstance(myProject).getCompilers(JavaSourceTransformingCompiler.class);
    if (transformers.length == 0) {
      return;
    }
    if (LOG.isDebugEnabled()) {
      LOG.debug("Running transforming compilers...");
    }
    final Module[] modules = chunk.getModules();
    for (final JavaSourceTransformingCompiler transformer : transformers) {
      final Map<VirtualFile, VirtualFile> originalToCopyFileMap =
          new HashMap<VirtualFile, VirtualFile>();
      final Application application = ApplicationManager.getApplication();
      application.invokeAndWait(
          new Runnable() {
            public void run() {
              for (final Module module : modules) {
                for (final VirtualFile file : chunk.getFilesToCompile(module)) {
                  final VirtualFile untransformed = chunk.getOriginalFile(file);
                  if (transformer.isTransformable(untransformed)) {
                    application.runWriteAction(
                        new Runnable() {
                          public void run() {
                            try {
                              // if untransformed != file, the file is already a (possibly
                              // transformed) copy of the original 'untransformed' file.
                              // If this is the case, just use already created copy and do not copy
                              // file content once again
                              final VirtualFile fileCopy =
                                  untransformed.equals(file)
                                      ? createFileCopy(getTempDir(module), file)
                                      : file;
                              originalToCopyFileMap.put(file, fileCopy);
                            } catch (IOException e) {
                              // skip it
                            }
                          }
                        });
                  }
                }
              }
            }
          },
          myCompileContext.getProgressIndicator().getModalityState());

      // do actual transform
      for (final Module module : modules) {
        final List<VirtualFile> filesToCompile = chunk.getFilesToCompile(module);
        for (int j = 0; j < filesToCompile.size(); j++) {
          final VirtualFile file = filesToCompile.get(j);
          final VirtualFile fileCopy = originalToCopyFileMap.get(file);
          if (fileCopy != null) {
            final boolean ok =
                transformer.transform(myCompileContext, fileCopy, chunk.getOriginalFile(file));
            if (ok) {
              chunk.substituteWithTransformedVersion(module, j, fileCopy);
            }
          }
        }
      }
    }
  }
  private static GenerationItem[] doGenerate(
      @NotNull final CompileContext context,
      @NotNull final GenerationItem[] items,
      VirtualFile outputRootDirectory) {
    if (context.getProject().isDisposed()) {
      return EMPTY_GENERATION_ITEM_ARRAY;
    }

    // we have one item per module there, so clear output directory
    final String genRootPath = FileUtil.toSystemDependentName(outputRootDirectory.getPath());
    final File genRootDir = new File(genRootPath);
    if (genRootDir.exists()) {
      if (!FileUtil.delete(genRootDir)) {
        context.addMessage(
            CompilerMessageCategory.ERROR, "Cannot delete directory " + genRootPath, null, -1, -1);
        return EMPTY_GENERATION_ITEM_ARRAY;
      }
      if (!genRootDir.mkdir()) {
        context.addMessage(
            CompilerMessageCategory.ERROR, "Cannot create directory " + genRootPath, null, -1, -1);
        return EMPTY_GENERATION_ITEM_ARRAY;
      }
    }

    final List<GenerationItem> results = new ArrayList<GenerationItem>(items.length);
    for (final GenerationItem item : items) {
      if (item instanceof MyGenerationItem) {
        final MyGenerationItem genItem = (MyGenerationItem) item;

        if (!AndroidCompileUtil.isModuleAffected(context, genItem.myModule)) {
          continue;
        }

        boolean success = true;

        for (final VirtualFile sourceFile : genItem.myFiles) {
          final String depFolderOsPath =
              getDependencyFolder(context.getProject(), sourceFile, outputRootDirectory);

          try {
            final Map<CompilerMessageCategory, List<String>> messages =
                AndroidCompileUtil.toCompilerMessageCategoryKeys(
                    AndroidRenderscript.execute(
                        genItem.mySdkLocation,
                        genItem.myAndroidTarget,
                        sourceFile.getPath(),
                        genRootPath,
                        depFolderOsPath,
                        genItem.myRawDirPath));

            ApplicationManager.getApplication()
                .runReadAction(
                    new Runnable() {
                      public void run() {
                        if (context.getProject().isDisposed()) {
                          return;
                        }
                        addMessages(context, messages, sourceFile.getUrl());
                      }
                    });

            if (messages.get(CompilerMessageCategory.ERROR).size() > 0) {
              success = false;
            }
          } catch (final IOException e) {
            ApplicationManager.getApplication()
                .runReadAction(
                    new Runnable() {
                      public void run() {
                        if (context.getProject().isDisposed()) return;
                        context.addMessage(
                            CompilerMessageCategory.ERROR,
                            e.getMessage(),
                            sourceFile.getUrl(),
                            -1,
                            -1);
                      }
                    });
            success = false;
          }
        }

        if (success) {
          results.add(genItem);
        }
      }
    }
    outputRootDirectory.refresh(false, true);
    return results.toArray(new GenerationItem[results.size()]);
  }
  public static void generate(GeneratingCompiler compiler, final CompileContext context) {
    if (context == null) {
      return;
    }

    final Set<Module> affectedModules = new HashSet<Module>();
    Collections.addAll(affectedModules, context.getCompileScope().getAffectedModules());

    ApplicationManager.getApplication()
        .invokeAndWait(
            new Runnable() {
              @Override
              public void run() {
                for (Module module : affectedModules) {
                  if (module.isDisposed() || module.getProject().isDisposed()) {
                    continue;
                  }

                  final AndroidFacet facet = AndroidFacet.getInstance(module);
                  if (facet != null) {
                    AndroidCompileUtil.createGenModulesAndSourceRoots(facet);
                  }
                }
              }
            },
            ModalityState.defaultModalityState());

    List<GeneratingCompiler.GenerationItem> itemsToGenerate =
        new ArrayList<GeneratingCompiler.GenerationItem>();
    for (GeneratingCompiler.GenerationItem item : compiler.getGenerationItems(context)) {
      if (affectedModules.contains(item.getModule())) {
        itemsToGenerate.add(item);
      }
    }

    GeneratingCompiler.GenerationItem[] items =
        itemsToGenerate.toArray(new GeneratingCompiler.GenerationItem[itemsToGenerate.size()]);

    final boolean[] run = {true};
    final VirtualFile[] files = getFilesToCheckReadonlyStatus(items);
    if (files.length > 0) {
      ApplicationManager.getApplication()
          .invokeAndWait(
              new Runnable() {
                @Override
                public void run() {
                  ApplicationManager.getApplication()
                      .runReadAction(
                          new Runnable() {
                            @Override
                            public void run() {
                              final Project project = context.getProject();
                              run[0] =
                                  !project.isDisposed()
                                      && ReadonlyStatusHandler.ensureFilesWritable(project, files);
                            }
                          });
                }
              },
              ModalityState.defaultModalityState());
    }

    if (run[0]) {
      compiler.generate(context, items, null);
    }
  }