1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-04-23 22:52:11 +02:00

- implemented better quick fix framework and extension point for it

This commit is contained in:
Alena Laskavaia 2010-04-13 01:13:59 +00:00
parent c9823a073f
commit 1732897f31
7 changed files with 505 additions and 8 deletions

View file

@ -10,7 +10,9 @@ Require-Bundle: org.eclipse.ui,
org.eclipse.jface.text;bundle-version="3.5.0",
org.eclipse.ui.editors;bundle-version="3.5.0",
org.eclipse.core.resources;bundle-version="3.5.0",
org.eclipse.cdt.codan.checkers;bundle-version="1.0.0"
org.eclipse.cdt.codan.checkers;bundle-version="1.0.0",
org.eclipse.cdt.ui;bundle-version="5.2.0",
org.eclipse.cdt.core;bundle-version="5.2.0"
Bundle-ActivationPolicy: lazy
Bundle-RequiredExecutionEnvironment: J2SE-1.5
Bundle-Vendor: Eclipse CDT

View file

@ -1,6 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.4"?>
<plugin>
<extension-point id="codanMarkerResolution" name="Codan Marker Resolution" schema="schema/codanMarkerResolution.exsd"/>
<extension
point="org.eclipse.ui.ide.markerResolution">
<markerResolutionGenerator
@ -8,4 +9,15 @@
markerType="org.eclipse.cdt.codan.core.codanProblem">
</markerResolutionGenerator>
</extension>
<extension
point="org.eclipse.cdt.codan.checkers.ui.codanMarkerResolution">
<resolution
class="org.eclipse.cdt.codan.internal.checkers.ui.quickfix.CatchByReferenceQuickFix"
problemId="org.eclipse.cdt.codan.internal.checkers.CatchByReference">
</resolution>
<resolution
class="org.eclipse.cdt.codan.internal.checkers.ui.quickfix.QuickFixAssignmentInCondition"
problemId="org.eclipse.cdt.codan.internal.checkers.AssignmentInConditionProblem">
</resolution>
</extension>
</plugin>

View file

@ -0,0 +1,130 @@
<?xml version='1.0' encoding='UTF-8'?>
<!-- Schema file written by PDE -->
<schema targetNamespace="org.eclipse.cdt.codan.checkers.ui" xmlns="http://www.w3.org/2001/XMLSchema">
<annotation>
<appinfo>
<meta.schema plugin="org.eclipse.cdt.codan.checkers.ui" id="codanMarkerResolution" name="Codan Marker Resolution"/>
</appinfo>
<documentation>
Extension point to plugin quick fix for codan markers
</documentation>
</annotation>
<element name="extension">
<annotation>
<appinfo>
<meta.element />
</appinfo>
</annotation>
<complexType>
<sequence minOccurs="1" maxOccurs="unbounded">
<element ref="resolution"/>
</sequence>
<attribute name="point" type="string" use="required">
<annotation>
<documentation>
</documentation>
</annotation>
</attribute>
<attribute name="id" type="string">
<annotation>
<documentation>
</documentation>
</annotation>
</attribute>
<attribute name="name" type="string">
<annotation>
<documentation>
</documentation>
<appinfo>
<meta.attribute translatable="true"/>
</appinfo>
</annotation>
</attribute>
</complexType>
</element>
<element name="resolution">
<annotation>
<documentation>
Contribute codan marker resolution
</documentation>
</annotation>
<complexType>
<attribute name="class" type="string" use="required">
<annotation>
<documentation>
Class that implement IMarkerResolution that provides a fix for the given problem
</documentation>
<appinfo>
<meta.attribute kind="java" basedOn=":org.eclipse.ui.IMarkerResolution"/>
</appinfo>
</annotation>
</attribute>
<attribute name="problemId" type="string" use="required">
<annotation>
<documentation>
Problem id of the problem for which quick fix is defined
</documentation>
<appinfo>
<meta.attribute kind="identifier" basedOn="org.eclipse.cdt.codan.core.checkers/checker/problem/@id"/>
</appinfo>
</annotation>
</attribute>
<attribute name="messagePattern" type="string">
<annotation>
<documentation>
If problem id is not enought to identity the fix messagePattern can be used to apply fix for given message
</documentation>
</annotation>
</attribute>
</complexType>
</element>
<annotation>
<appinfo>
<meta.section type="since"/>
</appinfo>
<documentation>
since 1.0
</documentation>
</annotation>
<annotation>
<appinfo>
<meta.section type="examples"/>
</appinfo>
<documentation>
&lt;extension
point=&quot;org.eclipse.cdt.codan.checkers.ui.codanMarkerResolution&quot;&gt;
&lt;resolution
class=&quot;org.eclipse.cdt.codan.internal.checkers.ui.quickfix.CatchByReferenceQuickFix&quot;
problemId=&quot;org.eclipse.cdt.codan.internal.checkers.CatchByReference&quot;&gt;
&lt;/resolution&gt;
&lt;/extension&gt;
</documentation>
</annotation>
<annotation>
<appinfo>
<meta.section type="apiinfo"/>
</appinfo>
<documentation>
[Enter API information here.]
</documentation>
</annotation>
<annotation>
<appinfo>
<meta.section type="implementation"/>
</appinfo>
<documentation>
[Enter information about supplied implementation of this extension point.]
</documentation>
</annotation>
</schema>

