mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-04-23 14:42:11 +02:00
- implemented better quick fix framework and extension point for it
This commit is contained in:
parent
c9823a073f
commit
1732897f31
7 changed files with 505 additions and 8 deletions
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
<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>
|
||||
</extension>
|
||||
</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>
|
|
@ -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);
|
||||
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue