mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-09-08 02:53:12 +02:00
Determination of output parameters for extracting function from
inside conditional statements and loops.
This commit is contained in:
parent
723ed9f912
commit
0f4f703be2
29 changed files with 3417 additions and 412 deletions
|
@ -259,7 +259,8 @@ public class DeclarationWriter extends NodeWriter {
|
|||
|
||||
private void writeFunctionDefinition(IASTFunctionDefinition funcDef) {
|
||||
IASTDeclSpecifier declSpecifier = funcDef.getDeclSpecifier();
|
||||
declSpecifier.accept(visitor);
|
||||
if (declSpecifier != null)
|
||||
declSpecifier.accept(visitor);
|
||||
if (declSpecifier instanceof IASTSimpleDeclSpecifier) {
|
||||
IASTSimpleDeclSpecifier simDeclSpec = (IASTSimpleDeclSpecifier) declSpecifier;
|
||||
if (simDeclSpec.getType() != IASTSimpleDeclSpecifier.t_unspecified) {
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,20 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2000, 2012 IBM Corporation 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:
|
||||
* IBM Corporation - initial API and implementation
|
||||
* Sergey Prigogin (Google)
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.internal.corext.refactoring.code.flow;
|
||||
|
||||
class BlockFlowInfo extends GenericSequentialFlowInfo {
|
||||
|
||||
public BlockFlowInfo() {
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2000, 2012 IBM Corporation 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:
|
||||
* IBM Corporation - initial API and implementation
|
||||
* Sergey Prigogin (Google)
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.internal.corext.refactoring.code.flow;
|
||||
|
||||
import java.util.HashSet;
|
||||
|
||||
import org.eclipse.cdt.core.dom.ast.IASTName;
|
||||
|
||||
class BranchFlowInfo extends FlowInfo {
|
||||
|
||||
public BranchFlowInfo(IASTName label, FlowContext context) {
|
||||
super(NO_RETURN);
|
||||
fBranches= new HashSet<String>(2);
|
||||
fBranches.add(makeString(label));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2000, 2012 IBM Corporation 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:
|
||||
* IBM Corporation - initial API and implementation
|
||||
* Sergey Prigogin (Google)
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.internal.corext.refactoring.code.flow;
|
||||
|
||||
class ConditionalFlowInfo extends FlowInfo {
|
||||
|
||||
public ConditionalFlowInfo() {
|
||||
super(NO_RETURN);
|
||||
}
|
||||
|
||||
public void mergeCondition(FlowInfo info, FlowContext context) {
|
||||
if (info == null)
|
||||
return;
|
||||
mergeAccessModeSequential(info, context);
|
||||
}
|
||||
|
||||
public void merge(FlowInfo truePart, FlowInfo falsePart, FlowContext context) {
|
||||
if (truePart == null && falsePart == null)
|
||||
return;
|
||||
|
||||
GenericConditionalFlowInfo cond= new GenericConditionalFlowInfo();
|
||||
if (truePart != null)
|
||||
cond.mergeAccessMode(truePart, context);
|
||||
|
||||
if (falsePart != null)
|
||||
cond.mergeAccessMode(falsePart, context);
|
||||
|
||||
if (truePart == null || falsePart == null)
|
||||
cond.mergeEmptyCondition(context);
|
||||
|
||||
mergeAccessModeSequential(cond, context);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2000, 2012 IBM Corporation 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:
|
||||
* IBM Corporation - initial API and implementation
|
||||
* Sergey Prigogin (Google)
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.internal.corext.refactoring.code.flow;
|
||||
|
||||
class DoWhileFlowInfo extends FlowInfo {
|
||||
private boolean fActionBranches;
|
||||
|
||||
public void mergeAction(FlowInfo info, FlowContext context) {
|
||||
if (info == null)
|
||||
return;
|
||||
|
||||
fActionBranches= info.branches();
|
||||
|
||||
assign(info);
|
||||
|
||||
if (fActionBranches && fReturnKind == VALUE_RETURN) {
|
||||
fReturnKind= PARTIAL_RETURN;
|
||||
}
|
||||
}
|
||||
|
||||
public void mergeCondition(FlowInfo info, FlowContext context) {
|
||||
if (fActionBranches || fReturnKind == VALUE_RETURN || fReturnKind == VOID_RETURN || info == null)
|
||||
return;
|
||||
mergeAccessModeSequential(info, context);
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,136 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2000, 2012 IBM Corporation 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:
|
||||
* IBM Corporation - initial API and implementation
|
||||
* Sergey Prigogin (Google)
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.internal.corext.refactoring.code.flow;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.core.runtime.Assert;
|
||||
|
||||
import org.eclipse.cdt.core.dom.ast.IASTDeclaration;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTDeclarator;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration;
|
||||
import org.eclipse.cdt.core.dom.ast.IType;
|
||||
import org.eclipse.cdt.core.dom.ast.IVariable;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCatchHandler;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTryBlockStatement;
|
||||
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor;
|
||||
|
||||
public class FlowContext extends LocalVariableIndex {
|
||||
private static class ComputeMode {
|
||||
}
|
||||
|
||||
public static final ComputeMode MERGE = new ComputeMode();
|
||||
public static final ComputeMode ARGUMENTS = new ComputeMode();
|
||||
public static final ComputeMode RETURN_VALUES = new ComputeMode();
|
||||
|
||||
private boolean fConsiderAccessMode;
|
||||
private boolean fLoopReentranceMode;
|
||||
private ComputeMode fComputeMode;
|
||||
private IVariable[] fLocals;
|
||||
private final List<ICPPASTCatchHandler[]> fExceptionStack;
|
||||
|
||||
public FlowContext(IASTFunctionDefinition functionDefinition) {
|
||||
super(functionDefinition);
|
||||
fExceptionStack= new ArrayList<ICPPASTCatchHandler[]>(3);
|
||||
}
|
||||
|
||||
public void setConsiderAccessMode(boolean b) {
|
||||
fConsiderAccessMode= b;
|
||||
}
|
||||
|
||||
public void setComputeMode(ComputeMode mode) {
|
||||
fComputeMode= mode;
|
||||
}
|
||||
|
||||
void setLoopReentranceMode(boolean b) {
|
||||
fLoopReentranceMode= b;
|
||||
}
|
||||
|
||||
int getArrayLength() {
|
||||
return getNumLocalVariables();
|
||||
}
|
||||
|
||||
boolean considerAccessMode() {
|
||||
return fConsiderAccessMode;
|
||||
}
|
||||
|
||||
boolean isLoopReentranceMode() {
|
||||
return fLoopReentranceMode;
|
||||
}
|
||||
|
||||
boolean computeMerge() {
|
||||
return fComputeMode == MERGE;
|
||||
}
|
||||
|
||||
boolean computeArguments() {
|
||||
return fComputeMode == ARGUMENTS;
|
||||
}
|
||||
|
||||
boolean computeReturnValues() {
|
||||
return fComputeMode == RETURN_VALUES;
|
||||
}
|
||||
|
||||
public IVariable getLocalFromIndex(int index) {
|
||||
if (fLocals == null || index > fLocals.length)
|
||||
return null;
|
||||
return fLocals[index];
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a local variable to the context.
|
||||
* @param localVariable the local variable to manage.
|
||||
*/
|
||||
void manageLocal(IVariable localVariable) {
|
||||
int index = getIndexFromLocal(localVariable);
|
||||
if (index >= 0) {
|
||||
if (fLocals == null)
|
||||
fLocals= new IVariable[getNumLocalVariables()];
|
||||
fLocals[index] = localVariable;
|
||||
}
|
||||
}
|
||||
|
||||
//---- Exception handling --------------------------------------------------------
|
||||
|
||||
void pushExceptions(ICPPASTTryBlockStatement node) {
|
||||
ICPPASTCatchHandler[] catchHandlers = node.getCatchHandlers();
|
||||
fExceptionStack.add(catchHandlers);
|
||||
}
|
||||
|
||||
void popExceptions() {
|
||||
Assert.isTrue(fExceptionStack.size() > 0);
|
||||
fExceptionStack.remove(fExceptionStack.size() - 1);
|
||||
}
|
||||
|
||||
boolean isExceptionCaught(IType exceptionType) {
|
||||
for (ICPPASTCatchHandler[] catchHandlers : fExceptionStack) {
|
||||
for (ICPPASTCatchHandler catchHandler : catchHandlers) {
|
||||
if (catchHandler.isCatchAll())
|
||||
return true;
|
||||
IASTDeclaration caughtException= catchHandler.getDeclaration();
|
||||
if (caughtException instanceof IASTSimpleDeclaration) {
|
||||
IASTDeclarator[] declarators = ((IASTSimpleDeclaration) caughtException).getDeclarators();
|
||||
IType caughtType = CPPVisitor.createType(declarators[0]);
|
||||
while (caughtType != null) {
|
||||
// 15.3
|
||||
if (caughtType.isSameType(exceptionType))
|
||||
return true;
|
||||
// TODO(sprigogin): Implement the rest of 15.3 matching logic.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,428 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2000, 2012 IBM Corporation 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:
|
||||
* IBM Corporation - initial API and implementation
|
||||
* Benjamin Muskalla <bmuskalla@eclipsesource.com> - [extract method] missing return type when code can throw exception - https://bugs.eclipse.org/bugs/show_bug.cgi?id=97413
|
||||
* Sergey Prigogin (Google)
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.internal.corext.refactoring.code.flow;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.cdt.core.dom.ast.IASTName;
|
||||
import org.eclipse.cdt.core.dom.ast.IVariable;
|
||||
|
||||
import org.eclipse.cdt.internal.core.pdom.dom.PDOMName;
|
||||
|
||||
public abstract class FlowInfo {
|
||||
// Return statement handling.
|
||||
protected static final int NOT_POSSIBLE= 0;
|
||||
protected static final int UNDEFINED= 1;
|
||||
protected static final int NO_RETURN= 2;
|
||||
protected static final int PARTIAL_RETURN= 3;
|
||||
protected static final int VOID_RETURN= 4;
|
||||
protected static final int VALUE_RETURN= 5;
|
||||
protected static final int THROW= 6;
|
||||
|
||||
// Local access handling.
|
||||
public static final int READ= PDOMName.READ_ACCESS; // 1 << 9
|
||||
public static final int WRITE= PDOMName.WRITE_ACCESS; // 1 << 10
|
||||
public static final int UNUSED= 1 << 0;
|
||||
public static final int READ_POTENTIAL= 1 << 1;
|
||||
public static final int WRITE_POTENTIAL= 1 << 2;
|
||||
public static final int UNKNOWN= 1 << 3;
|
||||
|
||||
// Table to merge access modes for condition statements (e.g branch[x] || branch[y]).
|
||||
private static final int[][] ACCESS_MODE_CONDITIONAL_TABLE= {
|
||||
/* UNUSED READ READ_POTENTIAL WRITE WRITE_POTENTIAL UNKNOWN */
|
||||
/* UNUSED */ { UNUSED, READ_POTENTIAL, READ_POTENTIAL, WRITE_POTENTIAL, WRITE_POTENTIAL, UNKNOWN },
|
||||
/* READ */ { READ_POTENTIAL, READ, READ_POTENTIAL, UNKNOWN, UNKNOWN, UNKNOWN },
|
||||
/* READ_POTENTIAL */ { READ_POTENTIAL, READ_POTENTIAL, READ_POTENTIAL, UNKNOWN, UNKNOWN, UNKNOWN },
|
||||
/* WRITE */ { WRITE_POTENTIAL, UNKNOWN, UNKNOWN, WRITE, WRITE_POTENTIAL, UNKNOWN },
|
||||
/* WRITE_POTENTIAL */ { WRITE_POTENTIAL, UNKNOWN, UNKNOWN, WRITE_POTENTIAL, WRITE_POTENTIAL, UNKNOWN },
|
||||
/* UNKNOWN */ { UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN }
|
||||
};
|
||||
|
||||
// Table to change access mode if there is an open branch statement
|
||||
private static final int[] ACCESS_MODE_OPEN_BRANCH_TABLE= {
|
||||
/* UNUSED READ READ_POTENTIAL WRITE WRITE_POTENTIAL UNKNOWN */
|
||||
UNUSED, READ_POTENTIAL, READ_POTENTIAL, WRITE_POTENTIAL, WRITE_POTENTIAL, UNKNOWN
|
||||
};
|
||||
|
||||
// Table to merge return modes for condition statements (y: fReturnKind, x: other.fReturnKind)
|
||||
private static final int[][] RETURN_KIND_CONDITIONAL_TABLE = {
|
||||
/* NOT_POSSIBLE UNDEFINED NO_RETURN PARTIAL_RETURN VOID_RETURN VALUE_RETURN THROW */
|
||||
/* NOT_POSSIBLE */ { NOT_POSSIBLE, NOT_POSSIBLE, NOT_POSSIBLE, NOT_POSSIBLE, NOT_POSSIBLE, NOT_POSSIBLE, NOT_POSSIBLE },
|
||||
/* UNDEFINED */ { NOT_POSSIBLE, UNDEFINED, NO_RETURN, PARTIAL_RETURN, VOID_RETURN, VALUE_RETURN, THROW },
|
||||
/* NO_RETURN */ { NOT_POSSIBLE, NO_RETURN, NO_RETURN, PARTIAL_RETURN, PARTIAL_RETURN, PARTIAL_RETURN, NO_RETURN },
|
||||
/* PARTIAL_RETURN */ { NOT_POSSIBLE, PARTIAL_RETURN, PARTIAL_RETURN, PARTIAL_RETURN, PARTIAL_RETURN, PARTIAL_RETURN, PARTIAL_RETURN },
|
||||
/* VOID_RETURN */ { NOT_POSSIBLE, VOID_RETURN, PARTIAL_RETURN, PARTIAL_RETURN, VOID_RETURN, NOT_POSSIBLE, VOID_RETURN },
|
||||
/* VALUE_RETURN */ { NOT_POSSIBLE, VALUE_RETURN, PARTIAL_RETURN, PARTIAL_RETURN, NOT_POSSIBLE, VALUE_RETURN, VALUE_RETURN },
|
||||
/* THROW */ { NOT_POSSIBLE, THROW, NO_RETURN, PARTIAL_RETURN, VOID_RETURN, VALUE_RETURN, THROW }
|
||||
};
|
||||
|
||||
// Table to merge return modes for sequential statements (y: fReturnKind, x: other.fReturnKind)
|
||||
private static final int[][] RETURN_KIND_SEQUENTIAL_TABLE = {
|
||||
/* NOT_POSSIBLE UNDEFINED NO_RETURN PARTIAL_RETURN VOID_RETURN VALUE_RETURN THROW */
|
||||
/* NOT_POSSIBLE */ { NOT_POSSIBLE, NOT_POSSIBLE, NOT_POSSIBLE, NOT_POSSIBLE, NOT_POSSIBLE, NOT_POSSIBLE, NOT_POSSIBLE },
|
||||
/* UNDEFINED */ { NOT_POSSIBLE, UNDEFINED, NO_RETURN, PARTIAL_RETURN, VOID_RETURN, VALUE_RETURN, THROW },
|
||||
/* NO_RETURN */ { NOT_POSSIBLE, NO_RETURN, NO_RETURN, PARTIAL_RETURN, VOID_RETURN, VALUE_RETURN, THROW },
|
||||
/* PARTIAL_RETURN */ { NOT_POSSIBLE, PARTIAL_RETURN, PARTIAL_RETURN, PARTIAL_RETURN, VOID_RETURN, VALUE_RETURN, VALUE_RETURN },
|
||||
/* VOID_RETURN */ { NOT_POSSIBLE, VOID_RETURN, VOID_RETURN, PARTIAL_RETURN, VOID_RETURN, NOT_POSSIBLE, NOT_POSSIBLE },
|
||||
/* VALUE_RETURN */ { NOT_POSSIBLE, VALUE_RETURN, VALUE_RETURN, PARTIAL_RETURN, NOT_POSSIBLE, VALUE_RETURN, NOT_POSSIBLE },
|
||||
/* THROW */ { NOT_POSSIBLE, THROW, THROW, VALUE_RETURN, VOID_RETURN, VALUE_RETURN, THROW }
|
||||
};
|
||||
|
||||
protected static final String UNLABELED = "@unlabeled"; //$NON-NLS-1$
|
||||
|
||||
protected int fReturnKind;
|
||||
protected int[] fAccessModes;
|
||||
protected Set<String> fBranches;
|
||||
|
||||
protected FlowInfo() {
|
||||
this(UNDEFINED);
|
||||
}
|
||||
|
||||
protected FlowInfo(int returnKind) {
|
||||
fReturnKind= returnKind;
|
||||
}
|
||||
|
||||
//---- General Helpers ----------------------------------------------------------
|
||||
|
||||
protected void assignExecutionFlow(FlowInfo right) {
|
||||
fReturnKind= right.fReturnKind;
|
||||
fBranches= right.fBranches;
|
||||
}
|
||||
|
||||
protected void assignAccessMode(FlowInfo right) {
|
||||
fAccessModes= right.fAccessModes;
|
||||
}
|
||||
|
||||
protected void assign(FlowInfo right) {
|
||||
assignExecutionFlow(right);
|
||||
assignAccessMode(right);
|
||||
}
|
||||
|
||||
protected void mergeConditional(FlowInfo info, FlowContext context) {
|
||||
mergeAccessModeConditional(info, context);
|
||||
mergeExecutionFlowConditional(info);
|
||||
}
|
||||
|
||||
protected void mergeSequential(FlowInfo info, FlowContext context) {
|
||||
mergeAccessModeSequential(info, context);
|
||||
mergeExecutionFlowSequential(info);
|
||||
}
|
||||
|
||||
//---- Return Kind ------------------------------------------------------------------
|
||||
|
||||
public void setNoReturn() {
|
||||
fReturnKind= NO_RETURN;
|
||||
}
|
||||
|
||||
public boolean isUndefined() {
|
||||
return fReturnKind == UNDEFINED;
|
||||
}
|
||||
|
||||
public boolean isNoReturn() {
|
||||
return fReturnKind == NO_RETURN;
|
||||
}
|
||||
|
||||
public boolean isPartialReturn() {
|
||||
return fReturnKind == PARTIAL_RETURN;
|
||||
}
|
||||
|
||||
public boolean isVoidReturn() {
|
||||
return fReturnKind == VOID_RETURN;
|
||||
}
|
||||
|
||||
public boolean isValueReturn() {
|
||||
return fReturnKind == VALUE_RETURN;
|
||||
}
|
||||
|
||||
public boolean isThrow() {
|
||||
return fReturnKind == THROW;
|
||||
}
|
||||
|
||||
public boolean isReturn() {
|
||||
return fReturnKind == VOID_RETURN || fReturnKind == VALUE_RETURN;
|
||||
}
|
||||
|
||||
//---- Branches -------------------------------------------------------------------------
|
||||
|
||||
public boolean branches() {
|
||||
return fBranches != null && !fBranches.isEmpty();
|
||||
}
|
||||
|
||||
protected Set<String> getBranches() {
|
||||
return fBranches;
|
||||
}
|
||||
|
||||
protected void removeLabel(IASTName label) {
|
||||
if (fBranches != null) {
|
||||
fBranches.remove(makeString(label));
|
||||
if (fBranches.isEmpty())
|
||||
fBranches= null;
|
||||
}
|
||||
}
|
||||
|
||||
protected static String makeString(IASTName label) {
|
||||
if (label == null) {
|
||||
return UNLABELED;
|
||||
} else {
|
||||
return String.valueOf(label.getSimpleID());
|
||||
}
|
||||
}
|
||||
|
||||
//---- Execution flow -------------------------------------------------------------------
|
||||
|
||||
private void mergeExecutionFlowSequential(FlowInfo otherInfo) {
|
||||
int other= otherInfo.fReturnKind;
|
||||
if (branches() && other == VALUE_RETURN)
|
||||
other= PARTIAL_RETURN;
|
||||
fReturnKind= RETURN_KIND_SEQUENTIAL_TABLE[fReturnKind][other];
|
||||
mergeBranches(otherInfo);
|
||||
}
|
||||
|
||||
private void mergeExecutionFlowConditional(FlowInfo otherInfo) {
|
||||
fReturnKind= RETURN_KIND_CONDITIONAL_TABLE[fReturnKind][otherInfo.fReturnKind];
|
||||
mergeBranches(otherInfo);
|
||||
}
|
||||
|
||||
private void mergeBranches(FlowInfo otherInfo) {
|
||||
fBranches= mergeSets(fBranches, otherInfo.fBranches);
|
||||
}
|
||||
|
||||
private static <T> Set<T> mergeSets(Set<T> thisSet, Set<T> otherSet) {
|
||||
if (otherSet != null) {
|
||||
if (thisSet == null) {
|
||||
thisSet= otherSet;
|
||||
} else {
|
||||
for (T element : otherSet) {
|
||||
thisSet.add(element);
|
||||
}
|
||||
}
|
||||
}
|
||||
return thisSet;
|
||||
}
|
||||
|
||||
//---- Local access handling --------------------------------------------------
|
||||
|
||||
/**
|
||||
* Returns a set of <code>IVariable</code> that conform to the given
|
||||
* access mode <code>mode</code>.
|
||||
*
|
||||
* @param context the flow context object used to compute this flow info
|
||||
* @param mode the access type. Valid values are <code>READ</code>, <code>WRITE</code>,
|
||||
* <code>UNKNOWN</code> and any combination of them.
|
||||
* @return an array of local variable bindings conforming to the given type.
|
||||
*/
|
||||
public Set<IVariable> get(FlowContext context, int mode) {
|
||||
if (fAccessModes == null)
|
||||
return Collections.emptySet();
|
||||
Set<IVariable> result= new HashSet<IVariable>(fAccessModes.length);
|
||||
for (int i= 0; i < fAccessModes.length; i++) {
|
||||
int accessMode= fAccessModes[i];
|
||||
if ((accessMode & mode) != 0)
|
||||
result.add(context.getLocalFromIndex(i));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the given local variable binding has the given access
|
||||
* mode.
|
||||
*
|
||||
* @param context the flow context used during flow analysis
|
||||
* @param local local variable of interest
|
||||
* @param mode the access mode of the local variable
|
||||
*
|
||||
* @return <code>true</code> if the binding has the given access mode.
|
||||
* <code>False</code> otherwise
|
||||
*/
|
||||
public boolean hasAccessMode(FlowContext context, IVariable local, int mode) {
|
||||
boolean unusedMode= (mode & UNUSED) != 0;
|
||||
if (fAccessModes == null && unusedMode)
|
||||
return true;
|
||||
int index= context.getIndexFromLocal(local);
|
||||
if (index == -1)
|
||||
return unusedMode;
|
||||
return (fAccessModes[index] & mode) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the access mode of the local variable identified by the given binding.
|
||||
*
|
||||
* @param context the flow context used during flow analysis
|
||||
* @param local the local variable of interest
|
||||
* @return the access mode of the local variable
|
||||
*/
|
||||
public int getAccessMode(FlowContext context, IVariable local) {
|
||||
if (fAccessModes == null)
|
||||
return UNUSED;
|
||||
int index= context.getIndexFromLocal(local);
|
||||
if (index == -1)
|
||||
return UNUSED;
|
||||
return fAccessModes[index];
|
||||
}
|
||||
|
||||
protected int[] getAccessModes() {
|
||||
return fAccessModes;
|
||||
}
|
||||
|
||||
protected void clearAccessMode(IVariable binding, FlowContext context) {
|
||||
if (fAccessModes == null) // All are unused
|
||||
return;
|
||||
int index = context.getIndexFromLocal(binding);
|
||||
if (index >= 0)
|
||||
fAccessModes[index]= UNUSED;
|
||||
}
|
||||
|
||||
protected void mergeAccessModeSequential(FlowInfo otherInfo, FlowContext context) {
|
||||
if (!context.considerAccessMode())
|
||||
return;
|
||||
|
||||
int[] others= otherInfo.fAccessModes;
|
||||
if (others == null) // others are all unused. So nothing to do
|
||||
return;
|
||||
|
||||
// Must not consider return kind since a return statement can't control execution flow
|
||||
// inside a method. It always leaves the method.
|
||||
if (branches()) {
|
||||
for (int i= 0; i < others.length; i++)
|
||||
others[i]= ACCESS_MODE_OPEN_BRANCH_TABLE[getIndex(others[i])];
|
||||
}
|
||||
|
||||
if (fAccessModes == null) { // all current variables are unused
|
||||
fAccessModes= others;
|
||||
return;
|
||||
}
|
||||
|
||||
if (context.computeArguments()) {
|
||||
handleComputeArguments(others);
|
||||
} else if (context.computeReturnValues()) {
|
||||
handleComputeReturnValues(others);
|
||||
} else if (context.computeMerge()) {
|
||||
handleMergeValues(others);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleComputeReturnValues(int[] others) {
|
||||
for (int i= 0; i < fAccessModes.length; i++) {
|
||||
int accessmode= fAccessModes[i];
|
||||
int othermode= others[i];
|
||||
if (accessmode == WRITE)
|
||||
continue;
|
||||
if (accessmode == WRITE_POTENTIAL) {
|
||||
if (othermode == WRITE)
|
||||
fAccessModes[i]= WRITE;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (others[i] != UNUSED)
|
||||
fAccessModes[i]= othermode;
|
||||
}
|
||||
}
|
||||
|
||||
private void handleComputeArguments(int[] others) {
|
||||
for (int i= 0; i < fAccessModes.length; i++) {
|
||||
int accessMode= fAccessModes[i];
|
||||
int otherMode= others[i];
|
||||
if (accessMode == UNUSED) {
|
||||
fAccessModes[i]= otherMode;
|
||||
} else if (accessMode == WRITE_POTENTIAL && (otherMode == READ || otherMode == READ_POTENTIAL)) {
|
||||
// Read always supersedes a potential write even if the read is potential as well
|
||||
// (we have to consider the potential read as an argument then).
|
||||
fAccessModes[i]= otherMode;
|
||||
} else if (accessMode == WRITE_POTENTIAL && otherMode == WRITE) {
|
||||
fAccessModes[i]= WRITE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void handleMergeValues(int[] others) {
|
||||
for (int i= 0; i < fAccessModes.length; i++) {
|
||||
fAccessModes[i]= ACCESS_MODE_CONDITIONAL_TABLE[getIndex(fAccessModes[i])][getIndex(others[i])];
|
||||
}
|
||||
}
|
||||
|
||||
protected void createAccessModeArray(FlowContext context) {
|
||||
fAccessModes= new int[context.getArrayLength()];
|
||||
for (int i= 0; i < fAccessModes.length; i++) {
|
||||
fAccessModes[i]= UNUSED;
|
||||
}
|
||||
}
|
||||
|
||||
protected void mergeAccessModeConditional(FlowInfo otherInfo, FlowContext context) {
|
||||
if (!context.considerAccessMode())
|
||||
return;
|
||||
|
||||
int[] others= otherInfo.fAccessModes;
|
||||
// first access
|
||||
if (fAccessModes == null) {
|
||||
if (others != null) {
|
||||
fAccessModes= others;
|
||||
} else {
|
||||
createAccessModeArray(context);
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
if (others == null) {
|
||||
for (int i= 0; i < fAccessModes.length; i++) {
|
||||
int unused_index= getIndex(UNUSED);
|
||||
fAccessModes[i]= ACCESS_MODE_CONDITIONAL_TABLE[getIndex(fAccessModes[i])][unused_index];
|
||||
}
|
||||
} else {
|
||||
for (int i= 0; i < fAccessModes.length; i++) {
|
||||
fAccessModes[i]= ACCESS_MODE_CONDITIONAL_TABLE[getIndex(fAccessModes[i])][getIndex(others[i])];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void mergeEmptyCondition(FlowContext context) {
|
||||
if (fReturnKind == VALUE_RETURN || fReturnKind == VOID_RETURN)
|
||||
fReturnKind= PARTIAL_RETURN;
|
||||
|
||||
if (!context.considerAccessMode())
|
||||
return;
|
||||
|
||||
if (fAccessModes == null) {
|
||||
createAccessModeArray(context);
|
||||
return;
|
||||
}
|
||||
|
||||
int unused_index= getIndex(UNUSED);
|
||||
for (int i= 0; i < fAccessModes.length; i++) {
|
||||
fAccessModes[i]= ACCESS_MODE_CONDITIONAL_TABLE[getIndex(fAccessModes[i])][unused_index];
|
||||
}
|
||||
}
|
||||
|
||||
private static int getIndex(int accessMode) {
|
||||
// Fast log function
|
||||
switch (accessMode) {
|
||||
case UNUSED:
|
||||
return 0;
|
||||
case READ:
|
||||
return 1;
|
||||
case READ_POTENTIAL:
|
||||
return 2;
|
||||
case WRITE:
|
||||
case READ | WRITE:
|
||||
return 3;
|
||||
case WRITE_POTENTIAL:
|
||||
return 4;
|
||||
case UNKNOWN:
|
||||
return 5;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2000, 2012 IBM Corporation 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:
|
||||
* IBM Corporation - initial API and implementation
|
||||
* Sergey Prigogin (Google)
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.internal.corext.refactoring.code.flow;
|
||||
|
||||
class ForFlowInfo extends FlowInfo {
|
||||
|
||||
public void mergeInitializer(FlowInfo info, FlowContext context) {
|
||||
if (info == null)
|
||||
return;
|
||||
mergeAccessModeSequential(info, context);
|
||||
}
|
||||
|
||||
public void mergeCondition(FlowInfo info, FlowContext context) {
|
||||
if (info == null)
|
||||
return;
|
||||
mergeAccessModeSequential(info, context);
|
||||
}
|
||||
|
||||
public void mergeIncrement(FlowInfo info, FlowContext context) {
|
||||
if (info == null)
|
||||
return;
|
||||
|
||||
info.mergeEmptyCondition(context);
|
||||
mergeAccessModeSequential(info, context);
|
||||
}
|
||||
|
||||
public void mergeAction(FlowInfo info, FlowContext context) {
|
||||
if (info == null)
|
||||
return;
|
||||
|
||||
info.mergeEmptyCondition(context);
|
||||
|
||||
mergeSequential(info, context);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2000, 2012 IBM Corporation 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:
|
||||
* IBM Corporation - initial API and implementation
|
||||
* Sergey Prigogin (Google)
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.internal.corext.refactoring.code.flow;
|
||||
|
||||
class FunctionCallFlowInfo extends FlowInfo {
|
||||
|
||||
public FunctionCallFlowInfo() {
|
||||
super(NO_RETURN);
|
||||
}
|
||||
|
||||
public void mergeArgument(FlowInfo info, FlowContext context) {
|
||||
if (info == null)
|
||||
return;
|
||||
mergeSequential(info, context);
|
||||
}
|
||||
|
||||
public void mergeReceiver(FlowInfo info, FlowContext context) {
|
||||
if (info == null)
|
||||
return;
|
||||
mergeSequential(info, context);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2000, 2012 IBM Corporation 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:
|
||||
* IBM Corporation - initial API and implementation
|
||||
* Sergey Prigogin (Google)
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.internal.corext.refactoring.code.flow;
|
||||
|
||||
class GenericConditionalFlowInfo extends FlowInfo {
|
||||
|
||||
public GenericConditionalFlowInfo() {
|
||||
super(UNDEFINED);
|
||||
}
|
||||
|
||||
public void merge(FlowInfo info, FlowContext context) {
|
||||
if (info == null)
|
||||
return;
|
||||
|
||||
mergeConditional(info, context);
|
||||
}
|
||||
|
||||
public void mergeAccessMode(FlowInfo info, FlowContext context) {
|
||||
if (info == null)
|
||||
return;
|
||||
|
||||
mergeAccessModeConditional(info, context);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2000, 2012 IBM Corporation 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:
|
||||
* IBM Corporation - initial API and implementation
|
||||
* Sergey Prigogin (Google)
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.internal.corext.refactoring.code.flow;
|
||||
|
||||
class GenericSequentialFlowInfo extends FlowInfo {
|
||||
|
||||
public GenericSequentialFlowInfo() {
|
||||
super(NO_RETURN);
|
||||
}
|
||||
|
||||
public void merge(FlowInfo info, FlowContext context) {
|
||||
if (info == null)
|
||||
return;
|
||||
mergeSequential(info, context);
|
||||
}
|
||||
|
||||
public void mergeAccessMode(FlowInfo info, FlowContext context) {
|
||||
if (info == null)
|
||||
return;
|
||||
mergeAccessModeSequential(info, context);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2000, 2012 IBM Corporation 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:
|
||||
* IBM Corporation - initial API and implementation
|
||||
* Sergey Prigogin (Google)
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.internal.corext.refactoring.code.flow;
|
||||
|
||||
class IfFlowInfo extends FlowInfo {
|
||||
|
||||
public void mergeCondition(FlowInfo info, FlowContext context) {
|
||||
if (info == null)
|
||||
return;
|
||||
mergeAccessModeSequential(info, context);
|
||||
}
|
||||
|
||||
public void merge(FlowInfo thenPart, FlowInfo elsePart, FlowContext context) {
|
||||
if (thenPart == null && elsePart == null)
|
||||
return;
|
||||
|
||||
GenericConditionalFlowInfo cond= new GenericConditionalFlowInfo();
|
||||
if (thenPart != null)
|
||||
cond.merge(thenPart, context);
|
||||
|
||||
if (elsePart != null)
|
||||
cond.merge(elsePart, context);
|
||||
|
||||
if (thenPart == null || elsePart == null)
|
||||
cond.mergeEmptyCondition(context);
|
||||
|
||||
mergeSequential(cond, context);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,143 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2000, 2012 IBM Corporation 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:
|
||||
* IBM Corporation - initial API and implementation
|
||||
* Sergey Prigogin (Google)
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.internal.corext.refactoring.code.flow;
|
||||
|
||||
import org.eclipse.cdt.core.dom.ast.IASTCompoundStatement;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTDeclaration;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTDeclarationStatement;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTDeclarator;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTForStatement;
|
||||
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.IASTReturnStatement;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTStandardFunctionDeclarator;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTStatement;
|
||||
import org.eclipse.cdt.core.dom.ast.IBinding;
|
||||
import org.eclipse.cdt.core.dom.ast.IField;
|
||||
import org.eclipse.cdt.core.dom.ast.IVariable;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCatchHandler;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTRangeBasedForStatement;
|
||||
import org.eclipse.cdt.core.dom.ast.gnu.c.ICASTKnRFunctionDeclarator;
|
||||
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor;
|
||||
|
||||
public class InOutFlowAnalyzer extends FlowAnalyzer {
|
||||
|
||||
public InOutFlowAnalyzer(FlowContext context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public FlowInfo perform(IASTNode[] selectedNodes) {
|
||||
FlowContext context= getFlowContext();
|
||||
GenericSequentialFlowInfo result= createSequential();
|
||||
for (int i= 0; i < selectedNodes.length; i++) {
|
||||
IASTNode node= selectedNodes[i];
|
||||
node.accept(this);
|
||||
result.merge(getFlowInfo(node), context);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean traverseNode(IASTNode node) {
|
||||
// We are only traversing the selected nodes.
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean createReturnFlowInfo(IASTReturnStatement node) {
|
||||
// We are only traversing selected nodes.
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int leave(IASTCompoundStatement node) {
|
||||
super.leave(node);
|
||||
clearAccessMode(accessFlowInfo(node), node.getStatements());
|
||||
return PROCESS_SKIP;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int leave(ICPPASTCatchHandler node) {
|
||||
super.leave(node);
|
||||
clearAccessMode(accessFlowInfo(node), node.getDeclaration());
|
||||
return PROCESS_SKIP;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int leave(IASTForStatement node) {
|
||||
super.leave(node);
|
||||
clearAccessMode(accessFlowInfo(node), node.getInitializerStatement());
|
||||
return PROCESS_SKIP;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int leave(ICPPASTRangeBasedForStatement node) {
|
||||
super.leave(node);
|
||||
clearAccessMode(accessFlowInfo(node), node.getDeclaration());
|
||||
return PROCESS_SKIP;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int leave(IASTFunctionDefinition node) {
|
||||
super.leave(node);
|
||||
FlowInfo info= accessFlowInfo(node);
|
||||
IASTFunctionDeclarator declarator = node.getDeclarator();
|
||||
if (declarator instanceof IASTStandardFunctionDeclarator) {
|
||||
for (IASTParameterDeclaration param : ((IASTStandardFunctionDeclarator) declarator).getParameters()) {
|
||||
clearAccessMode(info, param.getDeclarator());
|
||||
}
|
||||
} else if (declarator instanceof ICASTKnRFunctionDeclarator) {
|
||||
for (IASTDeclaration param : ((ICASTKnRFunctionDeclarator) declarator).getParameterDeclarations()) {
|
||||
clearAccessMode(info, param);
|
||||
}
|
||||
}
|
||||
return PROCESS_SKIP;
|
||||
}
|
||||
|
||||
private void clearAccessMode(FlowInfo info, IASTStatement[] statements) {
|
||||
if (statements == null || statements.length == 0 || info == null)
|
||||
return;
|
||||
for (IASTStatement statement : statements) {
|
||||
clearAccessMode(info, statement);
|
||||
}
|
||||
}
|
||||
|
||||
private void clearAccessMode(FlowInfo info, IASTStatement statement) {
|
||||
if (statement instanceof IASTDeclarationStatement) {
|
||||
IASTDeclaration declaration = ((IASTDeclarationStatement) statement).getDeclaration();
|
||||
clearAccessMode(info, declaration);
|
||||
}
|
||||
}
|
||||
|
||||
private void clearAccessMode(FlowInfo info, IASTDeclaration declaration) {
|
||||
if (declaration instanceof IASTSimpleDeclaration) {
|
||||
IASTDeclarator[] declarators = ((IASTSimpleDeclaration) declaration).getDeclarators();
|
||||
for (IASTDeclarator declarator : declarators) {
|
||||
clearAccessMode(info, declarator);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void clearAccessMode(FlowInfo info, IASTDeclarator declarator) {
|
||||
declarator = CPPVisitor.findInnermostDeclarator(declarator);
|
||||
IASTName name = declarator.getName();
|
||||
IBinding binding= name.resolveBinding();
|
||||
if (binding instanceof IVariable && !(binding instanceof IField))
|
||||
info.clearAccessMode((IVariable) binding, fFlowContext);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,304 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2000, 2012 IBM Corporation 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:
|
||||
* IBM Corporation - initial API and implementation
|
||||
* Dmitry Stalnov (dstalnov@fusionone.com) - contributed fix for
|
||||
* o inline call that is used in a field initializer
|
||||
* (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=38137)
|
||||
* Benjamin Muskalla <bmuskalla@eclipsesource.com> - [extract method] Missing return value,
|
||||
* while extracting code out of a loop - https://bugs.eclipse.org/bugs/show_bug.cgi?id=213519
|
||||
* Sergey Prigogin (Google)
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.internal.corext.refactoring.code.flow;
|
||||
|
||||
import org.eclipse.core.runtime.Assert;
|
||||
import org.eclipse.jface.text.IRegion;
|
||||
|
||||
import org.eclipse.cdt.core.dom.ast.IASTConditionalExpression;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTDoStatement;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTExpression;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTForStatement;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTIfStatement;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTNode;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTReturnStatement;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTStatement;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTSwitchStatement;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTWhileStatement;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTRangeBasedForStatement;
|
||||
|
||||
import org.eclipse.cdt.internal.corext.util.ASTNodes;
|
||||
|
||||
public class InputFlowAnalyzer extends FlowAnalyzer {
|
||||
|
||||
private static class LoopReentranceVisitor extends FlowAnalyzer {
|
||||
private Selection fSelection;
|
||||
private IASTNode fLoopNode;
|
||||
|
||||
public LoopReentranceVisitor(FlowContext context, Selection selection, IASTNode loopNode) {
|
||||
super(context);
|
||||
fSelection= selection;
|
||||
fLoopNode= loopNode;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean traverseNode(IASTNode node) {
|
||||
return true; // end <= fSelection.end || fSelection.enclosedBy(start, end);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean createReturnFlowInfo(IASTReturnStatement node) {
|
||||
// Make sure that the whole return statement is selected or located before the selection.
|
||||
return ASTNodes.endOffset(node) <= fSelection.getEnd();
|
||||
}
|
||||
|
||||
protected IASTNode getLoopNode() {
|
||||
return fLoopNode;
|
||||
}
|
||||
|
||||
public void process(IASTNode node) {
|
||||
try {
|
||||
fFlowContext.setLoopReentranceMode(true);
|
||||
node.accept(this);
|
||||
} finally {
|
||||
fFlowContext.setLoopReentranceMode(false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int leave(IASTDoStatement node) {
|
||||
if (skipNode(node))
|
||||
return PROCESS_SKIP;
|
||||
DoWhileFlowInfo info= createDoWhile();
|
||||
setFlowInfo(node, info);
|
||||
info.mergeAction(getFlowInfo(node.getBody()), fFlowContext);
|
||||
// No need to merge the condition. It was already considered by the InputFlowAnalyzer.
|
||||
info.removeLabel(null);
|
||||
return PROCESS_SKIP;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int leave(ICPPASTRangeBasedForStatement node) {
|
||||
if (skipNode(node))
|
||||
return PROCESS_SKIP;
|
||||
FlowInfo paramInfo= getFlowInfo(node.getDeclaration());
|
||||
FlowInfo expressionInfo= getFlowInfo(node.getInitializerClause());
|
||||
FlowInfo actionInfo= getFlowInfo(node.getBody());
|
||||
RangeBasedForFlowInfo forInfo= createEnhancedFor();
|
||||
setFlowInfo(node, forInfo);
|
||||
// If the for statement is the outermost loop then we only have to consider
|
||||
// the action. The parameter and expression are only evaluated once.
|
||||
if (node == fLoopNode) {
|
||||
forInfo.mergeAction(actionInfo, fFlowContext);
|
||||
} else {
|
||||
// Inner for loops are evaluated in the sequence expression, parameter,
|
||||
// action.
|
||||
forInfo.mergeInitializerClause(expressionInfo, fFlowContext);
|
||||
forInfo.mergeDeclaration(paramInfo, fFlowContext);
|
||||
forInfo.mergeAction(actionInfo, fFlowContext);
|
||||
}
|
||||
forInfo.removeLabel(null);
|
||||
return PROCESS_SKIP;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int leave(IASTForStatement node) {
|
||||
if (skipNode(node))
|
||||
return PROCESS_SKIP;
|
||||
FlowInfo initInfo= createSequential(node.getInitializerStatement());
|
||||
FlowInfo conditionInfo= getFlowInfo(node.getConditionExpression());
|
||||
FlowInfo incrementInfo= createSequential(node.getIterationExpression());
|
||||
FlowInfo actionInfo= getFlowInfo(node.getBody());
|
||||
ForFlowInfo forInfo= createFor();
|
||||
setFlowInfo(node, forInfo);
|
||||
// The for statement is the outermost loop. In this case we only have
|
||||
// to consider the increment, condition and action.
|
||||
if (node == fLoopNode) {
|
||||
forInfo.mergeIncrement(incrementInfo, fFlowContext);
|
||||
forInfo.mergeCondition(conditionInfo, fFlowContext);
|
||||
forInfo.mergeAction(actionInfo, fFlowContext);
|
||||
} else {
|
||||
// We have to merge two different cases. One if we reenter the for statement
|
||||
// immediatelly (that means we have to consider increments, condition and action)
|
||||
// and the other case if we reenter the for in the next loop of
|
||||
// the outer loop. Then we have to consider initializations, condtion and action.
|
||||
// For a conditional flow info that means:
|
||||
// (initializations | increments) & condition & action.
|
||||
GenericConditionalFlowInfo initIncr= new GenericConditionalFlowInfo();
|
||||
initIncr.merge(initInfo, fFlowContext);
|
||||
initIncr.merge(incrementInfo, fFlowContext);
|
||||
forInfo.mergeAccessModeSequential(initIncr, fFlowContext);
|
||||
forInfo.mergeCondition(conditionInfo, fFlowContext);
|
||||
forInfo.mergeAction(actionInfo, fFlowContext);
|
||||
}
|
||||
forInfo.removeLabel(null);
|
||||
return PROCESS_SKIP;
|
||||
}
|
||||
}
|
||||
|
||||
private Selection fSelection;
|
||||
private boolean fDoLoopReentrance;
|
||||
private LoopReentranceVisitor fLoopReentranceVisitor;
|
||||
|
||||
public InputFlowAnalyzer(FlowContext context, Selection selection, boolean doLoopReentrance) {
|
||||
super(context);
|
||||
fSelection= selection;
|
||||
Assert.isNotNull(fSelection);
|
||||
fDoLoopReentrance= doLoopReentrance;
|
||||
}
|
||||
|
||||
public FlowInfo perform(IASTFunctionDefinition node) {
|
||||
node.accept(this);
|
||||
return getFlowInfo(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean traverseNode(IASTNode node) {
|
||||
return ASTNodes.endOffset(node) > fSelection.getEnd();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean createReturnFlowInfo(IASTReturnStatement node) {
|
||||
// Make sure that the whole return statement is located after the selection.
|
||||
// There can be cases like return i + [x + 10] * 10; In this case we must not create
|
||||
// a return info node.
|
||||
return ASTNodes.offset(node) >= fSelection.getEnd();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int visit(IASTDoStatement node) {
|
||||
createLoopReentranceVisitor(node);
|
||||
return super.visit(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int visit(ICPPASTRangeBasedForStatement node) {
|
||||
createLoopReentranceVisitor(node);
|
||||
return super.visit(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int visit(IASTForStatement node) {
|
||||
createLoopReentranceVisitor(node);
|
||||
return super.visit(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int visit(IASTWhileStatement node) {
|
||||
createLoopReentranceVisitor(node);
|
||||
return super.visit(node);
|
||||
}
|
||||
|
||||
private void createLoopReentranceVisitor(IASTNode node) {
|
||||
if (fLoopReentranceVisitor == null && fDoLoopReentrance && fSelection.coveredBy(node)) {
|
||||
fLoopReentranceVisitor= new LoopReentranceVisitor(fFlowContext, fSelection, node);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int leave(IASTConditionalExpression node) {
|
||||
if (skipNode(node))
|
||||
return PROCESS_SKIP;
|
||||
IASTExpression thenPart= node.getPositiveResultExpression();
|
||||
IASTExpression elsePart= node.getNegativeResultExpression();
|
||||
if ((thenPart != null && fSelection.coveredBy(thenPart)) ||
|
||||
(elsePart != null && fSelection.coveredBy(elsePart))) {
|
||||
GenericSequentialFlowInfo info= createSequential();
|
||||
setFlowInfo(node, info);
|
||||
endVisitConditional(info, node.getLogicalConditionExpression(), new IASTNode[] { thenPart, elsePart });
|
||||
return PROCESS_SKIP;
|
||||
}
|
||||
return super.leave(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int leave(IASTDoStatement node) {
|
||||
super.leave(node);
|
||||
handleLoopReentrance(node);
|
||||
return PROCESS_SKIP;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int leave(IASTIfStatement node) {
|
||||
if (skipNode(node))
|
||||
return PROCESS_SKIP;
|
||||
IASTStatement thenPart= node.getThenClause();
|
||||
IASTStatement elsePart= node.getElseClause();
|
||||
if ((thenPart != null && fSelection.coveredBy(thenPart)) ||
|
||||
(elsePart != null && fSelection.coveredBy(elsePart))) {
|
||||
GenericSequentialFlowInfo info= createSequential();
|
||||
setFlowInfo(node, info);
|
||||
endVisitConditional(info, node.getConditionExpression(), new IASTNode[] { thenPart, elsePart });
|
||||
return PROCESS_SKIP;
|
||||
}
|
||||
return super.leave(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int leave(ICPPASTRangeBasedForStatement node) {
|
||||
super.leave(node);
|
||||
handleLoopReentrance(node);
|
||||
return PROCESS_SKIP;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int leave(IASTForStatement node) {
|
||||
super.leave(node);
|
||||
handleLoopReentrance(node);
|
||||
return PROCESS_SKIP;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int leave(IASTSwitchStatement node) {
|
||||
if (skipNode(node))
|
||||
return PROCESS_SKIP;
|
||||
SwitchData data= createSwitchData(node);
|
||||
IRegion[] ranges= data.getRanges();
|
||||
for (int i= 0; i < ranges.length; i++) {
|
||||
IRegion range= ranges[i];
|
||||
if (fSelection.coveredBy(range)) {
|
||||
GenericSequentialFlowInfo info= createSequential();
|
||||
setFlowInfo(node, info);
|
||||
info.merge(getFlowInfo(node.getControllerExpression()), fFlowContext);
|
||||
info.merge(data.getInfo(i), fFlowContext);
|
||||
info.removeLabel(null);
|
||||
return PROCESS_SKIP;
|
||||
}
|
||||
}
|
||||
return super.leave(node, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int leave(IASTWhileStatement node) {
|
||||
super.leave(node);
|
||||
handleLoopReentrance(node);
|
||||
return PROCESS_SKIP;
|
||||
}
|
||||
|
||||
private void endVisitConditional(GenericSequentialFlowInfo info, IASTNode condition, IASTNode[] branches) {
|
||||
info.merge(getFlowInfo(condition), fFlowContext);
|
||||
for (int i= 0; i < branches.length; i++) {
|
||||
IASTNode branch= branches[i];
|
||||
if (branch != null && fSelection.coveredBy(branch)) {
|
||||
info.merge(getFlowInfo(branch), fFlowContext);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void handleLoopReentrance(IASTNode node) {
|
||||
if (fLoopReentranceVisitor == null || fLoopReentranceVisitor.getLoopNode() != node)
|
||||
return;
|
||||
|
||||
fLoopReentranceVisitor.process(node);
|
||||
GenericSequentialFlowInfo info= createSequential();
|
||||
info.merge(getFlowInfo(node), fFlowContext);
|
||||
info.merge(fLoopReentranceVisitor.getFlowInfo(node), fFlowContext);
|
||||
setFlowInfo(node, info);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2000, 2012 IBM Corporation 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:
|
||||
* IBM Corporation - initial API and implementation
|
||||
* Sergey Prigogin (Google)
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.internal.corext.refactoring.code.flow;
|
||||
|
||||
import org.eclipse.cdt.core.dom.ast.IVariable;
|
||||
|
||||
class LocalFlowInfo extends FlowInfo {
|
||||
private final int fVariableIndex;
|
||||
|
||||
public LocalFlowInfo(IVariable binding, int localAccessMode, FlowContext context) {
|
||||
super(NO_RETURN);
|
||||
fVariableIndex= context.getIndexFromLocal(binding);
|
||||
if (fVariableIndex < 0)
|
||||
throw new IllegalStateException("Invalid local variable \"" + binding.getName() + "\" for the context."); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
if (context.considerAccessMode()) {
|
||||
createAccessModeArray(context);
|
||||
context.manageLocal(binding);
|
||||
fAccessModes[fVariableIndex]= localAccessMode;
|
||||
}
|
||||
}
|
||||
|
||||
public LocalFlowInfo(LocalFlowInfo info, int localAccessMode, FlowContext context) {
|
||||
super(NO_RETURN);
|
||||
fVariableIndex= info.fVariableIndex;
|
||||
if (context.considerAccessMode()) {
|
||||
createAccessModeArray(context);
|
||||
fAccessModes[fVariableIndex]= localAccessMode;
|
||||
}
|
||||
}
|
||||
|
||||
public void setWriteAccess(FlowContext context) {
|
||||
if (context.considerAccessMode()) {
|
||||
fAccessModes[fVariableIndex]= FlowInfo.WRITE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2012 Google, Inc 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:
|
||||
* Sergey Prigogin (Google) - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.internal.corext.refactoring.code.flow;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.cdt.core.dom.ast.ASTVisitor;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTName;
|
||||
import org.eclipse.cdt.core.dom.ast.IBinding;
|
||||
import org.eclipse.cdt.core.dom.ast.IField;
|
||||
import org.eclipse.cdt.core.dom.ast.IVariable;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTQualifiedName;
|
||||
|
||||
/**
|
||||
* Index of local variables inside a function. Each variable is assigned an integer index in normal
|
||||
* code reading order. A variable with a smaller index is declared before a variable with a larger
|
||||
* one.
|
||||
*/
|
||||
public class LocalVariableIndex {
|
||||
private final Map<IVariable, Integer> variableMap = new HashMap<IVariable, Integer>();
|
||||
|
||||
public LocalVariableIndex(IASTFunctionDefinition functionDefinition) {
|
||||
functionDefinition.accept(new ASTVisitor() {
|
||||
{
|
||||
shouldVisitNames = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int visit(IASTName name) {
|
||||
if (name instanceof ICPPASTQualifiedName || name.isQualified() || !name.isDeclaration()) {
|
||||
return PROCESS_CONTINUE;
|
||||
}
|
||||
|
||||
IBinding binding = name.resolveBinding();
|
||||
if (binding instanceof IVariable && !(binding instanceof IField)) {
|
||||
IVariable variable = (IVariable) binding;
|
||||
if (!variableMap.containsKey(variable)) {
|
||||
variableMap.put(variable, variableMap.size());
|
||||
}
|
||||
}
|
||||
return PROCESS_CONTINUE;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of local variables in the index.
|
||||
*/
|
||||
public int getNumLocalVariables() {
|
||||
return variableMap.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index for the given local variable.
|
||||
* @param variable the local variable
|
||||
* @return the index of the variable, or -1 if the variable in not contained in the index.
|
||||
*/
|
||||
public int getIndexFromLocal(IVariable variable) {
|
||||
Integer index = variableMap.get(variable);
|
||||
return index != null ? index.intValue() : -1;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2000, 2012 IBM Corporation 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:
|
||||
* IBM Corporation - initial API and implementation
|
||||
* Sergey Prigogin (Google)
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.internal.corext.refactoring.code.flow;
|
||||
|
||||
class RangeBasedForFlowInfo extends FlowInfo {
|
||||
|
||||
public void mergeDeclaration(FlowInfo info, FlowContext context) {
|
||||
if (info == null)
|
||||
return;
|
||||
mergeAccessModeSequential(info, context);
|
||||
}
|
||||
|
||||
public void mergeInitializerClause(FlowInfo info, FlowContext context) {
|
||||
if (info == null)
|
||||
return;
|
||||
mergeAccessModeSequential(info, context);
|
||||
}
|
||||
|
||||
public void mergeAction(FlowInfo info, FlowContext context) {
|
||||
if (info == null)
|
||||
return;
|
||||
|
||||
info.mergeEmptyCondition(context);
|
||||
mergeSequential(info, context);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2000, 2012 IBM Corporation 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:
|
||||
* IBM Corporation - initial API and implementation
|
||||
* Sergey Prigogin (Google)
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.internal.corext.refactoring.code.flow;
|
||||
|
||||
import org.eclipse.cdt.core.dom.ast.IASTExpression;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTReturnStatement;
|
||||
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil;
|
||||
|
||||
class ReturnFlowInfo extends FlowInfo {
|
||||
|
||||
public ReturnFlowInfo(IASTReturnStatement node) {
|
||||
super(getReturnFlag(node));
|
||||
}
|
||||
|
||||
public void merge(FlowInfo info, FlowContext context) {
|
||||
if (info == null)
|
||||
return;
|
||||
|
||||
assignAccessMode(info);
|
||||
}
|
||||
|
||||
private static int getReturnFlag(IASTReturnStatement node) {
|
||||
IASTExpression expression= node.getReturnValue();
|
||||
if (expression == null || SemanticUtil.isVoidType(expression.getExpressionType()))
|
||||
return VOID_RETURN;
|
||||
return VALUE_RETURN;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,164 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2000, 2011 IBM Corporation 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:
|
||||
* IBM Corporation - initial API and implementation
|
||||
* Sergey Prigogin (Google)
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.internal.corext.refactoring.code.flow;
|
||||
|
||||
import org.eclipse.core.runtime.Assert;
|
||||
import org.eclipse.jface.text.IRegion;
|
||||
|
||||
import org.eclipse.cdt.core.dom.ast.IASTFileLocation;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTNode;
|
||||
|
||||
public class Selection {
|
||||
/** Flag indicating that the AST node somehow intersects with the selection. */
|
||||
public static final int INTERSECTS= 0;
|
||||
|
||||
/** Flag that indicates that an AST node appears before the selected nodes. */
|
||||
public static final int BEFORE= 1;
|
||||
|
||||
/** Flag indicating that an AST node is covered by the selection. */
|
||||
public static final int SELECTED= 2;
|
||||
|
||||
/** Flag indicating that an AST nodes appears after the selected nodes. */
|
||||
public static final int AFTER= 3;
|
||||
|
||||
private int fStart;
|
||||
private int fLength;
|
||||
private int fEnd;
|
||||
|
||||
protected Selection() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new selection from the given start and length.
|
||||
*
|
||||
* @param start the start offset of the selection (inclusive)
|
||||
* @param length the length of the selection
|
||||
* @return the created selection object
|
||||
*/
|
||||
public static Selection createFromStartLength(int start, int length) {
|
||||
Assert.isTrue(start >= 0 && length >= 0);
|
||||
Selection result= new Selection();
|
||||
result.fStart= start;
|
||||
result.fLength= length;
|
||||
result.fEnd= start + length;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new selection from the given start and end.
|
||||
*
|
||||
* @param start the start offset of the selection (inclusive)
|
||||
* @param end the end offset of the selection (exclusive)
|
||||
* @return the created selection object
|
||||
*/
|
||||
public static Selection createFromStartEnd(int start, int end) {
|
||||
Assert.isTrue(start >= 0 && end >= start);
|
||||
Selection result= new Selection();
|
||||
result.fStart= start;
|
||||
result.fLength= end - start;
|
||||
result.fEnd= result.fStart + result.fLength;
|
||||
return result;
|
||||
}
|
||||
|
||||
public int getOffset() {
|
||||
return fStart;
|
||||
}
|
||||
|
||||
public int getLength() {
|
||||
return fLength;
|
||||
}
|
||||
|
||||
public int getEnd() {
|
||||
return fEnd;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the selection mode of the given AST node regarding this selection. Possible
|
||||
* values are <code>INTERSECTS</code>, <code>BEFORE</code>, <code>SELECTED</code>, and
|
||||
* <code>AFTER</code>.
|
||||
*
|
||||
* @param node the node to return the visit mode for
|
||||
*
|
||||
* @return the selection mode of the given AST node regarding this selection
|
||||
* @see #INTERSECTS
|
||||
* @see #BEFORE
|
||||
* @see #SELECTED
|
||||
* @see #AFTER
|
||||
*/
|
||||
public int getVisitSelectionMode(IASTNode node) {
|
||||
IASTFileLocation location = node.getFileLocation();
|
||||
int nodeStart= location.getNodeOffset();
|
||||
int nodeEnd= nodeStart + location.getNodeLength();
|
||||
if (nodeEnd <= fStart) {
|
||||
return BEFORE;
|
||||
} else if (covers(node)) {
|
||||
return SELECTED;
|
||||
} else if (fEnd <= nodeStart) {
|
||||
return AFTER;
|
||||
}
|
||||
return INTERSECTS;
|
||||
}
|
||||
|
||||
public int getEndVisitSelectionMode(IASTNode node) {
|
||||
IASTFileLocation location = node.getFileLocation();
|
||||
int nodeStart= location.getNodeOffset();
|
||||
int nodeEnd= nodeStart + location.getNodeLength();
|
||||
if (nodeEnd <= fStart) {
|
||||
return BEFORE;
|
||||
} else if (covers(node)) {
|
||||
return SELECTED;
|
||||
} else if (nodeEnd >= fEnd) {
|
||||
return AFTER;
|
||||
}
|
||||
return INTERSECTS;
|
||||
}
|
||||
|
||||
// cover* methods do a closed interval check.
|
||||
|
||||
public boolean covers(int position) {
|
||||
return fStart <= position && position < fStart + fLength;
|
||||
}
|
||||
|
||||
public boolean covers(IASTNode node) {
|
||||
IASTFileLocation location = node.getFileLocation();
|
||||
int nodeStart= location.getNodeOffset();
|
||||
return fStart <= nodeStart && nodeStart + location.getNodeLength() <= fEnd;
|
||||
}
|
||||
|
||||
public boolean coveredBy(IASTNode node) {
|
||||
IASTFileLocation location = node.getFileLocation();
|
||||
int nodeStart= location.getNodeOffset();
|
||||
return nodeStart <= fStart && fEnd <= nodeStart + location.getNodeLength();
|
||||
}
|
||||
|
||||
public boolean coveredBy(IRegion region) {
|
||||
int regionStart= region.getOffset();
|
||||
return regionStart <= fStart && fEnd <= regionStart + region.getLength();
|
||||
}
|
||||
|
||||
public boolean endsIn(IASTNode node) {
|
||||
IASTFileLocation location = node.getFileLocation();
|
||||
int nodeStart= location.getNodeOffset();
|
||||
return nodeStart < fEnd && fEnd < nodeStart + location.getNodeLength();
|
||||
}
|
||||
|
||||
public boolean liesOutside(IASTNode node) {
|
||||
IASTFileLocation location = node.getFileLocation();
|
||||
int nodeStart= location.getNodeOffset();
|
||||
return fEnd < nodeStart || nodeStart + location.getNodeLength() < fStart;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "<start == " + fStart + ", length == " + fLength + "/>"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2000, 2012 IBM Corporation 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:
|
||||
* IBM Corporation - initial API and implementation
|
||||
* Sergey Prigogin (Google)
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.internal.corext.refactoring.code.flow;
|
||||
|
||||
class SwitchFlowInfo extends FlowInfo {
|
||||
private GenericConditionalFlowInfo fCases;
|
||||
private boolean fHasNullCaseInfo;
|
||||
|
||||
public SwitchFlowInfo() {
|
||||
fCases= new GenericConditionalFlowInfo();
|
||||
}
|
||||
|
||||
public void mergeTest(FlowInfo info, FlowContext context) {
|
||||
if (info == null)
|
||||
return;
|
||||
mergeSequential(info, context);
|
||||
}
|
||||
|
||||
public void mergeCase(FlowInfo info, FlowContext context) {
|
||||
if (info == null) {
|
||||
fHasNullCaseInfo= true;
|
||||
return;
|
||||
}
|
||||
fCases.mergeConditional(info, context);
|
||||
}
|
||||
|
||||
public void mergeDefault(boolean defaultCaseExists, FlowContext context) {
|
||||
if (!defaultCaseExists || fHasNullCaseInfo)
|
||||
fCases.mergeEmptyCondition(context);
|
||||
mergeSequential(fCases, context);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2000, 2012 IBM Corporation 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:
|
||||
* IBM Corporation - initial API and implementation
|
||||
* Sergey Prigogin (Google)
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.internal.corext.refactoring.code.flow;
|
||||
|
||||
class ThrowFlowInfo extends FlowInfo {
|
||||
|
||||
public ThrowFlowInfo() {
|
||||
super(THROW);
|
||||
}
|
||||
|
||||
public void merge(FlowInfo info, FlowContext context) {
|
||||
if (info == null)
|
||||
return;
|
||||
|
||||
assignAccessMode(info);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2000, 2012 IBM Corporation 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:
|
||||
* IBM Corporation - initial API and implementation
|
||||
* Sergey Prigogin (Google)
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.internal.corext.refactoring.code.flow;
|
||||
|
||||
class TryFlowInfo extends FlowInfo {
|
||||
|
||||
public TryFlowInfo() {
|
||||
super();
|
||||
}
|
||||
|
||||
public void mergeTry(FlowInfo info, FlowContext context) {
|
||||
if (info == null)
|
||||
return;
|
||||
|
||||
assign(info);
|
||||
}
|
||||
|
||||
public void mergeCatch(FlowInfo info, FlowContext context) {
|
||||
if (info == null)
|
||||
return;
|
||||
|
||||
mergeConditional(info, context);
|
||||
}
|
||||
|
||||
public void mergeFinally(FlowInfo info, FlowContext context) {
|
||||
if (info == null)
|
||||
return;
|
||||
|
||||
mergeSequential(info, context);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2000, 2012 IBM Corporation 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:
|
||||
* IBM Corporation - initial API and implementation
|
||||
* Sergey Prigogin (Google)
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.internal.corext.refactoring.code.flow;
|
||||
|
||||
class WhileFlowInfo extends FlowInfo {
|
||||
|
||||
public void mergeCondition(FlowInfo info, FlowContext context) {
|
||||
if (info == null)
|
||||
return;
|
||||
|
||||
mergeAccessModeSequential(info, context);
|
||||
}
|
||||
|
||||
public void mergeAction(FlowInfo info, FlowContext context) {
|
||||
if (info == null)
|
||||
return;
|
||||
|
||||
info.mergeEmptyCondition(context);
|
||||
|
||||
mergeSequential(info, context);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2012 Google, Inc 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:
|
||||
* Sergey Prigogin (Google) - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.internal.corext.util;
|
||||
|
||||
import org.eclipse.cdt.core.dom.ast.IASTFileLocation;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTNode;
|
||||
|
||||
/**
|
||||
* Collection of helper methods for common operations on AST nodes.
|
||||
*/
|
||||
public class ASTNodes {
|
||||
|
||||
// Not instantiatable.
|
||||
private ASTNodes() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the offset of an AST node.
|
||||
*/
|
||||
public static int offset(IASTNode node) {
|
||||
return node.getFileLocation().getNodeOffset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the exclusive end offset of an AST node.
|
||||
*/
|
||||
public static int endOffset(IASTNode node) {
|
||||
IASTFileLocation location = node.getFileLocation();
|
||||
return location.getNodeOffset() + location.getNodeLength();
|
||||
}
|
||||
}
|
|
@ -46,10 +46,7 @@ public class NameInformation {
|
|||
|
||||
private final IASTName name;
|
||||
private IASTName declarationName;
|
||||
private final List<IASTName> references;
|
||||
private final List<IASTName> referencesBeforeSelection;
|
||||
private final List<IASTName> referencesInSelection;
|
||||
private final List<IASTName> referencesAfterSelection;
|
||||
private boolean isOutput;
|
||||
private boolean mustBeReturnValue;
|
||||
private boolean isWriteAccess;
|
||||
|
@ -65,10 +62,7 @@ public class NameInformation {
|
|||
public NameInformation(IASTName name) {
|
||||
this.name = name;
|
||||
this.newName = String.valueOf(name.getSimpleID());
|
||||
references = new ArrayList<IASTName>();
|
||||
referencesBeforeSelection = new ArrayList<IASTName>();
|
||||
referencesInSelection = new ArrayList<IASTName>();
|
||||
referencesAfterSelection = new ArrayList<IASTName>();
|
||||
}
|
||||
|
||||
public static NameInformation createInfoForAddedParameter(String type, String name,
|
||||
|
@ -205,14 +199,9 @@ public class NameInformation {
|
|||
}
|
||||
|
||||
void addReference(IASTName name, int startOffset, int endOffset) {
|
||||
references.add(name);
|
||||
int nodeOffset = name.getFileLocation().getNodeOffset();
|
||||
if (nodeOffset >= endOffset) {
|
||||
referencesAfterSelection.add(name);
|
||||
} else if (nodeOffset >= startOffset) {
|
||||
if (nodeOffset >= startOffset && nodeOffset < endOffset) {
|
||||
referencesInSelection.add(name);
|
||||
} else {
|
||||
referencesBeforeSelection.add(name);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -244,22 +233,10 @@ public class NameInformation {
|
|||
return writer.toString();
|
||||
}
|
||||
|
||||
public List<IASTName> getReferencesBeforeSelection() {
|
||||
return referencesBeforeSelection;
|
||||
}
|
||||
|
||||
public List<IASTName> getReferencesInSelection() {
|
||||
return referencesInSelection;
|
||||
}
|
||||
|
||||
public List<IASTName> getReferencesAfterSelection() {
|
||||
return referencesAfterSelection;
|
||||
}
|
||||
|
||||
public boolean isReferencedAfterSelection() {
|
||||
return !referencesAfterSelection.isEmpty();
|
||||
}
|
||||
|
||||
public IASTParameterDeclaration getParameterDeclaration(INodeFactory nodeFactory) {
|
||||
return getParameterDeclaration(nodeFactory, newName);
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ import org.eclipse.cdt.core.dom.ast.ASTVisitor;
|
|||
import org.eclipse.cdt.core.dom.ast.DOMException;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTDeclarator;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTFieldReference;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTMacroExpansionLocation;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTName;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTNode;
|
||||
|
@ -44,7 +45,13 @@ import org.eclipse.cdt.ui.CUIPlugin;
|
|||
import org.eclipse.cdt.ui.PreferenceConstants;
|
||||
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVariableReadWriteFlags;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor;
|
||||
import org.eclipse.cdt.internal.core.pdom.dom.PDOMName;
|
||||
import org.eclipse.cdt.internal.corext.refactoring.code.flow.FlowContext;
|
||||
import org.eclipse.cdt.internal.corext.refactoring.code.flow.FlowInfo;
|
||||
import org.eclipse.cdt.internal.corext.refactoring.code.flow.InputFlowAnalyzer;
|
||||
import org.eclipse.cdt.internal.corext.refactoring.code.flow.Selection;
|
||||
import org.eclipse.cdt.internal.corext.util.ASTNodes;
|
||||
|
||||
public class NodeContainer {
|
||||
private final List<IASTNode> nodes;
|
||||
|
@ -152,6 +159,8 @@ public class NodeContainer {
|
|||
if (interfaceNames == null) {
|
||||
findAllNames();
|
||||
|
||||
Set<IVariable> externalReads = getVariablesReadOutside();
|
||||
|
||||
Set<IASTName> declarations = new HashSet<IASTName>();
|
||||
interfaceNames = new ArrayList<NameInformation>();
|
||||
|
||||
|
@ -159,7 +168,7 @@ public class NodeContainer {
|
|||
IASTName declarationName = nameInfo.getDeclarationName();
|
||||
if (declarations.add(declarationName)) {
|
||||
if (isDeclaredInSelection(nameInfo)) {
|
||||
if (nameInfo.isReferencedAfterSelection()) {
|
||||
if (externalReads.contains(nameInfo.getName().resolveBinding())) {
|
||||
nameInfo.setMustBeReturnValue(true);
|
||||
interfaceNames.add(nameInfo);
|
||||
}
|
||||
|
@ -175,7 +184,8 @@ public class NodeContainer {
|
|||
}
|
||||
}
|
||||
}
|
||||
if (nameInfo.isWriteAccess() && nameInfo.isReferencedAfterSelection()) {
|
||||
if (nameInfo.isWriteAccess() &&
|
||||
externalReads.contains(nameInfo.getName().resolveBinding())) {
|
||||
nameInfo.setOutput(true);
|
||||
}
|
||||
}
|
||||
|
@ -188,6 +198,25 @@ public class NodeContainer {
|
|||
return interfaceNames;
|
||||
}
|
||||
|
||||
private Set<IVariable> getVariablesReadOutside() {
|
||||
if (nodes.isEmpty())
|
||||
return Collections.emptySet();
|
||||
|
||||
IASTNode firstNode = nodes.get(0);
|
||||
IASTFunctionDefinition enclosingFunction =
|
||||
CPPVisitor.findAncestorWithType(firstNode, IASTFunctionDefinition.class);
|
||||
FlowContext flowContext= new FlowContext(enclosingFunction);
|
||||
flowContext.setConsiderAccessMode(true);
|
||||
flowContext.setComputeMode(FlowContext.ARGUMENTS);
|
||||
// Compute a selection that exactly covers the selected nodes
|
||||
Selection selection= Selection.createFromStartEnd(ASTNodes.offset(firstNode),
|
||||
ASTNodes.endOffset(nodes.get(nodes.size() - 1)));
|
||||
|
||||
InputFlowAnalyzer analyzer = new InputFlowAnalyzer(flowContext, selection, true);
|
||||
FlowInfo argInfo= analyzer.perform(enclosingFunction);
|
||||
return argInfo.get(flowContext, FlowInfo.READ | FlowInfo.READ_POTENTIAL | FlowInfo.UNKNOWN);
|
||||
}
|
||||
|
||||
public static boolean hasReferenceOperator(IASTDeclarator declarator) {
|
||||
IASTPointerOperator[] operators = declarator.getPointerOperators();
|
||||
return operators.length != 0 && operators[operators.length - 1] instanceof ICPPASTReferenceOperator;
|
||||
|
|
|
@ -58,7 +58,8 @@ public class StatementExtractor extends FunctionExtractor {
|
|||
NameInformation returnVariable) {
|
||||
if (returnVariable != null) {
|
||||
IASTNode decl = ASTHelper.getDeclarationForNode(returnVariable.getDeclarationName());
|
||||
return ASTHelper.getDeclarationSpecifier(decl).copy(CopyStyle.withLocations);
|
||||
IASTDeclSpecifier declSpec = ASTHelper.getDeclarationSpecifier(decl);
|
||||
return declSpec != null ? declSpec.copy(CopyStyle.withLocations) : null;
|
||||
}
|
||||
IASTSimpleDeclSpecifier declSpec = new CPPASTSimpleDeclSpecifier();
|
||||
declSpec.setType(IASTSimpleDeclSpecifier.t_void);
|
||||
|
|
Loading…
Add table
Reference in a new issue