/** * This file is licensed under the University of Illinois/NCSA Open Source License. See LICENSE.TXT for details. */ package edu.illinois.keshmesh.transformer.core; import org.eclipse.core.filebuffers.FileBuffers; import org.eclipse.core.filebuffers.ITextFileBuffer; import org.eclipse.core.filebuffers.ITextFileBufferManager; import org.eclipse.core.filebuffers.LocationKind; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.OperationCanceledException; import org.eclipse.core.runtime.Status; import org.eclipse.jdt.core.dom.AST; import org.eclipse.jdt.core.dom.ASTNode; import org.eclipse.jdt.core.dom.ASTParser; import org.eclipse.jdt.core.dom.CompilationUnit; import org.eclipse.jdt.core.dom.NodeFinder; import org.eclipse.jdt.core.dom.SynchronizedStatement; import org.eclipse.jdt.core.dom.rewrite.ASTRewrite; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; import org.eclipse.ltk.core.refactoring.Change; import org.eclipse.ltk.core.refactoring.Refactoring; import org.eclipse.ltk.core.refactoring.RefactoringStatus; import org.eclipse.text.edits.MalformedTreeException; import org.eclipse.text.edits.TextEdit; import edu.illinois.keshmesh.detector.bugs.BugInstance; import edu.illinois.keshmesh.detector.bugs.CodePosition; import edu.illinois.keshmesh.detector.bugs.LCK02JFixInformation; import edu.illinois.keshmesh.detector.util.CollectionUtils; import edu.illinois.keshmesh.util.Logger; /** * * @author Mohsen Vakilian * @author Stas Negara * @author Samira Tasharofi * */ public class LCK02JFixer extends Refactoring { CodePosition bugPosition; BugInstance bugInstance; LCK02JFixInformation fixInformation; public LCK02JFixer(CodePosition bugPosition) { super(); this.bugPosition = bugPosition; } public LCK02JFixer(BugInstance bugInstance) { super(); this.bugInstance = bugInstance; this.bugPosition = bugInstance.getBugPosition(); this.fixInformation = (LCK02JFixInformation) bugInstance.getFixInformation(); } @Override public RefactoringStatus checkFinalConditions(IProgressMonitor progressMonitor) throws CoreException, OperationCanceledException { return null; } @Override public RefactoringStatus checkInitialConditions(IProgressMonitor progressMonitor) throws CoreException, OperationCanceledException { if (fixInformation.getTypeNames().size() == 1) { return RefactoringStatus.create(Status.OK_STATUS); } else { return RefactoringStatus.createFatalErrorStatus("More than one possible target classes were found: " + fixInformation.toString()); } } @Override public Change createChange(IProgressMonitor progressMonitor) throws CoreException, OperationCanceledException { ITextFileBufferManager textFileBufferManager = null; try { //Retrieving the Document out of IPath textFileBufferManager = FileBuffers.getTextFileBufferManager(); textFileBufferManager.connect(bugPosition.getSourcePath(), LocationKind.LOCATION, progressMonitor); ITextFileBuffer textFileBuffer = textFileBufferManager.getTextFileBuffer(bugPosition.getSourcePath(), LocationKind.IFILE); IDocument document = textFileBuffer.getDocument(); try { Logger.log(document.get(bugPosition.getFirstOffset(), bugPosition.getLength())); } catch (BadLocationException e1) { e1.printStackTrace(); } // Parsing the Document ASTParser parser = ASTParser.newParser(AST.JLS3); parser.setKind(ASTParser.K_COMPILATION_UNIT); parser.setSource(document.get().toCharArray()); parser.setResolveBindings(true); CompilationUnit compilationUnit = (CompilationUnit) parser.createAST(progressMonitor); //Rewriting the AST int bugLineOffset = document.getLineInformation(bugPosition.getFirstLine() - 1).getOffset(); int bugLineLength = document.getLineInformation(bugPosition.getFirstLine() - 1).getLength(); String bugLineContent = document.get(bugLineOffset, bugLineLength); String syncCommand = "synchronized"; int syncIndex = bugLineContent.indexOf(syncCommand); int start_comment_index = bugLineContent.indexOf("/*"); int end_comment_index = bugLineContent.indexOf("*/"); String temp_bugLineContent = bugLineContent; int temp_syncIndex = syncIndex; int temp_beginIndex = 0; // there is a possibility of having synchronized word within comments while (start_comment_index >= 0 && end_comment_index > 0 && temp_bugLineContent.length() > 0 && temp_syncIndex > start_comment_index) { temp_beginIndex += (end_comment_index + 2); temp_bugLineContent = temp_bugLineContent.substring(end_comment_index + 2); temp_syncIndex = temp_bugLineContent.indexOf(syncCommand); start_comment_index = temp_bugLineContent.indexOf("/*"); end_comment_index = temp_bugLineContent.indexOf("*/"); syncIndex = temp_beginIndex + temp_syncIndex; } String bugLineContentAfterSynch = bugLineContent.substring(syncIndex + syncCommand.length()); int openParenthesisIndex = bugLineContentAfterSynch.indexOf('(') + syncIndex + syncCommand.length(); int myFirstOffset = bugLineOffset + syncIndex; int index = openParenthesisIndex; int pcounter = 1; while (pcounter != 0 && index < bugLineLength) { index++; if (bugLineContent.charAt(index) == ')') { pcounter--; } else if (bugLineContent.charAt(index) == '(') { pcounter++; } } int myLastOffset = bugLineOffset + index; ASTNode monitorNode = NodeFinder.perform(compilationUnit, myFirstOffset, myLastOffset - myFirstOffset + 1); SynchronizedStatement synchronizedStatement = (SynchronizedStatement) monitorNode; AST ast = synchronizedStatement.getAST(); ASTRewrite rewriter = ASTRewrite.create(ast); ASTParser expressionParser = ASTParser.newParser(AST.JLS3); expressionParser.setKind(ASTParser.K_EXPRESSION); expressionParser.setSource(CollectionUtils.getTheOnlyElementOf(fixInformation.getTypeNames()).toCharArray()); ASTNode astNode = expressionParser.createAST(progressMonitor); rewriter.set(synchronizedStatement, SynchronizedStatement.EXPRESSION_PROPERTY, astNode, null); TextEdit textEdit = rewriter.rewriteAST(document, null); try { textEdit.apply(document); } catch (MalformedTreeException e) { e.printStackTrace(); } catch (BadLocationException e) { e.printStackTrace(); } //Committing changes to the source file textFileBuffer.commit(progressMonitor, true); } catch (BadLocationException e) { throw new RuntimeException(e); } finally { textFileBufferManager.disconnect(bugPosition.getSourcePath(), LocationKind.LOCATION, progressMonitor); } return null; } @Override public String getName() { return "LCK02J Fixer"; } }