| /******************************************************************************* |
| * 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$ |
| } |
| } |