private void compileFinished(int exitValue, final ModuleChunk chunk, final String outputDir) {
    if (exitValue != 0
        && !myCompileContext.getProgressIndicator().isCanceled()
        && myCompileContext.getMessageCount(CompilerMessageCategory.ERROR) == 0) {
      myCompileContext.addMessage(
          CompilerMessageCategory.ERROR,
          CompilerBundle.message("error.compiler.internal.error", exitValue),
          null,
          -1,
          -1);
    }

    myCompiler.compileFinished();
    final List<File> toRefresh = new ArrayList<File>();
    final Map<String, Collection<TranslatingCompiler.OutputItem>> results =
        new HashMap<String, Collection<TranslatingCompiler.OutputItem>>();
    try {
      final FileTypeManager typeManager = FileTypeManager.getInstance();
      final String outputDirPath = outputDir.replace(File.separatorChar, '/');
      try {
        for (final Module module : chunk.getModules()) {
          for (final VirtualFile root : chunk.getSourceRoots(module)) {
            final String packagePrefix = myProjectFileIndex.getPackageNameByDirectory(root);
            if (LOG.isDebugEnabled()) {
              LOG.debug(
                  "Building output items for "
                      + root.getPresentableUrl()
                      + "; output dir = "
                      + outputDirPath
                      + "; packagePrefix = \""
                      + packagePrefix
                      + "\"");
            }
            buildOutputItemsList(
                outputDirPath, module, root, typeManager, root, packagePrefix, toRefresh, results);
          }
        }
      } catch (CacheCorruptedException e) {
        myCompileContext.requestRebuildNextTime(
            CompilerBundle.message("error.compiler.caches.corrupted"));
        if (LOG.isDebugEnabled()) {
          LOG.debug(e);
        }
      }
    } finally {
      CompilerUtil.refreshIOFiles(toRefresh);
      for (Iterator<Map.Entry<String, Collection<TranslatingCompiler.OutputItem>>> it =
              results.entrySet().iterator();
          it.hasNext(); ) {
        Map.Entry<String, Collection<TranslatingCompiler.OutputItem>> entry = it.next();
        mySink.add(entry.getKey(), entry.getValue(), VirtualFile.EMPTY_ARRAY);
        it.remove(); // to free memory
      }
    }
    myFileNameToSourceMap.clear(); // clear the map before the next use
  }
 private void registerParsingException(final CompilerParsingThread outputParsingThread) {
   Throwable error = outputParsingThread == null ? null : outputParsingThread.getError();
   if (error != null) {
     String message = error.getMessage();
     if (error instanceof CacheCorruptedException) {
       myCompileContext.requestRebuildNextTime(message);
     } else {
       myCompileContext.addMessage(CompilerMessageCategory.ERROR, message, null, -1, -1);
     }
   }
 }
 private void validateEncoding(ModuleChunk chunk, String chunkPresentableName) {
   final CompilerEncodingService es = CompilerEncodingService.getInstance(myProject);
   Charset charset = null;
   for (Module module : chunk.getModules()) {
     final Charset moduleCharset = es.getPreferredModuleEncoding(module);
     if (charset == null) {
       charset = moduleCharset;
     } else {
       if (!Comparing.equal(charset, moduleCharset)) {
         // warn user
         final Charset chunkEncoding = CompilerEncodingService.getPreferredModuleEncoding(chunk);
         final StringBuilder message = new StringBuilder();
         message.append("Modules in chunk [");
         message.append(chunkPresentableName);
         message.append("] configured to use different encodings.\n");
         if (chunkEncoding != null) {
           message
               .append("\"")
               .append(chunkEncoding.name())
               .append("\" encoding will be used to compile the chunk");
         } else {
           message.append("Default compiler encoding will be used to compile the chunk");
         }
         myCompileContext.addMessage(
             CompilerMessageCategory.INFORMATION, message.toString(), null, -1, -1);
         break;
       }
     }
   }
 }
 private String getOutputDir(final Module module) {
   if (myModuleToOutput.containsKey(module)) {
     return myModuleToOutput.get(module);
   }
   final VirtualFile outputDirectory = myCompileContext.getModuleOutputDirectory(module);
   final String out = outputDirectory != null ? outputDirectory.getPath() : null;
   myModuleToOutput.put(module, out);
   return out;
 }
 public BackendCompilerWrapper(
     TranslatingCompiler translatingCompiler,
     Chunk<Module> chunk,
     @NotNull final Project project,
     @NotNull List<VirtualFile> filesToCompile,
     @NotNull CompileContextEx compileContext,
     @NotNull BackendCompiler compiler,
     TranslatingCompiler.OutputSink sink) {
   myTranslatingCompiler = translatingCompiler;
   myChunk = chunk;
   myProject = project;
   myCompiler = compiler;
   myCompileContext = compileContext;
   myFilesToCompile = filesToCompile;
   mySink = sink;
   myProjectFileIndex = ProjectRootManager.getInstance(myProject).getFileIndex();
   CompileStatistics stat = compileContext.getUserData(CompileStatistics.KEY);
   if (stat == null) {
     stat = new CompileStatistics();
     compileContext.putUserData(CompileStatistics.KEY, stat);
   }
   myStatistics = stat;
 }
  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 void updateStatistics() {
   final String msg;
   String moduleName = myModuleName;
   if (moduleName != null) {
     msg =
         CompilerBundle.message(
             "statistics.files.classes.module",
             myStatistics.getFilesCount(),
             myStatistics.getClassesCount(),
             moduleName);
   } else {
     msg =
         CompilerBundle.message(
             "statistics.files.classes",
             myStatistics.getFilesCount(),
             myStatistics.getClassesCount());
   }
   myCompileContext.getProgressIndicator().setText2(msg);
   // myCompileContext.getProgressIndicator().setFraction(1.0* myProcessedFilesCount
   // /myTotalFilesToCompile);
 }
  @Override
  public GenerationItem[] generate(
      final CompileContext context,
      final GenerationItem[] items,
      final VirtualFile outputRootDirectory) {
    if (items == null || items.length <= 0) {
      return EMPTY_GENERATION_ITEM_ARRAY;
    }

    context.getProgressIndicator().setText("Compiling RenderScript files...");
    final GenerationItem[] generationItems = doGenerate(context, items, outputRootDirectory);
    final Set<VirtualFile> generatedVFiles = new HashSet<VirtualFile>();
    final HashSet<VirtualFile> visited = new HashSet<VirtualFile>();

    outputRootDirectory.refresh(false, true);
    AndroidUtils.collectFiles(outputRootDirectory, visited, generatedVFiles);

    if (context instanceof CompileContextEx) {
      ((CompileContextEx) context).markGenerated(generatedVFiles);
    }
    return generationItems;
  }
  @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 updateOutputItemsList(
      final String outputDir,
      final VirtualFile srcFile,
      VirtualFile sourceRoot,
      final String packagePrefix,
      final List<File> filesToRefresh,
      Map<String, Collection<TranslatingCompiler.OutputItem>> results,
      final GlobalSearchScope srcRootScope)
      throws CacheCorruptedException {
    CompositeDependencyCache dependencyCache = myCompileContext.getDependencyCache();
    JavaDependencyCache child = dependencyCache.findChild(JavaDependencyCache.class);
    final Cache newCache = child.getNewClassesCache();
    final Set<CompiledClass> paths = myFileNameToSourceMap.get(srcFile.getName());
    if (paths == null || paths.isEmpty()) {
      return;
    }
    final String filePath = "/" + calcPackagePath(srcFile, sourceRoot, packagePrefix);
    for (final CompiledClass cc : paths) {
      myCompileContext.getProgressIndicator().checkCanceled();
      if (LOG.isDebugEnabled()) {
        LOG.debug("Checking [pathToClass; relPathToSource] = " + cc);
      }

      boolean pathsEquals = FileUtil.pathsEqual(filePath, cc.relativePathToSource);
      if (!pathsEquals) {
        final String qName = child.resolve(cc.qName);
        if (qName != null) {
          pathsEquals =
              ApplicationManager.getApplication()
                  .runReadAction(
                      new Computable<Boolean>() {
                        public Boolean compute() {
                          final JavaPsiFacade facade = JavaPsiFacade.getInstance(myProject);
                          PsiClass psiClass = facade.findClass(qName, srcRootScope);
                          if (psiClass == null) {
                            final int dollarIndex = qName.indexOf("$");
                            if (dollarIndex >= 0) {
                              final String topLevelClassName = qName.substring(0, dollarIndex);
                              psiClass = facade.findClass(topLevelClassName, srcRootScope);
                            }
                          }
                          if (psiClass != null) {
                            final VirtualFile vFile = psiClass.getContainingFile().getVirtualFile();
                            return vFile != null && vFile.equals(srcFile);
                          }
                          return false;
                        }
                      });
        }
      }

      if (pathsEquals) {
        final String outputPath = cc.pathToClass.replace(File.separatorChar, '/');
        final Pair<String, String> realLocation =
            moveToRealLocation(outputDir, outputPath, srcFile, filesToRefresh);
        if (realLocation != null) {
          Collection<TranslatingCompiler.OutputItem> outputs = results.get(realLocation.getFirst());
          if (outputs == null) {
            outputs = new ArrayList<TranslatingCompiler.OutputItem>();
            results.put(realLocation.getFirst(), outputs);
          }
          outputs.add(new OutputItemImpl(realLocation.getSecond(), srcFile));
          if (PACKAGE_ANNOTATION_FILE_NAME.equals(srcFile.getName())) {
            myProcessedPackageInfos.add(srcFile);
          }
          if (CompilerManager.MAKE_ENABLED) {
            newCache.setPath(cc.qName, realLocation.getSecond());
          }
          if (LOG.isDebugEnabled()) {
            LOG.debug(
                "Added output item: [outputDir; outputPath; sourceFile]  = ["
                    + realLocation.getFirst()
                    + "; "
                    + realLocation.getSecond()
                    + "; "
                    + srcFile.getPresentableUrl()
                    + "]");
          }
        } else {
          myCompileContext.addMessage(
              CompilerMessageCategory.ERROR,
              "Failed to copy from temporary location to output directory: "
                  + outputPath
                  + " (see idea.log for details)",
              null,
              -1,
              -1);
          if (LOG.isDebugEnabled()) {
            LOG.debug("Failed to move to real location: " + outputPath + "; from " + outputDir);
          }
        }
      }
    }
  }
  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 void doCompile(@NotNull final ModuleChunk chunk, @NotNull String outputDir)
      throws IOException {
    myCompileContext.getProgressIndicator().checkCanceled();

    if (ApplicationManager.getApplication()
        .runReadAction(
            new Computable<Boolean>() {
              public Boolean compute() {
                return chunk.getFilesToCompile().isEmpty() ? Boolean.TRUE : Boolean.FALSE;
              }
            })
        .booleanValue()) {
      return; // should not invoke javac with empty sources list
    }

    int exitValue = 0;
    try {
      final Process process = myCompiler.launchProcess(chunk, outputDir, myCompileContext);
      final long compilationStart = System.currentTimeMillis();
      final ClassParsingThread classParsingThread =
          new ClassParsingThread(isJdk6(JavaSdkUtil.getSdkForCompilation(chunk)), outputDir);
      final Future<?> classParsingThreadFuture =
          ApplicationManager.getApplication().executeOnPooledThread(classParsingThread);

      OutputParser errorParser = myCompiler.createErrorParser(outputDir, process);
      CompilerParsingThread errorParsingThread =
          errorParser == null
              ? null
              : new SynchedCompilerParsing(
                  process,
                  myCompileContext,
                  errorParser,
                  classParsingThread,
                  true,
                  errorParser.isTrimLines());
      Future<?> errorParsingThreadFuture = null;
      if (errorParsingThread != null) {
        errorParsingThreadFuture =
            ApplicationManager.getApplication().executeOnPooledThread(errorParsingThread);
      }

      OutputParser outputParser = myCompiler.createOutputParser(outputDir);
      CompilerParsingThread outputParsingThread =
          outputParser == null
              ? null
              : new SynchedCompilerParsing(
                  process,
                  myCompileContext,
                  outputParser,
                  classParsingThread,
                  false,
                  outputParser.isTrimLines());
      Future<?> outputParsingThreadFuture = null;
      if (outputParsingThread != null) {
        outputParsingThreadFuture =
            ApplicationManager.getApplication().executeOnPooledThread(outputParsingThread);
      }

      try {
        exitValue = process.waitFor();
      } catch (InterruptedException e) {
        process.destroy();
        exitValue = process.exitValue();
      } catch (Error e) {
        process.destroy();
        exitValue = process.exitValue();
        throw e;
      } finally {
        if (CompileDriver.ourDebugMode) {
          System.out.println("Compiler exit code is " + exitValue);
        }
        if (errorParsingThread != null) {
          errorParsingThread.setProcessTerminated(true);
        }
        if (outputParsingThread != null) {
          outputParsingThread.setProcessTerminated(true);
        }
        joinThread(errorParsingThreadFuture);
        joinThread(outputParsingThreadFuture);
        classParsingThread.stopParsing();
        joinThread(classParsingThreadFuture);

        registerParsingException(outputParsingThread);
        registerParsingException(errorParsingThread);
        assert outputParsingThread == null || !outputParsingThread.processing;
        assert errorParsingThread == null || !errorParsingThread.processing;
        assert classParsingThread == null || !classParsingThread.processing;
      }
    } finally {
      compileFinished(exitValue, chunk, outputDir);
      myModuleName = null;
    }
  }