/*******************************************************************************
* Copyright (c) 2009, 2010 Alena Laskavaia
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Alena Laskavaia - initial API and implementation
* Tomasz Wesolowski - extension
*******************************************************************************/
package org.eclipse.cdt.codan.ui;
import org.eclipse.cdt.codan.core.CodanRuntime;
import org.eclipse.cdt.codan.core.model.IProblem;
import org.eclipse.cdt.codan.core.model.IProblemProfile;
import org.eclipse.cdt.codan.internal.core.model.CodanProblemMarker;
import org.eclipse.cdt.codan.internal.ui.CodanUIActivator;
import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
import org.eclipse.cdt.core.index.IIndex;
import org.eclipse.cdt.core.model.CoreModel;
import org.eclipse.cdt.core.model.ICProject;
import org.eclipse.cdt.core.model.ITranslationUnit;
import org.eclipse.cdt.ui.CDTUITools;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IMarkerResolution2;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.texteditor.ITextEditor;
/**
* Generic class for codan marker resolution (for quick fix). Use as a base
* class for codanMarkerResolution extension. To add specific icon and
* description client class should additionally implement
* {@link IMarkerResolution2}
*
* @since 2.0
*/
public abstract class AbstractCodanCMarkerResolution implements ICodanMarkerResolution {
private boolean codanProblem;
/**
* Get position offset from marker. If CHAR_START attribute is not set for
* marker, line and document would be used.
*
* @param marker
* @param doc
* @return
*/
public int getOffset(IMarker marker, IDocument doc) {
int charStart = marker.getAttribute(IMarker.CHAR_START, -1);
int position;
if (charStart > 0) {
position = charStart;
} else {
int line = marker.getAttribute(IMarker.LINE_NUMBER, -1) - 1;
try {
position = doc.getLineOffset(line);
} catch (BadLocationException e) {
return -1;
}
}
return position;
}
public boolean isCodanProblem() {
return codanProblem;
}
public String getProblemArgument(IMarker marker, int index) {
return CodanProblemMarker.getProblemArgument(marker, index);
}
/**
* Runs this resolution.
*
* @param marker
* the marker to resolve
*/
public void run(IMarker marker) {
IDocument doc = openDocument(marker);
if (doc != null) {
codanProblem = getProblemId(marker) != null;
apply(marker, doc);
}
}
/**
* Apply marker resolution for given marker in given open document.
*
* @param marker
* @param document
*/
public abstract void apply(IMarker marker, IDocument document);
/**
* Override is extra checks is required to determine appicablity of marker
* resolution
*
* @param marker
* @return
*/
public boolean isApplicable(IMarker marker) {
return true;
}
/**
* Opens an editor with the document corresponding to the given problem and
* returns the corresponding IEditorPart. Please note that is code analysis
* is setup to run on reconsile this action would trigger checkers run, and
* original marker may be removed as a result.
*
* @param marker
* the problem marker
* @return the opened document
*/
protected IEditorPart openEditor(IMarker marker) {
IEditorPart editorPart;
try {
editorPart = CodanEditorUtility.openInEditor(marker);
} catch (PartInitException e) {
CodanUIActivator.log(e);
return null;
}
return editorPart;
}
/**
* Opens the editor and returns the document corresponding to a given
* marker.
*
* @param marker
* the marker to find the editor
* @return the corresponding document
*/
protected IDocument openDocument(IMarker marker) {
return openDocument(openEditor(marker));
}
/**
* Returns the document corresponding to a given editor part.
*
* @param editorPart
* an editor part
* @return the document of that part
*/
protected IDocument openDocument(IEditorPart editorPart) {
if (editorPart instanceof ITextEditor) {
ITextEditor editor = (ITextEditor) editorPart;
IDocument doc = editor.getDocumentProvider().getDocument(editor.getEditorInput());
return doc;
}
return null;
}
/**
* Receives a translation unit from a given marker. Opens the editor.
*
* @param marker
* A marker in an editor to get the translation unit
* @return The translation unit
*/
protected ITranslationUnit getTranslationUnitViaEditor(IMarker marker) {
ITranslationUnit tu = (ITranslationUnit) CDTUITools.getEditorInputCElement(openEditor(marker).getEditorInput());
return tu;
}
/**
* Receives a translation unit from a given marker using the marker's path.
*
* @param marker
* A marker in a translation unit
* @return The translation unit
*/
protected ITranslationUnit getTranslationUnitViaWorkspace(IMarker marker) {
IPath path = marker.getResource().getFullPath();
IFile file = ResourcesPlugin.getWorkspace().getRoot().getFile(path);
ITranslationUnit tu = (ITranslationUnit) CoreModel.getDefault().create(file);
return tu;
}
/**
* Receives an ASTName enclosing a given IMarker
*
* @param marker
* The marker enclosing an ASTName
* @param ast
* The AST to check
* @return The enclosing ASTName or null
*/
protected IASTName getASTNameFromMarker(IMarker marker, IASTTranslationUnit ast) {
final int charStart = marker.getAttribute(IMarker.CHAR_START, -1);
final int length = marker.getAttribute(IMarker.CHAR_END, -1) - charStart;
return getASTNameFromPositions(ast, charStart, length);
}
/**
* @param ast
* @param charStart
* @param length
* @return
*/
protected IASTName getASTNameFromPositions(IASTTranslationUnit ast, final int charStart, final int length) {
IASTName name = ast.getNodeSelector(null).findEnclosingName(charStart, length);
return name;
}
/**
* Receives an {@link IIndex} corresponding to the given {@link IMarker}'s
* resource.
*
* @param marker
* the marker to use
* @return the received index
* @throws CoreException
*/
protected IIndex getIndexFromMarker(final IMarker marker) throws CoreException {
IProject project = marker.getResource().getProject();
ICProject cProject = CoreModel.getDefault().create(project);
IIndex index = CCorePlugin.getIndexManager().getIndex(cProject);
return index;
}
/**
* @param marker
* @return
*/
public String getProblemId(IMarker marker) {
return CodanProblemMarker.getProblemId(marker);
}
public IProblem getProblem(IMarker marker) {
IPath path = marker.getResource().getFullPath();
IFile file = ResourcesPlugin.getWorkspace().getRoot().getFile(path);
if (file == null)
return null;
IProblemProfile profile = CodanRuntime.getInstance().getCheckersRegistry().getResourceProfile(file);
String id = getProblemId(marker);
return profile.findProblem(id);
}
/**
* @param marker
* @return
*/
public String getProblemMessage(IMarker marker) {
return CodanProblemMarker.getMessage(marker);
}
}