1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-09-10 12:03:16 +02:00

Bug 319196 - quick fixes for adding local variables,etc. based on patch from Tomasz Wesolowski

This commit is contained in:
Alena Laskavaia 2010-07-21 02:27:35 +00:00
parent 64b3c63063
commit 0c966168b9
9 changed files with 515 additions and 1 deletions

View file

@ -9,9 +9,13 @@ Require-Bundle: org.eclipse.ui,
org.eclipse.jface.text,
org.eclipse.core.resources,
org.eclipse.cdt.codan.ui,
org.eclipse.ui.ide
org.eclipse.ui.ide,
org.eclipse.cdt.core
Bundle-ActivationPolicy: lazy
Bundle-RequiredExecutionEnvironment: J2SE-1.5
Bundle-Vendor: %Bundle-Vendor
Export-Package: org.eclipse.cdt.codan.internal.checkers.ui;x-internal:=true,
org.eclipse.cdt.codan.internal.checkers.ui.quickfix;x-internal:=true
Import-Package: org.eclipse.cdt.codan.core.cxx,
org.eclipse.ltk.core.refactoring

View file

@ -17,6 +17,18 @@
class="org.eclipse.cdt.codan.internal.checkers.ui.quickfix.SuggestedParenthesisQuickFix"
problemId="org.eclipse.cdt.codan.internal.checkers.SuggestedParenthesisProblem">
</resolution>
<resolution
class="org.eclipse.cdt.codan.internal.checkers.ui.quickfix.QuickFixCreateLocalVariable"
problemId="org.eclipse.cdt.codan.internal.checkers.VariableResolutionProblem">
</resolution>
<resolution
class="org.eclipse.cdt.codan.internal.checkers.ui.quickfix.QuickFixCreateField"
problemId="org.eclipse.cdt.codan.internal.checkers.VariableResolutionProblem">
</resolution>
<resolution
class="org.eclipse.cdt.codan.internal.checkers.ui.quickfix.QuickFixCreateParameter"
problemId="org.eclipse.cdt.codan.internal.checkers.VariableResolutionProblem">
</resolution>
</extension>
</plugin>

View file

@ -0,0 +1,57 @@
/*******************************************************************************
* 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.internal.checkers.ui.CheckersUiActivator;
import org.eclipse.cdt.codan.ui.AbstractCodanCMarkerResolution;
import org.eclipse.cdt.core.index.IIndex;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.jface.text.IDocument;
public abstract class AbstractAstRewriteQuickFix extends
AbstractCodanCMarkerResolution {
@Override
public void apply(final IMarker marker, IDocument document) {
try {
openEditor(marker);
IIndex index;
try {
index = getIndexFromMarker(marker);
} catch (CoreException e) {
e.printStackTrace();
CheckersUiActivator.log(e);
return;
}
// lock the index for read access
try {
index.acquireReadLock();
} catch (InterruptedException e) {
return;
}
try {
modifyAST(index, marker);
} finally {
index.releaseReadLock();
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
*
* @param ast
* @param astName
* @param r
*/
public abstract void modifyAST(IIndex index, IMarker marker);
}

View file

@ -0,0 +1,17 @@
package org.eclipse.cdt.codan.internal.checkers.ui.quickfix;
import org.eclipse.osgi.util.NLS;
public class Messages extends NLS {
private static final String BUNDLE_NAME = "org.eclipse.cdt.codan.internal.checkers.ui.quickfix.messages"; //$NON-NLS-1$
public static String QuickFixCreateField_0;
public static String QuickFixCreateLocalVariable_0;
public static String QuickFixCreateParameter_0;
static {
// initialize resource bundle
NLS.initializeMessages(BUNDLE_NAME, Messages.class);
}
private Messages() {
}
}

View file