View file

@ -0,0 +1,106 @@
/*******************************************************************************
* Copyright (c) 2009 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
*******************************************************************************/
package org.eclipse.cdt.codan.checkers.ui;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.IMarkerResolution;
import org.eclipse.ui.IMarkerResolution2;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.ide.IDE;
import org.eclipse.ui.part.FileEditorInput;
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}
*/
public abstract class AbstarctCodanCMarkerResolution implements
IMarkerResolution {
/**
* 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;
}
/**
* Runs this resolution.
*
* @param marker the marker to resolve
*/
public void run(IMarker marker) {
// See if there is an open editor on the file containing the marker
IWorkbenchWindow w = PlatformUI.getWorkbench()
.getActiveWorkbenchWindow();
if (w == null) {
return;
}
IWorkbenchPage page = w.getActivePage();
if (page == null) {
return;
}
IFileEditorInput input = new FileEditorInput((IFile) marker
.getResource());
IEditorPart editorPart = page.findEditor(input);
if (editorPart == null) {
// open an editor
try {
editorPart = IDE.openEditor(page, (IFile) marker.getResource(),
true);
} catch (PartInitException e) {
e.printStackTrace();
}
}
if (editorPart == null) {
return;
}
if (editorPart instanceof ITextEditor) {
ITextEditor editor = (ITextEditor) editorPart;
IDocument doc = editor.getDocumentProvider().getDocument(
editor.getEditorInput());
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);
}

View file

@ -0,0 +1,97 @@
/*******************************************************************************
* Copyright (c) 2009 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
*******************************************************************************/
package org.eclipse.cdt.codan.checkers.ui;
import org.eclipse.cdt.core.model.ITranslationUnit;
import org.eclipse.cdt.internal.core.resources.ResourceLookup;
import org.eclipse.cdt.ui.text.ICCompletionProposal;
import org.eclipse.cdt.ui.text.IInvocationContext;
import org.eclipse.cdt.ui.text.IProblemLocation;
import org.eclipse.cdt.ui.text.IQuickFixProcessor;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
/**
* Abstract class IQuickFixProcessor - not used right now because it does not work
* properly for non hardcoded errors
* <p>
* <strong>EXPERIMENTAL</strong>. This class or interface has been added as part
* of a work in progress. There is no guarantee that this API will work or that
* it will remain the same.
* </p>
*/
public abstract class AbstractCodanCQuickFixProcessor implements IQuickFixProcessor {
/*
* (non-Javadoc)
*
* @see
* org.eclipse.cdt.ui.text.IQuickFixProcessor#hasCorrections(org.eclipse
* .cdt.ui.text.ITranslationUnit, int)
*/
public boolean hasCorrections(ITranslationUnit unit, int problemId) {
return problemId == 42;
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.cdt.ui.text.IQuickFixProcessor#getCorrections(org.eclipse
* .cdt.ui.text.IInvocationContext,
* org.eclipse.cdt.ui.text.IProblemLocation[])
*/
public ICCompletionProposal[] getCorrections(IInvocationContext context,
IProblemLocation[] locations) throws CoreException {
if (locations==null || locations.length==0) return null;
IProblemLocation loc = locations[0];
IPath location= context.getTranslationUnit().getLocation();
IFile astFile = ResourceLookup.selectFileForLocation(location, context.getTranslationUnit().getCProject().getProject());
IMarker[] markers = astFile.findMarkers(loc.getMarkerType(), false, 1);
for (int i = 0; i < markers.length; i++) {
IMarker m = markers[i];
int start = m.getAttribute(IMarker.CHAR_START, -1);
if (start==loc.getOffset()) {
String id = m.getAttribute(IMarker.PROBLEM,"");
return getCorrections(context, id, m);
}
}
return null;
}
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;
}
/**
* @param context
* @param loc
* @param marker
* @return
*/
public abstract ICCompletionProposal[] getCorrections(IInvocationContext context,
String problemId, IMarker marker);
}

View file

@ -0,0 +1,38 @@
/*******************************************************************************
* Copyright (c) 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
*******************************************************************************/
package org.eclipse.cdt.codan.internal.checkers.ui.quickfix;
import org.eclipse.cdt.codan.checkers.ui.AbstarctCodanCMarkerResolution;
import org.eclipse.cdt.codan.internal.checkers.ui.CheckersUiActivator;
import org.eclipse.core.resources.IMarker;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.FindReplaceDocumentAdapter;
import org.eclipse.jface.text.IDocument;
public class CatchByReferenceQuickFix extends AbstarctCodanCMarkerResolution {
public String getLabel() {
return "Change to use reference";
}
public void apply(IMarker marker, IDocument document) {
FindReplaceDocumentAdapter dad = new FindReplaceDocumentAdapter(
document);
try {
int pos = getOffset(marker, document);
dad.find(pos, " ", /* forwardSearch *///$NON-NLS-1$
true, /* caseSensitive */false,
/* wholeWord */false, /* regExSearch */false);
dad.replace(" & ", /* regExReplace */false); //$NON-NLS-1$
} catch (BadLocationException e) {
CheckersUiActivator.log(e);
}
}
}

