blob: 58c00693685096e79ddfe0d6dd4cc9cdfabbee2a [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2007, 2008 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:
* UIUC - Photran modifications
* Markus Schorn - initial API and implementation
*******************************************************************************/
package org.eclipse.photran.internal.core.preprocessor.c;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import org.eclipse.cdt.core.dom.ast.IASTFileLocation;
import org.eclipse.cdt.core.dom.ast.IASTNodeLocation;
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit.IDependencyTree.IASTInclusionNode;
/**
* Base class for all location contexts that can contain children.
* <p>
* @since 5.0
*/
class LocationCtxContainer extends LocationCtx {
/**
* The total length of all children in terms of sequence numbers.
*/
private int fChildSequenceLength;
private ArrayList<LocationCtx> fChildren;
private char[] fSource;
private int[] fLineOffsets;
public LocationCtxContainer(LocationCtxContainer parent, char[] source, int parentOffset, int parentEndOffset, int sequenceNumber) {
super(parent, parentOffset, parentEndOffset, sequenceNumber);
fSource= source;
}
@Override
public Collection<LocationCtx> getChildren() {
if (fChildren == null) {
return Collections.emptyList();
}
return fChildren;
}
public void addChild(LocationCtx locationCtx) {
if (fChildren == null) {
fChildren= new ArrayList<LocationCtx>();
}
fChildren.add(locationCtx);
}
public char[] getSource(int offset, int length) {
offset= Math.max(0, Math.min(offset, fSource.length));
length= Math.max(0, Math.min(length, fSource.length-offset));
char[] result= new char[length];
System.arraycopy(fSource, offset, result, 0, length);
return result;
}
@Override
public final int getSequenceLength() {
return fSource.length + fChildSequenceLength;
}
@Override
public final int getSequenceNumberForOffset(int offset, boolean checkChildren) {
int result= fSequenceNumber + fChildSequenceLength + offset;
if (checkChildren && fChildren != null) {
for (int i= fChildren.size()-1; i >= 0; i--) {
final LocationCtx child= fChildren.get(i);
if (child.fEndOffsetInParent > offset) { // child was inserted behind the offset, adjust sequence number
result-= child.getSequenceLength();
}
else {
return result;
}
}
}
return result;
}
@Override
public void addChildSequenceLength(int childLength) {
fChildSequenceLength+= childLength;
}
@Override
public final LocationCtx findSurroundingContext(int sequenceNumber, int length) {
int testEnd= length > 1 ? sequenceNumber+length-1 : sequenceNumber;
final LocationCtx child= findChildLessOrEqualThan(sequenceNumber, false);
if (child != null && child.fSequenceNumber+child.getSequenceLength() > testEnd) {
return child.findSurroundingContext(sequenceNumber, length);
}
return this;
}
@Override
public final LocationCtxMacroExpansion findEnclosingMacroExpansion(int sequenceNumber, int length) {
int testEnd= length > 1 ? sequenceNumber+length-1 : sequenceNumber;
final LocationCtx child= findChildLessOrEqualThan(sequenceNumber, true);
if (child != null && child.fSequenceNumber+child.getSequenceLength() > testEnd) {
return child.findEnclosingMacroExpansion(sequenceNumber, length);
}
return null;
}
@Override
public ASTFileLocation findMappedFileLocation(int sequenceNumber, int length) {
// try to delegate to a child.
int testEnd= length > 1 ? sequenceNumber+length-1 : sequenceNumber;
final LocationCtx child= findChildLessOrEqualThan(sequenceNumber, false);
if (child != null && child.fSequenceNumber+child.getSequenceLength() > testEnd) {
return child.findMappedFileLocation(sequenceNumber, length);
}
return super.findMappedFileLocation(sequenceNumber, length);
}
@Override
public boolean collectLocations(int sequenceNumber, final int length, ArrayList<IASTNodeLocation> locations) {
final int endSequenceNumber= sequenceNumber+length;
if (fChildren != null) {
int childIdx= Math.max(0, findChildIdxLessOrEqualThan(sequenceNumber, false));
for (; childIdx < fChildren.size(); childIdx++) {
final LocationCtx child= fChildren.get(childIdx);
// create the location between start and the child
if (sequenceNumber < child.fSequenceNumber) {
// compute offset backwards from the child's offset
final int offset= child.fEndOffsetInParent - (child.fSequenceNumber - sequenceNumber);
// it the child is not affected, we are done.
if (endSequenceNumber <= child.fSequenceNumber) {
addFileLocation(offset, endSequenceNumber-sequenceNumber, locations);
return true;
}
addFileLocation(offset, child.fOffsetInParent-offset, locations);
sequenceNumber= child.fSequenceNumber;
}
// let the child create locations
final int childEndSequenceNumber= child.fSequenceNumber + child.getSequenceLength();
if (sequenceNumber < childEndSequenceNumber) {
if (child.collectLocations(sequenceNumber, endSequenceNumber-sequenceNumber, locations)) {
return true;
}
sequenceNumber= childEndSequenceNumber;
}
}
}
// create the location after the last child.
final int myEndNumber = fSequenceNumber + getSequenceLength();
final int offset= fSource.length - (myEndNumber - sequenceNumber);
if (endSequenceNumber <= myEndNumber) {
addFileLocation(offset, endSequenceNumber-sequenceNumber, locations);
return true;
}
addFileLocation(offset, fSource.length-offset, locations);
return false;
}
private ArrayList<IASTNodeLocation> addFileLocation(int offset, int length, ArrayList<IASTNodeLocation> sofar) {
IASTFileLocation loc= createFileLocation(offset, length);
if (loc != null) {
sofar.add(loc);
}
return sofar;
}
ASTFileLocation createFileLocation(int start, int length) {
return null;
}
final int findChildIdxLessOrEqualThan(int sequenceNumber, boolean beforeReplacedChars) {
if (fChildren == null) {
return -1;
}
int upper= fChildren.size();
int lower= 0;
while (upper > lower) {
int middle= (upper+lower)/2;
LocationCtx child= fChildren.get(middle);
int childSequenceNumber= child.fSequenceNumber;
if (beforeReplacedChars) {
childSequenceNumber-= child.fEndOffsetInParent-child.fOffsetInParent;
}
if (childSequenceNumber <= sequenceNumber) {
lower= middle+1;
}
else {
upper= middle;
}
}
return lower-1;
}
final LocationCtx findChildLessOrEqualThan(final int sequenceNumber, boolean beforeReplacedChars) {
final int idx= findChildIdxLessOrEqualThan(sequenceNumber, beforeReplacedChars);
return idx >= 0 ? fChildren.get(idx) : null;
}
@Override
public void getInclusions(ArrayList<IASTInclusionNode> result) {
if (fChildren != null) {
for (LocationCtx ctx : fChildren) {
if (ctx.getInclusionStatement() != null) {
result.add(new ASTInclusionNode(ctx));
}
else {
ctx.getInclusions(result);
}
}
}
}
@Override
public int getLineNumber(int offset) {
if (fLineOffsets == null) {
fLineOffsets= computeLineOffsets();
}
int idx= Arrays.binarySearch(fLineOffsets, offset);
if (idx < 0) {
return -idx;
}
return idx+1;
}
private int[] computeLineOffsets() {
ArrayList<Integer> offsets= new ArrayList<Integer>();
for (int i = 0; i < fSource.length; i++) {
if (fSource[i] == '\n') {
offsets.add(new Integer(i));
}
}
int[] result= new int[offsets.size()];
for (int i = 0; i < result.length; i++) {
result[i]= offsets.get(i).intValue();
}
return result;
}
}