@ -0,0 +1,140 @@
/*******************************************************************************
* Copyright (c) 2010 Tomasz Wesolowski
* 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:
* Tomasz Wesolowski - initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.codan.internal.checkers.ui.quickfix;
import org.eclipse.cdt.codan.core.cxx.CxxAstUtils;
import org.eclipse.cdt.core.dom.ast.IASTCompositeTypeSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTDeclarator;
import org.eclipse.cdt.core.dom.ast.IASTFunctionDeclarator;
import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition;
import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier.ICPPASTBaseSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTVisibilityLabel;
import org.eclipse.cdt.core.dom.rewrite.ASTRewrite;
import org.eclipse.cdt.core.index.IIndex;
import org.eclipse.cdt.core.model.ITranslationUnit;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.ltk.core.refactoring.Change;
public class QuickFixCreateField extends AbstractAstRewriteQuickFix {
public String getLabel() {
return Messages.QuickFixCreateField_0;
}
@Override
public void modifyAST(IIndex index, IMarker marker) {
CxxAstUtils utils = CxxAstUtils.getInstance();
try {
IASTTranslationUnit ast = getTranslationUnitViaEditor(marker)
.getAST(null, ITranslationUnit.AST_SKIP_INDEXED_HEADERS);
IASTName astName = getASTNameFromMarker(marker, ast);
if (astName == null) {
return;
}
IASTDeclaration declaration = utils
.createDeclaration(astName, ast.getASTNodeFactory());
IASTCompositeTypeSpecifier targetCompositeType = utils
.getEnclosingCompositeTypeSpecifier(astName);
if (targetCompositeType == null) {
// We're not in an inline method;
// check if we're in a method at all
targetCompositeType = utils.getCompositeTypeFromFunction(
utils.getEnclosingFunction(astName), index);
if (targetCompositeType == null) {
return;
}
}
ASTRewrite r = ASTRewrite.create(targetCompositeType
.getTranslationUnit());
IASTNode where = findInsertionPlace(targetCompositeType);
r.insertBefore(targetCompositeType, where, declaration, null);
Change c = r.rewriteAST();
c.perform(new NullProgressMonitor());
} catch (CoreException e) {
e.printStackTrace();
}
}
/**
* Suggests a default place to insert a field:
*
* Default place to insert:
* <ul>
* <li>If in a class, after last private field or at the end</li>
* <li>If in a struct, after last public field or at the end</li>
* </ul>
*
* @param composite
* the composite to search
* @return an ASTNode inside composite to insert before, or null to insert
* at the end
*/
protected IASTNode findInsertionPlace(IASTCompositeTypeSpecifier composite) {
boolean wantPublicContext;
boolean inDesiredAccessibilityContext;
// Default: private context for classes, public otherwise
wantPublicContext = !(composite.getKey() == ICPPASTCompositeTypeSpecifier.k_class);
inDesiredAccessibilityContext = true;
IASTNode bestMatch = null;
IASTNode[] children = composite.getChildren();
// Get initial candidate at the beginning (after class name and
// composite type specifiers)
for (IASTNode child : children) {
if (child instanceof IASTName
|| child instanceof ICPPASTBaseSpecifier) {
continue;
}
bestMatch = child;
break;
}
// Check the class body for a better place (i.e. after the last variable
// declaration in the expected access scope)
for (int i = 0; i < children.length; ++i) {
IASTNode child = children[i];
if (child instanceof ICPPASTVisibilityLabel) {
ICPPASTVisibilityLabel label = (ICPPASTVisibilityLabel) child;
inDesiredAccessibilityContext = (wantPublicContext && label
.getVisibility() == ICPPASTVisibilityLabel.v_public)
|| (!wantPublicContext && label.getVisibility() == ICPPASTVisibilityLabel.v_private);
} else if (inDesiredAccessibilityContext
&& (child instanceof IASTDeclaration)
&& !(child instanceof IASTFunctionDefinition)) {
// TODO: the above condition needs to also check if child is not
// a typedef
for (IASTNode gchild : child.getChildren()) {
if ((gchild instanceof IASTDeclarator)
&& !(gchild instanceof IASTFunctionDeclarator)) {
// Before the next node or at the end (= after the
// current node)
bestMatch = (i + 1 < children.length) ? children[i + 1]
: null;
break;
}
}
}
}
return bestMatch;
}
@Override
public boolean isApplicable(IMarker marker) {
String problemArgument = getProblemArgument(marker, 1);
return problemArgument.contains(":class") && problemArgument.contains(":func"); //$NON-NLS-1$ //$NON-NLS-2$
}
}

View file

@ -0,0 +1,81 @@
/*******************************************************************************
* Copyright (c) 2010 Tomasz Wesolowski
* 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:
* Tomasz Wesolowski - initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.codan.internal.checkers.ui.quickfix;
import org.eclipse.cdt.codan.core.cxx.CxxAstUtils;
import org.eclipse.cdt.codan.internal.checkers.ui.CheckersUiActivator;
import org.eclipse.cdt.core.dom.ast.IASTDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTDeclarationStatement;
import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
import org.eclipse.cdt.core.dom.ast.INodeFactory;
import org.eclipse.cdt.core.dom.rewrite.ASTRewrite;
import org.eclipse.cdt.core.index.IIndex;
import org.eclipse.cdt.core.model.ITranslationUnit;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.ltk.core.refactoring.Change;
public class QuickFixCreateLocalVariable extends AbstractAstRewriteQuickFix {
public String getLabel() {
return Messages.QuickFixCreateLocalVariable_0;
}
/**
*
* @param ast
* @param astName
* @param r
*/
public void modifyAST(IIndex index, IMarker marker) {
CxxAstUtils utils = CxxAstUtils.getInstance();
IASTTranslationUnit ast;
try {
ITranslationUnit tu = getTranslationUnitViaEditor(marker);
ast = tu.getAST(index, ITranslationUnit.AST_SKIP_INDEXED_HEADERS);
} catch (CoreException e) {
CheckersUiActivator.log(e);
return;
}
IASTName astName = getASTNameFromMarker(marker, ast);
if (astName == null) {
return;
}
ASTRewrite r = ASTRewrite.create(ast);
INodeFactory factory = ast.getASTNodeFactory();
IASTDeclaration declaration = utils.createDeclaration(astName, factory);
IASTDeclarationStatement newStatement = factory
.newDeclarationStatement(declaration);
IASTNode targetStatement = utils.getEnclosingStatement(astName);
if (targetStatement == null) {
return;
}
r.insertBefore(targetStatement.getParent(), targetStatement,
newStatement, null);
Change c = r.rewriteAST();
try {
c.perform(new NullProgressMonitor());
} catch (CoreException e) {
CheckersUiActivator.log(e);
return;
}
}
@Override
public boolean isApplicable(IMarker marker) {
String problemArgument = getProblemArgument(marker, 1);
return problemArgument.contains(":func"); //$NON-NLS-1$
}
}

View file

