/******************************************************************************* * Copyright (c) 2009, 2012 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: * Mike Kucera (IBM) - Initial API and implementation *******************************************************************************/ package org.eclipse.cdt.internal.core.dom.parser.cpp; import java.util.Arrays; import org.eclipse.cdt.core.dom.ast.ASTVisitor; import org.eclipse.cdt.core.dom.ast.ExpansionOverlapsBoundaryException; import org.eclipse.cdt.core.dom.ast.IASTImplicitName; import org.eclipse.cdt.core.dom.ast.IASTImplicitNameOwner; import org.eclipse.cdt.core.dom.ast.IASTNode; import org.eclipse.cdt.core.parser.IToken; import org.eclipse.cdt.core.parser.Keywords; import org.eclipse.cdt.internal.core.dom.parser.ASTNode; import org.eclipse.cdt.internal.core.dom.parser.ASTNodeSearch; /** * An implicit name is used to resolve uses of implicit bindings, such as overloaded operators. * * @see IASTImplicitName */ public class CPPASTImplicitName extends CPPASTName implements IASTImplicitName { private boolean alternate; private boolean isOperator; private boolean isDefinition; public CPPASTImplicitName(char[] name, IASTNode parent) { super(name); setParent(parent); setPropertyInParent(IASTImplicitNameOwner.IMPLICIT_NAME); } public CPPASTImplicitName(OverloadableOperator op, IASTNode parent) { this(op.toCharArray(), parent); isOperator = true; } @Override public CPPASTImplicitName copy() { throw new UnsupportedOperationException(); } @Override public CPPASTImplicitName copy(CopyStyle style) { throw new UnsupportedOperationException(); } @Override public boolean isAlternate() { return alternate; } public void setAlternate(boolean alternate) { this.alternate = alternate; } @Override public boolean accept(ASTVisitor action) { if ((!alternate && action.shouldVisitImplicitNames) || (alternate && action.shouldVisitImplicitNameAlternates)) { switch (action.visit(this)) { case ASTVisitor.PROCESS_ABORT: return false; case ASTVisitor.PROCESS_SKIP: return true; } switch (action.leave(this)) { case ASTVisitor.PROCESS_ABORT: return false; case ASTVisitor.PROCESS_SKIP: return true; } } return true; } @Override public boolean isDeclaration() { return false; } @Override public boolean isDefinition() { return isDefinition; } @Override public boolean isReference() { return !isDefinition; } public void setIsDefinition(boolean val) { isDefinition= val; } /** * Utility method for setting offsets using operator syntax. * * @param trailing true for trailing syntax, false for leading syntax */ public void computeOperatorOffsets(IASTNode relativeNode, boolean trailing) { if (relativeNode == null) return; IToken first; try { first = trailing ? relativeNode.getTrailingSyntax() : relativeNode.getLeadingSyntax(); int offset = ((ASTNode) relativeNode).getOffset() + first.getOffset(); if (trailing) offset += ((ASTNode) relativeNode).getLength(); OverloadableOperator oo = OverloadableOperator.valueOf(first); if ((first.getNext() == null && oo != null) || Arrays.equals(first.getCharImage(), Keywords.cDELETE) || Arrays.equals(first.getCharImage(), Keywords.cNEW)) { int length = first.getLength(); setOffsetAndLength(offset, length); } else { setOffsetAndLength(offset, 0); } } catch (ExpansionOverlapsBoundaryException e) { if (!computeOperatorOffsetsFallback(relativeNode, trailing)) { // Fall-back for the fall-back ASTNode parent = (ASTNode) getParent(); setOffsetAndLength(parent.getOffset() + parent.getLength(), 0); } } } // Fallback algorithm to use in computeOperatorOffsets() when the operator is // in a macro expansion. private boolean computeOperatorOffsetsFallback(IASTNode relativeNode, boolean trailing) { if (!(relativeNode instanceof ASTNode)) { return false; } ASTNode relative = (ASTNode) relativeNode; // Find the sequence numbers denoting the bounds of the leading or // trailing syntax, much as IASTNode.getLeadingSyntax() or // getTrailingSyntax() would. The code here follows the // implementation of those functions closely. ASTNodeSearch visitor = new ASTNodeSearch(relativeNode); IASTNode sibling = trailing ? visitor.findRightSibling() : visitor.findLeftSibling(); IASTNode parent = sibling == null ? relativeNode.getParent() : null; if (!((sibling == null || sibling instanceof ASTNode) && (parent == null || parent instanceof ASTNode))) { return false; } ASTNode sib = (ASTNode) sibling; ASTNode par = (ASTNode) parent; @SuppressWarnings("null") int start = trailing ? relative.getOffset() + relative.getLength() : sib != null ? sib.getOffset() + sib.getLength() : par.getOffset(); @SuppressWarnings("null") int end = trailing ? sib != null ? sib.getOffset() : par.getOffset() + par.getLength() : relative.getOffset(); // If there is only one token within the bounds, it must be the // operator token, and we have our answer. if (end == start + 1) { setOffsetAndLength(start, 1); return true; } // Otherwise, give up. return false; } public void setOperator(boolean isOperator) { this.isOperator = isOperator; } @Override public boolean isOperator() { return isOperator; } }