1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-04-29 19:45:01 +02:00

Bug 341747: Ambiguity between template-id and binary expression.

This commit is contained in:
Markus Schorn 2011-04-11 12:40:25 +00:00
parent ee055684b2
commit 9a2e97825b
12 changed files with 1156 additions and 336 deletions

View file

@ -24,6 +24,7 @@ import org.eclipse.cdt.core.dom.ast.ASTTypeUtil;
import org.eclipse.cdt.core.dom.ast.IASTBinaryExpression;
import org.eclipse.cdt.core.dom.ast.IASTCompoundStatement;
import org.eclipse.cdt.core.dom.ast.IASTExpressionStatement;
import org.eclipse.cdt.core.dom.ast.IASTFunctionCallExpression;
import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition;
import org.eclipse.cdt.core.dom.ast.IASTIdExpression;
import org.eclipse.cdt.core.dom.ast.IASTImplicitName;
@ -5314,4 +5315,74 @@ public class AST2TemplateTests extends AST2BaseTest {
public void testPartialSpecAfterExplicitInst_339475() throws Exception {
parseAndCheckBindings();
}
// template<bool> struct S {
// static int m();
// };
// template<int> void g(int);
// int f();
// int s;
//
// void test() {
// f < 0 > (1); // Function pointer
// g<0>(1); // Function call
// S<1 && 2>::m(); // m is member of S
// s<1 && 2>::f(); // f is global
// }
public void testTemplateIDAmbiguity_341747a() throws Exception {
IASTTranslationUnit tu= parseAndCheckBindings();
IASTFunctionDefinition fdef= getDeclaration(tu, 4);
IASTExpressionStatement stmt;
stmt= getStatement(fdef, 0);
assertTrue(stmt.getExpression() instanceof IASTBinaryExpression);
stmt= getStatement(fdef, 1);
assertTrue(stmt.getExpression() instanceof IASTFunctionCallExpression);
stmt= getStatement(fdef, 2);
assertTrue(stmt.getExpression() instanceof IASTFunctionCallExpression);
stmt= getStatement(fdef, 0);
assertTrue(stmt.getExpression() instanceof IASTBinaryExpression);
}
// const int a=0, b=1;
// template<int> struct A{};
//
// template<bool B= a<b> struct S {};
// struct X : S<a<b> {};
//
// template<typename B= A<b>> struct T {};
// struct Y : T<A<b>> {};
public void testTemplateIDAmbiguity_341747b() throws Exception {
parseAndCheckBindings();
}
// int a=0, b=1;
// bool bl= false;
// template<bool B> struct S {
// int a;
// };
// void test() {
// S< a<b >::a;
// a < S<bl>::a;
// }
public void testTemplateIDAmbiguity_341747c() throws Exception {
parseAndCheckBindings();
}
// struct S {
// int B;
// };
// template<typename T> struct B {};
// int c;
// void test() {
// S* a=0;
// a->B<c && c>::c;
// }
public void testTemplateIDAmbiguity_341747d() throws Exception {
parseAndCheckBindings();
}
}

View file

