/******************************************************************************* * Copyright (c) 2011, 2015 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 * Sergey Prigogin (Google) *******************************************************************************/ 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.IASTImplicitDestructorName; 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.ICPPASTExpression; import org.eclipse.cdt.core.dom.ast.cpp.ICPPAliasTemplateInstance; 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, ICPPASTExpression { private final BinaryOperator fEndOperator; private final BranchPoint fVariants; private IASTNode[] fNodes; private final AbstractGNUSourceCodeParser fParser; public CPPASTTemplateIDAmbiguity(AbstractGNUSourceCodeParser parser, BinaryOperator endOperator, BranchPoint variants) { fParser= parser; fEndOperator= endOperator; fVariants= variants; } @Override protected final IASTNode doResolveAmbiguity(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= resolveNestedAmbiguities(expression, 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) { 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(fEndOperator.getNext(), fEndOperator.getExpression()); 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) { // It's sufficient to perform the first phase of binding resolution here, // because template names should never resolve to two-phase bindings. // The second phase of binding resolution, when performed for an incorrect // variant, can cause incorrect bindings to be cached in places where they // are hard to clear. IBinding b= templateName.resolvePreBinding(); if (b instanceof IProblemBinding) { if (!containsFunctionTemplate(((IProblemBinding) b).getCandidateBindings())) return -1; count++; } else if (b instanceof ICPPSpecialization || b instanceof ICPPTemplateDefinition || b instanceof ICPPAliasTemplateInstance || 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<>(); BinaryOperator op= fEndOperator; while (op != null) { nl.add(op.getExpression()); op= op.getNext(); } Collections.reverse(nl); fNodes= nl.toArray(new IASTNode[nl.size()]); } return fNodes; } @Override public IASTExpression copy() { throw new UnsupportedOperationException(); } @Override public IASTExpression copy(CopyStyle style) { throw new UnsupportedOperationException(); } @Override public void addExpression(IASTExpression e) { throw new UnsupportedOperationException(); } @Override public IASTExpression[] getExpressions() { throw new UnsupportedOperationException(); } @Override public IASTImplicitDestructorName[] getImplicitDestructorNames() { throw new UnsupportedOperationException(); } }