blob: 059b8cc16ddd8f1e2420fd44dddafbb52ce3b3af [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2004, 2014 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.CCorePlugin;
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;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPEvaluation;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPExecution;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.EvalFixed;
import org.eclipse.cdt.internal.core.parser.ParserException;
/**
* 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 = ArrayUtil.append(IASTName.class, names, name);
}
return PROCESS_CONTINUE;
}
public IASTName[] getNames() {
names = ArrayUtil.trimAt(IASTName.class, names, namesPos);
return names;
}
}
private IASTNode fResolution;
/**
* 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) {
return fResolution= doResolveAmbiguity(resolver);
}
protected IASTNode doResolveAmbiguity(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) {
// Setup the ast to use the alternative
owner.replace(nodeToReplace, alternative);
beforeAlternative(alternative);
// Handle nested ambiguities
alternative= resolveNestedAmbiguities(alternative, resolver);
nodeToReplace= alternative;
// 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;
}
protected IASTNode resolveNestedAmbiguities(IASTNode alternative, ASTVisitor resolver) {
alternative.accept(resolver);
if (alternative instanceof ASTAmbiguousNode)
return ((ASTAmbiguousNode) alternative).fResolution;
return alternative;
}
public final IType getExpressionType() {
logAmbiguousNodeError();
return ProblemType.UNKNOWN_FOR_EXPRESSION;
}
public final ValueCategory getValueCategory() {
logAmbiguousNodeError();
return ValueCategory.PRVALUE;
}
public final boolean isLValue() {
logAmbiguousNodeError();
return false;
}
public final ICPPEvaluation getEvaluation() {
logAmbiguousNodeError();
return EvalFixed.INCOMPLETE;
}
public final ICPPExecution getExecution() {
logAmbiguousNodeError();
return null;
}
private void logAmbiguousNodeError() {
CCorePlugin.log(new ParserException("Encountered an ambiguous node \"" + //$NON-NLS-1$
getRawSignature() + "\" at " + getFileLocation().getFileName() + //$NON-NLS-1$
", line " + getFileLocation().getStartingLineNumber() + //$NON-NLS-1$
" while parsing " + getTranslationUnit().getContainingFilename())); //$NON-NLS-1$
}
}