/******************************************************************************* * Copyright (c) 2004, 2010 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 - Initial API and implementation * Markus Schorn (Wind River Systems) *******************************************************************************/ package org.eclipse.cdt.internal.core.dom.parser; import org.eclipse.cdt.core.dom.ast.ASTVisitor; import org.eclipse.cdt.core.dom.ast.IASTDeclarator; import org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory; 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.IBinding; import org.eclipse.cdt.core.dom.ast.IProblemBinding; import org.eclipse.cdt.core.dom.ast.IType; import org.eclipse.cdt.core.parser.util.ArrayUtil; /** * Base implementation for all ambiguous nodes. */ public abstract class ASTAmbiguousNode extends ASTNode { public static class NameCollector extends ASTVisitor { private IASTName[] names = new IASTName[2]; private int namesPos = -1; public NameCollector() { shouldVisitNames = true; } @Override public int visit(IASTName name) { if (name != null) { namesPos++; names = (IASTName[]) ArrayUtil.append(IASTName.class, names, name); } return PROCESS_CONTINUE; } public IASTName[] getNames() { names = (IASTName[]) ArrayUtil.removeNullsAfter(IASTName.class, names, namesPos); return names; } } /** * Return the alternative nodes for this ambiguity. */ public abstract IASTNode[] getNodes(); @Override public final boolean accept(ASTVisitor visitor) { if (visitor.shouldVisitAmbiguousNodes && visitor.visit(this) == ASTVisitor.PROCESS_ABORT) return false; // alternatives are not visited on purpose. return true; } protected void beforeResolution() { } protected void beforeAlternative(IASTNode alternative) { } protected void afterResolution(ASTVisitor resolver, IASTNode best) { } public IASTNode resolveAmbiguity(ASTVisitor resolver) { beforeResolution(); final IASTAmbiguityParent owner= (IASTAmbiguityParent) getParent(); IASTNode nodeToReplace= this; final IASTNode[] alternatives= getNodes(); IASTNode bestAlternative= null; int minIssues = Integer.MAX_VALUE; for (IASTNode alternative : alternatives) { beforeAlternative(alternative); // setup the ast to use the alternative owner.replace(nodeToReplace, alternative); nodeToReplace= alternative; // handle nested ambiguities first, otherwise we cannot visit the alternative alternative.accept(resolver); // find nested names final NameCollector nameCollector= new NameCollector(); alternative.accept(nameCollector); final IASTName[] names= nameCollector.getNames(); // resolve names and count issues int issues= 0; for (IASTName name : names) { try { // avoid resolution of parameters (can always be resolved), // it can triggers resolution of declaration it belongs to, // while the declarator is still ambiguous. Could be solved by introducing an // intermediate binding for parameters, similar to template parameters. if (name.getPropertyInParent() == IASTDeclarator.DECLARATOR_NAME) { IASTNode parent= name.getParent(); if (parent instanceof IASTDeclarator) { parent= ASTQueries.findOutermostDeclarator((IASTDeclarator) parent); if (parent.getPropertyInParent() == IASTParameterDeclaration.DECLARATOR) continue; } } IBinding b= name.resolvePreBinding(); if (b instanceof IProblemBinding) { issues++; } } catch (Exception t) { issues++; } if (issues == minIssues) { break; } } if (issues < minIssues) { minIssues= issues; bestAlternative= alternative; if (issues == 0) { break; } } } // switch back to the best alternative, if necessary. if (nodeToReplace != bestAlternative) { owner.replace(nodeToReplace, bestAlternative); } afterResolution(resolver, bestAlternative); return bestAlternative; } public final IType getExpressionType() { throw new UnsupportedOperationException(); } public final ValueCategory getValueCategory() { throw new UnsupportedOperationException(); } public final boolean isLValue() { throw new UnsupportedOperationException(); } }