/** * */ package renaming.segmentranking; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; import java.io.File; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.util.Collection; import java.util.Map.Entry; 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.eclipse.jdt.core.dom.ASTNode; import renaming.renamers.AbstractIdentifierRenamings; import renaming.renamers.BaseIdentifierRenamings; import renaming.renamers.INGramIdentifierRenamer.Renaming; import codemining.java.codeutils.scopes.ScopesTUI; import codemining.java.codeutils.scopes.VariableScopeExtractor; import codemining.java.tokenizers.JavaTokenizer; import codemining.languagetools.IScopeExtractor; import codemining.languagetools.ITokenizer; import codemining.languagetools.Scope; import com.google.common.base.Objects; import com.google.common.collect.ComparisonChain; import com.google.common.collect.Multimap; import com.google.common.collect.Sets; /** * Rank renaming suggestions based on the confidence we have. * * @author Miltos Allamanis <[email protected]> * */ public class SegmentRenamingSuggestion { /** * Struct class for suggestions. * */ public static class Suggestion implements Comparable<Suggestion> { final double confidenceGap; public final Scope scope; final String identifierName; final SortedSet<Renaming> renamings; Suggestion(final String idName, final Scope scope, final double confidence, final SortedSet<Renaming> alternatives) { identifierName = idName; this.scope = scope; renamings = alternatives; confidenceGap = confidence; } @Override public int compareTo(final Suggestion other) { return ComparisonChain.start() .compare(confidenceGap, other.confidenceGap) .compare(identifierName, other.identifierName) .compare(scope, other.scope).result(); } @Override public boolean equals(final Object obj) { if (!(obj instanceof Suggestion)) { return false; } final Suggestion other = (Suggestion) obj; return Double.compare(confidenceGap, other.confidenceGap) == 0 && identifierName.compareTo(other.identifierName) == 0 && scope.compareTo(other.scope) == 0; } public double getConfidence() { return confidenceGap; } public String getIdentifierName() { return identifierName; } /** * Return the probability that this renaming will happen. * * @return */ public double getProbNotRename() { double probNotRename = 0; final String targetIdentifier = getIdentifierName(); double sum = 0; for (final Renaming renaming : getRenamings()) { sum += Math.pow(2, -renaming.score); } for (final Renaming renaming : getRenamings()) { if (renaming.name.equals(targetIdentifier) || renaming.name.equals("UNK_SYMBOL")) { probNotRename += Math.pow(2, -renaming.score) / sum; } } return probNotRename; } public SortedSet<Renaming> getRenamings() { return renamings; } @Override public int hashCode() { return Objects.hashCode(identifierName, scope, confidenceGap); } @Override public String toString() { return identifierName + "(" + confidenceGap + ")"; } } private static final Logger LOGGER = Logger .getLogger(SegmentRenamingSuggestion.class.getName()); public static SortedSet<Suggestion> getVariableSuggestions( final File currentFile, final File directory, final boolean useUNK) throws IOException { final ITokenizer tokenizer = new JavaTokenizer(); final AbstractIdentifierRenamings renamer = new BaseIdentifierRenamings( tokenizer); final Collection<java.io.File> trainingFiles = FileUtils.listFiles( directory, tokenizer.getFileFilter(), DirectoryFileFilter.DIRECTORY); trainingFiles.remove(currentFile); renamer.buildRenamingModel(trainingFiles); final IScopeExtractor scopeExtractor = new VariableScopeExtractor.VariableScopeSnippetExtractor(); final SegmentRenamingSuggestion suggestion = new SegmentRenamingSuggestion( renamer, scopeExtractor, useUNK); return suggestion.rankSuggestions(currentFile); } public static void main(final String[] args) throws IllegalArgumentException, SecurityException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException, ClassNotFoundException, IOException { if (args.length < 4) { System.err .println("Usage <TestFile> <TrainDirectory> <renamerClass> variable|method"); return; } final ITokenizer tokenizer = new JavaTokenizer(); final AbstractIdentifierRenamings renamer = (AbstractIdentifierRenamings) Class .forName(args[2]).getDeclaredConstructor(ITokenizer.class) .newInstance(tokenizer); renamer.buildRenamingModel(FileUtils.listFiles(new File(args[1]), tokenizer.getFileFilter(), DirectoryFileFilter.DIRECTORY)); final IScopeExtractor scopeExtractor = ScopesTUI .getScopeExtractorByName(args[3]); final SegmentRenamingSuggestion suggestion = new SegmentRenamingSuggestion( renamer, scopeExtractor, true); System.out.println(suggestion.rankSuggestions(new File(args[0]))); } final AbstractIdentifierRenamings renamer; final IScopeExtractor scopeExtractor; final boolean useUNK; public SegmentRenamingSuggestion(final AbstractIdentifierRenamings renamer, final boolean useUNK) { this.renamer = renamer; scopeExtractor = null; this.useUNK = useUNK; } /** * */ public SegmentRenamingSuggestion(final AbstractIdentifierRenamings renamer, final IScopeExtractor extractor, final boolean useUNK) { this.renamer = renamer; scopeExtractor = extractor; this.useUNK = useUNK; } private Suggestion addRenamingSuggestion( final SortedSet<Renaming> renamings, final String idName, final Scope scope) { final double topSuggestionXEnt = renamings.first().score; double currentNameXent = Double.NaN; for (final Renaming renaming : renamings) { if (renaming.name.equals(idName) || (renaming.name.equals("UNK_SYMBOL") && useUNK)) { currentNameXent = renaming.score; break; } } checkArgument(!Double.isNaN(currentNameXent)); final double confidence = topSuggestionXEnt - currentNameXent; return new Suggestion(idName, scope, confidence, renamings); } public void buildModel(final Collection<File> trainingFiles) { renamer.buildRenamingModel(trainingFiles); } public SortedSet<Suggestion> rankSuggestions(final ASTNode node) throws IOException { final Multimap<Scope, String> identifiers = checkNotNull( scopeExtractor, "No scope extractor available").getFromNode( node); return rankSuggestions(identifiers); } public SortedSet<Suggestion> rankSuggestions(final File f) throws IOException { final Multimap<Scope, String> identifiers = checkNotNull( scopeExtractor, "No scope extractor available").getFromFile(f); return rankSuggestions(identifiers); } /** * @param identifiers * @return */ public SortedSet<Suggestion> rankSuggestions( final Multimap<Scope, String> identifiers) { final SortedSet<Suggestion> suggestions = Sets.newTreeSet(); for (final Entry<Scope, String> s : identifiers.entries()) { try { final SortedSet<Renaming> renamings = renamer.getRenamings( s.getKey(), s.getValue()); suggestions.add(addRenamingSuggestion(renamings, s.getValue(), s.getKey())); } catch (final Throwable e) { LOGGER.warning("Failed to get suggestions for " + s + ExceptionUtils.getFullStackTrace(e)); } } return suggestions; } }