@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2004, 2010 IBM Corporation and others.
* Copyright (c) 2004, 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
@ -7102,12 +7102,12 @@ public class AST2Tests extends AST2BaseTest {
// void f() {
// int a=
public void testLargeExpression_294029() throws Exception {
// when running the test in a suite, it cannot handle more than 200 parenthesis.
// run as a single test it does > 600.
// when running the test in a suite, it cannot handle more than 160 parenthesis.
// run as a single test it does > 500.
sValidateCopy= false;
StringBuilder buf= new StringBuilder();
buf.append(getAboveComment());
final int depth= 200;
final int depth= 160;
for (int i = 0; i < depth; i++) {
buf.append('(');
}

View file

@ -89,6 +89,9 @@ import org.eclipse.cdt.internal.core.parser.scanner.ILocationResolver;
* Base class for the c- and c++ parser.
*/
public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
public interface ITemplateIdStrategy {
}
protected static class FoundAggregateInitializer extends Exception {
public final IASTDeclarator fDeclarator;
public final IASTDeclSpecifier fDeclSpec;
@ -154,7 +157,7 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
* Information about the context in which a cast-expression is parsed:
* in a binary expression, in a binary expression in a template-id, or elsewhere.
*/
protected static enum CastExprCtx {eBExpr, eBExprInTmplID, eNotBExpr}
protected static enum CastExprCtx {eDirectlyInBExpr, eInBExpr, eNotInBExpr}
protected static enum ExprKind {eExpression, eAssignment, eConstant}
protected static final int DEFAULT_DESIGNATOR_LIST_SIZE = 4;
@ -921,7 +924,7 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
* Models a cast expression followed by an operator. Can be linked into a chain.
* This is done right to left, such that a tree of variants can be built.
*/
protected static class BinaryOperator {
public static class BinaryOperator {
final int fOperatorToken;
final int fLeftPrecedence;
final int fRightPrecedence;
@ -949,9 +952,21 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
fExpression= expr;
return e;
}
public IASTInitializerClause getExpression() {
return fExpression;
}
public BinaryOperator getNext() {
return fNext;
}
public void setNext(BinaryOperator next) {
fNext = next;
}
}
protected final IASTExpression buildExpression(BinaryOperator leftChain, IASTInitializerClause expr) throws BacktrackException {
public final IASTExpression buildExpression(BinaryOperator leftChain, IASTInitializerClause expr) {
BinaryOperator rightChain= null;
for (;;) {
if (leftChain == null) {
@ -973,18 +988,13 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
}
}
private IASTExpression buildExpression(IASTExpression left, BinaryOperator operator) throws BacktrackException {
private IASTExpression buildExpression(IASTExpression left, BinaryOperator operator) {
int op, unaryOp= 0;
final IASTInitializerClause right= operator.fExpression;
switch(operator.fOperatorToken) {
case IToken.tQUESTION:
final IASTInitializerClause negative;
if (operator.fNext == null || operator.fNext.fOperatorToken != IToken.tCOLON) {
if (LTcatchEOF(1) != IToken.tEOC || operator.fNext != null) {
assert false;
ASTNode node= (ASTNode) left;
throwBacktrack(node.getOffset(), node.getLength());
}
negative= null;
} else {
negative= operator.fNext.fExpression;
@ -1116,25 +1126,26 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
default:
assert false;
ASTNode node= (ASTNode) left;
throwBacktrack(node.getOffset(), node.getLength());
return null;
}
IASTExpression result= buildBinaryExpression(op, left, right, calculateEndOffset(right));
final CastAmbiguityMarker am = operator.fAmbiguityMarker;
if (am != null) {
assert unaryOp != 0;
result = createCastVsBinaryExpressionAmbiguity((IASTBinaryExpression) result,
am.getTypeIdForCast(), unaryOp, am.getUnaryOperatorOffset());
if (unaryOp != 0) {
result = createCastVsBinaryExpressionAmbiguity((IASTBinaryExpression) result,
am.getTypeIdForCast(), unaryOp, am.getUnaryOperatorOffset());
} else {
assert false;
}
}
return result;
}
protected abstract IASTExpression expression() throws BacktrackException, EndOfFileException;
protected abstract IASTExpression constantExpression() throws BacktrackException, EndOfFileException;
protected abstract IASTExpression unaryExpression(CastExprCtx ctx) throws BacktrackException, EndOfFileException;
protected abstract IASTExpression primaryExpression(CastExprCtx ctx) throws BacktrackException, EndOfFileException;
protected abstract IASTExpression unaryExpression(CastExprCtx ctx, ITemplateIdStrategy strat) throws BacktrackException, EndOfFileException;
protected abstract IASTExpression primaryExpression(CastExprCtx ctx, ITemplateIdStrategy strat) throws BacktrackException, EndOfFileException;
protected abstract IASTTypeId typeId(DeclarationOptions option) throws EndOfFileException, BacktrackException;
private final static class CastAmbiguityMarker extends ASTNode implements IASTExpression {
@ -1186,7 +1197,7 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
}
}
protected final IASTExpression castExpression(CastExprCtx ctx) throws EndOfFileException, BacktrackException {
protected final IASTExpression castExpression(CastExprCtx ctx, ITemplateIdStrategy strat) throws EndOfFileException, BacktrackException {
if (LT(1) == IToken.tLPAREN) {
final IToken mark= mark();
final int startingOffset= mark.getOffset();
@ -1199,7 +1210,7 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
if (typeId != null && LT(1) == IToken.tRPAREN) {
consume();
boolean unaryFailed= false;
if (ctx != CastExprCtx.eNotBExpr) {
if (ctx == CastExprCtx.eDirectlyInBExpr) {
switch (LT(1)){
// ambiguity with unary operator
case IToken.tPLUS: case IToken.tMINUS:
@ -1208,7 +1219,7 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
IToken markEnd= mark();
backup(mark);
try {
IASTExpression unary= unaryExpression(CastExprCtx.eNotBExpr);
IASTExpression unary= unaryExpression(CastExprCtx.eInBExpr, strat);
return new CastAmbiguityMarker(unary, typeId, operatorOffset);
} catch (BacktrackException bt) {
backup(markEnd);
@ -1218,7 +1229,7 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
}
try {
boolean couldBeFunctionCall= LT(1) == IToken.tLPAREN;
IASTExpression rhs= castExpression(ctx);
IASTExpression rhs= castExpression(ctx, strat);
CastAmbiguityMarker ca= null;
if (rhs instanceof CastAmbiguityMarker) {
@ -1226,12 +1237,13 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
rhs= ca.getExpression();
assert !(rhs instanceof CastAmbiguityMarker);
}
IASTCastExpression result= buildCastExpression(IASTCastExpression.op_cast, typeId, rhs, startingOffset, calculateEndOffset(rhs));
IASTCastExpression result = buildCastExpression(IASTCastExpression.op_cast,
typeId, rhs, startingOffset, calculateEndOffset(rhs));
if (!unaryFailed && couldBeFunctionCall && rhs instanceof IASTCastExpression == false) {
IToken markEnd= mark();
backup(mark);
try {
IASTExpression expr= primaryExpression(ctx);
IASTExpression expr= primaryExpression(ctx, strat);
IASTFunctionCallExpression fcall = nodeFactory.newFunctionCallExpression(expr, (IASTExpression[]) null);
IASTAmbiguousExpression ambiguity = createAmbiguousCastVsFunctionCallExpression(result, fcall);
((ASTNode) ambiguity).setOffsetAndLength((ASTNode) result);
@ -1249,7 +1261,7 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
}
backup(mark);
}
return unaryExpression(ctx);
return unaryExpression(ctx, strat);
}
protected abstract IASTTranslationUnit getTranslationUnit();
@ -1363,7 +1375,8 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
abstract protected IASTExpression buildBinaryExpression(int operator, IASTExpression expr1, IASTInitializerClause expr2, int lastOffset);
private IASTExpression createCastVsBinaryExpressionAmbiguity(IASTBinaryExpression expr, final IASTTypeId typeid, int unaryOperator, int unaryOpOffset) {
private IASTExpression createCastVsBinaryExpressionAmbiguity(IASTBinaryExpression expr,
final IASTTypeId typeid, int unaryOperator, int unaryOpOffset) {
IASTUnaryExpression unary= nodeFactory.newUnaryExpression(unaryOperator, null);
((ASTNode) unary).setOffset(unaryOpOffset);
IASTCastExpression castExpr = buildCastExpression(IASTCastExpression.op_cast, typeid, unary, 0, 0);
@ -1372,9 +1385,9 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
return result;
}
protected IASTExpression unaryExpression(int operator, CastExprCtx ctx) throws EndOfFileException, BacktrackException {
protected IASTExpression unaryExpression(int operator, CastExprCtx ctx, ITemplateIdStrategy strat) throws EndOfFileException, BacktrackException {
final IToken operatorToken= consume();
IASTExpression operand= castExpression(ctx);
IASTExpression operand= castExpression(ctx, strat);
CastAmbiguityMarker ca= null;
if (operand instanceof CastAmbiguityMarker) {
@ -1814,13 +1827,12 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
return result;
}
protected IASTCastExpression buildCastExpression(int op, IASTTypeId typeId, IASTExpression operand, int offset, int endOffset) {
protected IASTCastExpression buildCastExpression(int op, IASTTypeId typeId,
IASTExpression operand, int offset, int endOffset) {
IASTCastExpression result = nodeFactory.newCastExpression(op, typeId, operand);
((ASTNode) result).setOffsetAndLength(offset, endOffset - offset);
return result;
}
/**
* There are many ambiguities in C and C++ between expressions and declarations.
@ -2173,7 +2185,7 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
}
protected IASTExpression parseTypeidInParenthesisOrUnaryExpression(boolean exprIsLimitedToParenthesis,
int offset, int typeExprKind, int unaryExprKind, CastExprCtx ctx) throws BacktrackException, EndOfFileException {
int offset, int typeExprKind, int unaryExprKind, CastExprCtx ctx, ITemplateIdStrategy strat) throws BacktrackException, EndOfFileException {
IASTTypeId typeid;
IASTExpression expr= null;
IToken typeidLA= null;
@ -2234,7 +2246,7 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
expr= expression();
endOffset2= consumeOrEOC(IToken.tRPAREN).getEndOffset();
} else {
expr= unaryExpression(ctx);
expr= unaryExpression(ctx, strat);
if (expr instanceof CastAmbiguityMarker) {
ca= (CastAmbiguityMarker) expr;
expr= ca.getExpression();

View file

@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2005, 2010 IBM Corporation and others.
* Copyright (c) 2005, 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
@ -467,7 +467,7 @@ public class GNUCSourceParser extends AbstractGNUSourceCodeParser {
int lt1;
int conditionCount= 0;
BinaryOperator lastOperator= null;
IASTExpression lastExpression= castExpression(CastExprCtx.eBExpr);
IASTExpression lastExpression= castExpression(CastExprCtx.eDirectlyInBExpr, null);
loop: while (true) {
lt1= LT(1);
switch(lt1) {
@ -564,7 +564,7 @@ public class GNUCSourceParser extends AbstractGNUSourceCodeParser {
}
consume(); // consume operator
lastExpression= castExpression(CastExprCtx.eBExpr); // next cast expression
lastExpression= castExpression(CastExprCtx.eDirectlyInBExpr, null); // next cast expression
}
// Check for incomplete conditional expression
@ -581,38 +581,38 @@ public class GNUCSourceParser extends AbstractGNUSourceCodeParser {
((ASTNode) result).setOffsetAndLength(o, lastOffset - o);
return result;
}
@Override
protected IASTExpression unaryExpression(CastExprCtx ctx) throws EndOfFileException, BacktrackException {
protected IASTExpression unaryExpression(CastExprCtx ctx, ITemplateIdStrategy strat) throws EndOfFileException, BacktrackException {
switch (LT(1)) {
case IToken.tSTAR:
return unaryExpression(IASTUnaryExpression.op_star, ctx);
return unaryExpression(IASTUnaryExpression.op_star, ctx, strat);
case IToken.tAMPER:
return unaryExpression(IASTUnaryExpression.op_amper, ctx);
return unaryExpression(IASTUnaryExpression.op_amper, ctx, strat);
case IToken.tPLUS:
return unaryExpression(IASTUnaryExpression.op_plus, ctx);
return unaryExpression(IASTUnaryExpression.op_plus, ctx, strat);
case IToken.tMINUS:
return unaryExpression(IASTUnaryExpression.op_minus, ctx);
return unaryExpression(IASTUnaryExpression.op_minus, ctx, strat);
case IToken.tNOT:
return unaryExpression(IASTUnaryExpression.op_not, ctx);
return unaryExpression(IASTUnaryExpression.op_not, ctx, strat);
case IToken.tBITCOMPLEMENT:
return unaryExpression(IASTUnaryExpression.op_tilde, ctx);
return unaryExpression(IASTUnaryExpression.op_tilde, ctx, strat);
case IToken.tINCR:
return unaryExpression(IASTUnaryExpression.op_prefixIncr, ctx);
return unaryExpression(IASTUnaryExpression.op_prefixIncr, ctx, strat);
case IToken.tDECR:
return unaryExpression(IASTUnaryExpression.op_prefixDecr, ctx);
return unaryExpression(IASTUnaryExpression.op_prefixDecr, ctx, strat);
case IToken.t_sizeof:
return parseTypeidInParenthesisOrUnaryExpression(false, consume().getOffset(),
IASTTypeIdExpression.op_sizeof, IASTUnaryExpression.op_sizeof, ctx);
IASTTypeIdExpression.op_sizeof, IASTUnaryExpression.op_sizeof, ctx, strat);
case IGCCToken.t___alignof__:
return parseTypeidInParenthesisOrUnaryExpression(false, consume().getOffset(),
IASTTypeIdExpression.op_alignof, IASTUnaryExpression.op_alignOf, ctx);
IASTTypeIdExpression.op_alignof, IASTUnaryExpression.op_alignOf, ctx, strat);
default:
return postfixExpression(ctx);
return postfixExpression(ctx, strat);
}
}
protected IASTExpression postfixExpression(CastExprCtx ctx) throws EndOfFileException, BacktrackException {
private IASTExpression postfixExpression(CastExprCtx ctx, ITemplateIdStrategy strat) throws EndOfFileException, BacktrackException {
IASTExpression firstExpression = null;
switch (LT(1)) {
case IToken.tLPAREN:
@ -632,11 +632,11 @@ public class GNUCSourceParser extends AbstractGNUSourceCodeParser {
} catch (BacktrackException bt) {
}
backup(m);
firstExpression= primaryExpression(ctx);
firstExpression= primaryExpression(ctx, strat);
break;
default:
firstExpression = primaryExpression(ctx);
firstExpression = primaryExpression(ctx, strat);
break;
}
@ -748,7 +748,7 @@ public class GNUCSourceParser extends AbstractGNUSourceCodeParser {
}
@Override
protected IASTExpression primaryExpression(CastExprCtx ctx) throws EndOfFileException, BacktrackException {
protected IASTExpression primaryExpression(CastExprCtx ctx, ITemplateIdStrategy strat) throws EndOfFileException, BacktrackException {
IToken t = null;
IASTLiteralExpression literalExpression = null;
switch (LT(1)) {
@ -1114,7 +1114,7 @@ public class GNUCSourceParser extends AbstractGNUSourceCodeParser {
simpleType= IASTSimpleDeclSpecifier.t_typeof;
consume(IGCCToken.t_typeof);
typeofExpression = parseTypeidInParenthesisOrUnaryExpression(false, LA(1).getOffset(),
IASTTypeIdExpression.op_typeof, -1, CastExprCtx.eNotBExpr);
IASTTypeIdExpression.op_typeof, -1, CastExprCtx.eNotInBExpr, null);
encounteredTypename= true;
endOffset= calculateEndOffset(typeofExpression);

View file

@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2009, 2010 Wind River Systems, Inc. and others.
* Copyright (c) 2009, 2011 Wind River Systems, 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
@ -14,6 +14,7 @@ import java.util.HashSet;
import java.util.LinkedList;
import org.eclipse.cdt.core.dom.ast.ASTVisitor;
import org.eclipse.cdt.core.dom.ast.IASTCompositeTypeSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTDeclarationStatement;
@ -21,11 +22,14 @@ import org.eclipse.cdt.core.dom.ast.IASTDeclarator;
import org.eclipse.cdt.core.dom.ast.IASTExpression;
import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition;
import org.eclipse.cdt.core.dom.ast.IASTInitializer;
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.IASTSimpleDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
import org.eclipse.cdt.core.dom.ast.IScope;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateId;
import org.eclipse.cdt.internal.core.dom.parser.ASTAmbiguousNode;
import org.eclipse.cdt.internal.core.dom.parser.ASTQueries;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPSemantics;
@ -115,6 +119,18 @@ final class CPPASTAmbiguityResolver extends ASTVisitor {
if (fRepopulate.remove(declaration)) {
repopulateScope(declaration);
}
// Explicit and partial class template specializations need to be resolved right away,
// otherwise we fail to correctly resolve qualified names that depend on a partial specialization.
if (declaration instanceof IASTSimpleDeclaration) {
IASTSimpleDeclaration sdecl= (IASTSimpleDeclaration) declaration;
IASTDeclSpecifier declspec = sdecl.getDeclSpecifier();
if (declspec instanceof IASTCompositeTypeSpecifier && sdecl.getDeclarators().length == 0) {
IASTName name= ((IASTCompositeTypeSpecifier) declspec).getName().getLastName();
if (name instanceof ICPPASTTemplateId) {
name.resolveBinding();
}
}
}
return PROCESS_CONTINUE;
}

View file

@ -0,0 +1,181 @@
/*******************************************************************************
* Copyright (c) 2011 Wind River Systems, 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:
* Markus Schorn - initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser.cpp;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.eclipse.cdt.core.dom.ast.ASTVisitor;
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.IASTNode;
import org.eclipse.cdt.core.dom.ast.IBinding;
import org.eclipse.cdt.core.dom.ast.IFunction;
import org.eclipse.cdt.core.dom.ast.IProblemBinding;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPConstructor;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunction;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunctionTemplate;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPSpecialization;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateDefinition;
import org.eclipse.cdt.internal.core.dom.parser.ASTAmbiguousNode;
import org.eclipse.cdt.internal.core.dom.parser.ASTNode;
import org.eclipse.cdt.internal.core.dom.parser.AbstractGNUSourceCodeParser;
import org.eclipse.cdt.internal.core.dom.parser.AbstractGNUSourceCodeParser.BinaryOperator;
import org.eclipse.cdt.internal.core.dom.parser.IASTAmbiguityParent;
import org.eclipse.cdt.internal.core.dom.parser.IASTAmbiguousExpression;
import org.eclipse.cdt.internal.core.dom.parser.cpp.NameOrTemplateIDVariants.BranchPoint;
import org.eclipse.cdt.internal.core.dom.parser.cpp.NameOrTemplateIDVariants.Variant;
/**
* Models expression variants for the ambiguity of a template id.
*/
public class CPPASTTemplateIDAmbiguity extends ASTAmbiguousNode implements IASTAmbiguousExpression {
private BinaryOperator fLastOperator;
private IASTInitializerClause fLastExpression;
private final BranchPoint fVariants;
private IASTNode[] fNodes;
private AbstractGNUSourceCodeParser fParser;
public CPPASTTemplateIDAmbiguity(AbstractGNUSourceCodeParser parser, BinaryOperator lastOperator, IASTInitializerClause expr,
BranchPoint variants) {
fParser= parser;
fLastOperator= lastOperator;
fLastExpression= expr;
fVariants= variants;
}
@Override
public IASTNode resolveAmbiguity(ASTVisitor resolver) {
final IASTAmbiguityParent owner= (IASTAmbiguityParent) getParent();
IASTNode nodeToReplace= this;
// Try all variants and under the ones with correct template-ids select the one with
// the most template-ids.
int minOffset= -1;
for (BranchPoint v= fVariants; v != null; v= v.getNext()) {
Variant selected= null;
int bestCount= 0;
for (Variant q= v.getFirstVariant(); q != null ; q=q.getNext()) {
final IASTName[] templateNames = q.getTemplateNames();
if (templateNames.length > bestCount) {
// Don't check branch-points inside of a selected variant.
final IASTExpression expression = q.getExpression();
if (((ASTNode) expression).getOffset() < minOffset)
break;
// Setup the ast to use the alternative
owner.replace(nodeToReplace, expression);
nodeToReplace= expression;
// Handle nested ambiguities first
expression.accept(resolver);
int count= checkNames(templateNames);
if (count > bestCount) {
selected= q;
bestCount= count;
}
}
}
// Adjust the operator sequence
if (selected != null) {
minOffset= selected.getRightOffset();
BinaryOperator targetOp = selected.getTargetOperator();
if (targetOp == null) {
fLastExpression= selected.getExpression();
fLastOperator= v.getLeftOperator();
} else {
targetOp.exchange(selected.getExpression());
targetOp.setNext(v.getLeftOperator());
}
}
}
// Important: Before building the expression remove it from the owner
owner.replace(nodeToReplace, this);
// Create the expression and replace it
IASTExpression expr = fParser.buildExpression(fLastOperator, fLastExpression);
owner.replace(this, expr);
// Resolve further ambiguities within the new expression.
expr.accept(resolver);
return expr;
}
private int checkNames(final IASTName[] templateNames) {
int count= 0;
for (IASTName templateName : templateNames) {
if (templateName.getTranslationUnit() != null) {
IBinding b= templateName.resolveBinding();
if (b instanceof IProblemBinding) {
if (!containsFunctionTemplate(((IProblemBinding) b).getCandidateBindings()))
return -1;
count++;
} else if (b instanceof ICPPSpecialization || b instanceof ICPPTemplateDefinition
|| b instanceof ICPPConstructor
|| (b instanceof IFunction && b instanceof ICPPUnknownBinding)) {
count++;
} else {
return -1;
}
}
}
return count;
}
private boolean containsFunctionTemplate(IBinding[] candidateBindings) {
for (IBinding cand : candidateBindings) {
if (cand instanceof ICPPFunctionTemplate ||
(cand instanceof ICPPFunction && cand instanceof ICPPSpecialization)) {
return true;
}
}
return false;
}
@Override
public IASTNode[] getNodes() {
if (fNodes == null) {
List<IASTNode> nl= new ArrayList<IASTNode>();
nl.add(fLastExpression);
BinaryOperator op= fLastOperator;
while (op != null) {
nl.add(op.getExpression());
op= op.getNext();
}
Collections.reverse(nl);
fNodes= nl.toArray(new IASTNode[nl.size()]);
}
return fNodes;
}
public IASTExpression copy() {
throw new UnsupportedOperationException();
}
public IASTExpression copy(CopyStyle style) {
throw new UnsupportedOperationException();
}
public void addExpression(IASTExpression e) {
throw new UnsupportedOperationException();
}
public IASTExpression[] getExpressions() {
throw new UnsupportedOperationException();
}
}

View file

@ -0,0 +1,239 @@
/*******************************************************************************
* Copyright (c) 2011 Wind River Systems, 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:
* Markus Schorn - initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser.cpp;
import org.eclipse.cdt.core.dom.ast.IASTExpression;
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;
/**
* Tracks variants of expressions due to the ambiguity between template-id and '<' operator.
*/
public class NameOrTemplateIDVariants {
/**
* A point where a '<' can be interpreted as less-than or as the angle-bracket of a template-id.
*/
static class BranchPoint {
private BranchPoint fNext;
private Variant fFirstVariant;
private final boolean fAllowAssignment;
private final int fConditionCount;
private final BinaryOperator fLeftOperator;
BranchPoint(BranchPoint next, Variant variant,
BinaryOperator left, boolean allowAssignment, int conditionCount) {
fNext= next;
fFirstVariant= variant;
fAllowAssignment= allowAssignment;
fConditionCount= conditionCount;
fLeftOperator= left;
// Set owner
while (variant != null) {
variant.fOwner= this;
variant= variant.getNext();
}
}
public boolean isAllowAssignment() {
return fAllowAssignment;
}
public int getConditionCount() {
return fConditionCount;
}
public BinaryOperator getLeftOperator() {
return fLeftOperator;
}
public Variant getFirstVariant() {
return fFirstVariant;
}
public BranchPoint getNext() {
return fNext;
}
public void reverseVariants() {
Variant prev= null;
Variant curr= fFirstVariant;
while (curr != null) {
Variant next= curr.getNext();
curr.fNext= prev;
prev= curr;
curr= next;
}
fFirstVariant= prev;
}
}
/**
* A variant for a branch-point is a cast-expression that can be used within a binary expression.
*/
static class Variant {
private BranchPoint fOwner;
private Variant fNext;
private final IASTExpression fExpression;
private BinaryOperator fTargetOperator;
private final int fRightOffset;
private final IASTName[] fTemplateNames;
public Variant(Variant next, IASTExpression expr, IASTName[] templateNames, int rightOffset) {
fNext= next;
fExpression= expr;
fRightOffset= rightOffset;
fTemplateNames= templateNames;
}
public BranchPoint getOwner() {
return fOwner;
}
public int getRightOffset() {
return fRightOffset;
}
public IASTName[] getTemplateNames() {
return fTemplateNames;
}
public Variant getNext() {
return fNext;
}
public IASTExpression getExpression() {
return fExpression;
}
public BinaryOperator getTargetOperator() {
return fTargetOperator;
}
public void setTargetOperator(BinaryOperator lastOperator) {
fTargetOperator= lastOperator;
}
}
private BranchPoint fFirst;
public boolean isEmpty() {
return fFirst == null;
}
public void addBranchPoint(Variant variants, BinaryOperator left,
boolean allowAssignment, int conditionCount) {
fFirst= new BranchPoint(fFirst, variants, left, allowAssignment, conditionCount);
}
public void closeVariants(int offset, BinaryOperator lastOperator) {
for (BranchPoint p = fFirst; p != null; p= p.getNext()) {
for (Variant v= p.getFirstVariant(); v != null; v= v.getNext()) {
if (v.getTargetOperator() == null) {
if (offset == v.getRightOffset()) {
v.setTargetOperator(lastOperator);
} else if (offset > v.getRightOffset()) {
// Should not happen
assert false;
remove(v);
}
}
}
}
}
public void discardOpenVariants(int operatorOffset) {
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
Variant best= null;
for (BranchPoint p = fFirst; p != null; p= p.getNext()) {
for (Variant v= p.getFirstVariant(); v != null; v= v.getNext()) {
if (v.fRightOffset > operatorOffset) {
if (best == null || v.fRightOffset < best.fRightOffset) {
best= v;
}
}
}
}
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);
}
}
}
}
private void remove(Variant remove) {
final BranchPoint owner = remove.fOwner;
final Variant next = remove.getNext();
Variant prev= owner.getFirstVariant();
if (remove == prev) {
owner.fFirstVariant= next;
if (next == null) {
remove(owner);
}
} else {
while (prev != null) {
Variant n = prev.getNext();
if (n == remove) {
prev.fNext= next;
break;
}
prev= n;
}
}
}
private void remove(BranchPoint remove) {
final BranchPoint next = remove.getNext();
if (remove == fFirst) {
fFirst= next;
} else {
BranchPoint prev= fFirst;
while (prev != null) {
BranchPoint n = prev.getNext();
if (n == remove) {
prev.fNext= next;
break;
}
prev= n;
}
}
}
public BranchPoint getOrderedBranchPoints() {
BranchPoint prev= null;
BranchPoint curr= fFirst;
while (curr != null) {
curr.reverseVariants();
BranchPoint next= curr.getNext();
curr.fNext= prev;
prev= curr;
curr= next;
}
fFirst= null;
return prev;
}
}

View file

@ -0,0 +1,81 @@
/*******************************************************************************
* Copyright (c) 2011 Wind River Systems, 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:
* Markus Schorn - initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser.cpp;
import java.util.BitSet;
import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.parser.util.ArrayUtil;
import org.eclipse.cdt.internal.core.dom.parser.AbstractGNUSourceCodeParser.ITemplateIdStrategy;
/**
* Governs backtracking through multiple variants due to the ambiguous meaning of '<'.
* @see NameOrTemplateIDVariants
*/
final class TemplateIdStrategy implements ITemplateIdStrategy {
private int fCurrentBranchPoint;
private BitSet fSimpleIDs;
private IASTName[] fTemplateNames;
public TemplateIdStrategy() {
reset();
}
public void reset() {
fCurrentBranchPoint= -1;
fTemplateNames= IASTName.EMPTY_NAME_ARRAY;
if (fSimpleIDs != null) {
fSimpleIDs.clear();
}
}
public boolean ignoreTemplateID() {
fCurrentBranchPoint++;
return fSimpleIDs == null ? false : fSimpleIDs.get(fCurrentBranchPoint);
}
public void addTemplateName(IASTName name) {
fTemplateNames= ArrayUtil.append(fTemplateNames, name);
}
public boolean setNextAlternative() {
final int bp = fCurrentBranchPoint;
if (bp < 0)
return false;
fCurrentBranchPoint= -1;
fTemplateNames= IASTName.EMPTY_NAME_ARRAY;
if (fSimpleIDs == null) {
fSimpleIDs= new BitSet();
}
// Set a new branch as far right as possible.
final int len = fSimpleIDs.length();
if (len <= bp) {
fSimpleIDs.set(bp);
return true;
}
for (int branch= Math.min(bp, len-2); branch>=0; branch--) {
if (!fSimpleIDs.get(branch)) {
fSimpleIDs.clear(branch+1, len);
fSimpleIDs.set(branch);
return true;
}
}
return false;
}
public IASTName[] getTemplateNames() {
return ArrayUtil.trim(fTemplateNames);
}
}

View file

@ -1069,8 +1069,11 @@ public class CPPVisitor extends ASTQueries {
if (qname.isFullyQualified()) {
return parent.getTranslationUnit().getScope();
}
}
if (i > 0) {
if (qname.getParent() instanceof ICPPASTFieldReference) {
name= qname;
parent= name.getParent();
}
} else if (i > 0) {
if (data != null) {
data.usesEnclosingScope= false;
}
@ -1111,7 +1114,9 @@ public class CPPVisitor extends ASTQueries {
return scope;
}
}
} else if (parent instanceof ICPPASTFieldReference) {
}
if (parent instanceof ICPPASTFieldReference) {
if (data != null) {
data.usesEnclosingScope= false;
}

View file

@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2004, 2010 IBM Corporation and others.
* Copyright (c) 2004, 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
@ -251,15 +251,27 @@ public class LookupData {
}
public boolean qualified() {
if (forceQualified) return true;
if (astName == null) return false;
if (astName.getPropertyInParent() == CPPSemantics.STRING_LOOKUP_PROPERTY) return false;
IASTNode p1 = astName.getParent();
if (p1 instanceof ICPPASTQualifiedName) {
final IASTName[] qnames = ((ICPPASTQualifiedName) p1).getNames();
return qnames.length == 1 || qnames[0] != astName;
if (forceQualified)
return true;
IASTName n= astName;
if (n == null || n.getPropertyInParent() == CPPSemantics.STRING_LOOKUP_PROPERTY)
return false;
IASTNode p = n.getParent();
if (p instanceof ICPPASTTemplateId) {
n= (IASTName) p;
p= p.getParent();
}
return p1 instanceof ICPPASTFieldReference;
if (p instanceof ICPPASTQualifiedName) {
final ICPPASTQualifiedName qname = (ICPPASTQualifiedName) p;
if (qname.isFullyQualified())
return true;
final IASTName[] qnames = qname.getNames();
if (qnames.length > 0 && qnames[0] != n)
return true;
}
return p instanceof ICPPASTFieldReference;
}
public boolean isFunctionCall() {

View file

@ -100,7 +100,7 @@ public class AddIncludeTest extends TestCase {
String file= createFileName(".expected");
String expected= ResourceTestHelper.read(file).toString();
assertEquals(expected, fDocument.get());
assertEquals(expected.replace("\r\n", "\n"), fDocument.get().replace("\r\n", "\n"));
}
private String createFileName(String suffix) {