diff options
author | Alena Laskavaia | 2010-07-21 02:27:35 +0000 |
---|---|---|
committer | Alena Laskavaia | 2010-07-21 02:27:35 +0000 |
commit | 0c966168b9bf821558c7d4d91d5235dd093b8196 (patch) | |
tree | bb9c06820eb62ea3929a2b84a245f8c9af866d7a /codan/org.eclipse.cdt.codan.checkers.ui | |
parent | 64b3c630630ff15e40be079af2b3c89d3a50db59 (diff) | |
download | org.eclipse.cdt-0c966168b9bf821558c7d4d91d5235dd093b8196.tar.gz org.eclipse.cdt-0c966168b9bf821558c7d4d91d5235dd093b8196.tar.xz org.eclipse.cdt-0c966168b9bf821558c7d4d91d5235dd093b8196.zip |
Bug 319196 - quick fixes for adding local variables,etc. based on patch from Tomasz Wesolowski
Diffstat (limited to 'codan/org.eclipse.cdt.codan.checkers.ui')
8 files changed, 445 insertions, 1 deletions
diff --git a/codan/org.eclipse.cdt.codan.checkers.ui/META-INF/MANIFEST.MF b/codan/org.eclipse.cdt.codan.checkers.ui/META-INF/MANIFEST.MF index 1aeed6b9cfc..350b4be2656 100644 --- a/codan/org.eclipse.cdt.codan.checkers.ui/META-INF/MANIFEST.MF +++ b/codan/org.eclipse.cdt.codan.checkers.ui/META-INF/MANIFEST.MF @@ -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 + diff --git a/codan/org.eclipse.cdt.codan.checkers.ui/plugin.xml b/codan/org.eclipse.cdt.codan.checkers.ui/plugin.xml index 7052603655e..4209861a9f0 100644 --- a/codan/org.eclipse.cdt.codan.checkers.ui/plugin.xml +++ b/codan/org.eclipse.cdt.codan.checkers.ui/plugin.xml @@ -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> diff --git a/codan/org.eclipse.cdt.codan.checkers.ui/src/org/eclipse/cdt/codan/internal/checkers/ui/quickfix/AbstractAstRewriteQuickFix.java b/codan/org.eclipse.cdt.codan.checkers.ui/src/org/eclipse/cdt/codan/internal/checkers/ui/quickfix/AbstractAstRewriteQuickFix.java new file mode 100644 index 00000000000..b3f1731ceb9 --- /dev/null +++ b/codan/org.eclipse.cdt.codan.checkers.ui/src/org/eclipse/cdt/codan/internal/checkers/ui/quickfix/AbstractAstRewriteQuickFix.java @@ -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); +} diff --git a/codan/org.eclipse.cdt.codan.checkers.ui/src/org/eclipse/cdt/codan/internal/checkers/ui/quickfix/Messages.java b/codan/org.eclipse.cdt.codan.checkers.ui/src/org/eclipse/cdt/codan/internal/checkers/ui/quickfix/Messages.java new file mode 100644 index 00000000000..dee3330d91b --- /dev/null +++ b/codan/org.eclipse.cdt.codan.checkers.ui/src/org/eclipse/cdt/codan/internal/checkers/ui/quickfix/Messages.java @@ -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() { + } +} diff --git a/codan/org.eclipse.cdt.codan.checkers.ui/src/org/eclipse/cdt/codan/internal/checkers/ui/quickfix/QuickFixCreateField.java b/codan/org.eclipse.cdt.codan.checkers.ui/src/org/eclipse/cdt/codan/internal/checkers/ui/quickfix/QuickFixCreateField.java new file mode 100644 index 00000000000..abdc9dfb70d --- /dev/null +++ b/codan/org.eclipse.cdt.codan.checkers.ui/src/org/eclipse/cdt/codan/internal/checkers/ui/quickfix/QuickFixCreateField.java @@ -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$ + } +} diff --git a/codan/org.eclipse.cdt.codan.checkers.ui/src/org/eclipse/cdt/codan/internal/checkers/ui/quickfix/QuickFixCreateLocalVariable.java b/codan/org.eclipse.cdt.codan.checkers.ui/src/org/eclipse/cdt/codan/internal/checkers/ui/quickfix/QuickFixCreateLocalVariable.java new file mode 100644 index 00000000000..507cc8fe3f0 --- /dev/null +++ b/codan/org.eclipse.cdt.codan.checkers.ui/src/org/eclipse/cdt/codan/internal/checkers/ui/quickfix/QuickFixCreateLocalVariable.java @@ -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$ + } +} diff --git a/codan/org.eclipse.cdt.codan.checkers.ui/src/org/eclipse/cdt/codan/internal/checkers/ui/quickfix/QuickFixCreateParameter.java b/codan/org.eclipse.cdt.codan.checkers.ui/src/org/eclipse/cdt/codan/internal/checkers/ui/quickfix/QuickFixCreateParameter.java new file mode 100644 index 00000000000..24d32350282 --- /dev/null +++ b/codan/org.eclipse.cdt.codan.checkers.ui/src/org/eclipse/cdt/codan/internal/checkers/ui/quickfix/QuickFixCreateParameter.java @@ -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$ + } +} diff --git a/codan/org.eclipse.cdt.codan.checkers.ui/src/org/eclipse/cdt/codan/internal/checkers/ui/quickfix/messages.properties b/codan/org.eclipse.cdt.codan.checkers.ui/src/org/eclipse/cdt/codan/internal/checkers/ui/quickfix/messages.properties new file mode 100644 index 00000000000..da3f433fce7 --- /dev/null +++ b/codan/org.eclipse.cdt.codan.checkers.ui/src/org/eclipse/cdt/codan/internal/checkers/ui/quickfix/messages.properties @@ -0,0 +1,3 @@ +QuickFixCreateField_0=Create field +QuickFixCreateLocalVariable_0=Create local variable +QuickFixCreateParameter_0=Create parameter
\ No newline at end of file |