/** * */ package renaming.evaluation; import static com.google.common.base.Preconditions.checkArgument; import java.io.File; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map.Entry; import java.util.Set; import java.util.SortedSet; import java.util.logging.Logger; import org.apache.commons.io.FileUtils; import org.apache.commons.io.filefilter.DirectoryFileFilter; import org.apache.commons.lang.exception.ExceptionUtils; import org.apache.commons.lang.math.RandomUtils; import org.eclipse.jdt.core.dom.ASTNode; import renaming.renamers.AbstractIdentifierRenamings; import renaming.renamers.INGramIdentifierRenamer.Renaming; import codemining.java.codeutils.scopes.VariableScopeExtractor; import codemining.java.codeutils.scopes.VariableScopeExtractor.Variable; import codemining.java.tokenizers.JavaTokenizer; import codemining.languagetools.ITokenizer; import codemining.languagetools.Scope; import codemining.util.SettingsLoader; import codemining.util.parallel.ParallelThreadPool; import com.google.common.collect.Lists; import com.google.common.collect.Multimap; import com.google.common.collect.Sets; /** * Evaluate the "problem" with junk variable names. * * @author Miltos Allamanis <[email protected]> * */ public class JunkIssueEvaluator { private static class JunkPercentage { public long totalVariables = 0; public long nJunkInTotal = 0; public synchronized void putResults(final long nVars, final long nJunk) { totalVariables += nVars; nJunkInTotal += nJunk; } } class JunkRenamingRunnable implements Runnable { final Collection<File> allFiles; final File testFile; final JunkPercentage resultObject; public JunkRenamingRunnable(final Collection<File> allFiles, final File testFile, final JunkPercentage resultObject) { this.allFiles = allFiles; this.testFile = testFile; this.resultObject = resultObject; } @Override public void run() { try { final Multimap<Scope, String> scopes = (new VariableScopeExtractor.VariableScopeSnippetExtractor()) .getFromFile(testFile); final List<Entry<Scope, String>> selectedScopes = sampleScopes(scopes); if (selectedScopes.isEmpty()) { return; } final Set<File> trainFiles = Sets.newTreeSet(allFiles); checkArgument(trainFiles.remove(testFile)); final AbstractIdentifierRenamings renamer = createRenamer( renamerClass, renamerConstructorParams); renamer.buildRenamingModel(trainFiles); final long nVars = selectedScopes.size(); long nJunk = 0; for (final Entry<Scope, String> variable : selectedScopes) { final SortedSet<Renaming> renamings = renamer.getRenamings( variable.getKey(), variable.getValue()); if (renamings.first().name.matches("^junk[0-9]+$")) { nJunk++; } } resultObject.putResults(nVars, nJunk); } catch (final IOException ioe) { LOGGER.warning("Failed to get scopes from " + testFile.getAbsolutePath() + " " + ExceptionUtils.getFullStackTrace(ioe)); } } /** * @param scopes * @return */ private List<Entry<Scope, String>> sampleScopes( final Multimap<Scope, String> scopes) { final List<Entry<Scope, String>> selectedScopes = Lists .newArrayList(); // Sample for (final Entry<Scope, String> variable : scopes.entries()) { if (RandomUtils.nextDouble() > SAMPLING_RATIO) { continue; } selectedScopes.add(variable); } return selectedScopes; } } public static final double SAMPLING_RATIO = SettingsLoader .getNumericSetting("samplingPercent", 1.); private static final Logger LOGGER = Logger .getLogger(JunkIssueEvaluator.class.getName()); /** * @param args */ public static void main(final String[] args) { if (args.length < 3) { System.err .println("Usage <projectDir> <tempDir> <renamerClass> [renamerConstructorParams]"); return; } final JunkIssueEvaluator jie = new JunkIssueEvaluator( new File(args[0]), new File(args[1]), args[2], args.length == 4 ? args[3] : null); final double[] results = jie.runExperiment(); System.out.println(Arrays.toString(results)); } JavaTokenizer tokenizer = new JavaTokenizer(); final double[] pJunkification = { .005, .01, .02, .03, .05, .07, .1, .15 }; final File tmpDir; final File prjDir; final String renamerClass; final String renamerConstructorParams; final List<File> junkVariables = Lists.newArrayList(); long nTotalVars; /** * */ public JunkIssueEvaluator(final File projectDir, final File tmpDir, final String renamerClass, final String renamerConstructorParams) { this.tmpDir = tmpDir; this.prjDir = projectDir; this.renamerClass = renamerClass; this.renamerConstructorParams = renamerConstructorParams; } private void addJunkVarsUpToPct(final double percent, final JunkVariableRenamer jvr) { // Find total num of variables that need to be renamed final long targetSize = (long) ((1. - percent) * nTotalVars); final long nVarsToRename = junkVariables.size() - targetSize; // Rename for (int i = 0; i < nVarsToRename; i++) { try { final File currentFile = junkVariables.remove(junkVariables .size() - 1); FileUtils.writeStringToFile(currentFile, jvr .renameSingleVariablesToJunk(FileUtils .readFileToString(currentFile))); } catch (final Exception e) { LOGGER.warning(ExceptionUtils.getFullStackTrace(e)); } } } /** * @param renamerClass * @param renamerConstructorParams * @throws IllegalArgumentException */ private AbstractIdentifierRenamings createRenamer( final String renamerClass, final String renamerConstructorParams) throws IllegalArgumentException { final AbstractIdentifierRenamings renamer; try { if (renamerConstructorParams == null) { renamer = (AbstractIdentifierRenamings) Class .forName(renamerClass) .getDeclaredConstructor(ITokenizer.class) .newInstance(tokenizer); } else { renamer = (AbstractIdentifierRenamings) Class .forName(renamerClass) .getDeclaredConstructor(ITokenizer.class, String.class) .newInstance(tokenizer, renamerConstructorParams); } } catch (final IllegalArgumentException e) { LOGGER.severe(ExceptionUtils.getFullStackTrace(e)); throw new IllegalArgumentException(e); } catch (final SecurityException e) { LOGGER.severe(ExceptionUtils.getFullStackTrace(e)); throw new IllegalArgumentException(e); } catch (final InstantiationException e) { LOGGER.severe(ExceptionUtils.getFullStackTrace(e)); throw new IllegalArgumentException(e); } catch (final IllegalAccessException e) { LOGGER.severe(ExceptionUtils.getFullStackTrace(e)); throw new IllegalArgumentException(e); } catch (final InvocationTargetException e) { LOGGER.severe(ExceptionUtils.getFullStackTrace(e)); throw new IllegalArgumentException(e); } catch (final NoSuchMethodException e) { LOGGER.severe(ExceptionUtils.getFullStackTrace(e)); throw new IllegalArgumentException(e); } catch (final ClassNotFoundException e) { LOGGER.severe(ExceptionUtils.getFullStackTrace(e)); throw new IllegalArgumentException(e); } return renamer; } private double evaluateNumJunkVars() { final Collection<File> allFiles = FileUtils.listFiles(tmpDir, tokenizer.getFileFilter(), DirectoryFileFilter.DIRECTORY); final ParallelThreadPool ptp = new ParallelThreadPool(); final JunkPercentage jp = new JunkPercentage(); for (final File testFile : allFiles) { ptp.pushTask(new JunkRenamingRunnable(allFiles, testFile, jp)); } ptp.waitForTermination(); LOGGER.info("accJunk = " + ((double) jp.nJunkInTotal) / jp.totalVariables); return ((double) jp.nJunkInTotal) / jp.totalVariables; } private void mirrorToTemporaryDir() { final Collection<File> allFiles = FileUtils.listFiles(prjDir, tokenizer.getFileFilter(), DirectoryFileFilter.DIRECTORY); try { FileUtils.cleanDirectory(tmpDir); } catch (final IOException e) { LOGGER.warning("Failed to clean temporary directory"); } for (final File file : allFiles) { try { final Multimap<ASTNode, Variable> vars = VariableScopeExtractor .getVariableScopes(file); final long nVars = vars.entries().size(); nTotalVars += nVars; final File outFile = new File(tmpDir.getAbsolutePath() + "/" + file.getName()); for (int i = 0; i < nVars; i++) { junkVariables.add(outFile); } FileUtils.copyFile(file, outFile); } catch (final IOException e) { e.printStackTrace(); } } Collections.shuffle(junkVariables); // Generate random plan } public double[] runExperiment() { final double[] pJunk = new double[pJunkification.length]; mirrorToTemporaryDir(); final JunkVariableRenamer jvr = new JunkVariableRenamer(); for (int i = 0; i < pJunkification.length; i++) { addJunkVarsUpToPct(pJunkification[i], jvr); pJunk[i] = evaluateNumJunkVars(); System.out.println(pJunkification[i] + ":" + pJunk[i]); } return pJunk; } }