@ -0,0 +1,130 @@
/*******************************************************************************
* Copyright (c) 2010 Tomasz Wesolowski
* 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:
* Tomasz Wesolowski - initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.codan.internal.checkers.ui.quickfix;
import java.util.HashMap;
import org.eclipse.cdt.codan.core.cxx.CxxAstUtils;
import org.eclipse.cdt.codan.core.cxx.CxxAstUtils.NameFinderVisitor;
import org.eclipse.cdt.codan.internal.checkers.ui.CheckersUiActivator;
import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTDeclarator;
import org.eclipse.cdt.core.dom.ast.IASTFileLocation;
import org.eclipse.cdt.core.dom.ast.IASTFunctionDeclarator;
import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition;
import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.dom.ast.IASTParameterDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
import org.eclipse.cdt.core.dom.ast.IBinding;
import org.eclipse.cdt.core.dom.ast.INodeFactory;
import org.eclipse.cdt.core.dom.rewrite.ASTRewrite;
import org.eclipse.cdt.core.index.IIndex;
import org.eclipse.cdt.core.index.IIndexName;
import org.eclipse.cdt.core.model.ITranslationUnit;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.ltk.core.refactoring.CompositeChange;
public class QuickFixCreateParameter extends AbstractAstRewriteQuickFix {
public String getLabel() {
return Messages.QuickFixCreateParameter_0;
}
@Override
public void modifyAST(IIndex index, IMarker marker) {
CxxAstUtils utils = CxxAstUtils.getInstance();
CompositeChange c = new CompositeChange(
Messages.QuickFixCreateParameter_0);
try {
ITranslationUnit baseTU = getTranslationUnitViaEditor(marker);
IASTTranslationUnit baseAST = baseTU.getAST(index,
ITranslationUnit.AST_SKIP_INDEXED_HEADERS);
IASTName astName = getASTNameFromMarker(marker, baseAST);
if (astName == null) {
return;
}
IASTDeclaration declaration = CxxAstUtils.getInstance()
.createDeclaration(astName, baseAST.getASTNodeFactory());
// We'll need a FunctionParameterDeclaration later
final IASTDeclSpecifier finalDeclSpec = (IASTDeclSpecifier) declaration
.getChildren()[0];
final IASTDeclarator finalDeclarator = (IASTDeclarator) declaration
.getChildren()[1];
IASTFunctionDefinition function = utils
.getEnclosingFunction(astName);
if (function == null) {
return;
}
// Find the function declarations
NameFinderVisitor nameFinderVisitor = new NameFinderVisitor();
function.accept(nameFinderVisitor);
IASTName funcName = nameFinderVisitor.name;
IBinding binding = funcName.resolveBinding();
IIndexName[] declarations = index.findNames(binding,
IIndex.FIND_DECLARATIONS_DEFINITIONS);
if (declarations.length == 0) {
return;
}
HashMap<ITranslationUnit, IASTTranslationUnit> cachedASTs = new HashMap<ITranslationUnit, IASTTranslationUnit>();
HashMap<ITranslationUnit, ASTRewrite> cachedRewrites = new HashMap<ITranslationUnit, ASTRewrite>();
for (IIndexName iname : declarations) {
ITranslationUnit declTU = utils
.getTranslationUnitFromIndexName(iname);
ASTRewrite rewrite;
IASTTranslationUnit declAST;
if (!cachedASTs.containsKey(declTU)) {
declAST = declTU.getAST(index,
ITranslationUnit.AST_SKIP_INDEXED_HEADERS);
rewrite = ASTRewrite.create(declAST);
cachedASTs.put(declTU, declAST);
cachedRewrites.put(declTU, rewrite);
} else {
declAST = cachedASTs.get(declTU);
rewrite = cachedRewrites.get(declTU);
}
IASTFileLocation fileLocation = iname.getFileLocation();
IASTName declName = declAST.getNodeSelector(null)
.findEnclosingName(fileLocation.getNodeOffset(),
fileLocation.getNodeLength());
if (declName == null) {
continue;
}
INodeFactory factory = declAST.getASTNodeFactory();
IASTFunctionDeclarator functionDecl;
{
IASTNode n = declName;
while (n instanceof IASTName) {
n = n.getParent();
}
functionDecl = (IASTFunctionDeclarator) n;
}
IASTParameterDeclaration newParam = factory
.newParameterDeclaration(finalDeclSpec, finalDeclarator);
rewrite.insertBefore(functionDecl, null, newParam, null);
}
for (ASTRewrite rewrite : cachedRewrites.values()) {
c.add(rewrite.rewriteAST());
}
c.perform(new NullProgressMonitor());
} catch (CoreException e) {
CheckersUiActivator.log(e);
}
}
@Override
public boolean isApplicable(IMarker marker) {
String problemArgument = getProblemArgument(marker, 1);
return problemArgument.contains(":func"); //$NON-NLS-1$
}
}

View file

@ -0,0 +1,3 @@
QuickFixCreateField_0=Create field
QuickFixCreateLocalVariable_0=Create local variable
QuickFixCreateParameter_0=Create parameter

View file

@ -0,0 +1,70 @@
/*******************************************************************************
* Copyright (c) 2010 Tomasz Wesolowski and others
* 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:
* Tomasz Wesolowski - initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.codan.internal.checkers.ui.quickfix;
import org.eclipse.cdt.codan.ui.AbstractCodanCMarkerResolution;
/**
* @author Tomasz Wesolowski
*/
public class CreateLocalVariableQuickFixTest extends QuickFixTestCase {
@SuppressWarnings("restriction")
@Override
protected AbstractCodanCMarkerResolution createQuickFix() {
return new QuickFixCreateLocalVariable();
}
// void func() {
// aChar = 'a';
// }
@SuppressWarnings("restriction")
public void testChar() {
loadcode(getAboveComment());
String result = runQuickFixOneFile();
assertContainedIn("char aChar;", result);
}
// void func() {
// aDouble = 40.;
// }
public void testDouble() {
loadcode(getAboveComment());
String result = runQuickFixOneFile();
assertContainedIn("double aDouble;", result);
}
// void func() {
// aString = "foo";
// }
public void testString() {
loadcode(getAboveComment());
String result = runQuickFixOneFile();
assertContainedIn("const char *aString;", result);
}
// void func() {
// aWString = L"foo";
// }
public void testWString() {
loadcode(getAboveComment());
String result = runQuickFixOneFile();
assertContainedIn("const wchar_t *aWString;", result);
}
// void func() {
// aFuncPtr = func;
// }
public void testFuncPtr() {
loadcode(getAboveComment());
String result = runQuickFixOneFile();
assertContainedIn("void (*aFuncPtr)();", result);
}
}