blob: 374750e3bb7cad958bf41208c6e78dca16801957 [file] [log] [blame]
/*******************************************************************************
* 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;
}
}