View file

@ -10,21 +10,133 @@
*******************************************************************************/
package org.eclipse.cdt.codan.internal.checkers.ui.quickfix;
import java.util.regex.Matcher;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.regex.Pattern;
import org.eclipse.cdt.codan.internal.checkers.ui.CheckersUiActivator;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExtensionPoint;
import org.eclipse.core.runtime.Platform;
import org.eclipse.ui.IMarkerResolution;
import org.eclipse.ui.IMarkerResolutionGenerator;
public class CodanProblemMarkerResolutionGenerator implements IMarkerResolutionGenerator {
public class CodanProblemMarkerResolutionGenerator implements
IMarkerResolutionGenerator {
private static final String EXTENSION_POINT_NAME = "codanMarkerResolution"; //$NON-NLS-1$
private static Map<String, Collection<ConditionalResolution>> resolutions = new HashMap<String, Collection<ConditionalResolution>>();
private static boolean resolutionsLoaded = false;
static class ConditionalResolution {
IMarkerResolution res;
String messagePattern;
public ConditionalResolution(IMarkerResolution res2,
String messagePattern2) {
res = res2;
messagePattern = messagePattern2;
}
}
public IMarkerResolution[] getResolutions(IMarker marker) {
final Pattern patternBuildDependsAdd = Pattern.compile("Possible assignment in condition.*");
String description = marker.getAttribute(IMarker.MESSAGE, "no message");
Matcher matcherBuildDependsAdd = patternBuildDependsAdd.matcher(description);
if (matcherBuildDependsAdd.matches()) {
return new IMarkerResolution[] { new QuickFixAssignmentInCondition() };
if (resolutionsLoaded == false) {
readExtensions();
}
String id = marker.getAttribute(IMarker.PROBLEM, null);
if (id == null)
return new IMarkerResolution[0];
String message = marker.getAttribute(IMarker.MESSAGE, ""); //$NON-NLS-1$
Collection<ConditionalResolution> collection = resolutions.get(id);
if (collection != null) {
ArrayList<IMarkerResolution> list = new ArrayList<IMarkerResolution>();
for (Iterator<ConditionalResolution> iterator = collection
.iterator(); iterator.hasNext();) {
ConditionalResolution res = iterator.next();
if (res.messagePattern != null) {
if (message.matches(res.messagePattern))
list.add(res.res);
} else {
list.add(res.res);
}
}
if (list.size() > 0)
return list.toArray(new IMarkerResolution[list.size()]);
}
return new IMarkerResolution[0];
}
private static synchronized void readExtensions() {
IExtensionPoint ep = Platform.getExtensionRegistry().getExtensionPoint(
CheckersUiActivator.PLUGIN_ID, EXTENSION_POINT_NAME);
if (ep == null)
return;
try {
IConfigurationElement[] elements = ep.getConfigurationElements();
// process categories
for (int i = 0; i < elements.length; i++) {
IConfigurationElement configurationElement = elements[i];
processResolution(configurationElement);
}
} finally {
resolutionsLoaded = true;
}
}
/**
* @param configurationElement
*/
private static void processResolution(
IConfigurationElement configurationElement) {
if (configurationElement.getName().equals("resolution")) { //$NON-NLS-1$
String id = configurationElement.getAttribute("problemId"); //$NON-NLS-1$
if (id == null) {
CheckersUiActivator.log("Extension for " + EXTENSION_POINT_NAME
+ " problemId is not defined");
return;
}
IMarkerResolution res;
try {
res = (IMarkerResolution) configurationElement
.createExecutableExtension("class");//$NON-NLS-1$
} catch (CoreException e) {
CheckersUiActivator.log(e);
return;
}
String messagePattern = configurationElement
.getAttribute("messagePattern"); //$NON-NLS-1$
if (messagePattern != null) {
try {
Pattern.compile(messagePattern);
} catch (Exception e) {
// bad pattern log and ignore
CheckersUiActivator.log("Extension for "
+ EXTENSION_POINT_NAME
+ " messagePattern is invalid: " + e.getMessage());
return;
}
}
ConditionalResolution co = new ConditionalResolution(res,
messagePattern);
addResolution(id, co);
}
}
public static void addResolution(String id, IMarkerResolution res,
String messagePattern) {
addResolution(id, new ConditionalResolution(res, messagePattern));
}
private static void addResolution(String id, ConditionalResolution res) {
Collection<ConditionalResolution> collection = resolutions.get(id);
if (collection == null) {
collection = new ArrayList<ConditionalResolution>();
resolutions.put(id, collection);
}
collection.add(res);
}
}