3939import java .io .File ;
4040import java .io .IOException ;
4141
42- import java .util .List ;
43- import java .util .ArrayList ;
44- import java .util .Arrays ;
45- import java .util .Collections ;
46- import java .util .HashSet ;
47- import java .util .LinkedList ;
48- import java .util .Iterator ;
42+ import java .util .*;
4943
5044import edu .rice .cs .drjava .model .DJError ;
5145import edu .rice .cs .drjava .model .GlobalModel ;
@@ -331,20 +325,12 @@ private void _compileFiles(List<? extends File> files, File buildDir) throws IOE
331325 }
332326 }
333327
334-
335328 /** Compiles the language levels files in the list. Adds any errors to the given error list.
336329 * @return An updated list for compilation containing no Language Levels files, or @code{null}
337330 * if there were no Language Levels files to process.
338331 */
339332 private List <? extends File > _compileLanguageLevelsFiles (List <? extends File > files , List <DJError > errors ,
340333 Iterable <File > classPath , Iterable <File > bootClassPath ) {
341- LanguageLevelConverter llc = new LanguageLevelConverter ();
342- Options llOpts ;
343- if (bootClassPath == null ) { llOpts = new Options (getActiveCompiler ().version (), classPath ); }
344- else { llOpts = new Options (getActiveCompiler ().version (), classPath , bootClassPath ); }
345- Pair <LinkedList <JExprParseException >, LinkedList <Pair <String , JExpressionIF >>> llErrors =
346- llc .convert (files .toArray (new File [0 ]), llOpts );
347-
348334 /* Rename any .dj0 files in files to be .java files, so the correct thing is compiled. The hashset is used to
349335 * make sure we never send in duplicate files. This can happen if the java file was sent in along with the
350336 * corresponding .dj* file. The dj* file is renamed to a .java file and thus we have two of the same file in
@@ -358,10 +344,82 @@ private List<? extends File> _compileLanguageLevelsFiles(List<? extends File> fi
358344 int lastIndex = fileName .lastIndexOf (".dj" );
359345 if (lastIndex != -1 ) {
360346 containsLanguageLevels = true ;
361- javaFileSet .add (new File (fileName .substring (0 , lastIndex ) + ".java" ));
347+ File javaFile = new File ( fileName .substring (0 , lastIndex ) + ".java" );
348+ javaFileSet .add (javaFile );
349+
350+ // Delete the .java file, it will be regenerated later
351+ javaFile .delete ();
362352 }
363353 else { javaFileSet .add (canonicalFile ); }
364354 }
355+
356+ LanguageLevelConverter llc = new LanguageLevelConverter ();
357+ Options llOpts ;
358+ if (bootClassPath == null ) { llOpts = new Options (getActiveCompiler ().version (), classPath ); }
359+ else { llOpts = new Options (getActiveCompiler ().version (), classPath , bootClassPath ); }
360+ Map <File ,Set <String >> sourceToTopLevelClassMap = new HashMap <File ,Set <String >>();
361+ Pair <LinkedList <JExprParseException >, LinkedList <Pair <String , JExpressionIF >>> llErrors =
362+ llc .convert (files .toArray (new File [0 ]), llOpts , sourceToTopLevelClassMap );
363+
364+ if (containsLanguageLevels ) {
365+ final File buildDir = _model .getBuildDirectory ();
366+ final File sourceDir = _model .getProjectRoot ();
367+ // System.out.println("Build dir : "+buildDir);
368+ // System.out.println("Source root: "+sourceDir);
369+ // Delete the .class files that match the following pattern:
370+ // XXX.dj? --> XXX.class
371+ // XXX$*.class
372+ // Accessing the disk is the most costly part; therefore, we want to scan each directory only once.
373+ // We create a map from parent directory to class names in that directory.
374+ // Then we scan the files in each directory and delete files that match the class names listed for it.
375+ // dirToClassNameMap: key=parent directory, value=set of classes in this directory
376+ Map <File ,Set <String >> dirToClassNameMap = new HashMap <File ,Set <String >>();
377+ for (Map .Entry <File ,Set <String >> e : sourceToTopLevelClassMap .entrySet ()) {
378+ try {
379+ File dir = e .getKey ().getParentFile ();
380+ if ((buildDir !=null )&&(buildDir !=FileOps .NULL_FILE )&&
381+ (sourceDir !=null )&&(sourceDir !=FileOps .NULL_FILE )) {
382+ // build directory set
383+ String rel = edu .rice .cs .util .FileOps .stringMakeRelativeTo (dir ,sourceDir );
384+ dir = new File (buildDir ,rel );
385+ }
386+ Set <String > classNames = dirToClassNameMap .get (dir );
387+ if (classNames ==null ) classNames = new HashSet <String >();
388+ classNames .addAll (e .getValue ());
389+ dirToClassNameMap .put (dir ,classNames );
390+ // System.out.println(e.getKey()+" --> "+dir);
391+ // for(String name: e.getValue()) {
392+ // System.out.println("\t"+name);
393+ // }
394+ }
395+ catch (IOException ioe ) { /* we'll fail to delete this, but that's better than deleting something we shouldn't */ }
396+ }
397+ // Now that we have a map from parent directories to the class names that should be deleted
398+ // in them, we scan the files in each directory, then check if the names match the class names.
399+ for (final Map .Entry <File ,Set <String >> e : dirToClassNameMap .entrySet ()) {
400+ // System.out.println("Processing dir: "+e.getKey());
401+ // System.out.println("\t"+java.util.Arrays.toString(e.getValue().toArray(new String[0])));
402+ e .getKey ().listFiles (new java .io .FilenameFilter () {
403+ public boolean accept (File dir , String name ) {
404+ // System.out.println("\t"+name);
405+ int endPos = name .lastIndexOf (".class" );
406+ if (endPos <0 ) return false ; // can't be a class file
407+ int dollarPos = name .indexOf ('$' );
408+ if ((dollarPos >=0 ) && (dollarPos <endPos )) endPos = dollarPos ;
409+ // class name goes to the .class or the first $, whichever comes first
410+ Set <String > classNames = e .getValue ();
411+ if (classNames .contains (name .substring (0 ,endPos ))) {
412+ // this is a class file that is generated from a .dj? file
413+ new File (dir ,name ).delete ();
414+ // don't need to return true, we're deleting the file here already
415+ // System.out.println("\t\tDeleted");
416+ }
417+ return false ;
418+ }
419+ });
420+ }
421+ }
422+
365423 files = new LinkedList <File >(javaFileSet );
366424
367425 errors .addAll (_parseExceptions2CompilerErrors (llErrors .getFirst ()));
0 commit comments