mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-08-04 23:05:47 +02:00
Bug 393959: Unhandled template id ambiguity.
This commit is contained in:
parent
352eae2865
commit
73968cb5f2
4 changed files with 146 additions and 129 deletions
|
@ -6181,4 +6181,14 @@ public class AST2TemplateTests extends AST2BaseTest {
|
||||||
public void testAddressAsTemplateArgument_391190() throws Exception {
|
public void testAddressAsTemplateArgument_391190() throws Exception {
|
||||||
parseAndCheckBindings(getAboveComment(), CPP, true);
|
parseAndCheckBindings(getAboveComment(), CPP, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// template <typename T> struct CT {
|
||||||
|
// const static int const_min= 1;
|
||||||
|
// };
|
||||||
|
// void test(int off) {
|
||||||
|
// off < CT<int>::const_min || off > CT<int>::const_min;
|
||||||
|
// }
|
||||||
|
public void testTemplateIDAmbiguity_393959() throws Exception {
|
||||||
|
parseAndCheckBindings(getAboveComment(), CPP, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,6 @@ import java.util.List;
|
||||||
|
|
||||||
import org.eclipse.cdt.core.dom.ast.ASTVisitor;
|
import org.eclipse.cdt.core.dom.ast.ASTVisitor;
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTExpression;
|
import org.eclipse.cdt.core.dom.ast.IASTExpression;
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTInitializerClause;
|
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTName;
|
import org.eclipse.cdt.core.dom.ast.IASTName;
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTNode;
|
import org.eclipse.cdt.core.dom.ast.IASTNode;
|
||||||
import org.eclipse.cdt.core.dom.ast.IBinding;
|
import org.eclipse.cdt.core.dom.ast.IBinding;
|
||||||
|
@ -43,17 +42,14 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.NameOrTemplateIDVariants.Var
|
||||||
*/
|
*/
|
||||||
public class CPPASTTemplateIDAmbiguity extends ASTAmbiguousNode implements IASTAmbiguousExpression,
|
public class CPPASTTemplateIDAmbiguity extends ASTAmbiguousNode implements IASTAmbiguousExpression,
|
||||||
ICPPASTExpression {
|
ICPPASTExpression {
|
||||||
private BinaryOperator fLastOperator;
|
private final BinaryOperator fEndOperator;
|
||||||
private IASTInitializerClause fLastExpression;
|
|
||||||
private final BranchPoint fVariants;
|
private final BranchPoint fVariants;
|
||||||
private IASTNode[] fNodes;
|
private IASTNode[] fNodes;
|
||||||
private final AbstractGNUSourceCodeParser fParser;
|
private final AbstractGNUSourceCodeParser fParser;
|
||||||
|
|
||||||
public CPPASTTemplateIDAmbiguity(AbstractGNUSourceCodeParser parser, BinaryOperator lastOperator, IASTInitializerClause expr,
|
public CPPASTTemplateIDAmbiguity(AbstractGNUSourceCodeParser parser, BinaryOperator endOperator, BranchPoint variants) {
|
||||||
BranchPoint variants) {
|
|
||||||
fParser= parser;
|
fParser= parser;
|
||||||
fLastOperator= lastOperator;
|
fEndOperator= endOperator;
|
||||||
fLastExpression= expr;
|
|
||||||
fVariants= variants;
|
fVariants= variants;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,10 +88,7 @@ public class CPPASTTemplateIDAmbiguity extends ASTAmbiguousNode implements IASTA
|
||||||
if (selected != null) {
|
if (selected != null) {
|
||||||
minOffset= selected.getRightOffset();
|
minOffset= selected.getRightOffset();
|
||||||
BinaryOperator targetOp = selected.getTargetOperator();
|
BinaryOperator targetOp = selected.getTargetOperator();
|
||||||
if (targetOp == null) {
|
if (targetOp != null) {
|
||||||
fLastExpression= selected.getExpression();
|
|
||||||
fLastOperator= v.getLeftOperator();
|
|
||||||
} else {
|
|
||||||
targetOp.exchange(selected.getExpression());
|
targetOp.exchange(selected.getExpression());
|
||||||
targetOp.setNext(v.getLeftOperator());
|
targetOp.setNext(v.getLeftOperator());
|
||||||
}
|
}
|
||||||
|
@ -106,7 +99,7 @@ public class CPPASTTemplateIDAmbiguity extends ASTAmbiguousNode implements IASTA
|
||||||
owner.replace(nodeToReplace, this);
|
owner.replace(nodeToReplace, this);
|
||||||
|
|
||||||
// Create the expression and replace it
|
// Create the expression and replace it
|
||||||
IASTExpression expr = fParser.buildExpression(fLastOperator, fLastExpression);
|
IASTExpression expr = fParser.buildExpression(fEndOperator.getNext(), fEndOperator.getExpression());
|
||||||
owner.replace(this, expr);
|
owner.replace(this, expr);
|
||||||
|
|
||||||
// Resolve further ambiguities within the new expression.
|
// Resolve further ambiguities within the new expression.
|
||||||
|
@ -149,8 +142,7 @@ public class CPPASTTemplateIDAmbiguity extends ASTAmbiguousNode implements IASTA
|
||||||
public IASTNode[] getNodes() {
|
public IASTNode[] getNodes() {
|
||||||
if (fNodes == null) {
|
if (fNodes == null) {
|
||||||
List<IASTNode> nl= new ArrayList<IASTNode>();
|
List<IASTNode> nl= new ArrayList<IASTNode>();
|
||||||
nl.add(fLastExpression);
|
BinaryOperator op= fEndOperator;
|
||||||
BinaryOperator op= fLastOperator;
|
|
||||||
while (op != null) {
|
while (op != null) {
|
||||||
nl.add(op.getExpression());
|
nl.add(op.getExpression());
|
||||||
op= op.getNext();
|
op= op.getNext();
|
||||||
|
|
|
@ -764,6 +764,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
|
||||||
BinaryOperator lastOperator= null;
|
BinaryOperator lastOperator= null;
|
||||||
NameOrTemplateIDVariants variants= null;
|
NameOrTemplateIDVariants variants= null;
|
||||||
|
|
||||||
|
IToken variantMark= mark();
|
||||||
if (expr == null) {
|
if (expr == null) {
|
||||||
Object e = castExpressionForBinaryExpression(strat);
|
Object e = castExpressionForBinaryExpression(strat);
|
||||||
if (e instanceof IASTExpression) {
|
if (e instanceof IASTExpression) {
|
||||||
|
@ -773,20 +774,21 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
|
||||||
|
|
||||||
final Variant variant = (Variant) e;
|
final Variant variant = (Variant) e;
|
||||||
expr= variant.getExpression();
|
expr= variant.getExpression();
|
||||||
variants.addBranchPoint(variant.getNext(), lastOperator, allowAssignment, conditionCount);
|
variants.addBranchPoint(variant.getNext(), null, allowAssignment, conditionCount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean doneExpression= false;
|
boolean stopWithNextOperator= false;
|
||||||
do {
|
castExprLoop: for(;;) {
|
||||||
// Typically after a binary operator there cannot be a throw expression
|
// Typically after a binary operator there cannot be a throw expression
|
||||||
boolean allowThrow= false;
|
boolean allowThrow= false;
|
||||||
// Brace initializers are allowed on the right hand side of an expression
|
// Brace initializers are allowed on the right hand side of an expression
|
||||||
boolean allowBraceInitializer= false;
|
boolean allowBraceInitializer= false;
|
||||||
|
|
||||||
BacktrackException tryRecovery= null;
|
boolean doneExpression= false;
|
||||||
final int operatorOffset= LA().getOffset();
|
BacktrackException failure= null;
|
||||||
lt1= LT(1);
|
final int opOffset= LA().getOffset();
|
||||||
|
lt1= stopWithNextOperator ? IToken.tSEMI : LT(1);
|
||||||
switch (lt1) {
|
switch (lt1) {
|
||||||
case IToken.tQUESTION:
|
case IToken.tQUESTION:
|
||||||
conditionCount++;
|
conditionCount++;
|
||||||
|
@ -879,7 +881,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
|
||||||
if (LT(2) != IToken.tGT_in_SHIFTR) {
|
if (LT(2) != IToken.tGT_in_SHIFTR) {
|
||||||
IToken token = LA(1);
|
IToken token = LA(1);
|
||||||
backtrack.initialize(token.getOffset(), token.getLength());
|
backtrack.initialize(token.getOffset(), token.getLength());
|
||||||
tryRecovery= backtrack;
|
failure= backtrack;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -908,34 +910,45 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!doneExpression && tryRecovery == null) {
|
// Close variants
|
||||||
consume(); // consumes the operator
|
if (failure == null) {
|
||||||
|
if (doneExpression) {
|
||||||
// Link variants that are closed by the new operator
|
if (variants != null && !variants.hasRightBound(opOffset)) {
|
||||||
if (variants != null) {
|
// We have a longer variant, ignore this one.
|
||||||
variants.closeVariants(operatorOffset, lastOperator);
|
backtrack.initialize(opOffset, 1);
|
||||||
|
failure= backtrack;
|
||||||
|
} else {
|
||||||
|
break castExprLoop;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
// Close variants with matching end
|
||||||
|
if (variants != null && lastOperator != null) {
|
||||||
|
variants.closeVariants(opOffset, lastOperator);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Determine next sub-expression
|
if (failure == null && !doneExpression) {
|
||||||
if (lt1 == IToken.tQUESTION && LT(1) == IToken.tCOLON) {
|
// Determine next cast-expression
|
||||||
// Missing sub-expression after '?' (gnu-extension)
|
consume(); // consumes the operator
|
||||||
expr= null;
|
stopWithNextOperator= false;
|
||||||
} else if (allowThrow && LT(1) == IToken.t_throw) {
|
try {
|
||||||
// Throw expression
|
if (lt1 == IToken.tQUESTION && LT(1) == IToken.tCOLON) {
|
||||||
expr= throwExpression();
|
// Missing sub-expression after '?' (gnu-extension)
|
||||||
lt1= LT(1);
|
expr= null;
|
||||||
if (lt1 != IToken.tCOLON && lt1 != IToken.tCOMMA)
|
} else if (allowThrow && LT(1) == IToken.t_throw) {
|
||||||
|
// Throw expression
|
||||||
|
expr= throwExpression();
|
||||||
|
lt1= LT(1);
|
||||||
|
if (lt1 != IToken.tCOLON && lt1 != IToken.tCOMMA)
|
||||||
|
stopWithNextOperator= true;
|
||||||
break;
|
break;
|
||||||
} else if (allowBraceInitializer && LT(1) == IToken.tLBRACE) {
|
} else if (allowBraceInitializer && LT(1) == IToken.tLBRACE) {
|
||||||
// Brace initializer
|
// Brace initializer
|
||||||
expr= bracedInitList(true);
|
expr= bracedInitList(true);
|
||||||
lt1= LT(1);
|
lt1= LT(1);
|
||||||
if (lt1 != IToken.tCOLON && lt1 != IToken.tCOMMA)
|
if (lt1 != IToken.tCOLON && lt1 != IToken.tCOMMA)
|
||||||
break;
|
stopWithNextOperator= true;
|
||||||
} else {
|
} else {
|
||||||
// Cast expression
|
|
||||||
IToken m= mark();
|
|
||||||
try {
|
|
||||||
Object e = castExpressionForBinaryExpression(strat);
|
Object e = castExpressionForBinaryExpression(strat);
|
||||||
if (e instanceof IASTExpression) {
|
if (e instanceof IASTExpression) {
|
||||||
expr= (IASTExpression) e;
|
expr= (IASTExpression) e;
|
||||||
|
@ -947,55 +960,49 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
|
||||||
|
|
||||||
variants.addBranchPoint(ae.getNext(), lastOperator, allowAssignment, conditionCount);
|
variants.addBranchPoint(ae.getNext(), lastOperator, allowAssignment, conditionCount);
|
||||||
}
|
}
|
||||||
} catch (BacktrackException e) {
|
|
||||||
if (variants == null)
|
|
||||||
throw e;
|
|
||||||
tryRecovery= e;
|
|
||||||
backup(m);
|
|
||||||
}
|
}
|
||||||
|
continue castExprLoop;
|
||||||
|
} catch (BacktrackException e) {
|
||||||
|
failure= e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tryRecovery != null || doneExpression) {
|
// We need a new variant
|
||||||
if (variants != null) {
|
Variant variant= variants == null ? null : variants.selectFallback();
|
||||||
if (lt1 == IToken.tEOC) {
|
if (variant == null) {
|
||||||
variants.discardOpenVariants(operatorOffset);
|
if (failure != null)
|
||||||
} else {
|
throw failure;
|
||||||
// Try fall-back to an open variant
|
throwBacktrack(LA(1));
|
||||||
Variant fallback= variants.findFallback(operatorOffset);
|
} else {
|
||||||
if (fallback == null) {
|
// Restore variant and continue
|
||||||
if (tryRecovery != null)
|
BranchPoint varPoint= variant.getOwner();
|
||||||
throw tryRecovery;
|
allowAssignment= varPoint.isAllowAssignment();
|
||||||
variants.discardOpenVariants(operatorOffset);
|
conditionCount= varPoint.getConditionCount();
|
||||||
} else {
|
lastOperator= varPoint.getLeftOperator();
|
||||||
// Restore state and continue
|
expr= variant.getExpression();
|
||||||
doneExpression= false;
|
|
||||||
BranchPoint varPoint= fallback.getOwner();
|
|
||||||
allowAssignment= varPoint.isAllowAssignment();
|
|
||||||
conditionCount= varPoint.getConditionCount();
|
|
||||||
lastOperator= varPoint.getLeftOperator();
|
|
||||||
expr= fallback.getExpression();
|
|
||||||
variants.useFallback(fallback);
|
|
||||||
|
|
||||||
// Advance to the right token
|
backup(variantMark);
|
||||||
int offset= fallback.getRightOffset();
|
int offset= variant.getRightOffset();
|
||||||
while (LA().getOffset() < offset) {
|
while (LA().getOffset() < offset) {
|
||||||
consume();
|
consume();
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
variantMark= mark();
|
||||||
}
|
}
|
||||||
} while (!doneExpression);
|
}
|
||||||
|
|
||||||
// Check for incomplete conditional expression
|
// Check for incomplete conditional expression
|
||||||
if (lt1 != IToken.tEOC && conditionCount > 0)
|
if (lt1 != IToken.tEOC && conditionCount > 0)
|
||||||
throwBacktrack(LA(1));
|
throwBacktrack(LA(1));
|
||||||
|
|
||||||
if (variants != null && !variants.isEmpty()) {
|
if (variants != null) {
|
||||||
CPPASTTemplateIDAmbiguity result = new CPPASTTemplateIDAmbiguity(this, lastOperator, expr, variants.getOrderedBranchPoints());
|
BinaryOperator end = new BinaryOperator(lastOperator, expr, -1, 0, 0);
|
||||||
setRange(result, startOffset, calculateEndOffset(expr));
|
variants.closeVariants(LA(1).getOffset(), end);
|
||||||
return result;
|
variants.removeInvalid(end);
|
||||||
|
if (!variants.isEmpty()) {
|
||||||
|
CPPASTTemplateIDAmbiguity result = new CPPASTTemplateIDAmbiguity(this, end, variants.getOrderedBranchPoints());
|
||||||
|
setRange(result, startOffset, calculateEndOffset(expr));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return buildExpression(lastOperator, expr);
|
return buildExpression(lastOperator, expr);
|
||||||
|
@ -1009,7 +1016,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
|
||||||
|
|
||||||
TemplateIdStrategy strat= new TemplateIdStrategy();
|
TemplateIdStrategy strat= new TemplateIdStrategy();
|
||||||
Variant variants= null;
|
Variant variants= null;
|
||||||
IASTExpression singleExpression= null;
|
IASTExpression singleResult= null;
|
||||||
IASTName[] firstNames= null;
|
IASTName[] firstNames= null;
|
||||||
|
|
||||||
final IToken mark= mark();
|
final IToken mark= mark();
|
||||||
|
@ -1018,12 +1025,12 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
|
||||||
try {
|
try {
|
||||||
IASTExpression e = castExpression(CastExprCtx.eDirectlyInBExpr, strat);
|
IASTExpression e = castExpression(CastExprCtx.eDirectlyInBExpr, strat);
|
||||||
if (variants == null) {
|
if (variants == null) {
|
||||||
if (singleExpression == null || lastToken == null) {
|
if (singleResult == null || lastToken == null) {
|
||||||
singleExpression= e;
|
singleResult= e;
|
||||||
firstNames= strat.getTemplateNames();
|
firstNames= strat.getTemplateNames();
|
||||||
} else {
|
} else {
|
||||||
variants= new Variant(null, singleExpression, firstNames, lastToken.getOffset());
|
variants= new Variant(null, singleResult, firstNames, lastToken.getOffset());
|
||||||
singleExpression= null;
|
singleResult= null;
|
||||||
firstNames= null;
|
firstNames= null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1045,7 +1052,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
|
||||||
}
|
}
|
||||||
backup(mark);
|
backup(mark);
|
||||||
}
|
}
|
||||||
return variants != null ? variants : singleExpression;
|
return variants != null ? variants : singleResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -13,7 +13,6 @@ package org.eclipse.cdt.internal.core.dom.parser.cpp;
|
||||||
|
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTExpression;
|
import org.eclipse.cdt.core.dom.ast.IASTExpression;
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTName;
|
import org.eclipse.cdt.core.dom.ast.IASTName;
|
||||||
import org.eclipse.cdt.internal.core.dom.parser.ASTNode;
|
|
||||||
import org.eclipse.cdt.internal.core.dom.parser.AbstractGNUSourceCodeParser.BinaryOperator;
|
import org.eclipse.cdt.internal.core.dom.parser.AbstractGNUSourceCodeParser.BinaryOperator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -132,59 +131,31 @@ public class NameOrTemplateIDVariants {
|
||||||
if (v.getTargetOperator() == null) {
|
if (v.getTargetOperator() == null) {
|
||||||
if (offset == v.getRightOffset()) {
|
if (offset == v.getRightOffset()) {
|
||||||
v.setTargetOperator(lastOperator);
|
v.setTargetOperator(lastOperator);
|
||||||
} else if (offset > v.getRightOffset()) {
|
|
||||||
// Should not happen
|
|
||||||
assert false;
|
|
||||||
remove(v);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void discardOpenVariants(int operatorOffset) {
|
public Variant selectFallback() {
|
||||||
for (BranchPoint p = fFirst; p != null; p= p.getNext()) {
|
|
||||||
for (Variant v= p.getFirstVariant(); v != null; v= v.getNext()) {
|
|
||||||
if (v.getTargetOperator() == null && v.getRightOffset() != operatorOffset) {
|
|
||||||
remove(v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Variant findFallback(int operatorOffset) {
|
|
||||||
// Search for an open variant, with a small right offset and a large left offset
|
// Search for an open variant, with a small right offset and a large left offset
|
||||||
Variant best= null;
|
|
||||||
for (BranchPoint p = fFirst; p != null; p= p.getNext()) {
|
for (BranchPoint p = fFirst; p != null; p= p.getNext()) {
|
||||||
|
Variant best= null;
|
||||||
for (Variant v= p.getFirstVariant(); v != null; v= v.getNext()) {
|
for (Variant v= p.getFirstVariant(); v != null; v= v.getNext()) {
|
||||||
if (v.fRightOffset > operatorOffset) {
|
if (v.getTargetOperator() == null) {
|
||||||
if (best == null || v.fRightOffset < best.fRightOffset) {
|
if (best == null || v.fRightOffset < best.fRightOffset) {
|
||||||
best= v;
|
best= v;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
if (best != null) {
|
||||||
return best;
|
remove(best);
|
||||||
}
|
return best;
|
||||||
|
|
||||||
public void useFallback(Variant fallback) {
|
|
||||||
// Discard variants that end within the fallback
|
|
||||||
int begin= ((ASTNode) fallback.getExpression()).getOffset();
|
|
||||||
int end= fallback.getRightOffset();
|
|
||||||
for (BranchPoint p = fFirst; p != null; p= p.getNext()) {
|
|
||||||
for (Variant v= p.getFirstVariant(); v != null; v= v.getNext()) {
|
|
||||||
if (v == fallback) {
|
|
||||||
remove(v);
|
|
||||||
} else {
|
|
||||||
int vend= v.getRightOffset();
|
|
||||||
if (vend > begin && vend < end)
|
|
||||||
remove(v);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void remove(Variant remove) {
|
private void remove(Variant remove) {
|
||||||
final BranchPoint owner = remove.fOwner;
|
final BranchPoint owner = remove.fOwner;
|
||||||
final Variant next = remove.getNext();
|
final Variant next = remove.getNext();
|
||||||
|
@ -236,4 +207,41 @@ public class NameOrTemplateIDVariants {
|
||||||
fFirst= null;
|
fFirst= null;
|
||||||
return prev;
|
return prev;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean hasRightBound(int opOffset) {
|
||||||
|
// Search for an open variant, with a small right offset and a large left offset
|
||||||
|
for (BranchPoint p = fFirst; p != null; p= p.getNext()) {
|
||||||
|
for (Variant v= p.getFirstVariant(); v != null; v= v.getNext()) {
|
||||||
|
if (v.fRightOffset > opOffset)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeInvalid(BinaryOperator lastOperator) {
|
||||||
|
for (BranchPoint p = fFirst; p != null; p= p.getNext()) {
|
||||||
|
if (!isReachable(p, lastOperator)) {
|
||||||
|
remove(p);
|
||||||
|
} else {
|
||||||
|
for (Variant v= p.getFirstVariant(); v != null; v= v.getNext()) {
|
||||||
|
if (v.getTargetOperator() == null) {
|
||||||
|
remove(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isReachable(BranchPoint bp, BinaryOperator endOperator) {
|
||||||
|
BinaryOperator op = bp.getLeftOperator();
|
||||||
|
if (op == null)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
for(; endOperator != null; endOperator= endOperator.getNext()) {
|
||||||
|
if (endOperator == op)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue